diff --git a/.env.example b/.env.example index 7752b76bf..be3163da5 100644 --- a/.env.example +++ b/.env.example @@ -7,14 +7,20 @@ # They are NOT managed by the Admin UI and are not stored in the database. # === First Install Token === -# if set the user is required to enter this token on the /first_install page +# If set the user is required to enter this token on the /first_install page # FIRST_INSTALL_TOKEN="myaccesstoken" +# === Security === +# When enabled (recommended), auth cookies require HTTPS and SSO will reject insecure HTTP. +AUTH_HTTPS_ONLY=true + # === Logging and Development === DEBUG=False DEBUG_DATABASE=False BUNDLE_ASSETS=True +# add `?profiler=true` to the url to enable the profiler for that request +PROFILER=False # logging into LNBITS_DATA_FOLDER/logs/ ENABLE_LOG_TO_FILE=true @@ -24,6 +30,10 @@ LOG_ROTATION="100 MB" LOG_RETENTION="3 months" # for database cleanup commands # CLEANUP_WALLETS_DAYS=90 +# Hard limit for total created users. Set to 0 to disable the limit. +# LNBITS_MAX_USERS=0 +# Hard limit for total installed extensions. Set to 0 to disable the limit. +# LNBITS_MAX_EXTENSIONS=0 # === Admin Settings === @@ -59,7 +69,7 @@ LNBITS_EXTENSIONS_DEFAULT_INSTALL="tpos" # LNBITS_EXT_GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxxxxxx # which fundingsources are allowed in the admin ui -# LNBITS_ALLOWED_FUNDING_SOURCES="VoidWallet, FakeWallet, CoreLightningWallet, CoreLightningRestWallet, LndRestWallet, EclairWallet, LndWallet, LnTipsWallet, LNPayWallet, LNbitsWallet, BlinkWallet, AlbyWallet, ZBDWallet, PhoenixdWallet, OpenNodeWallet, NWCWallet, BreezSdkWallet, BoltzWallet, StrikeWallet, CLNRestWallet, SparkWallet, SparkL2Wallet" +# LNBITS_ALLOWED_FUNDING_SOURCES="VoidWallet, FakeWallet, CoreLightningWallet, CoreLightningRestWallet, LndRestWallet, EclairWallet, LndWallet, LnTipsWallet, LNPayWallet, LNbitsWallet, BlinkWallet, AlbyWallet, BarkWallet, ZBDWallet, PhoenixdWallet, OpenNodeWallet, NWCWallet, BreezSdkWallet, BoltzWallet, StrikeWallet, CLNRestWallet, SparkWallet, SparkL2Wallet" # uvicorn variable, allow https behind a proxy # IMPORTANT: this also needs the webserver to be configured to forward the headers @@ -70,6 +80,9 @@ FORWARDED_ALLOW_IPS="*" # Inside this directory the `extensions` and `upgrades` sub-directories will be created. # LNBITS_EXTENSIONS_PATH="/path/to/some/dir" +# Path where WASM extensions will be installed (defaults to `LNBITS_DATA_FOLDER/wasm_extensions`). +# LNBITS_WASM_EXTENSIONS_PATH="/path/to/some/dir" + # ID of the super user. The user ID must exist. # SUPER_USER="" @@ -94,7 +107,7 @@ AUTH_SECRET_KEY="" ###################################### AUTH_TOKEN_EXPIRE_MINUTES=525600 -# Possible authorization methods: user-id-only, username-password, nostr-auth-nip98, google-auth, github-auth, keycloak-auth +# Possible authorization methods: user-id-only, username-password, nostr-auth-nip98, google-auth, github-auth, keycloak-auth, oidc-auth AUTH_ALLOWED_METHODS="user-id-only, username-password" # Set this flag if HTTP is used for OAuth # OAUTHLIB_INSECURE_TRANSPORT="1" @@ -109,6 +122,8 @@ LNBITS_SITE_TAGLINE="Open Source Lightning Payments Platform" LNBITS_SITE_DESCRIPTION="The world's most powerful suite of bitcoin tools. Run for yourself, for others, or as part of a stack." # Choose from bitcoin, mint, flamingo, freedom, salvador, autumn, monochrome, classic, cyber LNBITS_THEME_OPTIONS="classic, bitcoin, flamingo, freedom, mint, autumn, monochrome, salvador, cyber" +# Toggle the background styling on burger menus / drawers +# LNBITS_DEFAULT_BURGER_MENU_BACKGROUND=true # LNBITS_CUSTOM_LOGO="https://lnbits.com/assets/images/logo/logo.svg" ###################################### @@ -132,6 +147,10 @@ CLICHE_ENDPOINT=ws://127.0.0.1:12000 SPARK_URL=http://localhost:9737/rpc SPARK_TOKEN=myaccesstoken +# BarkWallet +BARK_API_ENDPOINT=http://localhost:3000 +BARK_API_TOKEN=auth_token + #CLNRest (using runes) CLNREST_URL=https://127.0.0.1:3010 CLNREST_CA=/home/lightningd/.lightning/bitcoin/ca.pem @@ -271,6 +290,50 @@ KEYCLOAK_DISCOVERY_URL="" KEYCLOAK_CLIENT_CUSTOM_ORG="" KEYCLOAK_CLIENT_CUSTOM_ICON="" +# OIDC OAuth Config +# Generic OIDC provider configuration +# Make sure that the redirect URI in your OIDC provider is set to: https://{domain}/api/v1/auth/oidc/token +# Required scopes: openid, email, profile +# The discovery URL must be accessible from your LNbits server +# Always use HTTPS in production environments +# The CUSTOM_ORG and CUSTOM_ICON settings allow you to customize the login button +# For example: "Login via Zitadel" with the Zitadel logo +OIDC_DISCOVERY_URL="" +OIDC_CLIENT_ID="" +OIDC_CLIENT_SECRET="" +OIDC_CLIENT_CUSTOM_ORG="" +OIDC_CLIENT_CUSTOM_ICON="" + +# Example OIDC configurations for various providers: +# +# ZITADEL: +# OIDC_DISCOVERY_URL=https://login.yourdomain.de/.well-known/openid-configuration +# OIDC_CLIENT_ID=your-zitadel-client-id@project-id +# OIDC_CLIENT_SECRET=your-zitadel-client-secret +# OIDC_CLIENT_CUSTOM_ORG=Zitadel +# OIDC_CLIENT_CUSTOM_ICON=/static/images/zitadel.png +# +# AUTHENTIK: +# OIDC_DISCOVERY_URL=https://authentik.yourdomain.com/application/o/lnbits/.well-known/openid-configuration +# OIDC_CLIENT_ID=your-authentik-client-id +# OIDC_CLIENT_SECRET=your-authentik-client-secret +# OIDC_CLIENT_CUSTOM_ORG=Authentik +# OIDC_CLIENT_CUSTOM_ICON=/static/images/authentik.png +# +# AUTHELIA: +# OIDC_DISCOVERY_URL=https://auth.yourdomain.com/.well-known/openid-configuration +# OIDC_CLIENT_ID=your-authelia-client-id +# OIDC_CLIENT_SECRET=your-authelia-client-secret +# OIDC_CLIENT_CUSTOM_ORG=Authelia +# OIDC_CLIENT_CUSTOM_ICON=/static/images/authelia.png +# +# OKTA: +# OIDC_DISCOVERY_URL=https://your-domain.okta.com/.well-known/openid-configuration +# OIDC_CLIENT_ID=your-okta-client-id +# OIDC_CLIENT_SECRET=your-okta-client-secret +# OIDC_CLIENT_CUSTOM_ORG=Okta +# OIDC_CLIENT_CUSTOM_ICON=/static/images/okta.png + ###################################### diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 9662b1065..84e27eea0 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -7,10 +7,6 @@ on: description: 'The tag name for the release' required: true type: string - upload_url: - description: 'The upload URL for the release' - required: true - type: string workflow_dispatch: inputs: @@ -18,10 +14,6 @@ on: description: 'The tag name for the release' required: true type: string - upload_url: - description: 'The upload URL for the release' - required: true - type: string jobs: build-linux-package: @@ -69,7 +61,10 @@ jobs: --onefile \ --name lnbits \ --hidden-import=embit \ + --hidden-import=bitstring.bitstore_bitarray \ --collect-all embit \ + --collect-all bitstring \ + --collect-all bitarray \ --collect-all lnbits \ --collect-all sqlalchemy \ --collect-all breez_sdk \ @@ -110,11 +105,6 @@ jobs: shell: bash - name: Upload Linux Release Asset - uses: actions/upload-release-asset@v1 - with: - upload_url: ${{ inputs.upload_url }} - asset_path: ${{ env.APPIMAGE_NAME }} - asset_name: ${{ env.APPIMAGE_NAME }} - asset_content_type: application/octet-stream env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload "${{ inputs.tag_name }}" "${{ env.APPIMAGE_NAME }}" --clobber diff --git a/.github/workflows/bundle.yml b/.github/workflows/bundle.yml new file mode 100644 index 000000000..a67045f7f --- /dev/null +++ b/.github/workflows/bundle.yml @@ -0,0 +1,33 @@ +name: bundle +on: + workflow_call: + +jobs: + bundle: + permissions: + contents: write + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.head_ref || github.event.pull_request.head.sha }} + - uses: lnbits/lnbits/.github/actions/prepare@dev + with: + python-version: "3.10" + node-version: "24.x" + npm: true + - name: Build and commit bundle (same-repo PR) + if: github.event.pull_request.head.repo.full_name == github.repository + run: | + make bundle + git config user.name "alan" + git config user.email "alan@lnbits.com" + git add lnbits/static + if git diff --cached --quiet; then + exit 0 + fi + git commit -m "chore: make bundle [skip ci]" + git push + - name: Check bundle is up-to-date (fork PR) + if: github.event.pull_request.head.repo.full_name != github.repository + run: make checkbundle diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1afd181fb..8aa8bcc94 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,9 @@ name: LNbits CI on: - push: - branches: - - main - - dev pull_request: jobs: - lint: uses: ./.github/workflows/lint.yml @@ -16,7 +11,7 @@ jobs: needs: [ lint ] strategy: matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.12"] db-url: ["", "postgres://lnbits:lnbits@0.0.0.0:5432/lnbits"] uses: ./.github/workflows/tests.yml with: @@ -30,7 +25,7 @@ jobs: needs: [ lint ] strategy: matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.12"] db-url: ["", "postgres://lnbits:lnbits@0.0.0.0:5432/lnbits"] uses: ./.github/workflows/tests.yml with: @@ -44,7 +39,7 @@ jobs: needs: [ lint ] strategy: matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.12"] db-url: ["", "postgres://lnbits:lnbits@0.0.0.0:5432/lnbits"] uses: ./.github/workflows/tests.yml with: @@ -58,7 +53,7 @@ jobs: needs: [ lint ] strategy: matrix: - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.10", "3.12"] uses: ./.github/workflows/migration.yml with: python-version: ${{ matrix.python-version }} @@ -69,12 +64,17 @@ jobs: with: make: openapi + test-e2e: + if: ${{ false }} + needs: [ lint ] + uses: ./.github/workflows/e2e.yml + regtest: needs: [ lint ] uses: ./.github/workflows/regtest.yml strategy: matrix: - python-version: ["3.10"] + python-version: ["3.12"] backend-wallet-class: - BoltzWallet - LndRestWallet @@ -94,7 +94,11 @@ jobs: needs: [ lint ] strategy: matrix: - python-version: ["3.10"] + python-version: ["3.12"] uses: ./.github/workflows/jmeter.yml with: python-version: ${{ matrix.python-version }} + + bundle: + needs: [ lint, test-api, test-wallets, test-unit, migration, openapi, regtest, jmeter ] + uses: ./.github/workflows/bundle.yml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 000000000..2cf395d1c --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,41 @@ +name: e2e + +on: + workflow_call: + workflow_dispatch: + +jobs: + test-e2e: + name: test-e2e (${{ matrix.name }}) + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + include: + - name: bigpayment + spec: tests/e2e/bigpayment.spec.ts + - name: paysplit + spec: tests/e2e/paysplit.spec.ts + - name: pingpong + spec: tests/e2e/pingpong.spec.ts + - name: tips + spec: tests/e2e/tips.spec.ts + + steps: + - uses: actions/checkout@v4 + - uses: lnbits/lnbits/.github/actions/prepare@dev + with: + python-version: "3.12" + node-version: "24.x" + npm: true + - name: Install Playwright browser + run: npm exec playwright install chromium + - name: Run ${{ matrix.name }} e2e tests + run: npm run test:e2e -- "${{ matrix.spec }}" + - name: Upload Playwright report + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-${{ matrix.name }} + path: test-reports + if-no-files-found: ignore diff --git a/.github/workflows/jmeter.yml b/.github/workflows/jmeter.yml index 19fe0008c..a2e29d5d1 100644 --- a/.github/workflows/jmeter.yml +++ b/.github/workflows/jmeter.yml @@ -22,6 +22,7 @@ jobs: - name: run LNbits env: LNBITS_ADMIN_UI: true + AUTH_HTTPS_ONLY: false LNBITS_EXTENSIONS_DEFAULT_INSTALL: "watchonly, satspay, tipjar, tpos, lnurlp, withdraw" LNBITS_BACKEND_WALLET_CLASS: FakeWallet run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 69313c4fd..4b3e4ff4a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,53 +6,30 @@ jobs: black: uses: ./.github/workflows/make.yml - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] with: make: checkblack - python-version: ${{ matrix.python-version }} ruff: uses: ./.github/workflows/make.yml - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] with: make: checkruff - python-version: ${{ matrix.python-version }} mypy: uses: ./.github/workflows/make.yml - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] with: make: mypy - python-version: ${{ matrix.python-version }} pyright: uses: ./.github/workflows/make.yml - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] with: make: pyright - python-version: ${{ matrix.python-version }} npm: true - prettier: uses: ./.github/workflows/make.yml with: make: checkprettier npm: true - bundle: - uses: ./.github/workflows/make.yml - with: - make: checkbundle - npm: true - poetry: uses: ./.github/workflows/poetry.yml diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 661d98011..7b6df407d 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -14,7 +14,7 @@ on: python-version: description: "python version" type: string - default: "3.10" + default: "3.12" jobs: make: @@ -22,7 +22,7 @@ jobs: strategy: matrix: os-version: ["ubuntu-24.04"] - node-version: ["18.x"] + node-version: ["24.x"] runs-on: ${{ matrix.os-version }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml index 8cb2bcc1c..53d0b95b6 100644 --- a/.github/workflows/regtest.yml +++ b/.github/workflows/regtest.yml @@ -8,7 +8,7 @@ on: required: true type: string python-version: - default: "3.10" + default: "3.12" type: string os-version: default: "ubuntu-24.04" @@ -66,6 +66,7 @@ jobs: BOLTZ_MNEMONIC: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about LNBITS_MAX_OUTGOING_PAYMENT_AMOUNT_SATS: 1000000000 LNBITS_MAX_INCOMING_PAYMENT_AMOUNT_SATS: 1000000000 + LNBITS_FUNDING_SOURCE_PAY_INVOICE_WAIT_SECONDS: ${{ inputs.backend-wallet-class == 'CoreLightningRestWallet' && 60 || 5 }} ECLAIR_PASS: lnbits PYTHONUNBUFFERED: 1 DEBUG: true diff --git a/.github/workflows/release-rc.yml b/.github/workflows/release-rc.yml index 9bf71caac..12fd0ffba 100644 --- a/.github/workflows/release-rc.yml +++ b/.github/workflows/release-rc.yml @@ -12,8 +12,6 @@ jobs: release: runs-on: ubuntu-24.04 - outputs: - upload_url: ${{ steps.get_upload_url.outputs.upload_url }} steps: - uses: actions/checkout@v4 - name: Create github pre-release @@ -22,14 +20,6 @@ jobs: tag: ${{ github.ref_name }} run: | gh release create "$tag" --prerelease --generate-notes --draft - - id: get_upload_url - name: Get upload url of Github release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ github.ref_name }} - run: | - upload_url=$(gh release view "$tag" --json uploadUrl -q ".uploadUrl") - echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT" docker: if: github.repository == 'lnbits/lnbits' @@ -74,4 +64,3 @@ jobs: uses: ./.github/workflows/appimage.yml with: tag_name: ${{ github.ref_name }} - upload_url: ${{ needs.release.outputs.upload_url }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03b7a952a..de16cd613 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,8 +13,6 @@ jobs: release: runs-on: ubuntu-24.04 - outputs: - upload_url: ${{ steps.get_upload_url.outputs.upload_url }} steps: - uses: actions/checkout@v4 - name: Create github release @@ -23,14 +21,6 @@ jobs: tag: ${{ github.ref_name }} run: | gh release create "$tag" --generate-notes --draft - - id: get_upload_url - name: Get upload url of Github release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - tag: ${{ github.ref_name }} - run: | - upload_url=$(gh release view "$tag" --json uploadUrl -q ".uploadUrl") - echo "upload_url=$upload_url" >> "$GITHUB_OUTPUT" docker: if: github.repository == 'lnbits/lnbits' @@ -85,4 +75,3 @@ jobs: uses: ./.github/workflows/appimage.yml with: tag_name: ${{ github.ref_name }} - upload_url: ${{ needs.release.outputs.upload_url }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5e77097e1..f5df593f6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: required: true type: string python-version: - default: "3.10" + default: "3.12" type: string os-version: default: "ubuntu-24.04" diff --git a/.gitignore b/.gitignore index 7790682cc..2b2c7c876 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__ *$py.class .mypy_cache .vscode +.codex *-lock.json .python-version diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..7253a5cee --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +min-release-age=7 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 621ed1dab..420a5e5dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,11 +14,11 @@ repos: - id: mixed-line-ending - id: check-case-conflict - repo: https://github.com/psf/black - rev: 25.1.0 + rev: 26.3.1 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.10 + rev: v0.14.10 hooks: - id: ruff args: [ --fix, --exit-non-zero-on-fix ] diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..eb4aba853 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,60 @@ +# AGENTS.md - AI Coding Agent Guide for LNbits + +This file guides AI coding agents working on LNbits. Keep changes small, verified, and aligned with existing project patterns. + +## Core Behavior + +- Think before coding. State material assumptions. Ask when ambiguity affects correctness, security, payments, wallets, or data migrations. +- Prefer the simplest implementation that solves the request. +- Make surgical changes. Every changed line should trace back to the task. +- Do not refactor, reformat, rename, or clean adjacent code unless required. +- Remove only dead code or imports created by your own changes. +- Define success criteria for non-trivial work and verify them before reporting done. + +## LNbits Architecture + +- Keep core lean. Prefer/assess extensions for non-core features. +- Preserve compatibility with existing extensions and wallet backends. +- Follow existing patterns in `lnbits/core`, `lnbits/wallets`, `lnbits/extensions`, and frontend code. +- Use existing CRUD, services, settings, and migration patterns. +- Do not edit generated files, bundled vendor files, or unrelated extension code. + +## Security-Sensitive Areas + +Be extra cautious with payments, wallet balances, admin routes, keys, LNURL, Bolt11, funding sources, migrations, and authentication. + +Do not expose raw stack traces or sensitive values. Do not add synchronous blocking work in hot async paths without justification. + +## Commands and Verification + +Read `Makefile` before running project commands. + +Use Makefile targets instead of hand-written commands when available: + +- `make check` for full checks. +- `make test-unit` for unit tests. +- `make test-api` for API tests. +- `make test-wallets` for wallet tests. +- `make checkbundle` when bundled frontend assets may be affected. +- `make format` only when formatting is intended. + +Do not run `make test` by default. Use the targeted tests available in the Makefile that are related to the work done, unless the user explicitly asks for broader test coverage. + +## Dependencies + +Do not add dependencies without approval. If approved, update the correct project files and explain why the dependency is necessary. + +## Maintenance + +LNbits maintainers own this file. They should update it when the development workflow, architecture, or verification commands materially change. + +Do not edit, commit, push, or include changes to this file in a PR as part of normal feature work unless the user explicitly asks for `AGENTS.md` changes. + +## Reporting + +When finished, report: + +- Summary of what changed. +- Files touched. +- Makefile targets or checks run. +- Anything not verified and why. diff --git a/Dockerfile b/Dockerfile index afb10c123..a430c9bae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,4 +43,4 @@ ENV LNBITS_HOST="0.0.0.0" EXPOSE 5000 -CMD ["sh", "-c", "uv run lnbits --port $LNBITS_PORT --host $LNBITS_HOST --forwarded-allow-ips='*'"] +CMD ["sh", "-c", "uv --offline run --no-sync lnbits --port $LNBITS_PORT --host $LNBITS_HOST --forwarded-allow-ips='*'"] diff --git a/Makefile b/Makefile index ff0effae0..48b903281 100644 --- a/Makefile +++ b/Makefile @@ -62,10 +62,15 @@ test-api: DEBUG=true \ uv run pytest tests/api +test-e2e: + npm exec playwright install chromium + npm run test:e2e + test-regtest: LNBITS_DATA_FOLDER="./tests/data" \ PYTHONUNBUFFERED=1 \ DEBUG=true \ + rm -rf ./tests/data \ uv run pytest tests/regtest test-migration: @@ -88,16 +93,36 @@ migration: uv run python tools/conv.py openapi: + @OPENAPI_SPEC_FILE=$$(mktemp); \ + OPENAPI_DATA_DIR=$$(mktemp -d); \ LNBITS_ADMIN_UI=False \ LNBITS_BACKEND_WALLET_CLASS="FakeWallet" \ - LNBITS_DATA_FOLDER="./tests/data" \ + LNBITS_DATA_FOLDER="$$OPENAPI_DATA_DIR" \ + LNBITS_EXTENSIONS_DEFAULT_INSTALL='[]' \ + LNBITS_EXTENSIONS_DEACTIVATE_ALL=true \ PYTHONUNBUFFERED=1 \ + DEBUG=false \ HOST=0.0.0.0 \ PORT=5003 \ - uv run lnbits & - sleep 15 - curl -s http://0.0.0.0:5003/openapi.json | uv run openapi-spec-validator --errors=all - - # kill -9 %1 + uv run lnbits & \ + OPENAPI_SERVER_PID=$$!; \ + trap 'kill "$$OPENAPI_SERVER_PID" 2>/dev/null || true; wait "$$OPENAPI_SERVER_PID" 2>/dev/null || true; rm -f "$$OPENAPI_SPEC_FILE"; rm -rf "$$OPENAPI_DATA_DIR"' EXIT; \ + OPENAPI_ATTEMPT=0; \ + while [ "$$OPENAPI_ATTEMPT" -lt 60 ]; do \ + if curl --fail --silent --max-time 2 --output "$$OPENAPI_SPEC_FILE" \ + http://127.0.0.1:5003/openapi.json; then \ + uv run openapi-spec-validator --errors=all "$$OPENAPI_SPEC_FILE"; \ + exit $$?; \ + fi; \ + if ! kill -0 "$$OPENAPI_SERVER_PID" 2>/dev/null; then \ + echo "LNbits exited before serving the OpenAPI schema." >&2; \ + exit 1; \ + fi; \ + OPENAPI_ATTEMPT=$$((OPENAPI_ATTEMPT + 1)); \ + sleep 1; \ + done; \ + echo "LNbits did not serve the OpenAPI schema within 60 seconds." >&2; \ + exit 1 bak: # LNBITS_DATABASE_URL=postgres://postgres:postgres@0.0.0.0:5432/postgres diff --git a/README.md b/README.md index 4a34df408..94cb3d02f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ - - LNbits + + LNbits -![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) [![license-badge]](LICENSE) [![docs-badge]][docs] ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [![explore: LNbits extensions](https://img.shields.io/badge/explore-LNbits%20extensions-10B981)](https://extensions.lnbits.com/) [![hardware: LNBitsShop](https://img.shields.io/badge/hardware-LNBitsShop-7C3AED)](https://shop.lnbits.com/) [](https://t.me/lnbits) [](https://opensats.org) -lnbits_head +![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) [![license-badge]](LICENSE) [![docs-badge]][docs] ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [![explore: LNbits extensions](https://img.shields.io/badge/explore-LNbits%20extensions-10B981)](https://extensions.lnbits.com/) [![hardware: LNBitsShop](https://img.shields.io/badge/hardware-LNBitsShop-7C3AED)](https://shop.lnbits.com/) [](https://t.me/lnbits) +lnbits_head [![tip-hero](https://img.shields.io/badge/TipJar-LNBits%20Hero-9b5cff?labelColor=6b7280&logo=lightning&logoColor=white)](https://demo.lnbits.com/tipjar/DwaUiE4kBX6mUW6pj3X5Kg) # LNbits — The most powerful Bitcoin & Lightning toolkit @@ -46,7 +46,7 @@ Get yourself familiar and test on our demo server [demo.lnbits.com](https://demo LNbits is packaged with tools to help manage funds, such as a table of transactions, line chart of spending, export to csv. Each wallet also comes with its own API keys, to help partition the exposure of your funding source. - +lnbits_wallet ## LNbits extension universe @@ -54,25 +54,25 @@ Extend YOUR LNbits to meet YOUR needs. All non-core features are installed as extensions, reducing your code base and making your LNbits unique to you. Extend your LNbits install in any direction, and even create and share your own extensions. - +lnbits_extensions ## LNbits API LNbits has a powerful API, many projects use LNbits to do the heavy lifting for their bitcoin/lightning services. - +lnbits_api ## LNbits node manager LNbits comes packaged with a light node management UI, to make running your node that much easier. - +lnbits_api -## LNbits across all your devices +## LNbits merchant tools -As well as working great in a browser, LNbits has native IoS and Android apps as well as a chrome extension. So you can enjoy the same UI across ALL your devices. +The LNbits stack can process both bitcoin and fiat payments, making it a turnkey, all-in-one solution for merchants. With orders and inventory shared across extensions, and built-in notifications for Nostr, Telegram, and email, LNbits keeps everything in sync, freeing merchants to focus on their business. - +lnbits_merchants ## Powered by LNbits diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..2d0d1b64b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,36 @@ +# Security Policy + +## Supported Versions + +Security fixes are provided for the current released version of LNbits and the +`dev` branch. Older releases and release candidates are not supported unless a +maintainer explicitly states otherwise. + +| Version | Supported | +| ------------------ | --------- | +| Current release | Yes | +| `dev` branch | Yes | +| Older releases | No | +| Release candidates | No | + +## Reporting a Vulnerability + +Please report suspected vulnerabilities privately using [GitHub's private +vulnerability reporting](https://github.com/lnbits/lnbits/security/advisories/new). +Do not open a public issue, discussion, or pull request for a security +vulnerability. + +Include enough detail for maintainers to reproduce and assess the issue, such +as the affected version or commit, configuration, steps to reproduce, impact, +and any proof of concept. Do not include credentials, API keys, wallet data, or +other sensitive information unless it is necessary and can be shared safely. + +Maintainers will acknowledge the report, investigate it, and coordinate a fix +and disclosure timeline with you. Please allow time for a fix to be prepared +before publicly disclosing the vulnerability. + +## Scope + +This policy covers the LNbits core repository and LNbits extensions in the LNbits GitHub organisation. Vulnerabilities in third-party +funding sources, dependencies or hosted LNbits instances may need to be reported to their respective maintainers or +operators as well. diff --git a/docs/assets/api.jpg b/docs/assets/api.jpg new file mode 100644 index 000000000..a4f6507c9 Binary files /dev/null and b/docs/assets/api.jpg differ diff --git a/docs/assets/extensions.jpg b/docs/assets/extensions.jpg new file mode 100644 index 000000000..d85d53a1d Binary files /dev/null and b/docs/assets/extensions.jpg differ diff --git a/docs/assets/header.jpg b/docs/assets/header.jpg new file mode 100644 index 000000000..51d6ff055 Binary files /dev/null and b/docs/assets/header.jpg differ diff --git a/docs/assets/lightning_node.jpg b/docs/assets/lightning_node.jpg new file mode 100644 index 000000000..59b3d3159 Binary files /dev/null and b/docs/assets/lightning_node.jpg differ diff --git a/docs/assets/merchants_small.webp b/docs/assets/merchants_small.webp new file mode 100644 index 000000000..3b8d6dd20 Binary files /dev/null and b/docs/assets/merchants_small.webp differ diff --git a/docs/assets/wallet.jpg b/docs/assets/wallet.jpg new file mode 100644 index 000000000..42580d748 Binary files /dev/null and b/docs/assets/wallet.jpg differ diff --git a/docs/guide/admin_ui.md b/docs/guide/admin_ui.md index f71019a28..a1fa1c7c9 100644 --- a/docs/guide/admin_ui.md +++ b/docs/guide/admin_ui.md @@ -14,7 +14,6 @@ nav_order: 1 ![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [](https://t.me/lnbits) -[](https://opensats.org) # LNBits Admin UI @@ -119,7 +118,7 @@ When set **at least one**, LNbits becomes private: only the listed users and Adm - **[Backend Wallets](./wallets.md)** — Explore options to fund your LNbits instance. - **[User Roles](./user_roles.md)** — Overview of existing roles in LNbits. - **[Funding sources](./funding-sources-table.md)** — What is available and how to configure each. -- **[Install LNBits](./installation.md)** — Choose your prefared way to install LNBits. +- **[Install LNbits](./installation.md)** — Choose your preferred way to install LNbits. ## Powered by LNbits diff --git a/docs/guide/funding-sources-table.md b/docs/guide/funding-sources-table.md index f8dd54c0a..420c791f5 100644 --- a/docs/guide/funding-sources-table.md +++ b/docs/guide/funding-sources-table.md @@ -14,7 +14,6 @@ nav_order: 1 ![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [](https://t.me/lnbits) -[](https://opensats.org) # Backend Wallet Comparison Table @@ -72,8 +71,8 @@ Spark L2 uses a local Node.js sidecar to expose an HTTP API that LNbits can use ## Additional Guides - **[Admin UI](./admin_ui.md)** — Manage server settings via a clean UI (avoid editing `.env` by hand). -- **[User Roles](./User_Roles.md)** — Quick Overview of existing Roles in LNBits. -- **[Funding sources](./funding-sources_table.md)** — What’s available and how to enable/configure each. +- **[User Roles](./user_roles.md)** — Quick Overview of existing Roles in LNBits. +- **[Backend Wallets](./wallets.md)** — Explore options to fund your LNbits instance. ## Powered by LNbits diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 4e4e08b67..4ade1877e 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -11,7 +11,7 @@ nav_order: 1 -![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![License: MIT](https://img.shields.io/badge/License-MIT-blue) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [![explore: LNbits extensions](https://img.shields.io/badge/explore-LNbits%20extensions-10B981)](https://extensions.lnbits.com/) [](https://t.me/lnbits) +![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![License: MIT](https://img.shields.io/badge/License-MIT-blue) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [![explore: LNbits extensions](https://img.shields.io/badge/explore-LNbits%20extensions-10B981)](https://extensions.lnbits.com/) [](https://t.me/lnbits) # Basic installation @@ -51,7 +51,7 @@ nav_order: 1 sudo apt-get install jq libfuse2 wget $(curl -s https://api.github.com/repos/lnbits/lnbits/releases/latest | jq -r '.assets[] | select(.name | endswith(".AppImage")) | .browser_download_url') -O LNbits-latest.AppImage chmod +x LNbits-latest.AppImage -LNBITS_ADMIN_UI=true HOST=0.0.0.0 PORT=5000 ./LNbits-latest.AppImage # most system settings are now in the admin UI, but pass additional .env variables here +LNBITS_ADMIN_UI=true HOST=0.0.0.0 PORT=5000 AUTH_HTTPS_ONLY=false ./LNbits-latest.AppImage # most system settings are now in the admin UI, but pass additional .env variables here ``` - LNbits will create a folder for DB and extension files **in the same directory** as the AppImage. @@ -285,10 +285,7 @@ but you can also set the env variables or pass command line arguments: ```sh # .env variables are currently passed when running, but LNbits can be managed with the admin UI. -LNBITS_ADMIN_UI=true ./result/bin/lnbits --port 9000 --host 0.0.0.0 - -# Once you have created a user, you can set as the super_user -SUPER_USER=be54db7f245346c8833eaa430e1e0405 LNBITS_ADMIN_UI=true ./result/bin/lnbits --port 9000 +LNBITS_ADMIN_UI=true AUTH_HTTPS_ONLY=false ./result/bin/lnbits --port 9000 --host 0.0.0.0 ``` > ![NOTE](https://img.shields.io/badge/NOTE-3b82f6?labelColor=494949) diff --git a/docs/guide/oidc-authentication.md b/docs/guide/oidc-authentication.md new file mode 100644 index 000000000..da371c1ba --- /dev/null +++ b/docs/guide/oidc-authentication.md @@ -0,0 +1,139 @@ +# Generic OIDC Authentication Configuration + +This document explains how to configure generic OIDC authentication for LNbits, which allows integration with various OIDC-compliant authentication providers such as Zitadel, Authentik, and others. + +## Overview + +The generic OIDC provider (`oidc`) complements the existing Keycloak provider and allows you to integrate any OIDC-compliant authentication service. You can customize the login button with your own organization name and icon. + +## Configuration + +Add the following environment variables to your `.env` file or system environment: + +### Required Settings + +```bash +# Enable OIDC authentication +LNBITS_AUTH_ALLOWED_METHODS=oidc-auth + +# OIDC Discovery URL (well-known endpoint) +LNBITS_OIDC_DISCOVERY_URL=https://your-oidc-provider-domain/.well-known/openid-configuration + +# Client credentials from your OIDC provider +LNBITS_OIDC_CLIENT_ID=your-client-id +LNBITS_OIDC_CLIENT_SECRET=your-client-secret +``` + +### Optional Settings - Customize the Login Button + +You can customize how the OIDC login button appears to your users: + +```bash +# Custom organization name (displayed on the login button) +# Example: "Login via Zitadel" or "Login via Authentik" +LNBITS_OIDC_CLIENT_CUSTOM_ORG="Zitadel" + +# Custom icon URL (displayed on the login button) +# Can be a full URL or a path to a local image +LNBITS_OIDC_CLIENT_CUSTOM_ICON=https://zitadel.com/favicon.svg +``` + +If not set, the button will display "Login via OIDC" with a generic lock icon. + +## Zitadel Configuration Example + +For Zitadel, configure as follows: + +1. Create a new application in Zitadel +2. Choose "Web" application type +3. Configure the redirect URI: `https://your-lnbits-domain/api/v1/auth/oidc/token` +4. Save the Client ID and Client Secret +5. Use these environment variables: + +```bash +LNBITS_AUTH_ALLOWED_METHODS=oidc-auth +LNBITS_OIDC_DISCOVERY_URL=https://your-oidc-provider-domain/.well-known/openid-configuration +LNBITS_OIDC_CLIENT_ID=your-zitadel-client-id +LNBITS_OIDC_CLIENT_SECRET=your-zitadel-client-secret +# Customize the button to show "Login via Zitadel" with Zitadel's logo +LNBITS_OIDC_CLIENT_CUSTOM_ORG="Zitadel" +LNBITS_OIDC_CLIENT_CUSTOM_ICON="https://zitadel.com/favicon.svg" +``` + +**Result**: The login page will display a button with the text "Login via Zitadel" and the Zitadel logo. + +## Authentik Configuration Example + +For Authentik: + +1. Create a new OAuth2/OpenID Provider +2. Set the redirect URI: `https://your-lnbits-domain/api/v1/auth/oidc/token` +3. Configure scopes: `openid`, `email`, `profile` +4. Get the Client ID and Client Secret + +```bash +LNBITS_AUTH_ALLOWED_METHODS=oidc-auth +LNBITS_OIDC_DISCOVERY_URL=https://authentik.yourdomain.com/application/o/your-app/.well-known/openid-configuration +LNBITS_OIDC_CLIENT_ID=your-authentik-client-id +LNBITS_OIDC_CLIENT_SECRET=your-authentik-client-secret +LNBITS_OIDC_CLIENT_CUSTOM_ORG="Authentik" +``` + +## Multiple Auth Methods + +You can enable multiple authentication methods simultaneously: + +```bash +LNBITS_AUTH_ALLOWED_METHODS=username-password,oidc-auth,keycloak-auth +``` + +## Discovery Endpoint Requirements + +Your OIDC provider must expose a standard discovery endpoint (`.well-known/openid-configuration`) that includes: + +- `authorization_endpoint` +- `token_endpoint` +- `userinfo_endpoint` +- `jwks_uri` (JSON Web Key Set) + +The OIDC implementation will automatically fetch these endpoints from the discovery URL. + +## User Mapping + +The OIDC provider maps user information from the OIDC userinfo endpoint: + +- `sub` → User ID +- `email` → Email address +- `given_name` → First name +- `family_name` → Last name +- `name` or `preferred_username` → Display name +- `picture` → Profile picture URL + +## Troubleshooting + +### Authentication fails + +1. Verify the discovery URL is accessible +2. Check that Client ID and Client Secret are correct +3. Ensure redirect URI in your OIDC provider matches: `https://your-lnbits-domain/api/v1/auth/oidc/token` +4. Check LNbits logs for detailed error messages + +### User info not populated + +Some OIDC providers may use different claim names. If user information is not correctly populated, check your provider's userinfo endpoint response format and adjust the provider class if needed. + +## Security Considerations + +- Always use HTTPS in production +- Keep client secrets secure and never commit them to version control +- Use environment variables or secure configuration management +- Regularly rotate client secrets +- Review OIDC provider's security best practices + +## Implementation Details + +The OIDC provider is implemented in `lnbits/core/models/sso/oidc.py` and extends the `fastapi_sso` library's `SSOBase` class. It uses the standard OpenID Connect flow with: + +- Scopes: `openid`, `email`, `profile` +- Response type: `code` (authorization code flow) +- Discovery document for automatic endpoint resolution diff --git a/docs/guide/super_user.md b/docs/guide/super_user.md index f7b0db186..8aa8935c6 100644 --- a/docs/guide/super_user.md +++ b/docs/guide/super_user.md @@ -14,7 +14,6 @@ nav_order: 1 ![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [](https://t.me/lnbits) -[](https://opensats.org) # LNbits Super User (SU) @@ -43,7 +42,7 @@ nav_order: 1 The **Super User** is the owner-operator account of an LNbits instance. Think of it as your “break glass” operator with a few capabilities that are intentionally reserved for the person ultimately responsible for the server and the funding rails. -The SU is created alongside the [Admin UI](./admin_ui.md) and is meant to keep enviroment operations pleasant in the UI while keeping the most sensitive knobs in trusted hands. +The SU is created alongside the [Admin UI](./admin_ui.md) and is meant to keep environment operations pleasant in the UI while keeping the most sensitive knobs in trusted hands. **Key SU capabilities** @@ -118,7 +117,7 @@ These are practical tips for running a safe and friendly instance. - **[Admin UI](./admin_ui.md)** — Manage server settings in the browser instead of editing `.env` or using the CLI for routine tasks. - **[User Roles](./user_roles.md)** — Overview of roles and what they can do. - **[Funding sources](./funding-sources-table.md)** — Available options and how to enable and configure them. -- **[Install LNBits](./installation.md)** — Choose your prefared way to install LNBits. +- **[Install LNbits](./installation.md)** — Choose your preferred way to install LNbits. ## Powered by LNbits diff --git a/docs/guide/user_roles.md b/docs/guide/user_roles.md index 39b42442d..3abbfe3f6 100644 --- a/docs/guide/user_roles.md +++ b/docs/guide/user_roles.md @@ -14,7 +14,6 @@ nav_order: 1 ![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [](https://t.me/lnbits) -[](https://opensats.org) # LNbits Roles: A Quick Overview diff --git a/docs/guide/wallets.md b/docs/guide/wallets.md index 0d3991ff1..eb9bc4f6c 100644 --- a/docs/guide/wallets.md +++ b/docs/guide/wallets.md @@ -14,7 +14,6 @@ nav_order: 3 ![phase: stable](https://img.shields.io/badge/phase-stable-2EA043) ![PRs: welcome](https://img.shields.io/badge/PRs-Welcome-yellow) [](https://t.me/lnbits) -[](https://opensats.org) # Backend wallets @@ -42,7 +41,7 @@ A backend wallet is selected and configured entirely through LNbits environment | [CoreLightning REST](#corelightning-rest) | [LNbits](#lnbits) | [Alby](#alby) | | [Spark (Core Lightning)](#spark-core-lightning) | [LNPay](#lnpay) | [Boltz](#boltz) | | [Spark L2](#spark-l2) | [ZBD](#zbd) | [Phoenixd](#phoenixd) | -| [Cliche Wallet](#cliche-wallet) | | | +| [Cliche Wallet](#cliche-wallet) | [Bark](#bark) | | | [Breez SDK](#breez-sdk) | [Breez Liquid SDK](#breez-liquid-sdk) | [Nostr Wallet Connect](#nostr-wallet-connect-nwc) | | [Strike](#strike) | [Eclair (ACINQ)](#eclair-acinq) | [LN.tips](#lntips) | | [Fake Wallet](#fake-wallet) | | | @@ -128,6 +127,22 @@ Old REST interface using [RTL c-lightning-REST](https://github.com/Ride-The-Ligh - `SPARK_URL`: `http://10.147.17.230:9737/rpc` - `SPARK_TOKEN`: `secret_access_key` +## Bark + +This connects LNbits to an external [barkd](https://second.tech/docs/barkd) REST daemon. Initialize the Bark wallet before starting LNbits using `bark create`, then run `barkd` separately, keep its data directory persistent, and set `BARK_API_TOKEN` to the auth token from `~/.bark/auth_token`. + +**Required env vars** + +- `LNBITS_BACKEND_WALLET_CLASS`: `BarkWallet` +- `BARK_API_ENDPOINT`: `http://localhost:3000` +- `BARK_API_TOKEN`: `auth_token` + +Bark fee estimates can be higher than LNbits' default minimum routing fee reserve. If small outgoing payments fail with an error like `fee of 20000 msat exceeds limit of 5000 msat`, raise the minimum reserve fee under **Settings → Funding** or set: + +```bash +LNBITS_RESERVE_FEE_MIN=20000 +``` + ## Spark L2 Self-custodial funding source using the [Spark L2](https://docs.spark.money/start/overview) network. Requires a Node.js [sidecar](https://github.com/lnbits/spark_sidecar) that bridges lnbits talking to Spark. Works in addition with any Spark-compatible seed (Wallet of Satoshi, BuhoGO, BlitzWallet). @@ -198,7 +213,7 @@ uv run lnbits-cli encrypt macaroon ## LNPay -For the invoice listener to work you must have a publicly accessible URL in your LNbits and set up [LNPay webhooks](https://dashboard.lnpay.co/webhook/) pointing to `/wallet/webhook` with the event **Wallet Receive** and no secret. Example: [https://mylnbits/wallet/webhook](`https://mylnbits/wallet/webhook). +For the invoice listener to work you must have a publicly accessible URL in your LNbits and set up [LNPay webhooks](https://dashboard.lnpay.co/webhook/) pointing to `/wallet/webhook` with the event **Wallet Receive** and no secret. Example: `https://mylnbits.example/wallet/webhook`. **Required env vars** diff --git a/lnbits/app.py b/lnbits/app.py index a00d71577..d930caba5 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -23,29 +23,44 @@ from lnbits.core.crud import ( get_installed_extensions, update_installed_extension_state, ) +from lnbits.core.crud.audit import delete_expired_audit_entries from lnbits.core.crud.extensions import create_installed_extension from lnbits.core.helpers import migrate_extension_database from lnbits.core.models.notifications import NotificationType from lnbits.core.services.extensions import deactivate_extension, get_valid_extensions -from lnbits.core.services.notifications import enqueue_admin_notification -from lnbits.core.services.payments import check_pending_payments +from lnbits.core.services.funding_source import ( + check_balance_delta_changed, + check_server_balance_against_node, +) +from lnbits.core.services.notifications import ( + dispatch_payment_notification, + enqueue_admin_notification, + process_next_notification, +) +from lnbits.core.services.payments import ( + check_pending_payments, + fundingsource_invoice_producer, +) from lnbits.core.tasks import ( audit_queue, collect_exchange_rates_data, - purge_audit_data, - run_by_the_minute_tasks, - wait_for_audit_data, - wait_for_paid_invoices, - wait_notification_messages, + notify_server_status, + process_next_audit_entry, + refresh_extension_cache, +) +from lnbits.core.wasm_ext.routes.register import ( + register_wasm_extension, + unregister_wasm_extension, +) +from lnbits.core.wasm_ext.wasm.events import dispatch_wasm_invoice_paid +from lnbits.core.wasm_ext.wasm.loader import ( + is_wasm_extension_dir, + is_wasm_extension_id, ) from lnbits.exceptions import register_exception_handlers from lnbits.helpers import version_parse +from lnbits.llms_txt import create_llms_txt_route from lnbits.settings import settings -from lnbits.tasks import ( - cancel_all_tasks, - create_permanent_task, - register_invoice_listener, -) from lnbits.utils.cache import cache from lnbits.utils.logger import ( configure_logger, @@ -65,9 +80,10 @@ from .middleware import ( InstalledExtensionMiddleware, add_first_install_middleware, add_ip_block_middleware, + add_profiler_middleware, add_ratelimit_middleware, ) -from .tasks import internal_invoice_listener, invoice_listener, run_interval +from .task_manager import task_manager async def startup(app: FastAPI): @@ -101,6 +117,9 @@ async def startup(app: FastAPI): # register core routes init_core_routers(app) + # register llms.txt endpoint for AI agents + create_llms_txt_route(app) + # initialize tasks register_async_tasks() @@ -128,7 +147,7 @@ async def shutdown(): settings.lnbits_running = False # shutdown event - cancel_all_tasks() + task_manager.cancel_all_tasks() # wait a bit to allow them to finish, so that cleanup can run without problems await asyncio.sleep(0.1) @@ -161,6 +180,8 @@ def create_app() -> FastAPI: # Allow registering new extensions routes without direct access to the `app` object core_app_extra.register_new_ext_routes = register_new_ext_routes(app) + core_app_extra.register_new_wasm_ext_routes = register_new_wasm_ext_routes(app) + core_app_extra.unregister_wasm_ext_routes = unregister_wasm_ext_routes(app) core_app_extra.register_new_ratelimiter = register_new_ratelimiter(app) # register static files @@ -196,6 +217,9 @@ def create_app() -> FastAPI: register_exception_handlers(app) + if settings.profiler: + add_profiler_middleware(app) + return app @@ -289,7 +313,30 @@ async def build_all_installed_extensions_list( # noqa: C901 installed_extensions = await get_installed_extensions() settings.lnbits_installed_extensions_ids = {e.id for e in installed_extensions} - for ext_dir in Path(settings.lnbits_extensions_path, "extensions").iterdir(): + settings.wasm_extensions_dir.mkdir(parents=True, exist_ok=True) + for ext_dir in settings.wasm_extensions_dir.iterdir(): + try: + if not ext_dir.is_dir() or not is_wasm_extension_dir(ext_dir): + continue + ext_id = ext_dir.name + if ext_id in settings.lnbits_installed_extensions_ids: + continue + ext_info = InstallableExtension.from_wasm_ext_dir(ext_id) + if not ext_info: + continue + + installed_extensions.append(ext_info) + settings.lnbits_installed_extensions_ids.add(ext_id) + await create_installed_extension(ext_info) + current_version = await get_db_version(ext_id) + await migrate_extension_database(ext_info, current_version) + + except Exception as e: + logger.warning(e) + + ext_dir_path = Path(settings.lnbits_extensions_path, "extensions") + existing_ext_dirs = ext_dir_path.iterdir() if ext_dir_path.is_dir() else [] + for ext_dir in existing_ext_dirs: try: if not ext_dir.is_dir(): continue @@ -344,14 +391,18 @@ async def build_all_installed_extensions_list( # noqa: C901 async def check_installed_extension_files(ext: InstallableExtension) -> bool: - if ext.has_installed_version: + if ext.is_wasm or ext.has_installed_version: return True zip_files = glob.glob(os.path.join(settings.lnbits_data_folder, "zips", "*.zip")) if f"./{ext.zip_path!s}" not in zip_files: await ext.download_archive() - ext.extract_archive() + archive_config = ext.load_archive_config() + if archive_config.get("extension_type") == "wasm": + ext.extract_wasm_archive() + else: + ext.extract_archive() return False @@ -373,7 +424,6 @@ def register_custom_extensions_path(): upgrades_dir = settings.lnbits_extensions_upgrade_path shutil.rmtree(upgrades_dir, True) Path(upgrades_dir).mkdir(parents=True, exist_ok=True) - sys.path.append(str(upgrades_dir)) if settings.has_default_extension_path: return @@ -392,6 +442,7 @@ def register_custom_extensions_path(): extensions_dir = Path(settings.lnbits_extensions_path, "extensions") Path(extensions_dir).mkdir(parents=True, exist_ok=True) sys.path.append(str(extensions_dir)) + settings.wasm_extensions_dir.mkdir(parents=True, exist_ok=True) def register_new_ext_routes(app: FastAPI) -> Callable: @@ -404,6 +455,20 @@ def register_new_ext_routes(app: FastAPI) -> Callable: return register_new_ext_routes_fn +def register_new_wasm_ext_routes(app: FastAPI) -> Callable: + def register_new_wasm_ext_routes_fn(ext_id: str): + register_wasm_extension(app, ext_id) + + return register_new_wasm_ext_routes_fn + + +def unregister_wasm_ext_routes(app: FastAPI) -> Callable: + def unregister_wasm_ext_routes_fn(ext_id: str): + unregister_wasm_extension(app, ext_id) + + return unregister_wasm_ext_routes_fn + + def register_new_ratelimiter(app: FastAPI) -> Callable: def register_new_ratelimiter_fn(): limiter = Limiter( @@ -428,10 +493,54 @@ def register_ext_tasks(ext: Extension) -> None: def register_ext_routes(app: FastAPI, ext: Extension) -> None: """Register FastAPI routes for extension.""" - ext_module = importlib.import_module(ext.module_name) + module_name = ext.module_name + # Clear all cached sub-modules so a fresh import picks up new files from ext_dir. + # A simple reload() would reuse cached sub-modules (e.g. views_api) and serve + # stale code even after the extension files have been replaced on disk. + stale = [ + k for k in sys.modules if k == module_name or k.startswith(f"{module_name}.") + ] + for k in stale: + del sys.modules[k] + if stale: + # Pydantic v1 keeps a global _FUNCS set of validator qualnames to detect + # duplicates. Clear the extension's entries so reimport doesn't raise + # "duplicate validator" errors for validators with the same qualname. + try: + import pydantic.class_validators as _pydantic_cv + + _pydantic_cv._FUNCS = { + f for f in _pydantic_cv._FUNCS if not f.startswith(f"{module_name}.") + } + except (ImportError, AttributeError): + pass + ext_module = importlib.import_module(module_name) ext_route = getattr(ext_module, f"{ext.code}_ext") + ext_redirects = ( + getattr(ext_module, f"{ext.code}_redirect_paths") + if hasattr(ext_module, f"{ext.code}_redirect_paths") + else [] + ) + + settings.activate_extension_paths(ext.code, ext_redirects) + + # Remove existing routes for this extension before re-registering so that + # an upgraded extension replaces the old one at the same paths (no prefix). + ext_prefix = f"/{ext.code}" + app.router.routes = [ + r + for r in app.router.routes + if not ( + getattr(r, "path", "") == ext_prefix + or getattr(r, "path", "").startswith(f"{ext_prefix}/") + ) + ] + # Invalidate FastAPI's cached OpenAPI schema so the next /openapi.json + # request reflects the updated routes. + app.openapi_schema = None + if hasattr(ext_module, f"{ext.code}_static_files"): ext_statics = getattr(ext_module, f"{ext.code}_static_files") for s in ext_statics: @@ -440,49 +549,66 @@ def register_ext_routes(app: FastAPI, ext: Extension) -> None: ) app.mount(s["path"], StaticFiles(directory=static_dir), s["name"]) - ext_redirects = ( - getattr(ext_module, f"{ext.code}_redirect_paths") - if hasattr(ext_module, f"{ext.code}_redirect_paths") - else [] - ) - - settings.activate_extension_paths(ext.code, ext.upgrade_hash, ext_redirects) - logger.trace(f"Adding route for extension {ext_module}.") - prefix = f"/upgrades/{ext.upgrade_hash}" if ext.upgrade_hash != "" else "" - app.include_router(router=ext_route, prefix=prefix) + app.include_router(router=ext_route) async def check_and_register_extensions(app: FastAPI) -> None: await check_installed_extensions(app) for ext in await get_valid_extensions(False): try: + if is_wasm_extension_id(ext.code): + register_wasm_extension(app, ext.code) + continue register_ext_routes(app, ext) register_ext_tasks(ext) except Exception as exc: logger.error(f"Could not load extension `{ext.code}`: {exc!s}") + await update_installed_extension_state(ext_id=ext.code, active=False) def register_async_tasks() -> None: + task_manager.init() - create_permanent_task(wait_for_audit_data) - create_permanent_task(wait_notification_messages) + # listen to all incoming payments and dispatch payment notifications + # note: should be the first in task list for a bit quicker notifications + task_manager.register_invoice_listener(dispatch_payment_notification, "core") - create_permanent_task(run_interval(30 * 60, check_pending_payments)) - create_permanent_task(invoice_listener) - create_permanent_task(internal_invoice_listener) - create_permanent_task(cache.invalidate_forever) + # periodic tasks + task_manager.create_permanent_task(cache.invalidate_cache, interval=10) + task_manager.create_permanent_task(delete_expired_audit_entries, interval=60 * 60) + task_manager.create_permanent_task( + check_pending_payments, + interval=settings.lnbits_funding_source_pending_interval_seconds, + ) + task_manager.create_permanent_task( + collect_exchange_rates_data, + interval=max(60, settings.lnbits_exchange_history_refresh_interval_seconds), + ) + task_manager.create_permanent_task(check_balance_delta_changed, interval=60) + task_manager.create_permanent_task( + check_server_balance_against_node, + interval=60 * settings.lnbits_watchdog_interval_minutes, + ) + task_manager.create_permanent_task( + notify_server_status, + interval=60 * 60 * settings.lnbits_notification_server_status_hours, + ) + task_manager.create_permanent_task(refresh_extension_cache, interval=60) - # core invoice listener - invoice_queue: asyncio.Queue = asyncio.Queue() - register_invoice_listener(invoice_queue, "core") - create_permanent_task(lambda: wait_for_paid_invoices(invoice_queue)) + # permanent tasks run in a loop, will be restarted if they fail + task_manager.create_permanent_task(fundingsource_invoice_producer) + task_manager.create_permanent_task(process_next_notification) + task_manager.create_permanent_task(process_next_audit_entry) - create_permanent_task(run_by_the_minute_tasks) - create_permanent_task(purge_audit_data) - create_permanent_task(collect_exchange_rates_data) + async def dispatch_extension_invoice_paid(payment) -> None: + await dispatch_wasm_invoice_paid(payment) + + task_manager.register_invoice_listener(dispatch_extension_invoice_paid, "core_wasm") # server logs for websocket if settings.lnbits_admin_ui: server_log_task = initialize_server_websocket_logger() - create_permanent_task(server_log_task) + task_manager.create_permanent_task( + server_log_task, name="server_websocket_logger" + ) diff --git a/lnbits/commands.py b/lnbits/commands.py index 87c8ddff9..6070a003e 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -1,6 +1,5 @@ import asyncio import importlib -import sys import time from functools import wraps from getpass import getpass @@ -377,10 +376,6 @@ async def extensions_update( # noqa: C901 if not await _can_run_operation(url): return - upgrades_dir = settings.lnbits_extensions_upgrade_path - Path(upgrades_dir).mkdir(parents=True, exist_ok=True) - sys.path.append(str(upgrades_dir)) - if extension: await update_extension(extension, repo_index, source_repo, url, admin_user) return diff --git a/lnbits/core/__init__.py b/lnbits/core/__init__.py index ff2587aed..a0804cb1e 100644 --- a/lnbits/core/__init__.py +++ b/lnbits/core/__init__.py @@ -6,6 +6,7 @@ from .views.api import api_router from .views.asset_api import asset_router from .views.audit_api import audit_router from .views.auth_api import auth_router +from .views.blockexplorer_api import blockexplorer_router from .views.callback_api import callback_router from .views.extension_api import extension_router from .views.extensions_builder_api import extension_builder_router @@ -20,7 +21,7 @@ from .views.tinyurl_api import tinyurl_router from .views.user_api import users_router from .views.wallet_api import wallet_router from .views.webpush_api import webpush_router -from .views.websocket_api import websocket_router +from .views.websocket_api import extension_websocket_router, websocket_router # backwards compatibility for extensions core_app = APIRouter(tags=["Core"]) @@ -33,6 +34,7 @@ def init_core_routers(app: FastAPI): app.include_router(admin_router) app.include_router(node_router) app.include_router(extension_router) + app.include_router(extension_websocket_router) app.include_router(extension_builder_router) app.include_router(super_node_router) app.include_router(public_node_router) @@ -48,6 +50,7 @@ def init_core_routers(app: FastAPI): app.include_router(asset_router) app.include_router(fiat_router) app.include_router(lnurl_router) + app.include_router(blockexplorer_router) __all__ = ["core_app", "core_app_extra", "db"] diff --git a/lnbits/core/crud/__init__.py b/lnbits/core/crud/__init__.py index 2108d23d5..cb381dce2 100644 --- a/lnbits/core/crud/__init__.py +++ b/lnbits/core/crud/__init__.py @@ -12,18 +12,19 @@ from .extensions import ( drop_extension_db, get_installed_extension, get_installed_extensions, + get_installed_extensions_count, get_user_active_extensions_ids, get_user_extension, get_user_extensions, update_installed_extension, update_installed_extension_state, + update_installed_extension_wasm_runtime_limits, update_user_extension, ) from .payments import ( DateTrunc, check_internal, create_payment, - delete_expired_invoices, delete_wallet_payment, get_latest_payments_by_extension, get_payment, @@ -58,6 +59,7 @@ from .users import ( get_account_by_username, get_account_by_username_or_email, get_accounts, + get_accounts_count, get_user, get_user_access_control_lists, get_user_from_account, @@ -100,7 +102,6 @@ __all__ = [ "delete_accounts_no_wallets", "delete_admin_settings", "delete_dbversion", - "delete_expired_invoices", "delete_installed_extension", "delete_tinyurl", "delete_unused_wallets", @@ -117,11 +118,13 @@ __all__ = [ "get_account_by_username", "get_account_by_username_or_email", "get_accounts", + "get_accounts_count", "get_admin_settings", "get_db_version", "get_db_versions", "get_installed_extension", "get_installed_extensions", + "get_installed_extensions_count", "get_latest_payments_by_extension", "get_payment", "get_payments", @@ -152,6 +155,7 @@ __all__ = [ "update_admin_settings", "update_installed_extension", "update_installed_extension_state", + "update_installed_extension_wasm_runtime_limits", "update_migration_version", "update_payment", "update_payment_checking_id", diff --git a/lnbits/core/crud/extensions.py b/lnbits/core/crud/extensions.py index e4fbd7e80..7348f7f3d 100644 --- a/lnbits/core/crud/extensions.py +++ b/lnbits/core/crud/extensions.py @@ -1,7 +1,12 @@ +import json +from datetime import datetime, timedelta, timezone + from lnbits.core.db import db from lnbits.core.models.extensions import ( InstallableExtension, UserExtension, + WasmInvocation, + WasmInvocationStats, ) from lnbits.db import Connection, Database @@ -11,6 +16,11 @@ async def create_installed_extension( conn: Connection | None = None, ) -> None: await (conn or db).insert("installed_extensions", ext) + await update_installed_extension_wasm_runtime_limits( + ext_id=ext.id, + limits=ext.wasm_runtime_limits, + conn=conn, + ) async def update_installed_extension( @@ -18,6 +28,11 @@ async def update_installed_extension( conn: Connection | None = None, ) -> None: await (conn or db).update("installed_extensions", ext) + await update_installed_extension_wasm_runtime_limits( + ext_id=ext.id, + limits=ext.wasm_runtime_limits, + conn=conn, + ) async def update_installed_extension_state( @@ -31,6 +46,33 @@ async def update_installed_extension_state( ) +async def update_installed_extension_wasm_runtime_limits( + *, ext_id: str, limits: dict, conn: Connection | None = None +) -> None: + if not await _has_installed_extension_wasm_runtime_limits_column(conn=conn): + return + + await (conn or db).execute( + """ + UPDATE installed_extensions + SET wasm_runtime_limits = :limits + WHERE id = :id + """, + {"id": ext_id, "limits": json.dumps(limits)}, + ) + + +async def _has_installed_extension_wasm_runtime_limits_column( + conn: Connection | None = None, +) -> bool: + row: dict | None = await (conn or db).fetchone( + "SELECT version FROM dbversions WHERE db = 'core'" + ) + if not row: + return False + return int(row["version"] or 0) >= 48 + + async def delete_installed_extension( *, ext_id: str, conn: Connection | None = None ) -> None: @@ -90,6 +132,13 @@ async def get_installed_extensions( return all_extensions +async def get_installed_extensions_count(conn: Connection | None = None) -> int: + row: dict | None = await (conn or db).fetchone( + "SELECT COUNT(*) as count FROM installed_extensions" + ) + return int(row["count"]) if row else 0 + + async def get_user_extension( user_id: str, extension: str, conn: Connection | None = None ) -> UserExtension | None: @@ -137,3 +186,158 @@ async def get_user_active_extensions_ids( UserExtension, ) return [ext.extension for ext in exts] + + +async def create_wasm_invocation( + invocation: WasmInvocation, + conn: Connection | None = None, +) -> None: + await (conn or db).insert("wasm_invocations", invocation) + + +async def update_wasm_invocation( + invocation: WasmInvocation, + conn: Connection | None = None, +) -> None: + await (conn or db).update("wasm_invocations", invocation) + + +async def get_wasm_invocation( + invocation_id: str, + conn: Connection | None = None, +) -> WasmInvocation | None: + return await (conn or db).fetchone( + "SELECT * FROM wasm_invocations WHERE id = :id", + {"id": invocation_id}, + model=WasmInvocation, + ) + + +async def get_wasm_invocations( + *, + extension_id: str | None = None, + status: str | None = None, + limit: int = 100, + offset: int = 0, + conn: Connection | None = None, +) -> list[WasmInvocation]: + where: list[str] = [] + values: dict = { + "limit": max(1, min(limit, 500)), + "offset": max(offset, 0), + } + if extension_id: + where.append("extension_id = :extension_id") + values["extension_id"] = extension_id + if status: + where.append("status = :status") + values["status"] = status + + query = "SELECT * FROM wasm_invocations" + if where: + query += f" WHERE {' AND '.join(where)}" + query += " ORDER BY started_at DESC LIMIT :limit OFFSET :offset" + + return await (conn or db).fetchall(query, values, model=WasmInvocation) + + +async def get_running_wasm_invocations( + conn: Connection | None = None, +) -> list[WasmInvocation]: + return await get_wasm_invocations(status="running", conn=conn) + + +async def get_wasm_invocation_stats( + *, + extension_id: str | None = None, + since: datetime | None = None, + conn: Connection | None = None, +) -> WasmInvocationStats: + database = conn or db + where: list[str] = [] + values: dict = {} + if extension_id: + where.append("extension_id = :extension_id") + values["extension_id"] = extension_id + if since: + where.append(f"started_at >= {database.timestamp_placeholder('since')}") + values["since"] = since + + query = """ + SELECT + COUNT(*) AS total, + COALESCE(SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END), 0) + AS running, + COALESCE(SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END), 0) + AS completed, + COALESCE(SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END), 0) + AS failed, + COALESCE(SUM(CASE WHEN status = 'stopped' THEN 1 ELSE 0 END), 0) + AS stopped, + COALESCE(SUM(CASE WHEN status = 'timeout' THEN 1 ELSE 0 END), 0) + AS timeout, + COALESCE(AVG(duration_ms), 0) AS avg_duration_ms, + COALESCE(MAX(duration_ms), 0) AS max_duration_ms, + COALESCE(SUM(host_call_count), 0) AS host_call_count, + COALESCE(SUM(http_call_count), 0) AS http_call_count, + COALESCE(SUM(storage_call_count), 0) AS storage_call_count, + COALESCE(SUM(wallet_call_count), 0) AS wallet_call_count + FROM wasm_invocations + """ + if where: + query += f" WHERE {' AND '.join(where)}" + + row: dict | None = await (conn or db).fetchone(query, values) + if not row: + return WasmInvocationStats() + + return WasmInvocationStats( + total=int(row["total"] or 0), + running=int(row["running"] or 0), + completed=int(row["completed"] or 0), + failed=int(row["failed"] or 0), + stopped=int(row["stopped"] or 0), + timeout=int(row["timeout"] or 0), + avg_duration_ms=float(row["avg_duration_ms"] or 0), + max_duration_ms=int(row["max_duration_ms"] or 0), + host_call_count=int(row["host_call_count"] or 0), + http_call_count=int(row["http_call_count"] or 0), + storage_call_count=int(row["storage_call_count"] or 0), + wallet_call_count=int(row["wallet_call_count"] or 0), + ) + + +async def delete_old_wasm_invocations( + retention_days: int, + conn: Connection | None = None, +) -> int: + if retention_days <= 0: + return 0 + + cutoff = datetime.now(timezone.utc) - timedelta(days=retention_days) + database = conn or db + result = await database.execute( + f""" + DELETE FROM wasm_invocations + WHERE status != 'running' + AND started_at < {database.timestamp_placeholder("cutoff")} + """, # noqa: S608 + {"cutoff": cutoff}, + ) + return int(result.rowcount or 0) + + +async def mark_stale_wasm_invocations( + conn: Connection | None = None, +) -> None: + database = conn or db + await database.execute( + f""" + UPDATE wasm_invocations + SET status = 'abandoned', + finished_at = {database.timestamp_placeholder("finished_at")}, + stop_reason = 'Server restarted before invocation finished.' + WHERE status = 'running' + """, # noqa: S608 + {"finished_at": datetime.now(timezone.utc)}, + ) diff --git a/lnbits/core/crud/payments.py b/lnbits/core/crud/payments.py index 6cedd2711..6825ffbbc 100644 --- a/lnbits/core/crud/payments.py +++ b/lnbits/core/crud/payments.py @@ -16,6 +16,7 @@ from ..models import ( PaymentFilters, PaymentHistoryPoint, PaymentsStatusCount, + PaymentTotalBreakdown, PaymentWalletStats, ) @@ -149,14 +150,12 @@ async def get_payments_paginated( # noqa: C901 f"(status = '{PaymentState.SUCCESS}' OR status = '{PaymentState.PENDING}')" ) elif complete: - clause.append( - f""" + clause.append(f""" ( status = '{PaymentState.SUCCESS}' OR (amount < 0 AND status = '{PaymentState.PENDING}') ) - """ - ) + """) elif pending: clause.append(f"status = '{PaymentState.PENDING}'") elif failed: @@ -240,32 +239,6 @@ async def get_payments_status_count() -> PaymentsStatusCount: ) -async def delete_expired_invoices( - conn: Connection | None = None, -) -> None: - # first we delete all invoices older than one month - - await (conn or db).execute( - # Timestamp placeholder is safe from SQL injection (not user input) - f""" - DELETE FROM apipayments - WHERE status = :status AND amount > 0 - AND time < {db.timestamp_placeholder("delta")} - """, # noqa: S608 - {"status": f"{PaymentState.PENDING}", "delta": int(time() - 2592000)}, - ) - # then we delete all invoices whose expiry date is in the past - await (conn or db).execute( - # Timestamp placeholder is safe from SQL injection (not user input) - f""" - DELETE FROM apipayments - WHERE status = :status AND amount > 0 - AND expiry < {db.timestamp_placeholder("now")} - """, # noqa: S608 - {"status": f"{PaymentState.PENDING}", "now": int(time())}, - ) - - async def create_payment( checking_id: str, data: CreatePayment, @@ -292,8 +265,10 @@ async def create_payment( webhook=data.webhook, fee=-abs(data.fee), tag=extra.get("tag", None), + extension=data.extension, extra=extra, labels=data.labels or [], + external_id=data.external_id, ) await (conn or db).insert("apipayments", payment) @@ -307,7 +282,7 @@ async def update_payment_checking_id( await (conn or db).execute( f""" UPDATE apipayments - SET checking_id = :new_id, updated_at = {db.timestamp_placeholder('now')} + SET checking_id = :new_id, updated_at = {db.timestamp_placeholder("now")} WHERE checking_id = :old_id """, # noqa: S608 { @@ -322,13 +297,15 @@ async def update_payment( payment: Payment, new_checking_id: str | None = None, conn: Connection | None = None, -) -> None: +) -> Payment: payment.updated_at = datetime.now(timezone.utc) await (conn or db).update( "apipayments", payment, "WHERE checking_id = :checking_id" ) if new_checking_id and new_checking_id != payment.checking_id: await update_payment_checking_id(payment.checking_id, new_checking_id, conn) + payment.checking_id = new_checking_id + return payment async def get_payments_history( @@ -346,14 +323,12 @@ async def get_payments_history( "wallet_id": wallet_id, } # count outgoing payments if they are still pending - where = [ - f""" + where = [f""" wallet_id = :wallet_id AND ( status = '{PaymentState.SUCCESS}' OR (amount < 0 AND status = '{PaymentState.PENDING}') ) - """ - ] + """] clause = filters.where(where) transactions: list[dict] = await db.fetchall( # This query is safe from SQL injection: @@ -402,7 +377,6 @@ async def get_payment_count_stats( user_id: str | None = None, conn: Connection | None = None, ) -> list[PaymentCountStat]: - if not filters: filters = Filters() extra_stmts = [] @@ -430,12 +404,46 @@ async def get_payment_count_stats( return data +async def get_wallet_payment_total_breakdown( + wallet_id: str, + conn: Connection | None = None, +) -> list[PaymentTotalBreakdown]: + wallet = await get_wallet(wallet_id, conn=conn) + if not wallet or not wallet.can_view_payments: + return [] + + values = {"wallet_id": wallet.source_wallet_id} + data = await (conn or db).fetchall( + query=f""" + SELECT tag, + CASE + WHEN fiat_provider IS NOT NULL + THEN true + ELSE false + END AS is_fiat, + COUNT(*) AS payments_count, + SUM(amount - ABS(fee)) AS total + FROM apipayments + WHERE wallet_id = :wallet_id + AND ( + status = '{PaymentState.SUCCESS}' + OR (amount < 0 AND status = '{PaymentState.PENDING}') + ) + GROUP BY tag, is_fiat + ORDER BY tag + """, # noqa: S608 + values=values, + model=PaymentTotalBreakdown, + ) + + return data + + async def get_daily_stats( filters: Filters[PaymentFilters] | None = None, user_id: str | None = None, conn: Connection | None = None, ) -> tuple[list[PaymentDailyStats], list[PaymentDailyStats]]: - if not filters: filters = Filters() @@ -485,7 +493,6 @@ async def get_wallets_stats( user_id: str | None = None, conn: Connection | None = None, ) -> list[PaymentWalletStats]: - if not filters: filters = Filters() diff --git a/lnbits/core/crud/settings.py b/lnbits/core/crud/settings.py index 9e9023e6f..79eb415d6 100644 --- a/lnbits/core/crud/settings.py +++ b/lnbits/core/crud/settings.py @@ -8,11 +8,18 @@ from lnbits.db import dict_to_model from lnbits.settings import ( AdminSettings, EditableSettings, + FundingSourcesSettings, SettingsField, SuperSettings, settings, ) +RESET_PRESERVED_SETTINGS = ( + "lnbits_webpush_pubkey", + "lnbits_webpush_privkey", + *FundingSourcesSettings.__fields__, +) + async def get_super_settings() -> SuperSettings | None: data = await get_settings_by_tag("core") @@ -69,16 +76,14 @@ async def delete_admin_settings(tag: str | None = "core") -> None: async def reset_core_settings() -> None: - await db.execute( - """ - DELETE FROM system_settings WHERE tag = 'core' - AND id NOT IN ( - 'super_user', - 'lnbits_webpush_pubkey', - 'lnbits_webpush_privkey' - ) - """, - ) + core_settings = await get_settings_by_tag("core") or {} + super_user = await get_settings_field("super_user") + await delete_admin_settings() + if super_user: + await set_settings_field("super_user", super_user.value) + for field in RESET_PRESERVED_SETTINGS: + if field in core_settings: + await set_settings_field(field, core_settings[field]) async def create_admin_settings(super_user: str, new_settings: dict) -> SuperSettings: @@ -105,7 +110,8 @@ async def get_settings_field( ) if not row: return None - return SettingsField(id=row["id"], value=json.loads(row["value"]), tag=row["tag"]) + value = json.loads(row["value"]) if row["value"] else None + return SettingsField(id=row["id"], value=value, tag=row["tag"]) async def set_settings_field(id_: str, value: Any | None, tag: str | None = "core"): diff --git a/lnbits/core/crud/users.py b/lnbits/core/crud/users.py index fc68162a1..e5001e0ec 100644 --- a/lnbits/core/crud/users.py +++ b/lnbits/core/crud/users.py @@ -4,7 +4,12 @@ from typing import Any from uuid import uuid4 from lnbits.core.crud.extensions import get_user_active_extensions_ids -from lnbits.core.crud.wallets import clear_wallet_cache, create_wallet, get_wallets +from lnbits.core.crud.wallets import ( + clear_wallet_cache, + create_wallet, + get_standalone_wallet, + get_wallets, +) from lnbits.core.db import db from lnbits.core.models import UserAcls from lnbits.db import Connection, Filters, Page @@ -32,6 +37,13 @@ async def create_account( return account +async def get_accounts_count(conn: Connection | None = None) -> int: + row: dict | None = await (conn or db).fetchone( + "SELECT COUNT(*) as count FROM accounts" + ) + return int(row["count"]) if row else 0 + + async def update_account(account: Account, conn: Connection | None = None) -> Account: account.updated_at = datetime.now(timezone.utc) await (conn or db).update("accounts", account) @@ -52,17 +64,22 @@ async def get_accounts( ) -> Page[AccountOverview]: where_clauses = [] values: dict[str, Any] = {} + filters = filters or Filters() - # Make wallet filter explicit - wallet_filter = ( - next((f for f in filters.filters if f.field == "wallet_id"), None) - if filters - else None - ) - if filters and wallet_filter and wallet_filter.values: - where_clauses.append("wallets.id = :wallet_id") - values = {**values, "wallet_id": next(iter(wallet_filter.values.values()))} - filters.filters = [f for f in filters.filters if f.field != "wallet_id"] + wallet_filter = filters.get_filter_by_field("wallet_id") + + if wallet_filter and wallet_filter.values: + wallet_id_value = next(iter(wallet_filter.values.values()), None) + wallet = ( + await get_standalone_wallet(wallet_id_value, deleted=None, conn=conn) + if wallet_id_value + else None + ) + if not wallet: + return Page(data=[], total=0) + where_clauses.append("accounts.id = :account_id") + values = {**values, "account_id": wallet.user} + filters.remove_filter_by_field("wallet_id") return await (conn or db).fetch_page( """ diff --git a/lnbits/core/crud/wallets.py b/lnbits/core/crud/wallets.py index 4f080b82a..a88259515 100644 --- a/lnbits/core/crud/wallets.py +++ b/lnbits/core/crud/wallets.py @@ -5,6 +5,7 @@ from uuid import uuid4 from lnbits.core.db import db from lnbits.core.models.wallets import BaseWallet, WalletsFilters, WalletType from lnbits.db import Connection, Filters, Page +from lnbits.helpers import generate_ln_address from lnbits.settings import settings from lnbits.utils.cache import cache @@ -30,6 +31,8 @@ async def create_wallet( inkey=uuid4().hex, currency=settings.lnbits_default_accounting_currency or "USD", ) + if settings.ln_address_creation_allowed and wallet.is_lightning_wallet: + wallet.lightning_address = await generate_lightning_address_local_part(conn) await (conn or db).insert("wallets", wallet) return wallet @@ -123,11 +126,21 @@ async def get_standalone_wallet( """ if deleted is not None: query += " AND deleted = :deleted " - return await (conn or db).fetchone( + wallet = await (conn or db).fetchone( query, {"wallet": wallet_id, "deleted": deleted}, Wallet, ) + if not wallet: + return None + if deleted is True: + return wallet + + if not wallet.lightning_address and settings.ln_address_creation_allowed: + wallet.lightning_address = await generate_lightning_address_local_part(conn) + await update_wallet(wallet, conn) + + return wallet async def get_wallet( @@ -220,6 +233,30 @@ async def get_wallets_count(): return row.get("count", 0) +async def generate_lightning_address_local_part( + conn: Connection | None = None, +) -> str: + for _ in range(100): + local_part = generate_ln_address() + if await get_wallet_id_by_ln_address(local_part, conn): + continue + return local_part + raise ValueError("Could not generate a unique wallet lightning address.") + + +async def get_wallet_id_by_ln_address( + local_part: str, conn: Connection | None = None +) -> str | None: + row: dict = await (conn or db).fetchone( + """ + SELECT id FROM wallets + WHERE lightning_address = :lightning_address + """, + {"lightning_address": local_part.lower()}, + ) + return row["id"] if row else None + + async def get_wallet_for_key( key: str, conn: Connection | None = None, diff --git a/lnbits/core/helpers.py b/lnbits/core/helpers.py index 1b1c24b1b..35b92629a 100644 --- a/lnbits/core/helpers.py +++ b/lnbits/core/helpers.py @@ -15,6 +15,8 @@ from lnbits.core.crud import ( from lnbits.core.db import db as core_db from lnbits.core.models import DbVersion from lnbits.core.models.extensions import InstallableExtension +from lnbits.core.wasm_ext.storage.crud import migrate_wasm_extension_database +from lnbits.core.wasm_ext.wasm.loader import is_wasm_extension_id from lnbits.db import COCKROACH, POSTGRES, SQLITE, Connection from lnbits.settings import settings @@ -22,7 +24,16 @@ from lnbits.settings import settings async def migrate_extension_database( ext: InstallableExtension, current_version: DbVersion | None = None ): + if is_wasm_extension_id(ext.id): + await migrate_wasm_extension_database(ext, current_version) + return + else: + await migrate_py_extension_database(ext, current_version) + +async def migrate_py_extension_database( + ext: InstallableExtension, current_version: DbVersion | None = None +): try: ext_migrations = importlib.import_module(f"{ext.module_name}.migrations") ext_db = importlib.import_module(ext.module_name).db diff --git a/lnbits/core/migrations.py b/lnbits/core/migrations.py index 19aa2b9a2..8796f2e86 100644 --- a/lnbits/core/migrations.py +++ b/lnbits/core/migrations.py @@ -10,31 +10,26 @@ from lnbits.db import Connection async def m000_create_migrations_table(db: Connection): - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS dbversions ( db TEXT PRIMARY KEY, version INT NOT NULL ) - """ - ) + """) async def m001_initial(db: Connection): """ Initial LNbits tables. """ - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS accounts ( id TEXT PRIMARY KEY, email TEXT, pass TEXT ); - """ - ) - await db.execute( - """ + """) + await db.execute(""" CREATE TABLE IF NOT EXISTS extensions ( "user" TEXT NOT NULL, extension TEXT NOT NULL, @@ -42,10 +37,8 @@ async def m001_initial(db: Connection): UNIQUE ("user", extension) ); - """ - ) - await db.execute( - """ + """) + await db.execute(""" CREATE TABLE IF NOT EXISTS wallets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, @@ -53,10 +46,8 @@ async def m001_initial(db: Connection): adminkey TEXT NOT NULL, inkey TEXT ); - """ - ) - await db.execute( - f""" + """) + await db.execute(f""" CREATE TABLE IF NOT EXISTS apipayments ( payhash TEXT NOT NULL, amount {db.big_int} NOT NULL, @@ -67,11 +58,9 @@ async def m001_initial(db: Connection): time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}, UNIQUE (wallet, payhash) ); - """ - ) + """) - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT wallet, COALESCE(SUM(s), 0) AS balance FROM ( SELECT wallet, SUM(amount) AS s -- incoming @@ -85,8 +74,7 @@ async def m001_initial(db: Connection): GROUP BY wallet )x GROUP BY wallet; - """ - ) + """) async def m002_add_fields_to_apipayments(db: Connection): @@ -149,8 +137,7 @@ async def m004_ensure_fees_are_always_negative(db: Connection): """ await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT wallet, COALESCE(SUM(s), 0) AS balance FROM ( SELECT wallet, SUM(amount) AS s -- incoming @@ -164,8 +151,7 @@ async def m004_ensure_fees_are_always_negative(db: Connection): GROUP BY wallet )x GROUP BY wallet; - """ - ) + """) async def m005_balance_check_balance_notify(db: Connection): @@ -174,8 +160,7 @@ async def m005_balance_check_balance_notify(db: Connection): LNbits wallet and of balanceNotify URLs supplied by users to empty their wallets. """ - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS balance_check ( wallet TEXT NOT NULL REFERENCES wallets (id), service TEXT NOT NULL, @@ -183,19 +168,16 @@ async def m005_balance_check_balance_notify(db: Connection): UNIQUE(wallet, service) ); - """ - ) + """) - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS balance_notify ( wallet TEXT NOT NULL REFERENCES wallets (id), url TEXT NOT NULL, UNIQUE(wallet, url) ); - """ - ) + """) async def m006_add_invoice_expiry_to_apipayments(db: Connection): @@ -262,19 +244,16 @@ async def m007_set_invoice_expiries(db: Connection): async def m008_create_admin_settings_table(db: Connection): - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS settings ( super_user TEXT, editable_settings TEXT NOT NULL DEFAULT '{}' ); - """ - ) + """) async def m009_create_tinyurl_table(db: Connection): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS tiny_url ( id TEXT PRIMARY KEY, url TEXT, @@ -282,13 +261,11 @@ async def m009_create_tinyurl_table(db: Connection): wallet TEXT, time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} ); - """ - ) + """) async def m010_create_installed_extensions_table(db: Connection): - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS installed_extensions ( id TEXT PRIMARY KEY, version TEXT NOT NULL, @@ -299,8 +276,7 @@ async def m010_create_installed_extensions_table(db: Connection): active BOOLEAN DEFAULT false, meta TEXT NOT NULL DEFAULT '{}' ); - """ - ) + """) async def m011_optimize_balances_view(db: Connection): @@ -309,23 +285,19 @@ async def m011_optimize_balances_view(db: Connection): over the payments table instead of 2. """ await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT wallet, SUM(amount - abs(fee)) AS balance FROM apipayments WHERE (pending = false AND amount > 0) OR amount < 0 GROUP BY wallet - """ - ) + """) async def m012_add_currency_to_wallet(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE wallets ADD COLUMN currency TEXT - """ - ) + """) async def m013_add_deleted_to_wallets(db: Connection): @@ -345,15 +317,13 @@ async def m014_set_deleted_wallets(db: Connection): Sets deleted column to wallets. """ try: - result = await db.execute( - """ + result = await db.execute(""" SELECT * FROM wallets WHERE user LIKE 'del:%' AND adminkey LIKE 'del:%' AND inkey LIKE 'del:%' - """ - ) + """) rows = result.mappings().all() for row in rows: @@ -386,8 +356,7 @@ async def m014_set_deleted_wallets(db: Connection): async def m015_create_push_notification_subscriptions_table(db: Connection): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS webpush_subscriptions ( endpoint TEXT NOT NULL, "user" TEXT NOT NULL, @@ -396,8 +365,7 @@ async def m015_create_push_notification_subscriptions_table(db: Connection): timestamp TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}, PRIMARY KEY (endpoint, "user") ); - """ - ) + """) async def m016_add_username_column_to_accounts(db: Connection): @@ -484,8 +452,7 @@ async def m018_balances_view_exclude_deleted(db: Connection): Make deleted wallets not show up in the balances view. """ await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT apipayments.wallet, SUM(apipayments.amount - ABS(apipayments.fee)) AS balance @@ -495,8 +462,7 @@ async def m018_balances_view_exclude_deleted(db: Connection): AND ((apipayments.pending = false AND apipayments.amount > 0) OR apipayments.amount < 0) GROUP BY wallet - """ - ) + """) async def m019_balances_view_based_on_wallets(db: Connection): @@ -505,8 +471,7 @@ async def m019_balances_view_based_on_wallets(db: Connection): Important for querying whole lnbits balances. """ await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT apipayments.wallet, SUM(apipayments.amount - ABS(apipayments.fee)) AS balance @@ -516,8 +481,7 @@ async def m019_balances_view_based_on_wallets(db: Connection): AND ((apipayments.pending = false AND apipayments.amount > 0) OR apipayments.amount < 0) GROUP BY apipayments.wallet - """ - ) + """) async def m020_add_column_column_to_user_extensions(db: Connection): @@ -536,8 +500,7 @@ async def m021_add_success_failed_to_apipayments(db: Connection): await db.execute("UPDATE apipayments SET status = 'success' WHERE NOT pending") await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT apipayments.wallet, SUM(apipayments.amount - ABS(apipayments.fee)) AS balance @@ -549,8 +512,7 @@ async def m021_add_success_failed_to_apipayments(db: Connection): OR (apipayments.status IN ('success', 'pending') AND apipayments.amount < 0) ) GROUP BY apipayments.wallet - """ - ) + """) async def m022_add_pubkey_to_accounts(db: Connection): @@ -581,8 +543,7 @@ async def m024_drop_pending(db: Connection): async def m025_refresh_view(db: Connection): await db.execute("DROP VIEW balances") - await db.execute( - """ + await db.execute(""" CREATE VIEW balances AS SELECT apipayments.wallet_id, SUM(apipayments.amount - ABS(apipayments.fee)) AS balance @@ -594,8 +555,7 @@ async def m025_refresh_view(db: Connection): OR (apipayments.status IN ('success', 'pending') AND apipayments.amount < 0) ) GROUP BY apipayments.wallet_id - """ - ) + """) async def m026_update_payment_table(db: Connection): @@ -658,8 +618,7 @@ async def m027_update_apipayments_data(db: Connection): async def m028_update_settings(db: Connection): - await db.execute( - """ + await db.execute(""" CREATE TABLE IF NOT EXISTS system_settings ( id TEXT PRIMARY KEY, value TEXT, @@ -667,8 +626,7 @@ async def m028_update_settings(db: Connection): UNIQUE (id, tag) ); - """ - ) + """) async def _insert_key_value(id_: str, value: Any): await db.execute( @@ -691,8 +649,7 @@ async def m028_update_settings(db: Connection): async def m029_create_audit_table(db: Connection): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS audit ( component TEXT, ip_address TEXT, @@ -706,16 +663,13 @@ async def m029_create_audit_table(db: Connection): delete_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} ); - """ - ) + """) async def m030_add_user_api_tokens_column(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE accounts ADD COLUMN access_control_list TEXT - """ - ) + """) async def m031_add_color_and_icon_to_wallets(db: Connection): @@ -738,32 +692,25 @@ async def m033_update_payment_table(db: Connection): async def m034_add_stored_paylinks_to_wallet(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE wallets ADD COLUMN stored_paylinks TEXT - """ - ) + """) async def m035_add_wallet_type_column(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE wallets ADD COLUMN wallet_type TEXT DEFAULT 'lightning' - """ - ) + """) async def m036_add_shared_wallet_column(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE wallets ADD COLUMN shared_wallet_id TEXT - """ - ) + """) async def m037_create_assets_table(db: Connection): - await db.execute( - f""" + await db.execute(f""" CREATE TABLE IF NOT EXISTS assets ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, @@ -776,16 +723,13 @@ async def m037_create_assets_table(db: Connection): data {db.blob} NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} ); - """ - ) + """) async def m038_add_labels_for_payments(db: Connection): - await db.execute( - """ + await db.execute(""" ALTER TABLE apipayments ADD COLUMN labels TEXT - """ - ) + """) async def m039_index_payments(db: Connection): @@ -804,11 +748,9 @@ async def m039_index_payments(db: Connection): ] for index in indexes: logger.debug(f"Creating index idx_payments_{index}...") - await db.execute( - f""" + await db.execute(f""" CREATE INDEX IF NOT EXISTS idx_payments_{index} ON apipayments ({index}); - """ - ) + """) async def m040_index_wallets(db: Connection): @@ -825,11 +767,9 @@ async def m040_index_wallets(db: Connection): for index in indexes: logger.debug(f"Creating index idx_wallets_{index}...") - await db.execute( - f""" + await db.execute(f""" CREATE INDEX IF NOT EXISTS idx_wallets_{index} ON wallets ("{index}"); - """ - ) + """) async def m042_index_accounts(db: Connection): @@ -843,11 +783,9 @@ async def m042_index_accounts(db: Connection): for index in indexes: logger.debug(f"Creating index idx_wallets_{index}...") - await db.execute( - f""" + await db.execute(f""" CREATE INDEX IF NOT EXISTS idx_accounts_{index} ON accounts ("{index}"); - """ - ) + """) async def m043_add_ui_customization_to_accounts(db: Connection): @@ -864,3 +802,103 @@ async def m044_add_activated_to_accounts(db: Connection): Used for account activation status. """ await db.execute("ALTER TABLE accounts ADD COLUMN activated BOOLEAN DEFAULT true") + + +async def m045_add_external_id_to_payments(db: Connection): + """ + Adds external_id column to apipayments. + Used for external payment references. + """ + await db.execute("ALTER TABLE apipayments ADD COLUMN external_id TEXT") + logger.debug("Creating index idx_payments_external_id...") + await db.execute(""" + CREATE INDEX IF NOT EXISTS idx_payments_external_id + ON apipayments (external_id); + """) + + +async def m046_add_permissions_to_installed_extensions(db: Connection): + """ + Adds granted permissions to installed extensions. + """ + await db.execute( + "ALTER TABLE installed_extensions ADD COLUMN permissions TEXT DEFAULT '[]'" + ) + + +async def m047_create_wasm_invocations_table(db: Connection): + """ + Tracks WASM extension invocations for runtime monitoring and controls. + """ + await db.execute(f""" + CREATE TABLE IF NOT EXISTS wasm_invocations ( + id TEXT PRIMARY KEY, + extension_id TEXT NOT NULL, + export_name TEXT NOT NULL, + trigger_type TEXT NOT NULL DEFAULT 'unknown', + status TEXT NOT NULL DEFAULT 'running', + started_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}, + finished_at TIMESTAMP, + duration_ms INT, + user_id TEXT, + wallet_id TEXT, + request_id TEXT, + method TEXT, + path TEXT, + event_type TEXT, + payment_hash TEXT, + checking_id TEXT, + memory_peak_bytes INT, + request_bytes INT, + response_bytes INT, + host_call_count INT NOT NULL DEFAULT 0, + http_call_count INT NOT NULL DEFAULT 0, + storage_call_count INT NOT NULL DEFAULT 0, + wallet_call_count INT NOT NULL DEFAULT 0, + error_type TEXT, + error_message TEXT, + stop_reason TEXT, + "context" TEXT NOT NULL DEFAULT '{{}}' + ); + """) + await db.execute(""" + CREATE INDEX IF NOT EXISTS idx_wasm_invocations_extension_started + ON wasm_invocations (extension_id, started_at); + """) + await db.execute(""" + CREATE INDEX IF NOT EXISTS idx_wasm_invocations_status + ON wasm_invocations (status); + """) + await db.execute(""" + CREATE INDEX IF NOT EXISTS idx_wasm_invocations_started + ON wasm_invocations (started_at); + """) + + +async def m048_add_wasm_runtime_limits_to_installed_extensions(db: Connection): + """ + Adds per-extension WASM runtime limit overrides. + """ + await db.execute( + "ALTER TABLE installed_extensions " + "ADD COLUMN wasm_runtime_limits TEXT DEFAULT '{}'" + ) + + +async def m049_add_permissions_to_user_extensions(db: Connection): + """ + Adds user-level extension permission grants. + """ + await db.execute("ALTER TABLE extensions ADD COLUMN permissions TEXT DEFAULT '{}'") + + +async def m050_add_lightning_address_to_wallets(db: Connection): + """ + Adds a LUD-16 lightning address local-part to wallets. + """ + await db.execute("ALTER TABLE wallets ADD COLUMN lightning_address TEXT") + logger.debug("Creating index idx_wallets_lightning_address...") + await db.execute(""" + CREATE UNIQUE INDEX IF NOT EXISTS idx_wallets_lightning_address + ON wallets (lightning_address); + """) diff --git a/lnbits/core/models/__init__.py b/lnbits/core/models/__init__.py index c896b3d54..eaf3f65e3 100644 --- a/lnbits/core/models/__init__.py +++ b/lnbits/core/models/__init__.py @@ -23,8 +23,10 @@ from .payments import ( PaymentHistoryPoint, PaymentsStatusCount, PaymentState, + PaymentTotalBreakdown, PaymentWalletStats, SettleInvoice, + UpdatePaymentExtra, ) from .tinyurl import TinyURL from .users import ( @@ -82,6 +84,7 @@ __all__ = [ "PaymentFilters", "PaymentHistoryPoint", "PaymentState", + "PaymentTotalBreakdown", "PaymentWalletStats", "PaymentsStatusCount", "RegisterUser", @@ -90,6 +93,7 @@ __all__ = [ "SimpleStatus", "TinyURL", "UpdateBalance", + "UpdatePaymentExtra", "UpdateSuperuserPassword", "UpdateUser", "UpdateUserPassword", diff --git a/lnbits/core/models/extensions.py b/lnbits/core/models/extensions.py index c0cfa3260..ecc62421f 100644 --- a/lnbits/core/models/extensions.py +++ b/lnbits/core/models/extensions.py @@ -6,13 +6,16 @@ import json import os import shutil import zipfile -from asyncio.tasks import create_task -from pathlib import Path +from collections.abc import Mapping +from datetime import datetime, timezone +from enum import Enum +from pathlib import Path, PurePosixPath from typing import Any +from uuid import uuid4 import httpx from loguru import logger -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, StrictStr from lnbits.helpers import ( download_url, @@ -21,9 +24,14 @@ from lnbits.helpers import ( version_parse, ) from lnbits.settings import settings +from lnbits.task_manager import task_manager from lnbits.utils.cache import cache +class ExtensionArchiveValidationError(ValueError): + pass + + class ExplicitRelease(BaseModel): id: str name: str @@ -43,6 +51,7 @@ class ExplicitRelease(BaseModel): details_link: str | None paid_features: str | None pay_link: str | None + extension_type: str | None = None def is_version_compatible(self): return is_lnbits_version_ok(self.min_lnbits_version, self.max_lnbits_version) @@ -55,9 +64,15 @@ class GitHubRelease(BaseModel): class Manifest(BaseModel): - featured: list[str] = [] extensions: list[ExplicitRelease] = [] repos: list[GitHubRelease] = [] + featured: list[str] = [] + categories: dict[str, list[str]] = {} + + +class ExtensionManifestType(str, Enum): + PYTHON = "python" + WASM = "wasm" class GitHubRepoRelease(BaseModel): @@ -76,6 +91,23 @@ class GitHubRepo(BaseModel): default_branch: str +class ExtensionPermission(BaseModel): + id: StrictStr + description: StrictStr | None = None + policies: list[Any] | None = None + + class Config: + extra = "ignore" + + @staticmethod + def list_from_config(config_json: Mapping[str, Any]) -> list[ExtensionPermission]: + return [ + ExtensionPermission.parse_obj(permission) + for permission in config_json.get("permissions") or [] + if isinstance(permission, dict) and permission.get("id") + ] + + class ExtensionConfig(BaseModel): name: str short_description: str @@ -83,10 +115,18 @@ class ExtensionConfig(BaseModel): warning: str | None = "" min_lnbits_version: str | None max_lnbits_version: str | None + extension_type: str | None = None + permissions: list[ExtensionPermission] = [] def is_version_compatible(self) -> bool: return is_lnbits_version_ok(self.min_lnbits_version, self.max_lnbits_version) + @classmethod + async def fetch_release_config(cls, url: str) -> ExtensionConfig: + error_msg = "Cannot fetch extension release config" + config = await extension_metadata_get(url, error_msg) + return ExtensionConfig.parse_obj(config) + @classmethod async def fetch_github_release_config( cls, org: str, repo: str, tag_name: str @@ -94,7 +134,7 @@ class ExtensionConfig(BaseModel): config_url = ( f"https://raw.githubusercontent.com/{org}/{repo}/{tag_name}/config.json" ) - error_msg = "Cannot fetch GitHub extension config" + error_msg = "Cannot fetch extension release config" config = await github_api_get(config_url, error_msg) return ExtensionConfig.parse_obj(config) @@ -117,11 +157,87 @@ class UserExtensionInfo(BaseModel): payment_hash_to_enable: str | None = None +class ExtensionBackgroundPaymentDestinationPolicy(str, Enum): + OWN_WALLETS_ONLY = "own_wallets_only" + EXTERNAL_ALLOWED = "external_allowed" + + +class ExtensionBackgroundPaymentGrant(BaseModel): + id: StrictStr = Field(..., min_length=1, max_length=128) + wallet_id: str = Field(..., min_length=1, max_length=128) + enabled: bool = True + max_amount: int = Field(..., gt=0) + destination_policy: ExtensionBackgroundPaymentDestinationPolicy + + +class ExtensionBackgroundPaymentGrantRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + max_amount: int = Field(..., gt=0) + destination_policy: ExtensionBackgroundPaymentDestinationPolicy + + def to_grant(self, grant_id: str | None = None) -> ExtensionBackgroundPaymentGrant: + return ExtensionBackgroundPaymentGrant( + id=grant_id or str(uuid4()), + wallet_id=self.wallet_id, + enabled=True, + max_amount=self.max_amount, + destination_policy=self.destination_policy, + ) + + +class ExtensionWalletPaymentsWatchGrant(BaseModel): + id: StrictStr = Field(..., min_length=1, max_length=128) + wallet_id: str = Field(..., min_length=1, max_length=128) + enabled: bool = True + + +class ExtensionWalletPaymentsWatchGrantRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + + def to_grant( + self, grant_id: str | None = None + ) -> ExtensionWalletPaymentsWatchGrant: + return ExtensionWalletPaymentsWatchGrant( + id=grant_id or str(uuid4()), + wallet_id=self.wallet_id, + enabled=True, + ) + + +class ExtensionPermissionCheckItem(BaseModel): + id: StrictStr + grant: dict[str, Any] = Field(default_factory=dict) + + +class ExtensionPermissionCheckRequest(BaseModel): + permissions: list[ExtensionPermissionCheckItem] = Field(default_factory=list) + + +class ExtensionPermissionCheckResult(BaseModel): + id: StrictStr + approved: bool + grant: dict[str, Any] = Field(default_factory=dict) + + +class ExtensionPermissionCheckResponse(BaseModel): + permissions: list[ExtensionPermissionCheckResult] = Field(default_factory=list) + + +class ExtensionPermissionsResponse(BaseModel): + extension_permissions: list[ExtensionPermission] = Field(default_factory=list) + user_permissions: dict[str, list[dict[str, Any]]] = Field(default_factory=dict) + + +class ExtensionPermissionsUpdate(BaseModel): + permissions: list[ExtensionPermission] = Field(default_factory=list) + + class UserExtension(BaseModel): user: str extension: str active: bool extra: UserExtensionInfo | None = None + permissions: dict = Field(default_factory=dict) @property def is_paid(self) -> bool: @@ -143,36 +259,86 @@ class UserExtension(BaseModel): class Extension(BaseModel): code: str is_valid: bool + is_wasm: bool = False name: str | None = None short_description: str | None = None tile: str | None = None - upgrade_hash: str | None = "" @property def module_name(self) -> str: - if self.is_upgrade_extension: - return f"{self.code}-{self.upgrade_hash}" - if settings.has_default_extension_path: return f"lnbits.extensions.{self.code}" return self.code - @property - def is_upgrade_extension(self) -> bool: - return self.upgrade_hash != "" - @classmethod def from_installable_ext(cls, ext_info: InstallableExtension) -> Extension: return Extension( code=ext_info.id, is_valid=True, + is_wasm=ext_info.is_wasm, name=ext_info.name, short_description=ext_info.short_description, - tile=ext_info.icon, - upgrade_hash=ext_info.hash if ext_info.ext_upgrade_dir.is_dir() else "", + tile=_extension_tile(ext_info), ) +class WasmInvocation(BaseModel): + id: str + extension_id: str + export_name: str + trigger_type: str = "unknown" + status: str = "running" + started_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + finished_at: datetime | None = None + duration_ms: int | None = None + user_id: str | None = None + wallet_id: str | None = None + request_id: str | None = None + method: str | None = None + path: str | None = None + event_type: str | None = None + payment_hash: str | None = None + checking_id: str | None = None + memory_peak_bytes: int | None = None + request_bytes: int | None = None + response_bytes: int | None = None + host_call_count: int = 0 + http_call_count: int = 0 + storage_call_count: int = 0 + wallet_call_count: int = 0 + error_type: str | None = None + error_message: str | None = None + stop_reason: str | None = None + context: dict = Field(default_factory=dict) + + +class WasmInvocationStats(BaseModel): + total: int = 0 + running: int = 0 + completed: int = 0 + failed: int = 0 + stopped: int = 0 + timeout: int = 0 + avg_duration_ms: float = 0 + max_duration_ms: int = 0 + host_call_count: int = 0 + http_call_count: int = 0 + storage_call_count: int = 0 + wallet_call_count: int = 0 + + +class WasmRuntimeLimitsUpdate(BaseModel): + limits: dict[str, Any] = Field(default_factory=dict) + + +class WasmRuntimeLimitsInfo(BaseModel): + id: str + name: str + active: bool | None = False + wasm_runtime_limits: dict[str, int] = Field(default_factory=dict) + effective_wasm_runtime_limits: dict[str, int] = Field(default_factory=dict) + + class ExtensionRelease(BaseModel): name: str version: str @@ -189,6 +355,9 @@ class ExtensionRelease(BaseModel): repo: str | None = None icon: str | None = None details_link: str | None = None + extension_type: str | None = None + manifest_type: ExtensionManifestType | None = Field(default=None, exclude=True) + permissions: list[ExtensionPermission] = [] paid_features: str | None = None pay_link: str | None = None @@ -196,6 +365,14 @@ class ExtensionRelease(BaseModel): paid_sats: int | None = 0 payment_hash: str | None = None + def apply_config(self, config: ExtensionConfig) -> None: + self.min_lnbits_version = config.min_lnbits_version + self.max_lnbits_version = config.max_lnbits_version + self.is_version_compatible = config.is_version_compatible() + self.warning = config.warning + self.extension_type = config.extension_type + self.permissions = config.permissions + @property def archive_url(self) -> str: if not self.pay_link: @@ -259,6 +436,7 @@ class ExtensionRelease(BaseModel): warning=e.warning, html_url=e.html_url, details_link=e.details_link, + extension_type=e.extension_type, pay_link=e.pay_link, paid_features=e.paid_features, repo=e.repo, @@ -286,10 +464,7 @@ class ExtensionRelease(BaseModel): if not config: continue - release.min_lnbits_version = config.min_lnbits_version - release.max_lnbits_version = config.max_lnbits_version - release.is_version_compatible = config.is_version_compatible() - + release.apply_config(config) release.icon = icon_to_github_url(f"{org}/{repo}", config.tile) return extension_releases @@ -308,7 +483,6 @@ class ExtensionRelease(BaseModel): @classmethod async def fetch_release_details(cls, details_link: str) -> dict | None: - try: async with httpx.AsyncClient() as client: resp = await client.get(details_link) @@ -333,6 +507,7 @@ class ExtensionMeta(BaseModel): dependencies: list[str] = [] archive: str | None = None featured: bool = False + categories: list[str] = [] paid_features: str | None = None has_paid_release: bool = False has_free_release: bool = False @@ -347,6 +522,8 @@ class InstallableExtension(BaseModel): icon: str | None = None stars: int = 0 meta: ExtensionMeta | None = None + permissions: list[ExtensionPermission] = [] + wasm_runtime_limits: dict = Field(default_factory=dict, no_database=True) @property def hash(self) -> str: @@ -368,15 +545,16 @@ class InstallableExtension(BaseModel): def ext_dir(self) -> Path: return Path(settings.lnbits_extensions_path, "extensions", self.id) + @property + def wasm_ext_dir(self) -> Path: + return Path(settings.wasm_extensions_dir, self.id) + @property def ext_upgrade_dir(self) -> Path: return Path(settings.lnbits_extensions_upgrade_path, f"{self.id}-{self.hash}") @property def module_name(self) -> str: - if self.ext_upgrade_dir.is_dir(): - return f"{self.id}-{self.hash}" - if settings.has_default_extension_path: return f"lnbits.extensions.{self.id}" return self.id @@ -399,6 +577,18 @@ class InstallableExtension(BaseModel): return False return self.meta.pay_to_enable.required is True + @property + def is_wasm(self) -> bool: + config_path = Path(self.wasm_ext_dir, "config.json") + if not config_path.is_file(): + return False + try: + with open(config_path, encoding="utf-8") as json_file: + config_json = json.load(json_file) + except Exception: + return False + return config_json.get("extension_type") == "wasm" + async def download_archive(self): logger.info(f"Downloading extension {self.name} ({self.installed_version}).") ext_zip_file = self.zip_path @@ -431,6 +621,57 @@ class InstallableExtension(BaseModel): os.remove(ext_zip_file) raise AssertionError("File hash missmatch. Will not install.") + def load_archive_config(self) -> dict[str, Any]: + if not self.zip_path.is_file(): + return {} + + try: + with zipfile.ZipFile(self.zip_path, "r") as archive: + config_name = _archive_config_name(archive.namelist()) + if not config_name: + return {} + with archive.open(config_name) as config_file: + config = json.load(config_file) + except Exception as exc: + raise ValueError(f"Cannot read extension config for '{self.id}'.") from exc + + return config if isinstance(config, dict) else {} + + def validate_archive(self, config: Mapping[str, Any]) -> None: + release = self.meta.installed_release if self.meta else None + manifest_type = release.manifest_type if release else None + is_wasm = config.get("extension_type") == "wasm" + + if manifest_type == ExtensionManifestType.PYTHON and is_wasm: + raise ExtensionArchiveValidationError( + f"Python extension manifest cannot install WASM extension '{self.id}'." + ) + if manifest_type == ExtensionManifestType.WASM and not is_wasm: + raise ExtensionArchiveValidationError( + "WASM extension manifest requires extension_type 'wasm' " + f"for extension '{self.id}'." + ) + if not is_wasm: + return + + with zipfile.ZipFile(self.zip_path, "r") as archive: + python_file = next( + ( + item.filename + for item in archive.infolist() + if not item.is_dir() + and PurePosixPath(item.filename).suffix.lower() + in {".py", ".pyc", ".pyo", ".so", ".pyd"} + ), + None, + ) + + if python_file: + raise ExtensionArchiveValidationError( + f"WASM extension '{self.id}' contains forbidden Python file " + f"'{python_file}'." + ) + def extract_archive(self): logger.info(f"Extracting extension {self.name} ({self.installed_version}).") Path(settings.lnbits_extensions_upgrade_path).mkdir(parents=True, exist_ok=True) @@ -467,6 +708,38 @@ class InstallableExtension(BaseModel): shutil.rmtree(self.ext_dir, True) shutil.copytree(Path(self.ext_upgrade_dir), Path(self.ext_dir)) + shutil.rmtree(self.ext_upgrade_dir, True) + logger.info(f"Extension {self.name} ({self.installed_version}) extracted.") + + def extract_wasm_archive(self): + logger.info(f"Extracting extension {self.name} ({self.installed_version}).") + + tmp_dir = Path(settings.lnbits_data_folder, "unzip-temp", self.hash) + shutil.rmtree(tmp_dir, True) + with zipfile.ZipFile(self.zip_path, "r") as zip_ref: + zip_ref.extractall(tmp_dir) + generated_dir_name = os.listdir(tmp_dir)[0] + extracted_dir = Path(tmp_dir, generated_dir_name) + + with open(Path(extracted_dir, "config.json"), "r+") as json_file: + config_json = json.load(json_file) + + self.name = config_json.get("name") + self.short_description = config_json.get("short_description") + + if ( + self.meta + and self.meta.installed_release + and self.meta.installed_release.is_github_release + and config_json.get("tile") + ): + self.icon = icon_to_github_url( + self.meta.installed_release.source_repo, config_json.get("tile") + ) + + shutil.rmtree(self.wasm_ext_dir, True) + shutil.copytree(extracted_dir, self.wasm_ext_dir) + shutil.rmtree(tmp_dir, True) logger.info(f"Extension {self.name} ({self.installed_version}) extracted.") def clean_extension_files(self): @@ -479,6 +752,12 @@ class InstallableExtension(BaseModel): shutil.rmtree(self.ext_upgrade_dir, True) + def clean_wasm_extension_files(self): + if self.zip_path.is_file(): + os.remove(self.zip_path) + + shutil.rmtree(self.wasm_ext_dir, True) + def check_release_updates(self, release: ExtensionRelease | None): self._check_latest_version(release) self._check_payment_link(release) @@ -609,6 +888,42 @@ class InstallableExtension(BaseModel): version=version, short_description=config_json.get("short_description"), icon=config_json.get("tile"), + permissions=ExtensionPermission.list_from_config(config_json), + meta=ExtensionMeta( + installed_release=ExtensionRelease( + name=ext_id, + version=version, + archive=f"{conf_path}", + source_repo=f"{conf_path}", + min_lnbits_version=config_json.get("min_lnbits_version"), + max_lnbits_version=config_json.get("max_lnbits_version"), + ) + ), + ) + + except Exception as e: + logger.warning(e) + + return None + + @classmethod + def from_wasm_ext_dir(cls, ext_id: str) -> InstallableExtension | None: + try: + conf_path = Path(settings.wasm_extensions_dir, ext_id, "config.json") + if not conf_path.is_file(): + return None + with open(conf_path, "r+") as json_file: + config_json = json.load(json_file) + version = config_json.get("version", "0.0") + + return InstallableExtension( + id=ext_id, + name=config_json.get("name", ext_id), + active=True, + version=version, + short_description=config_json.get("short_description"), + icon=config_json.get("tile"), + permissions=ExtensionPermission.list_from_config(config_json), meta=ExtensionMeta( installed_release=ExtensionRelease( name=ext_id, @@ -641,7 +956,10 @@ class InstallableExtension(BaseModel): if cache_value.older_than(10 * 60) or post_refresh_cache: # refresh cache in background if older than 10 minutes or requested - create_task(cls._refresh_installable_extensions_cache()) + task_manager.create_task( + cls._refresh_installable_extensions_cache(), + "refresh_installable_extensions_cache", + ) extension_list = cache_value.value # type: ignore return extension_list @@ -663,7 +981,7 @@ class InstallableExtension(BaseModel): ) -> list[InstallableExtension]: extension_list: list[InstallableExtension] = [] - for url in settings.lnbits_extensions_manifests: + for url, manifest_type in _extension_manifest_sources(): try: manifest = await cls.fetch_manifest(url) @@ -671,6 +989,8 @@ class InstallableExtension(BaseModel): ext = await InstallableExtension.from_github_release(r) if not ext: continue + if ext.meta and ext.meta.latest_release: + ext.meta.latest_release.manifest_type = manifest_type existing_ext = next( (ee for ee in extension_list if ee.id == r.id), None ) @@ -680,11 +1000,17 @@ class InstallableExtension(BaseModel): meta = ext.meta or ExtensionMeta() meta.featured = ext.id in manifest.featured + meta.categories = [ + category + for category, ext_ids in manifest.categories.items() + if ext.id in ext_ids + ] ext.meta = meta extension_list += [ext] for e in manifest.extensions: release = ExtensionRelease.from_explicit_release(url, e) + release.manifest_type = manifest_type existing_ext = next( (ee for ee in extension_list if ee.id == e.id), None ) @@ -695,6 +1021,11 @@ class InstallableExtension(BaseModel): ext.check_release_updates(release) meta = ext.meta or ExtensionMeta() meta.featured = ext.id in manifest.featured + meta.categories = [ + category + for category, ext_ids in manifest.categories.items() + if ext.id in ext_ids + ] ext.meta = meta extension_list += [ext] except Exception as e: @@ -706,11 +1037,9 @@ class InstallableExtension(BaseModel): @classmethod async def get_extension_releases(cls, ext_id: str) -> list[ExtensionRelease]: extension_releases: list[ExtensionRelease] = [] - all_manifests = [ - *settings.lnbits_extensions_manifests, - settings.lnbits_extensions_builder_manifest_url, - ] - for url in all_manifests: + for url, manifest_type in _extension_manifest_sources( + include_builder=True, deduplicate=False + ): try: manifest = await cls.fetch_manifest(url) for r in manifest.repos: @@ -719,12 +1048,23 @@ class InstallableExtension(BaseModel): repo_releases = await ExtensionRelease.get_github_releases( r.organisation, r.repository ) + for release in repo_releases: + release.manifest_type = manifest_type extension_releases += repo_releases for e in manifest.extensions: if e.id != ext_id: continue explicit_release = ExtensionRelease.from_explicit_release(url, e) + if ( + explicit_release.extension_type == "wasm" + and explicit_release.details_link + ): + config = await ExtensionConfig.fetch_release_config( + explicit_release.details_link + ) + explicit_release.apply_config(config) + explicit_release.manifest_type = manifest_type await explicit_release.check_payment_requirements() extension_releases.append(explicit_release) @@ -778,7 +1118,7 @@ class InstallableExtension(BaseModel): @classmethod async def fetch_manifest(cls, url) -> Manifest: error_msg = "Cannot fetch extensions manifest" - manifest = await github_api_get(url, error_msg) + manifest = await extension_metadata_get(url, error_msg) return Manifest.parse_obj(manifest) @@ -789,6 +1129,7 @@ class CreateExtension(BaseModel): version: str cost_sats: int | None = 0 payment_hash: str | None = None + permissions: list[ExtensionPermission] = [] class ExtensionDetailsRequest(BaseModel): @@ -823,11 +1164,36 @@ class ExtensionReview(BaseModel): comment: str | None = Field(default=None) +async def extension_metadata_get(url: str, error_msg: str | None) -> Any: + try: + parsed_url = httpx.URL(url) + except Exception as exc: + raise ValueError("Invalid extension metadata URL") from exc + if parsed_url.userinfo: + raise ValueError("Extension metadata URLs must not contain credentials") + if _is_github_token_url(url): + return await github_api_get(url, error_msg) + return await unauthenticated_json_get(url, error_msg) + + +async def unauthenticated_json_get(url: str, error_msg: str | None) -> Any: + headers = {"User-Agent": settings.user_agent} + async with httpx.AsyncClient(headers=headers, follow_redirects=False) as client: + resp = await client.get(url) + if resp.status_code != 200: + logger.warning(f"{error_msg} ({url}): {resp.text}") + resp.raise_for_status() + return resp.json() + + async def github_api_get(url: str, error_msg: str | None) -> Any: + if not _is_github_token_url(url): + raise ValueError("Refusing GitHub authentication for an untrusted origin") + headers = {"User-Agent": settings.user_agent} if settings.lnbits_ext_github_token: headers["Authorization"] = f"Bearer {settings.lnbits_ext_github_token}" - async with httpx.AsyncClient(headers=headers) as client: + async with httpx.AsyncClient(headers=headers, follow_redirects=False) as client: resp = await client.get(url) if resp.status_code != 200: logger.warning(f"{error_msg} ({url}): {resp.text}") @@ -841,3 +1207,65 @@ def icon_to_github_url(source_repo: str, path: str | None) -> str: _, _, *rest = path.split("/") tail = "/".join(rest) return f"https://github.com/{source_repo}/raw/main/{tail}" + + +def wasm_extension_icon_url(ext_id: str) -> str: + return f"/ext-assets/{ext_id}/assets/icon.png" + + +def _extension_tile(ext_info: InstallableExtension) -> str | None: + if ext_info.is_wasm: + return wasm_extension_icon_url(ext_info.id) + return ext_info.icon + + +def _archive_config_name(names: list[str]) -> str | None: + for name in names: + path = PurePosixPath(name) + if len(path.parts) == 2 and path.name == "config.json": + return name + return None + + +def _extension_manifest_sources( + *, include_builder: bool = False, deduplicate: bool = True +) -> list[tuple[str, ExtensionManifestType]]: + sources = [ + *( + (url, ExtensionManifestType.PYTHON) + for url in settings.lnbits_extensions_manifests + ), + *( + (url, ExtensionManifestType.WASM) + for url in settings.lnbits_wasm_extensions_manifests + ), + ] + if include_builder: + sources.append( + ( + settings.lnbits_extensions_builder_manifest_url, + ExtensionManifestType.PYTHON, + ) + ) + if not deduplicate: + return sources + unique_sources: dict[str, ExtensionManifestType] = {} + for url, manifest_type in sources: + unique_sources.setdefault(url, manifest_type) + return list(unique_sources.items()) + + +_GITHUB_TOKEN_HOSTS = frozenset({"api.github.com", "raw.githubusercontent.com"}) + + +def _is_github_token_url(url: str) -> bool: + try: + parsed_url = httpx.URL(url) + except Exception: + return False + return ( + parsed_url.scheme == "https" + and parsed_url.host in _GITHUB_TOKEN_HOSTS + and parsed_url.port is None + and not parsed_url.userinfo + ) diff --git a/lnbits/core/models/misc.py b/lnbits/core/models/misc.py index 5aad3fdc9..8a7e8ced3 100644 --- a/lnbits/core/models/misc.py +++ b/lnbits/core/models/misc.py @@ -1,6 +1,8 @@ from __future__ import annotations from collections.abc import Callable +from pathlib import Path +from typing import Any from pydantic import BaseModel @@ -11,8 +13,45 @@ def _do_nothing(*_): class CoreAppExtra: register_new_ext_routes: Callable = _do_nothing + register_new_wasm_ext_routes: Callable = _do_nothing + unregister_wasm_ext_routes: Callable = _do_nothing register_new_ratelimiter: Callable + def __init__(self) -> None: + self.wasm_extension_registry = WasmExtensionRegistry() + + +class WasmExtensionRegistry: + def __init__(self) -> None: + self._extensions: dict[str, Any] = {} + + def register(self, extension: Any) -> None: + self.require_available(extension) + self._extensions[extension.id] = extension + + def require_available(self, extension: Any) -> None: + existing = self._extensions.get(extension.id) + if existing and not _same_wasm_extension_registration(existing, extension): + raise ValueError( + f"WASM extension id '{extension.id}' is already registered." + ) + + def get(self, ext_id: str) -> Any | None: + return self._extensions.get(ext_id) + + def unregister(self, ext_id: str) -> None: + self._extensions.pop(ext_id, None) + + def list(self) -> list[Any]: + return list(self._extensions.values()) + + +def _same_wasm_extension_registration(left: Any, right: Any) -> bool: + try: + return Path(left.root_path).resolve() == Path(right.root_path).resolve() + except (AttributeError, TypeError): + return left is right + class ConversionData(BaseModel): from_: str = "sat" @@ -41,6 +80,7 @@ class SimpleStatus(BaseModel): class SimpleItem(BaseModel): id: str name: str + expires_at: int | None = None class DbVersion(BaseModel): diff --git a/lnbits/core/models/payments.py b/lnbits/core/models/payments.py index b6d530d5f..4c3ebb4bb 100644 --- a/lnbits/core/models/payments.py +++ b/lnbits/core/models/payments.py @@ -13,6 +13,7 @@ from lnbits.db import FilterModel from lnbits.fiat.base import ( FiatPaymentStatus, ) +from lnbits.helpers import is_valid_external_id from lnbits.utils.exchange_rates import allowed_currencies from lnbits.wallets.base import ( PaymentStatus, @@ -34,6 +35,11 @@ class PaymentExtra(BaseModel): lnurl_response: str | None = None +class UpdatePaymentExtra(BaseModel): + payment_hash: str + extra: dict = Field(default_factory=dict) + + class PayInvoice(BaseModel): payment_request: str description: str | None = None @@ -48,11 +54,17 @@ class CreatePayment(BaseModel): amount_msat: int memo: str extra: dict | None = {} + extension: str | None = None preimage: str | None = None expiry: datetime | None = None webhook: str | None = None fee: int = 0 labels: list[str] | None = None + external_id: str | None = None + + @validator("external_id") + def validate_external_id(cls, external_id): + return _validate_external_id(external_id) class Payment(BaseModel): @@ -77,6 +89,11 @@ class Payment(BaseModel): updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) labels: list[str] = [] extra: dict = {} + external_id: str | None = None + + @validator("external_id") + def validate_external_id(cls, external_id): + return _validate_external_id(external_id) def __init__(self, **data): super().__init__(**data) @@ -124,22 +141,18 @@ class Payment(BaseModel): ) # DEPRECATED: in v1.5.0, use service check_payment_status instead - async def check_status( - self, skip_internal_payment_notifications: bool | None = False - ) -> PaymentStatus: + async def check_status(self) -> PaymentStatus: logger.warning("payment.check_status() is deprecated.") from lnbits.core.services.payments import check_payment_status - return await check_payment_status(self, skip_internal_payment_notifications) + return await check_payment_status(self) # DEPRECATED: in v1.5.0, use service check_payment_status instead - async def check_fiat_status( - self, skip_internal_payment_notifications: bool | None = False - ) -> FiatPaymentStatus: + async def check_fiat_status(self) -> FiatPaymentStatus: logger.warning("payment.check_fiat_status() is deprecated.") from lnbits.core.services.fiat_providers import check_fiat_status - return await check_fiat_status(self, skip_internal_payment_notifications) + return await check_fiat_status(self) class PaymentFilters(FilterModel): @@ -151,6 +164,7 @@ class PaymentFilters(FilterModel): "status", "time", "labels", + "external_id", ] __sort_fields__ = [ @@ -161,11 +175,13 @@ class PaymentFilters(FilterModel): "memo", "time", "tag", + "external_id", ] status: str | None tag: str | None checking_id: str | None + external_id: str | None amount: int fee: int memo: str | None @@ -205,6 +221,13 @@ class PaymentWalletStats(BaseModel): balance: float = 0 +class PaymentTotalBreakdown(BaseModel): + tag: str | None = None + is_fiat: bool = False + payments_count: int = 0 + total: int = 0 + + class PaymentDailyStats(BaseModel): date: datetime balance: float = 0 @@ -244,11 +267,16 @@ class CreateInvoice(BaseModel): ) expiry: int | None = None extra: dict | None = None + extension: str | None = None webhook: str | None = None bolt11: str | None = None lnurl_withdraw: LnurlWithdrawResponse | None = None fiat_provider: str | None = None labels: list[str] = [] + external_id: str | None = Query(default=None, max_length=256) + + def is_fiat_subscription(self) -> bool: + return (self.extra or {}).get("fiat_method") == "subscription" @validator("payment_hash") def check_hex(cls, v): @@ -263,6 +291,10 @@ class CreateInvoice(BaseModel): raise ValueError("The provided unit is not supported") return v + @validator("external_id") + def validate_external_id(cls, external_id): + return _validate_external_id(external_id) + class PaymentsStatusCount(BaseModel): incoming: int = 0 @@ -301,3 +333,12 @@ class CancelInvoice(BaseModel): class UpdatePaymentLabels(BaseModel): labels: list[str] = [] + + +def _validate_external_id(external_id: str | None) -> str | None: + if external_id and not is_valid_external_id(external_id): + raise ValueError( + "Invalid external id. Max length is 256 characters. " + "Space and newlines are not allowed." + ) + return external_id diff --git a/lnbits/core/models/sso/__init__.py b/lnbits/core/models/sso/__init__.py new file mode 100644 index 000000000..3e20e144f --- /dev/null +++ b/lnbits/core/models/sso/__init__.py @@ -0,0 +1 @@ +"""SSO authentication providers for LNbits""" diff --git a/lnbits/core/models/sso/oidc.py b/lnbits/core/models/sso/oidc.py new file mode 100644 index 000000000..89625fa04 --- /dev/null +++ b/lnbits/core/models/sso/oidc.py @@ -0,0 +1,36 @@ +"""Generic OIDC SSO Login Helper""" + +from typing import Optional + +import httpx +from fastapi_sso.sso.base import DiscoveryDocument, OpenID, SSOBase + + +class OidcSSO(SSOBase): + """Class providing login via Generic OIDC OAuth (e.g., Zitadel, Authentik, etc.)""" + + provider = "oidc" + scope = ["openid", "email", "profile"] + discovery_url = "" + + async def openid_from_response( + self, response: dict, session: Optional["httpx.AsyncClient"] = None + ) -> OpenID: + """Return OpenID from user information provided by OIDC provider""" + return OpenID( + email=response.get("email", ""), + provider=self.provider, + id=response.get("sub"), + first_name=response.get("given_name"), + last_name=response.get("family_name"), + display_name=response.get("name") or response.get("preferred_username"), + picture=response.get("picture"), + ) + + async def get_discovery_document(self) -> DiscoveryDocument: + """Get document containing handy urls""" + async with httpx.AsyncClient() as session: + response = await session.get(self.discovery_url) + content = response.json() + + return content diff --git a/lnbits/core/models/tinyurl.py b/lnbits/core/models/tinyurl.py index a9e4cdff5..af96b60f8 100644 --- a/lnbits/core/models/tinyurl.py +++ b/lnbits/core/models/tinyurl.py @@ -1,4 +1,6 @@ -from pydantic import BaseModel +from datetime import datetime, timezone + +from pydantic import BaseModel, Field class TinyURL(BaseModel): @@ -6,4 +8,4 @@ class TinyURL(BaseModel): url: str endless: bool wallet: str - time: float + time: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) diff --git a/lnbits/core/models/wallets.py b/lnbits/core/models/wallets.py index 69cb61879..8e6241948 100644 --- a/lnbits/core/models/wallets.py +++ b/lnbits/core/models/wallets.py @@ -126,6 +126,7 @@ class Wallet(BaseWallet): created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) currency: str | None = None + lightning_address: str | None = None balance_msat: int = Field(default=0, no_database=True) extra: WalletExtra = WalletExtra() stored_paylinks: StoredPayLinks = StoredPayLinks() @@ -150,6 +151,7 @@ class Wallet(BaseWallet): if len(self.share_permissions): self.currency = shared_wallet.currency + self.lightning_address = shared_wallet.lightning_address self.balance_msat = shared_wallet.balance_msat self.stored_paylinks = shared_wallet.stored_paylinks @@ -240,10 +242,18 @@ class BaseWalletTypeInfo: class WalletsFilters(FilterModel): - __search_fields__ = ["id", "name", "currency"] + __search_fields__ = ["id", "name", "currency", "lightning_address"] - __sort_fields__ = ["id", "name", "currency", "created_at", "updated_at"] + __sort_fields__ = [ + "id", + "name", + "currency", + "lightning_address", + "created_at", + "updated_at", + ] id: str | None name: str | None currency: str | None + lightning_address: str | None diff --git a/lnbits/core/services/__init__.py b/lnbits/core/services/__init__.py index 82eabd3ae..f95ef4a5c 100644 --- a/lnbits/core/services/__init__.py +++ b/lnbits/core/services/__init__.py @@ -1,3 +1,10 @@ +from .blockexplorer import ( + fetch_fee_estimates, + fetch_onchain_balance, + fetch_recent_blocks, + fetch_tip, + fetch_transaction, +) from .fiat_providers import check_fiat_status from .funding_source import ( get_balance_delta, @@ -56,7 +63,12 @@ __all__ = [ "enqueue_admin_notification", "fee_reserve", "fee_reserve_total", + "fetch_fee_estimates", "fetch_lnurl_pay_request", + "fetch_onchain_balance", + "fetch_recent_blocks", + "fetch_tip", + "fetch_transaction", "get_balance_delta", "get_payments_daily_stats", "get_pr_from_lnurl", diff --git a/lnbits/core/services/assets.py b/lnbits/core/services/assets.py index 2ed4aab20..ae9e96b00 100644 --- a/lnbits/core/services/assets.py +++ b/lnbits/core/services/assets.py @@ -1,7 +1,9 @@ import base64 import io +from urllib.parse import quote from uuid import uuid4 +import filetype from fastapi import UploadFile from loguru import logger from PIL import Image @@ -10,11 +12,48 @@ from lnbits.core.crud.assets import create_asset, get_user_assets_count from lnbits.core.models.assets import Asset from lnbits.settings import settings +IMAGE_MIME_TYPE_ALIASES = { + "heic": "image/heic", + "heics": "image/heics", + "heif": "image/heif", + "image/jpg": "image/jpeg", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "png": "image/png", +} +PIL_IMAGE_FORMAT_MIME_TYPES = { + "JPEG": "image/jpeg", + "PNG": "image/png", +} +INLINE_ASSET_MIME_TYPES = { + "image/heic", + "image/heics", + "image/heif", + "image/jpeg", + "image/png", +} +ASSET_SECURITY_HEADERS = { + "X-Content-Type-Options": "nosniff", + "Content-Security-Policy": ( + "sandbox; default-src 'none'; script-src 'none'; " + "object-src 'none'; base-uri 'none'" + ), +} +THUMBNAIL_FORMAT_MIME_TYPES = { + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "png": "image/png", +} + async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) -> Asset: if not file.content_type: raise ValueError("File must have a content type.") - if file.content_type.lower() not in settings.lnbits_assets_allowed_mime_types: + + content_type = normalize_asset_mime_type(file.content_type) + filename = file.filename or "unnamed" + + if content_type not in allowed_asset_mime_types(): raise ValueError(f"File type '{file.content_type}' not allowed.") if not settings.is_unlimited_assets_user(user_id): @@ -30,14 +69,26 @@ async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) -> f"File limit of {settings.lnbits_max_asset_size_mb}MB exceeded." ) + stored_mime_type = detect_image_mime_type(contents) + if stored_mime_type != content_type: + logger.warning( + "Image MIME type mismatch: declared={}, detected={}", + content_type, + stored_mime_type, + ) + raise ValueError( + "Image file content does not match declared file type. " + f"Declared: '{content_type}', detected: '{stored_mime_type}'." + ) + thumb_buffer = thumbnail_from_bytes(contents) asset = Asset( id=uuid4().hex, user_id=user_id, - mime_type=file.content_type, + mime_type=stored_mime_type, is_public=is_public, - name=file.filename or "unnamed", + name=filename, size_bytes=len(contents), thumbnail_base64=( base64.b64encode(thumb_buffer.getvalue()).decode("utf-8") @@ -51,6 +102,79 @@ async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) -> return asset +def normalize_asset_mime_type(content_type: str) -> str: + content_type = content_type.split(";", 1)[0].strip().lower() + return IMAGE_MIME_TYPE_ALIASES.get(content_type, content_type) + + +def normalize_media_type(media_type: str) -> str: + return media_type.split(";", 1)[0].strip().lower() or "application/octet-stream" + + +def thumbnail_media_type() -> str: + thumbnail_format = (settings.lnbits_asset_thumbnail_format or "png").strip().lower() + return THUMBNAIL_FORMAT_MIME_TYPES.get(thumbnail_format, "application/octet-stream") + + +def content_disposition(disposition: str, filename: str) -> str: + safe_filename = filename or "unnamed" + quoted_filename = quote(safe_filename, safe="") + if quoted_filename == safe_filename: + return f'{disposition}; filename="{safe_filename}"' + return f"{disposition}; filename*=utf-8''{quoted_filename}" + + +def allowed_asset_mime_types() -> set[str]: + return { + mime_type + for mime_type in ( + normalize_asset_mime_type(mime_type) + for mime_type in settings.lnbits_assets_allowed_mime_types + ) + if mime_type.startswith("image/") + } + + +def detect_image_mime_type(contents: bytes) -> str: + kind = filetype.guess(contents) + mime_type = normalize_asset_mime_type(kind.mime) if kind else None + + if mime_type and mime_type in PIL_IMAGE_FORMAT_MIME_TYPES.values(): + verify_pil_image(contents, mime_type) + return mime_type + + if mime_type and mime_type.startswith("image/"): + return mime_type + + try: + with Image.open(io.BytesIO(contents)) as image: + image.verify() + mime_type = PIL_IMAGE_FORMAT_MIME_TYPES.get(image.format or "") + except Exception as exc: + raise ValueError( + "Image file content does not match declared file type." + ) from exc + + if not mime_type: + raise ValueError("Image file content does not match declared file type.") + + return mime_type + + +def verify_pil_image(contents: bytes, mime_type: str) -> None: + try: + with Image.open(io.BytesIO(contents)) as image: + image.verify() + detected_mime_type = PIL_IMAGE_FORMAT_MIME_TYPES.get(image.format or "") + except Exception as exc: + raise ValueError( + "Image file content does not match declared file type." + ) from exc + + if detected_mime_type != mime_type: + raise ValueError("Image file content does not match declared file type.") + + def thumbnail_from_bytes(contents: bytes) -> io.BytesIO | None: try: image = Image.open(io.BytesIO(contents)) diff --git a/lnbits/core/services/blockexplorer.py b/lnbits/core/services/blockexplorer.py new file mode 100644 index 000000000..31f03a862 --- /dev/null +++ b/lnbits/core/services/blockexplorer.py @@ -0,0 +1,97 @@ +import asyncio + +from lnbits.settings import settings +from lnbits.task_manager import OnchainAddressEvent +from lnbits.utils.electrum import ( + UTXO, + AddressResponse, + Balance, + BlockHeader, + BlockInfo, + ElectrumClient, + FeeResponse, + Transaction, + network_from_name, + parse_block_header, + parse_raw_tx, + scripthash_from_address, +) + + +def _client() -> ElectrumClient: + return ElectrumClient( + settings.lnbits_blockexplorer_electrum_url, + network=network_from_name(settings.lnbits_blockexplorer_network), + ) + + +async def fetch_recent_blocks(count: int = 5) -> list[BlockInfo]: + async with _client() as c: + tip = await c.get_tip() + start = max(0, tip.height - count + 1) + headers = await c.get_block_headers(start, tip.height - start + 1) + raw = bytes.fromhex(headers.hex) + blocks = [ + parse_block_header(raw[i * 80 : (i + 1) * 80].hex(), start + i) + for i in range(headers.count) + ] + return list(reversed(blocks)) + + +async def fetch_tip() -> BlockHeader: + async with _client() as c: + return await c.get_tip() + + +async def fetch_fee_estimates() -> FeeResponse: + async with _client() as c: + estimates_raw = await asyncio.gather( + c.estimate_fee(1), + c.estimate_fee(3), + c.estimate_fee(6), + c.estimate_fee(144), + ) + histogram = await c.fee_histogram() + estimates = { + str(blocks): fee + for blocks, fee in zip([1, 3, 6, 144], estimates_raw, strict=False) + if fee >= 0 + } + return FeeResponse(estimates=estimates, histogram=histogram) + + +async def fetch_transaction(txid: str) -> Transaction: + async with _client() as c: + raw_hex = await c.get_transaction(txid) + return parse_raw_tx(raw_hex, network=c.network) + + +async def fetch_onchain_balance(onchain_address: str) -> AddressResponse: + scripthash = scripthash_from_address(onchain_address) + async with _client() as client: + balance_res, history_res = await asyncio.gather( + client.get_balance(scripthash), + client.get_history(scripthash), + return_exceptions=True, + ) + if isinstance(balance_res, BaseException): + raise balance_res + history = [] if isinstance(history_res, BaseException) else history_res + history_error = str(history_res) if isinstance(history_res, BaseException) else None + return AddressResponse( + balance=balance_res, history=history, history_error=history_error + ) + + +async def fetch_utxos(onchain_address: str) -> list[UTXO]: + scripthash = scripthash_from_address(onchain_address) + async with _client() as client: + return await client.listunspent(scripthash) + + +def address_event_to_response(event: OnchainAddressEvent) -> AddressResponse: + return AddressResponse( + balance=Balance(confirmed=event.confirmed, unconfirmed=event.unconfirmed), + history=event.history, + history_error=event.history_error, + ) diff --git a/lnbits/core/services/extensions.py b/lnbits/core/services/extensions.py index 8743efbc2..690eedcbd 100644 --- a/lnbits/core/services/extensions.py +++ b/lnbits/core/services/extensions.py @@ -1,5 +1,12 @@ import asyncio import importlib +import re +from collections.abc import Mapping +from dataclasses import dataclass +from datetime import datetime, timedelta, timezone +from threading import RLock +from typing import Any +from uuid import uuid4 from loguru import logger @@ -9,21 +16,178 @@ from lnbits.core.crud import ( delete_installed_extension, get_db_version, get_installed_extension, + get_installed_extensions_count, update_installed_extension_state, ) from lnbits.core.crud.extensions import ( + create_wasm_invocation, + delete_old_wasm_invocations, get_installed_extensions, + get_wasm_invocation, + mark_stale_wasm_invocations, update_installed_extension, + update_installed_extension_wasm_runtime_limits, + update_wasm_invocation, +) +from lnbits.core.crud.extensions import ( + get_wasm_invocation_stats as get_wasm_invocation_stats_crud, +) +from lnbits.core.crud.extensions import ( + get_wasm_invocations as get_wasm_invocations_crud, ) from lnbits.core.helpers import migrate_extension_database +from lnbits.core.wasm_ext.api.permissions import validate_wasm_extension_permissions +from lnbits.core.wasm_ext.wasm.loader import is_wasm_extension_id from lnbits.db import Connection -from lnbits.settings import settings +from lnbits.settings import WasmRuntimeLimits, settings -from ..models.extensions import Extension, ExtensionMeta, InstallableExtension +from ..models.extensions import ( + Extension, + ExtensionMeta, + ExtensionPermission, + InstallableExtension, + WasmInvocation, + WasmInvocationStats, +) + +_WASM_INVOCATION_CLEANUP_INTERVAL = timedelta(hours=1) +WASM_RUNTIME_LIMIT_FIELDS = tuple(WasmRuntimeLimits.__fields__.keys()) + + +@dataclass +class WasmInvocationHandle: + invocation: WasmInvocation + engine: Any | None = None + store: Any | None = None + runtime_limits: dict[str, int] | None = None + stop_requested: bool = False + stop_reason: str | None = None + + +_wasm_invocation_lock = RLock() +_wasm_invocation_ready_lock = asyncio.Lock() +_wasm_invocation_handles: dict[str, WasmInvocationHandle] = {} +_wasm_invocations_marked_stale = False +_wasm_invocations_last_cleanup_at: datetime | None = None + + +def wasm_runtime_limit_defaults() -> dict[str, int]: + return {field: int(getattr(settings, field)) for field in WASM_RUNTIME_LIMIT_FIELDS} + + +def validate_wasm_runtime_limit_overrides( + limits: Mapping[str, Any] | None, + *, + strict: bool = True, +) -> dict[str, int]: + if not limits: + return {} + + validated: dict[str, int] = {} + for field, raw_value in limits.items(): + if field not in WASM_RUNTIME_LIMIT_FIELDS: + if strict: + raise ValueError(f"Unknown WASM runtime limit field '{field}'.") + continue + + value = _validate_wasm_runtime_limit_value(field, raw_value, strict=strict) + if value is None: + continue + validated[field] = value + + return validated + + +def _validate_wasm_runtime_limit_value( + field: str, + raw_value: Any, + *, + strict: bool, +) -> int | None: + if raw_value is None or raw_value == "": + return None + if isinstance(raw_value, bool): + return _invalid_wasm_runtime_limit(field, strict, "must be an integer") + if isinstance(raw_value, str): + raw_value = raw_value.strip() + if raw_value == "": + return None + if not raw_value.isdecimal(): + return _invalid_wasm_runtime_limit(field, strict, "must be an integer") + if isinstance(raw_value, float) and not raw_value.is_integer(): + return _invalid_wasm_runtime_limit(field, strict, "must be an integer") + + try: + value = int(raw_value) + except (TypeError, ValueError) as exc: + return _invalid_wasm_runtime_limit( + field, + strict, + "must be an integer", + exc=exc, + ) + if value < 0: + return _invalid_wasm_runtime_limit(field, strict, "cannot be negative") + return value + + +def _invalid_wasm_runtime_limit( + field: str, + strict: bool, + message: str, + *, + exc: Exception | None = None, +) -> int | None: + if not strict: + return None + error = ValueError(f"WASM runtime limit '{field}' {message}.") + if exc: + raise error from exc + raise error + + +def resolve_wasm_runtime_limits( + installed_extension: InstallableExtension | None = None, +) -> dict[str, int]: + limits = wasm_runtime_limit_defaults() + if installed_extension: + limits.update( + validate_wasm_runtime_limit_overrides( + installed_extension.wasm_runtime_limits, + strict=False, + ) + ) + return limits + + +async def get_wasm_runtime_limits_for_extension(ext_id: str) -> dict[str, int]: + installed_extension = await get_installed_extension(ext_id) + return resolve_wasm_runtime_limits(installed_extension) + + +async def update_wasm_extension_runtime_limits( + ext_id: str, + limits: Mapping[str, Any] | None, +) -> dict[str, int]: + installed_extension = await get_installed_extension(ext_id) + if not installed_extension: + raise ValueError(f"Extension '{ext_id}' is not installed.") + if not installed_extension.is_wasm: + raise ValueError(f"Extension '{ext_id}' is not a WASM extension.") + + validated_limits = validate_wasm_runtime_limit_overrides(limits) + await update_installed_extension_wasm_runtime_limits( + ext_id=ext_id, + limits=validated_limits, + ) + return validated_limits async def install_extension( - ext_info: InstallableExtension, skip_download: bool | None = False + ext_info: InstallableExtension, + skip_download: bool | None = False, + granted_permissions: list[ExtensionPermission] | None = None, + allow_admin_policy_overrides: bool = False, ) -> Extension: ext_info.meta = ext_info.meta or ExtensionMeta() @@ -37,11 +201,27 @@ async def install_extension( installed_ext = await get_installed_extension(ext_info.id) if installed_ext and installed_ext.meta: ext_info.meta.payments = installed_ext.meta.payments + if installed_ext: + ext_info.wasm_runtime_limits = installed_ext.wasm_runtime_limits + + await check_extensions_limit(installed_ext) if not skip_download: await ext_info.download_archive() - ext_info.extract_archive() + extension_config = ext_info.load_archive_config() + ext_info.validate_archive(extension_config) + ext_info.permissions = validate_wasm_extension_permissions( + ext_info, + granted_permissions, + extension_config, + allow_admin_policy_overrides=allow_admin_policy_overrides, + ) + + if extension_config.get("extension_type") == "wasm": + ext_info.extract_wasm_archive() + else: + ext_info.extract_archive() db_version = await get_db_version(ext_info.id) await migrate_extension_database(ext_info, db_version) @@ -53,34 +233,438 @@ async def install_extension( else: await update_installed_extension(ext_info) - extension = Extension.from_installable_ext(ext_info) - if extension.is_upgrade_extension: - # call stop while the old routes are still active + if installed_ext: await stop_extension_background_work(ext_info.id) - await start_extension_background_work(ext_info.id) + return Extension.from_installable_ext(ext_info) - return extension + +async def check_extensions_limit(installed_ext: InstallableExtension | None = None): + if settings.lnbits_max_extensions == 0 or installed_ext: + return + + extensions_count = await get_installed_extensions_count() + if extensions_count >= settings.lnbits_max_extensions: + raise ValueError("Max amount of extensions have been installed") + + +async def ensure_wasm_invocation_monitoring_ready() -> None: + global _wasm_invocations_last_cleanup_at, _wasm_invocations_marked_stale + + async with _wasm_invocation_ready_lock: + now = _now() + if not _wasm_invocations_marked_stale: + await mark_stale_wasm_invocations() + _wasm_invocations_marked_stale = True + + if ( + _wasm_invocations_last_cleanup_at is None + or now - _wasm_invocations_last_cleanup_at + >= _WASM_INVOCATION_CLEANUP_INTERVAL + ): + _wasm_invocations_last_cleanup_at = now + await delete_old_wasm_invocations( + settings.lnbits_wasm_invocation_retention_days + ) + + +async def start_wasm_invocation( + *, + extension_id: str, + export_name: str, + trigger_type: str = "unknown", + user_id: str | None = None, + wallet_id: str | None = None, + request_id: str | None = None, + method: str | None = None, + path: str | None = None, + event_type: str | None = None, + payment_hash: str | None = None, + checking_id: str | None = None, + request_bytes: int | None = None, + context: dict | None = None, + runtime_limits: dict[str, int] | None = None, +) -> WasmInvocation: + await ensure_wasm_invocation_monitoring_ready() + _check_wasm_invocation_concurrency( + extension_id=extension_id, + user_id=user_id, + limits=runtime_limits, + ) + + invocation = WasmInvocation( + id=uuid4().hex, + extension_id=extension_id, + export_name=export_name, + trigger_type=trigger_type, + user_id=user_id, + wallet_id=wallet_id, + request_id=request_id, + method=method, + path=path, + event_type=event_type, + payment_hash=payment_hash, + checking_id=checking_id, + request_bytes=request_bytes, + context=_safe_wasm_invocation_context(context or {}), + ) + await create_wasm_invocation(invocation) + + with _wasm_invocation_lock: + _wasm_invocation_handles[invocation.id] = WasmInvocationHandle( + invocation, + runtime_limits=runtime_limits, + ) + + return invocation + + +def attach_wasm_invocation_runtime( + invocation_id: str, + *, + engine: Any, + store: Any, +) -> None: + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.get(invocation_id) + if not handle: + return + handle.engine = engine + handle.store = store + if handle.stop_requested: + _interrupt_wasm_invocation(handle) + + +def record_wasm_invocation_host_call( + invocation_id: str | None, + method_id: str, +) -> None: + if not invocation_id: + return + + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.get(invocation_id) + if not handle: + return + + invocation = handle.invocation + invocation.host_call_count += 1 + category = _wasm_host_call_category(method_id) + if category == "http": + invocation.http_call_count += 1 + elif category == "storage": + invocation.storage_call_count += 1 + elif category == "wallet": + invocation.wallet_call_count += 1 + + _check_wasm_host_call_limit(invocation, category, handle.runtime_limits) + + +async def stop_wasm_invocation( + invocation_id: str, + *, + reason: str = "Stopped by admin.", +) -> bool: + interrupted = False + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.get(invocation_id) + if handle: + handle.stop_requested = True + handle.stop_reason = reason + handle.invocation.stop_reason = reason + interrupted = _interrupt_wasm_invocation(handle) + + invocation = await get_wasm_invocation(invocation_id) + if invocation and invocation.status == "running": + invocation.stop_reason = reason + await update_wasm_invocation(invocation) + + return interrupted + + +async def stop_wasm_extension_invocations( + extension_id: str, + *, + reason: str = "Extension deactivated.", +) -> int: + with _wasm_invocation_lock: + invocation_ids = [ + invocation_id + for invocation_id, handle in _wasm_invocation_handles.items() + if handle.invocation.extension_id == extension_id + ] + + for invocation_id in invocation_ids: + await stop_wasm_invocation(invocation_id, reason=reason) + + return len(invocation_ids) + + +def wasm_invocation_stop_requested(invocation_id: str) -> bool: + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.get(invocation_id) + return bool(handle and handle.stop_requested) + + +def get_wasm_invocation_stop_reason(invocation_id: str) -> str | None: + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.get(invocation_id) + return handle.stop_reason if handle else None + + +async def finish_wasm_invocation( + invocation_id: str, + *, + status: str, + response_bytes: int | None = None, + memory_peak_bytes: int | None = None, + error_type: str | None = None, + error_message: str | None = None, + stop_reason: str | None = None, +) -> None: + with _wasm_invocation_lock: + handle = _wasm_invocation_handles.pop(invocation_id, None) + + invocation = ( + handle.invocation if handle else await get_wasm_invocation(invocation_id) + ) + if not invocation: + return + + reason = stop_reason or (handle.stop_reason if handle else None) + if handle and handle.stop_requested and status == "failed": + status = "stopped" + reason = reason or "Stopped by admin." + + finished_at = _now() + invocation.status = status + invocation.finished_at = finished_at + invocation.duration_ms = max( + 0, int((finished_at - invocation.started_at).total_seconds() * 1000) + ) + invocation.response_bytes = response_bytes + invocation.memory_peak_bytes = memory_peak_bytes + invocation.error_type = error_type + invocation.error_message = _safe_wasm_error_message(error_message) + invocation.stop_reason = reason + + await update_wasm_invocation(invocation) + + +def get_current_wasm_invocations( + extension_id: str | None = None, +) -> list[WasmInvocation]: + with _wasm_invocation_lock: + invocations = [] + for handle in _wasm_invocation_handles.values(): + if extension_id and handle.invocation.extension_id != extension_id: + continue + invocation = handle.invocation.copy(deep=True) + if handle.stop_requested and invocation.status == "running": + invocation.status = "stopping" + invocation.stop_reason = handle.stop_reason + invocations.append(invocation) + + return sorted( + invocations, key=lambda invocation: invocation.started_at, reverse=True + ) + + +def _check_wasm_invocation_concurrency( + *, + extension_id: str, + user_id: str | None, + limits: dict[str, int] | None, +) -> None: + if not limits: + return + + with _wasm_invocation_lock: + handles = list(_wasm_invocation_handles.values()) + if _wasm_limit_exceeded( + limits["wasm_runtime_max_concurrent_invocations"], + len(handles) + 1, + ): + raise ValueError("WASM runtime has too many active invocations.") + + extension_invocations = sum( + 1 for handle in handles if handle.invocation.extension_id == extension_id + ) + if _wasm_limit_exceeded( + limits["wasm_runtime_max_concurrent_invocations_per_extension"], + extension_invocations + 1, + ): + raise ValueError( + f"WASM extension '{extension_id}' has too many active invocations." + ) + + if not user_id: + return + + user_invocations = sum( + 1 for handle in handles if handle.invocation.user_id == user_id + ) + if _wasm_limit_exceeded( + limits["wasm_runtime_max_concurrent_invocations_per_user"], + user_invocations + 1, + ): + raise ValueError("WASM user has too many active invocations.") + + +def _check_wasm_host_call_limit( + invocation: WasmInvocation, + category: str, + limits: dict[str, int] | None, +) -> None: + if not limits: + return + + if _wasm_limit_exceeded( + limits["wasm_runtime_max_host_calls"], + invocation.host_call_count, + ): + raise ValueError("WASM host call limit exceeded.") + + category_limits = { + "http": ( + limits["wasm_runtime_max_http_calls"], + invocation.http_call_count, + ), + "storage": ( + limits["wasm_runtime_max_storage_calls"], + invocation.storage_call_count, + ), + "wallet": ( + limits["wasm_runtime_max_wallet_calls"], + invocation.wallet_call_count, + ), + } + category_limit = category_limits.get(category) + if category_limit and _wasm_limit_exceeded(*category_limit): + raise ValueError(f"WASM {category} host call limit exceeded.") + + +def _wasm_limit_exceeded(limit: int, value: int) -> bool: + return limit > 0 and value > limit + + +async def get_wasm_invocation_history( + *, + extension_id: str | None = None, + status: str | None = None, + limit: int = 100, + offset: int = 0, +) -> list[WasmInvocation]: + await ensure_wasm_invocation_monitoring_ready() + return await get_wasm_invocations_crud( + extension_id=extension_id, + status=status, + limit=limit, + offset=offset, + ) + + +async def get_wasm_invocation_summary( + *, + extension_id: str | None = None, + hours: int = 24, +) -> WasmInvocationStats: + await ensure_wasm_invocation_monitoring_ready() + since = _now() - timedelta(hours=max(1, min(hours, 24 * 30))) + return await get_wasm_invocation_stats_crud( + extension_id=extension_id, + since=since, + ) + + +def _interrupt_wasm_invocation(handle: WasmInvocationHandle) -> bool: + if not handle.store or not handle.engine: + return False + try: + handle.store.set_epoch_deadline(1) + handle.engine.increment_epoch() + return True + except Exception as exc: + logger.warning( + f"Failed to interrupt WASM invocation '{handle.invocation.id}': {exc}" + ) + return False + + +def _wasm_host_call_category(method_id: str) -> str: + if method_id.startswith("http.") or method_id.startswith("extension.api."): + return "http" + if method_id.startswith("storage."): + return "storage" + if method_id.startswith("wallet."): + return "wallet" + return "host" + + +def _safe_wasm_invocation_context(context: dict) -> dict: + safe_context: dict = {} + for key, value in context.items(): + if not isinstance(key, str): + continue + if value is None or isinstance(value, (bool, int, float)): + safe_context[key[:64]] = value + elif isinstance(value, str): + safe_context[key[:64]] = value[:256] + return safe_context + + +def _safe_wasm_error_message(message: str | None) -> str | None: + if not message: + return None + + safe_message = message[:500] + redactions = [ + ( + r"(?i)(api[-_ ]?key|token|authorization|password|secret|preimage)" + r"\s*[:=]\s*[^\s,;]+", + r"\1=[redacted]", + ), + (r"(?i)bearer\s+[A-Za-z0-9._~+/=-]+", "Bearer [redacted]"), + (r"\b[a-fA-F0-9]{64}\b", "[redacted-hex]"), + ] + for pattern, replacement in redactions: + safe_message = re.sub(pattern, replacement, safe_message) + return safe_message + + +def _now() -> datetime: + return datetime.now(timezone.utc) async def uninstall_extension(ext_id: str): await stop_extension_background_work(ext_id) + core_app_extra.unregister_wasm_ext_routes(ext_id) settings.deactivate_extension_paths(ext_id) extension = await get_installed_extension(ext_id) if extension: - extension.clean_extension_files() + if extension.is_wasm: + extension.clean_wasm_extension_files() + else: + extension.clean_extension_files() await delete_installed_extension(ext_id=ext_id) async def activate_extension(ext: Extension): + if ext.is_wasm: + core_app_extra.register_new_wasm_ext_routes(ext.code) + await update_installed_extension_state(ext_id=ext.code, active=True) + return + core_app_extra.register_new_ext_routes(ext) await update_installed_extension_state(ext_id=ext.code, active=True) await start_extension_background_work(ext.code) async def deactivate_extension(ext_id: str): + if is_wasm_extension_id(ext_id): + await stop_wasm_extension_invocations(ext_id, reason="Extension deactivated.") settings.deactivate_extension_paths(ext_id) await update_installed_extension_state(ext_id=ext_id, active=False) await stop_extension_background_work(ext_id) @@ -91,16 +675,19 @@ async def stop_extension_background_work(ext_id: str) -> bool: Stop background work for extension (like asyncio.Tasks, WebSockets, etc). Extension must expose a `myextension_stop()` function if it is starting tasks. """ - upgrade_hash = settings.extension_upgrade_hash(ext_id) - ext = Extension(code=ext_id, is_valid=True, upgrade_hash=upgrade_hash) + if is_wasm_extension_id(ext_id): + return True + + ext = Extension(code=ext_id, is_valid=True) + module_name = ext.module_name try: - logger.info(f"Stopping background work for extension '{ext.module_name}'.") - old_module = importlib.import_module(ext.module_name) + logger.info(f"Stopping background work for extension '{module_name}'.") + old_module = importlib.import_module(module_name) stop_fn_name = f"{ext_id}_stop" if not hasattr(old_module, stop_fn_name): - raise ValueError(f"No stop function found for '{ext.module_name}'.") + raise ValueError(f"No stop function found for '{module_name}'.") stop_fn = getattr(old_module, stop_fn_name) if stop_fn: @@ -108,9 +695,9 @@ async def stop_extension_background_work(ext_id: str) -> bool: await stop_fn() else: stop_fn() - logger.info(f"Stopped background work for extension '{ext.module_name}'.") + logger.info(f"Stopped background work for extension '{module_name}'.") except Exception as ex: - logger.warning(f"Failed to stop background work for '{ext.module_name}'.") + logger.warning(f"Failed to stop background work for '{module_name}'.") logger.warning(ex) return False @@ -123,12 +710,15 @@ async def start_extension_background_work(ext_id: str) -> bool: Extension CAN expose a `myextension_start()` function if it is starting tasks. Extension MUST expose a `myextension_stop()` in that case. """ - upgrade_hash = settings.extension_upgrade_hash(ext_id) - ext = Extension(code=ext_id, is_valid=True, upgrade_hash=upgrade_hash) + if is_wasm_extension_id(ext_id): + return False + + ext = Extension(code=ext_id, is_valid=True) + module_name = ext.module_name try: - logger.info(f"Starting background work for extension '{ext.module_name}'.") - new_module = importlib.import_module(ext.module_name) + logger.info(f"Starting background work for extension '{module_name}'.") + new_module = importlib.import_module(module_name) start_fn_name = f"{ext_id}_start" # start function is optional, return False if not found @@ -141,10 +731,10 @@ async def start_extension_background_work(ext_id: str) -> bool: await start_fn() else: start_fn() - logger.info(f"Started background work for extension '{ext.module_name}'.") + logger.info(f"Started background work for extension '{module_name}'.") return True except Exception as ex: - logger.warning(f"Failed to start background work for '{ext.module_name}'.") + logger.warning(f"Failed to start background work for '{module_name}'.") logger.warning(ex) return False diff --git a/lnbits/core/services/fiat_providers.py b/lnbits/core/services/fiat_providers.py index 9041010b4..6f3c6fdcc 100644 --- a/lnbits/core/services/fiat_providers.py +++ b/lnbits/core/services/fiat_providers.py @@ -2,12 +2,13 @@ import hashlib import hmac import json import time +from base64 import b64encode import httpx from loguru import logger from lnbits.core.crud import get_wallet -from lnbits.core.crud.payments import create_payment +from lnbits.core.crud.payments import create_payment, update_payment from lnbits.core.models import CreatePayment, Payment, PaymentState from lnbits.core.models.misc import SimpleStatus from lnbits.db import Connection @@ -19,6 +20,7 @@ from lnbits.fiat.base import ( FiatPaymentSuccessStatus, ) from lnbits.settings import settings +from lnbits.task_manager import task_manager async def handle_fiat_payment_confirmation( @@ -35,9 +37,7 @@ async def handle_fiat_payment_confirmation( logger.warning(e) -async def check_fiat_status( - payment: Payment, skip_internal_payment_notifications: bool | None = False -) -> FiatPaymentStatus: +async def check_fiat_status(payment: Payment) -> FiatPaymentStatus: if not payment.is_internal: return FiatPaymentPendingStatus() if payment.success: @@ -57,14 +57,11 @@ async def check_fiat_status( return FiatPaymentPendingStatus() fiat_status = await fiat_provider.get_invoice_status(checking_id) - if skip_internal_payment_notifications: - return fiat_status - if fiat_status.success: - # notify receivers asynchronously - from lnbits.tasks import internal_invoice_queue - - await internal_invoice_queue.put(payment.checking_id) + payment.status = PaymentState.SUCCESS.value + await update_payment(payment) + await handle_fiat_payment_confirmation(payment) + task_manager.internal_invoice_queue.put_nowait(payment) return fiat_status @@ -169,6 +166,82 @@ async def verify_paypal_webhook(headers, payload: bytes): raise ValueError("PayPal webhook cannot be verified.") from exc +def check_square_signature( + payload: bytes, + sig_header: str | None, + secret: str | None, + notification_url: str | None, +): + if not sig_header: + logger.warning("Square signature header is missing.") + raise ValueError("Square signature header is missing.") + + if not secret: + logger.warning("Square webhook signature key is not set.") + raise ValueError("Square webhook cannot be verified.") + + if not notification_url: + logger.warning("Square webhook notification URL is not set.") + raise ValueError("Square webhook cannot be verified.") + + signed_payload = notification_url.encode() + payload + computed_signature = b64encode( + hmac.new( + key=secret.encode(), msg=signed_payload, digestmod=hashlib.sha256 + ).digest() + ).decode() + + if hmac.compare_digest(computed_signature, sig_header) is not True: + logger.warning("Square signature verification failed.") + raise ValueError("Square signature verification failed.") + + +def check_revolut_signature( + payload: bytes, + sig_header: str | None, + timestamp_header: str | None, + secret: str | None, + tolerance_seconds=300, +): + if not sig_header: + logger.warning("Revolut signature header is missing.") + raise ValueError("Revolut signature header is missing.") + + if not timestamp_header: + logger.warning("Revolut timestamp header is missing.") + raise ValueError("Revolut timestamp header is missing.") + + if not secret: + logger.warning("Revolut webhook signing secret is not set.") + raise ValueError("Revolut webhook cannot be verified.") + + try: + timestamp = int(timestamp_header) + except ValueError as exc: + logger.warning("Invalid Revolut timestamp.") + raise ValueError("Invalid Revolut timestamp.") from exc + + timestamp_seconds = timestamp / 1000 if timestamp > 9999999999 else timestamp + + if abs(time.time() - timestamp_seconds) > tolerance_seconds: + logger.warning("Timestamp outside tolerance.") + raise ValueError("Timestamp outside tolerance." f"Timestamp: {timestamp}") + + signed_payload = b"v1." + timestamp_header.encode() + b"." + payload + digest = hmac.new( + key=secret.encode(), msg=signed_payload, digestmod=hashlib.sha256 + ).hexdigest() + expected_signature = f"v1={digest}" + + provided_signatures = [sig.strip() for sig in sig_header.split(",") if sig.strip()] + if not any( + hmac.compare_digest(expected_signature, provided) + for provided in provided_signatures + ): + logger.warning("Revolut signature verification failed.") + raise ValueError("Revolut signature verification failed.") + + async def test_connection(provider: str) -> SimpleStatus: """ Test the connection to Stripe by checking if the API key is valid. diff --git a/lnbits/core/services/funding_source.py b/lnbits/core/services/funding_source.py index 02caab058..ce9437dc1 100644 --- a/lnbits/core/services/funding_source.py +++ b/lnbits/core/services/funding_source.py @@ -66,6 +66,8 @@ async def check_server_balance_against_node(): async def check_balance_delta_changed(): + if settings.notification_balance_delta_threshold_sats <= 0: + return status = await get_balance_delta() if settings.latest_balance_delta_sats is None: settings.latest_balance_delta_sats = status.delta_sats diff --git a/lnbits/core/services/lightning_address.py b/lnbits/core/services/lightning_address.py new file mode 100644 index 000000000..421b33156 --- /dev/null +++ b/lnbits/core/services/lightning_address.py @@ -0,0 +1,242 @@ +import json +import re + +from fastapi import Query, Request +from lnurl import ( + CallbackUrl, + LightningInvoice, + LnurlErrorResponse, + LnurlPayActionResponse, + LnurlPayMetadata, + LnurlPayResponse, + MilliSatoshi, +) +from pydantic import parse_obj_as + +from lnbits.core.crud.wallets import ( + get_wallet, + get_wallet_id_by_ln_address, + update_wallet, +) +from lnbits.core.models.payments import CreateInvoice +from lnbits.core.models.wallets import Wallet +from lnbits.core.services.payments import ( + create_invoice, + create_wallet_invoice, + pay_invoice, +) +from lnbits.db import Connection +from lnbits.exceptions import PaymentError +from lnbits.settings import settings + +MAX_SENDABLE_MSAT = 2_100_000_000_000_000_000 +COMMENT_ALLOWED = 799 +LIGHTNING_ADDRESS_REGEX = re.compile(r"^[a-z0-9_.-]{1,210}$") + + +async def set_wallet_lightning_address( + *, + wallet: Wallet, + local_part: str, + allow_blacklisted: bool = False, + charge: bool = False, + conn: Connection | None = None, +) -> Wallet: + if not settings.ln_address_creation_allowed: + raise ValueError("Wallet Lightning Addresses are disabled.") + if not wallet.is_lightning_wallet or wallet.deleted: + raise ValueError("Lightning Address can only be set for active wallets.") + + local_part = await _validate_local_part( + local_part, wallet.id, allow_blacklisted, conn=conn + ) + if wallet.lightning_address == local_part: + return wallet + + if charge: + await _charge_for_lightning_address(wallet) + + wallet.lightning_address = local_part + return await update_wallet(wallet, conn=conn) + + +async def wallet_lightning_address_response( + username: str, request: Request +) -> LnurlPayResponse | LnurlErrorResponse: + local_part, tag = _split_tagged_local_part(username) + wallet_id = await get_wallet_id_by_ln_address(local_part) + if not wallet_id: + return LnurlErrorResponse(reason="Lightning address not found.") + + tagged_local_part = local_part + if tag: + tagged_local_part = f"{tagged_local_part}+{tag}" + + callback = request.url_for( + "lnurl.api_wallet_lightning_address_callback", + username=tagged_local_part, + ) + identifier = _lightning_address_for_request(request, tagged_local_part) + return LnurlPayResponse( + callback=parse_obj_as(CallbackUrl, str(callback)), + minSendable=MilliSatoshi(1000), + maxSendable=MilliSatoshi(MAX_SENDABLE_MSAT), + metadata=LnurlPayMetadata(json.dumps(_metadata(identifier, tag))), + commentAllowed=COMMENT_ALLOWED, + ) + + +async def wallet_lightning_address_callback( + username: str, + request: Request, + amount: int = Query(...), +) -> LnurlErrorResponse | LnurlPayActionResponse: + local_part, tag = _split_tagged_local_part(username) + wallet_id = await get_wallet_id_by_ln_address(local_part) + if not wallet_id: + return LnurlErrorResponse(reason="Lightning address not found.") + + if amount < 1000: + return LnurlErrorResponse(reason="Amount is smaller than minimum 1000.") + if amount > MAX_SENDABLE_MSAT: + return LnurlErrorResponse( + reason=f"Amount is greater than maximum {MAX_SENDABLE_MSAT}." + ) + + comment = request.query_params.get("comment") + if len(comment or "") > COMMENT_ALLOWED: + return LnurlErrorResponse( + reason=( + f"Got a comment with {len(comment or '')} characters, " + f"but can only accept {COMMENT_ALLOWED}" + ) + ) + + tagged_local_part = local_part + if tag: + tagged_local_part = f"{tagged_local_part}+{tag}" + identifier = _lightning_address_for_request(request, tagged_local_part) + extra = { + "tag": "wallet_lightning_address", + "lnaddress": identifier, + } + if tag: + extra["lnaddress_tag"] = tag + if comment: + extra["comment"] = comment + + metadata = LnurlPayMetadata(json.dumps(_metadata(identifier, tag))) + payment = await create_invoice( + wallet_id=wallet_id, + amount=int(amount / 1000), + memo=f"Payment to {identifier}", + unhashed_description=metadata.encode(), + extra=extra, + ) + invoice = parse_obj_as(LightningInvoice, LightningInvoice(payment.bolt11)) + return LnurlPayActionResponse(pr=invoice, disposable=False) + + +def _lightning_address_for_request(request: Request, local_part: str) -> str: + return f"{local_part}@{request.url.netloc}" + + +async def _validate_local_part( + local_part: str, + wallet_id: str, + allow_blacklisted: bool = False, + conn: Connection | None = None, +) -> str: + local_part = local_part.strip().lower() + if not local_part: + raise ValueError("Lightning Address is required.") + if "+" in local_part: + raise ValueError("Lightning Address cannot include tags.") + if "@" in local_part: + raise ValueError("Enter only the Lightning Address name before @.") + if not LIGHTNING_ADDRESS_REGEX.match(local_part): + raise ValueError( + "Lightning Address can only contain lowercase letters, numbers, " + "dash, underscore, and dot." + ) + if not allow_blacklisted and _uses_blacklisted_word(local_part): + raise ValueError("Lightning Address contains a reserved word.") + existing_wallet_id = await get_wallet_id_by_ln_address(local_part, conn=conn) + if existing_wallet_id and existing_wallet_id != wallet_id: + raise ValueError("Lightning Address is already taken.") + + return local_part + + +def _split_tagged_local_part(local_part: str) -> tuple[str, str | None]: + username, separator, tag = local_part.partition("+") + if not separator or not tag: + return username.lower(), None + return username.lower(), tag + + +def _metadata(identifier: str, tag: str | None = None) -> list[list[str]]: + metadata = [ + ["text/plain", f"Payment to {identifier}"], + ["text/identifier", identifier], + ] + if tag: + metadata.append(["text/tag", tag]) + return metadata + + +async def _charge_for_lightning_address(wallet: Wallet) -> None: + price_sats = settings.lnbits_wallet_lightning_address_price_sats + if not settings.lnbits_charge_wallet_lightning_addresses or price_sats <= 0: + return + if not settings.lnbits_service_fee_wallet: + raise ValueError("Lightning Address fee wallet is not configured.") + if settings.lnbits_service_fee_wallet == wallet.source_wallet_id: + raise ValueError("Lightning Address fee wallet cannot be the same wallet.") + + fee_wallet = await get_wallet(settings.lnbits_service_fee_wallet) + if not fee_wallet: + raise ValueError("Lightning Address fee wallet is not configured.") + + invoice = await create_wallet_invoice( + settings.lnbits_service_fee_wallet, + CreateInvoice( + out=False, + amount=price_sats, + memo="Lightning Address fee", + internal=True, + extra={ + "tag": "wallet_lightning_address_fee", + "wallet": wallet.source_wallet_id, + }, + ), + ) + try: + await pay_invoice( + wallet_id=wallet.source_wallet_id, + payment_request=invoice.bolt11, + description="Lightning Address fee", + tag="wallet_lightning_address_fee", + extra={ + "tag": "wallet_lightning_address_fee", + "fee_wallet": settings.lnbits_service_fee_wallet, + }, + ) + except PaymentError as exc: + raise ValueError(exc.message) from exc + + +def _blacklist_words() -> set[str]: + return { + word.strip().lower() + for word in settings.lnbits_wallet_lightning_address_blacklist + if word.strip() + } + + +def _uses_blacklisted_word(local_part: str) -> bool: + words = _blacklist_words() + if not words: + return False + segments = [segment for segment in re.split(r"[._-]+", local_part) if segment] + return local_part in words or any(segment in words for segment in segments) diff --git a/lnbits/core/services/notifications.py b/lnbits/core/services/notifications.py index 8860fbd6a..bed83e842 100644 --- a/lnbits/core/services/notifications.py +++ b/lnbits/core/services/notifications.py @@ -74,7 +74,7 @@ async def send_admin_notification( message: str, message_type: str | None = None, ) -> None: - return await send_notification( + return await send_notification_in_background( settings.lnbits_telegram_notifications_chat_id, settings.lnbits_nostr_notifications_identifiers, settings.lnbits_email_notifications_to_emails, @@ -97,7 +97,7 @@ async def send_user_notification( if user_notifications.nostr_identifier else [] ) - return await send_notification( + return await send_notification_in_background( user_notifications.telegram_chat_id, nostr_identifiers, email_address, @@ -222,12 +222,29 @@ async def send_email( msg["Subject"] = subject msg.attach(MIMEText(message, "plain")) username = username if len(username) > 0 else from_email - with smtplib.SMTP(server, port) as smtp_server: - smtp_server.starttls() - smtp_server.login(username, password) - smtp_server.sendmail(from_email, to_emails, msg.as_string()) + + def _send() -> bool: + with smtplib.SMTP(server, port) as smtp_server: + smtp_server.starttls() + smtp_server.login(username, password) + smtp_server.sendmail(from_email, to_emails, msg.as_string()) return True + try: + return await asyncio.to_thread(_send) + except Exception as e: + logger.warning(f"Sending Email failed. {e!s}") + return False + + +async def dispatch_payment_notification(payment: Payment) -> None: + """ + This worker dispatches the payment notifications. + """ + wallet = await get_wallet(payment.wallet_id) + if wallet: + await send_payment_notification(wallet, payment) + async def dispatch_webhook(payment: Payment): """ @@ -294,6 +311,27 @@ def send_payment_notification_in_background(wallet: Wallet, payment: Payment): logger.warning(f"Error sending payment notification: {e}") +async def send_notification_in_background( + telegram_chat_id: str | None, + nostr_identifiers: list[str] | None, + email_addresses: list[str] | None, + message: str, + message_type: str | None = None, +): + try: + create_task( + send_notification( + telegram_chat_id, + nostr_identifiers, + email_addresses, + message, + message_type, + ) + ) + except Exception as e: + logger.warning(f"Error sending notification in background: {e}") + + async def send_ws_payment_notification(wallet: Wallet, payment: Payment): # TODO: websocket message should be a clean payment model # await websocket_manager.send(wallet.inkey, payment.json()) diff --git a/lnbits/core/services/payments.py b/lnbits/core/services/payments.py index ef1d07dbd..4987dd517 100644 --- a/lnbits/core/services/payments.py +++ b/lnbits/core/services/payments.py @@ -17,9 +17,9 @@ from lnbits.db import Connection, Filters from lnbits.decorators import check_user_extension_access from lnbits.exceptions import InvoiceError, PaymentError, UnsupportedError from lnbits.fiat import get_fiat_provider -from lnbits.helpers import check_callback_url +from lnbits.helpers import check_callback_url, daystart_timestamp from lnbits.settings import settings -from lnbits.tasks import create_task, internal_invoice_queue_put +from lnbits.task_manager import task_manager from lnbits.utils.crypto import fake_privkey, random_secret_and_hash, verify_preimage from lnbits.utils.exchange_rates import fiat_amount_as_satoshis, satoshis_amount_as_fiat from lnbits.wallets import fake_wallet, get_funding_source @@ -64,6 +64,7 @@ async def pay_invoice( description: str = "", tag: str = "", labels: list[str] | None = None, + external_id: str | None = None, conn: Connection | None = None, ) -> Payment: if settings.lnbits_only_allow_incoming_payments: @@ -97,6 +98,7 @@ async def pay_invoice( memo=description or invoice.description or "", extra=extra, labels=labels, + external_id=external_id, ) async with db.reuse_conn(conn) if conn else db.connect() as new_conn: @@ -116,6 +118,8 @@ async def create_payment_request( Create a lightning invoice or a fiat payment request. """ if invoice_data.fiat_provider: + if invoice_data.is_fiat_subscription(): + raise ValueError("Cannot create direct fiat subscription payments.") return await create_fiat_invoice(wallet_id, invoice_data) return await create_wallet_invoice(wallet_id, invoice_data) @@ -169,15 +173,15 @@ async def create_fiat_invoice( internal_payment.fiat_provider = fiat_provider_name internal_payment.extra["fiat_checking_id"] = fiat_invoice.checking_id - # todo: move to payent + # TODO: move to payment internal_payment.extra["fiat_payment_request"] = fiat_invoice.payment_request new_checking_id = ( f"fiat_{fiat_provider_name}_" f"{fiat_invoice.checking_id or internal_payment.checking_id}" ) - await update_payment(internal_payment, new_checking_id, conn=conn) - internal_payment.checking_id = new_checking_id - + internal_payment = await update_payment( + internal_payment, new_checking_id, conn=conn + ) return internal_payment @@ -213,10 +217,12 @@ async def create_wallet_invoice(wallet_id: str, data: CreateInvoice) -> Payment: unhashed_description=unhashed_description, expiry=data.expiry, extra=data.extra, + extension=data.extension, webhook=data.webhook, internal=data.internal, payment_hash=data.payment_hash, labels=data.labels, + external_id=data.external_id, conn=conn, ) @@ -257,7 +263,9 @@ async def create_invoice( webhook: str | None = None, internal: bool | None = False, payment_hash: str | None = None, + extension: str | None = None, labels: list[str] | None = None, + external_id: str | None = None, conn: Connection | None = None, ) -> Payment: if not amount > 0: @@ -339,9 +347,11 @@ async def create_invoice( expiry=invoice.expiry_date, memo=memo, extra=extra, + extension=extension, webhook=webhook, fee=invoice_response.fee_msat or 0, labels=labels, + external_id=external_id, ) payment = await create_payment( @@ -366,10 +376,17 @@ async def update_pending_payments(wallet_id: str): async def update_pending_payment( payment: Payment, conn: Connection | None = None ) -> Payment: + if payment.is_in and payment.is_expired: + payment.status = PaymentState.FAILED + payment.labels.append("expired") + await update_payment(payment, conn=conn) + logger.info(f"invoice {payment.checking_id} expired, marked as failed") + return payment + status = await check_payment_status(payment) if status.failed: payment.status = PaymentState.FAILED - await update_payment(payment, conn=conn) + payment = await update_payment(payment, conn=conn) elif status.success: payment = await update_payment_success_status(payment, status, conn=conn) return payment @@ -509,7 +526,7 @@ async def update_wallet_balance( ) payment.status = PaymentState.SUCCESS await update_payment(payment, conn=conn) - await internal_invoice_queue_put(payment.checking_id) + task_manager.internal_invoice_queue.put_nowait(payment) async def check_wallet_limits( @@ -549,10 +566,9 @@ async def check_wallet_daily_withdraw_limit( raise ValueError("It is not allowed to spend funds from this server.") payments = await get_payments( - since=int(time.time()) - 60 * 60 * 24, + since=daystart_timestamp(), outgoing=True, wallet_id=wallet_id, - limit=1, conn=conn, ) if len(payments) == 0: @@ -618,23 +634,19 @@ async def check_transaction_status( return PaymentPendingStatus() if payment.status == PaymentState.SUCCESS.value: - return PaymentSuccessStatus(fee_msat=payment.fee) + return PaymentSuccessStatus(fee_msat=payment.fee, preimage=payment.preimage) return await check_payment_status(payment) -async def check_payment_status( - payment: Payment, skip_internal_payment_notifications: bool | None = False -) -> PaymentStatus: +async def check_payment_status(payment: Payment) -> PaymentStatus: if payment.is_internal: if payment.success: - return PaymentSuccessStatus() + return PaymentSuccessStatus(fee_msat=payment.fee, preimage=payment.preimage) if payment.failed: return PaymentFailedStatus() if payment.is_in and payment.fiat_provider: - fiat_status = await check_fiat_status( - payment, skip_internal_payment_notifications - ) + fiat_status = await check_fiat_status(payment) return PaymentStatus(paid=fiat_status.paid) return PaymentPendingStatus() funding_source = get_funding_source() @@ -776,13 +788,16 @@ async def _pay_internal_invoice( await update_payment(internal_payment, conn=conn) logger.success(f"internal payment successful {internal_payment.checking_id}") - await _send_payment_notification_in_background(wallet.id, payment, conn=conn) - - # notify receiver asynchronously - from lnbits.tasks import internal_invoice_queue + await _send_payment_notification_in_background( + wallet.id, payment, conn=conn + ) # notify the sender + await _send_payment_notification_in_background( + internal_payment.wallet_id, internal_payment, conn=conn + ) # notify the receiver + # notify receiver asynchronously (extension listeners) logger.debug(f"enqueuing internal invoice {internal_payment.checking_id}") - await internal_invoice_queue.put(internal_payment.checking_id) + task_manager.internal_invoice_queue.put_nowait(internal_payment) return payment @@ -819,14 +834,15 @@ async def _pay_external_invoice( fee_reserve_msat = fee_reserve(amount_msat, internal=False) - task = create_task( - _fundingsource_pay_invoice(checking_id, payment.bolt11, fee_reserve_msat) + task = task_manager.create_task( + _fundingsource_pay_invoice(checking_id, payment.bolt11, fee_reserve_msat), + f"fundingsource_pay_invoice_{checking_id}", ) # make sure a hold invoice or deferred payment is not blocking the server wait_time = max(1, settings.lnbits_funding_source_pay_invoice_wait_seconds) try: - payment_response = await asyncio.wait_for(task, timeout=wait_time) + payment_response = await asyncio.wait_for(task.task, timeout=wait_time) except asyncio.TimeoutError: # return pending payment on timeout logger.debug( @@ -834,26 +850,46 @@ async def _pay_external_invoice( ) return payment + # IMPORTANT PAYMENT RULES! + # True -> success + # False-> failed + # None -> pending (any ambigous payment responses MUST be set as pending) + # payment failed - if ( - payment_response.checking_id is None - or payment_response.ok is False - or payment_response.checking_id != checking_id - ): + if payment_response.failed: payment.status = PaymentState.FAILED await update_payment(payment, conn=conn) message = payment_response.error_message or "without an error message." raise PaymentError(f"Payment failed: {message}", status="failed") - if payment_response.success: + # payment successful + elif payment_response.success: payment = await update_payment_success_status( - payment, payment_response, conn=conn + payment, + payment_response, + conn=conn, + new_checking_id=payment_response.checking_id, ) await _send_payment_notification_in_background(wallet.id, payment, conn=conn) - logger.success(f"payment successful {payment_response.checking_id}") + logger.success(f"payment successful {payment.checking_id}") + + # payment pending + else: + if ( + payment_response.checking_id + and payment_response.checking_id != payment.checking_id + ): + payment = await update_payment( + payment, + new_checking_id=payment_response.checking_id, + conn=conn, + ) + logger.warning( + f"payment status unknown {payment.checking_id}: " + f"{payment_response.error_message or 'no error message'}" + ) - payment.checking_id = payment_response.checking_id return payment @@ -861,13 +897,16 @@ async def update_payment_success_status( payment: Payment, status: PaymentStatus, conn: Connection | None = None, + new_checking_id: str | None = None, ) -> Payment: if status.success: service_fee_msat = service_fee(payment.amount, internal=False) payment.status = PaymentState.SUCCESS payment.fee = -(abs(status.fee_msat or 0) + abs(service_fee_msat)) payment.preimage = payment.preimage or status.preimage - await update_payment(payment, conn=conn) + payment = await update_payment( + payment, new_checking_id=new_checking_id, conn=conn + ) return payment @@ -1068,3 +1107,46 @@ async def _send_payment_notification_in_background( if not wallet: raise PaymentError(f"Could not fetch wallet '{wallet_id}'.", status="failed") send_payment_notification_in_background(wallet, payment) + + +async def update_invoice_from_paid_invoices_stream(checking_id: str) -> Payment | None: + """ + Takes a checking_id of an incoming payment from paid_invoices_stream() + Checks its status, updates its status and returns it. + returns None if no incoming payment was found or the status is not successful + """ + payment = await get_standalone_payment(checking_id, incoming=True) + if not payment: + logger.warning(f"No incoming payment found for '{checking_id}'.") + return None + + status = await check_payment_status(payment) + + if not status.success: + logger.error( + "Unexpected status response from paid_invoices_stream. Skipping update." + ) + return None + + payment.fee = status.fee_msat or payment.fee + # only overwrite preimage if status.preimage provides it + payment.preimage = status.preimage or payment.preimage + payment.status = PaymentState.SUCCESS + payment = await update_payment(payment) + + return payment + + +async def fundingsource_invoice_producer() -> None: + """ + will collect all invoices that come directly from the backend wallet. + + Called registered in the app startup sequence and run by taskmanager. + """ + funding_source = get_funding_source() + async for checking_id in funding_source.paid_invoices_stream(): + logger.info(f"got a payment notification {checking_id}") + payment = await update_invoice_from_paid_invoices_stream(checking_id) + if payment: + logger.success(f"fundingsource invoice {checking_id} settled") + task_manager.invoice_queue.put_nowait(payment) diff --git a/lnbits/core/services/users.py b/lnbits/core/services/users.py index 37f2c998c..049583911 100644 --- a/lnbits/core/services/users.py +++ b/lnbits/core/services/users.py @@ -23,6 +23,7 @@ from ..crud import ( get_account_by_email, get_account_by_pubkey, get_account_by_username, + get_accounts_count, get_super_settings, get_user_extensions, get_user_from_account, @@ -55,6 +56,8 @@ async def create_user_account_no_ckeck( conn: Connection | None = None, ) -> User: async with db.reuse_conn(conn) if conn else db.connect() as conn: + await check_users_limit(conn) + if account: account.validate_fields() if account.username and await get_account_by_username( @@ -95,6 +98,15 @@ async def create_user_account_no_ckeck( return user +async def check_users_limit(conn: Connection | None = None): + if settings.lnbits_max_users == 0: + return + + users_count = await get_accounts_count(conn=conn) + if users_count >= settings.lnbits_max_users: + raise ValueError("Max amount of users have been created") + + async def update_user_account(account: Account) -> Account: account.validate_fields() @@ -173,6 +185,12 @@ async def check_admin_settings(): if account and account.extra and account.extra.provider == "env": settings.first_install = True + if settings.has_first_install_token_changed(): + logger.warning("First install token is changed. Resetting admin settings.") + new_settings = await init_admin_settings() + settings.super_user = new_settings.super_user + settings.first_install = True + logger.success( "✔️ Admin UI is enabled. run `uv run lnbits-cli superuser` " "to get the superuser." diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index a27756ce2..e11e205bf 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -2,76 +2,43 @@ import asyncio from loguru import logger -from lnbits.core.crud import ( - create_audit_entry, - get_wallet, -) -from lnbits.core.crud.audit import delete_expired_audit_entries +from lnbits.core.crud import create_audit_entry from lnbits.core.crud.payments import get_payments_status_count from lnbits.core.crud.users import get_accounts from lnbits.core.crud.wallets import get_wallets_count from lnbits.core.models.audit import AuditEntry from lnbits.core.models.extensions import InstallableExtension from lnbits.core.models.notifications import NotificationType -from lnbits.core.services.funding_source import ( - check_balance_delta_changed, - check_server_balance_against_node, - get_balance_delta, -) +from lnbits.core.services.funding_source import get_balance_delta from lnbits.core.services.notifications import ( enqueue_admin_notification, - process_next_notification, - send_payment_notification, ) from lnbits.db import Filters from lnbits.settings import settings -from lnbits.utils.exchange_rates import btc_rates +from lnbits.utils.cache import cache +from lnbits.utils.exchange_rates import btc_price_from_aggregator, btc_rates audit_queue: asyncio.Queue[AuditEntry] = asyncio.Queue() -async def run_by_the_minute_tasks() -> None: - minute_counter = 0 - while settings.lnbits_running: - status_minutes = settings.lnbits_notification_server_status_hours * 60 - - if settings.notification_balance_delta_threshold_sats > 0: - try: - # runs by default every minute, the delta should not change that often - await check_balance_delta_changed() - except Exception as ex: - logger.error(ex) - - if minute_counter % settings.lnbits_watchdog_interval_minutes == 0: - try: - await check_server_balance_against_node() - except Exception as ex: - logger.error(ex) - - if minute_counter % status_minutes == 0: - try: - await _notify_server_status() - except Exception as ex: - logger.error(ex) - - if minute_counter % 60 == 0: - try: - # initialize the list of all extensions - await InstallableExtension.get_installable_extensions( - post_refresh_cache=True - ) - except Exception as ex: - logger.error(ex) - - minute_counter += 1 - await asyncio.sleep(60) +async def process_next_audit_entry() -> None: + """ + Waits for audit entries to be pushed to the queue. + Then it inserts the entries into the DB. + """ + data = await audit_queue.get() + await create_audit_entry(data) -async def _notify_server_status() -> None: +async def refresh_extension_cache() -> None: + # only refreshes every 10 minutes + await InstallableExtension.get_installable_extensions() + + +async def notify_server_status() -> None: accounts = await get_accounts(filters=Filters(limit=0)) wallets_count = await get_wallets_count() payments = await get_payments_status_count() - status = await get_balance_delta() values = { "up_time": settings.lnbits_server_up_time, @@ -88,76 +55,38 @@ async def _notify_server_status() -> None: enqueue_admin_notification(NotificationType.server_status, values) -async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue) -> None: - """ - This worker dispatches events to all extensions and dispatches webhooks. - """ - while settings.lnbits_running: - payment = await invoice_paid_queue.get() - logger.trace("received invoice paid event") - # payment notification - wallet = await get_wallet(payment.wallet_id) - if wallet: - await send_payment_notification(wallet, payment) - - -async def wait_for_audit_data() -> None: - """ - Waits for audit entries to be pushed to the queue. - Then it inserts the entries into the DB. - """ - while settings.lnbits_running: - data = await audit_queue.get() - try: - await create_audit_entry(data) - except Exception as ex: - logger.warning(ex) - await asyncio.sleep(3) - - -async def wait_notification_messages() -> None: - - while settings.lnbits_running: - try: - await process_next_notification() - except Exception as ex: - logger.warning("Payment notification error", ex) - await asyncio.sleep(3) - - -async def purge_audit_data() -> None: - """ - Remove audit entries which have passed their retention period. - """ - while settings.lnbits_running: - try: - await delete_expired_audit_entries() - except Exception as ex: - logger.warning(ex) - - # clean every hour - await asyncio.sleep(60 * 60) - - async def collect_exchange_rates_data() -> None: """ Collect exchange rates data. Used for monitoring only. """ - while settings.lnbits_running: - currency = settings.lnbits_default_accounting_currency or "USD" - max_history_size = settings.lnbits_exchange_history_size - sleep_time = settings.lnbits_exchange_history_refresh_interval_seconds - - if sleep_time > 0: - try: - rates = await btc_rates(currency) - if rates: - rates_values = [r[1] for r in rates] - lnbits_rate = sum(rates_values) / len(rates_values) - rates.append(("LNbits", lnbits_rate)) - settings.append_exchange_rate_datapoint(dict(rates), max_history_size) - except Exception as ex: - logger.warning(ex) + currency = settings.lnbits_default_accounting_currency or "USD" + max_history_size = settings.lnbits_exchange_history_size + try: + if ( + settings.lnbits_price_aggregator_enabled + and settings.lnbits_price_aggregator_url + ): + price = await btc_price_from_aggregator(currency) + if price: + cache.set( + f"btc-price-{currency}", + price, + expiry=settings.lnbits_exchange_rate_cache_seconds, + ) + settings.append_exchange_rate_datapoint( + {"Aggregator": price}, max_history_size + ) else: - sleep_time = 60 - await asyncio.sleep(sleep_time) + rates = await btc_rates(currency) + if rates: + rates_values = [r[1] for r in rates] + lnbits_rate = sum(rates_values) / len(rates_values) + rates.append(("LNbits", lnbits_rate)) + cache.set( + f"btc-price-{currency}", + lnbits_rate, + expiry=settings.lnbits_exchange_rate_cache_seconds, + ) + settings.append_exchange_rate_datapoint(dict(rates), max_history_size) + except Exception as ex: + logger.warning(ex) diff --git a/lnbits/core/templates/index.html b/lnbits/core/templates/index.html deleted file mode 100644 index 6cd686af4..000000000 --- a/lnbits/core/templates/index.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block page %}{% -endblock %} diff --git a/lnbits/core/templates/index_public.html b/lnbits/core/templates/index_public.html deleted file mode 100644 index bd50c957f..000000000 --- a/lnbits/core/templates/index_public.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "public.html" %} {% from "macros.jinja" import window_vars with -context %} {% block scripts %} {{ window_vars() }} {% endblock %} {% block page -%} {% endblock %} diff --git a/lnbits/core/views/admin_api.py b/lnbits/core/views/admin_api.py index 6e69d07c8..c46498b70 100644 --- a/lnbits/core/views/admin_api.py +++ b/lnbits/core/views/admin_api.py @@ -20,7 +20,7 @@ from lnbits.core.services.settings import dict_to_settings from lnbits.decorators import check_admin, check_super_user from lnbits.server import server_restart from lnbits.settings import AdminSettings, Settings, UpdateSettings, settings -from lnbits.tasks import invoice_listeners +from lnbits.task_manager import PublicTask, task_manager from .. import core_app_extra from ..crud import get_admin_settings, reset_core_settings, update_admin_settings @@ -44,11 +44,10 @@ async def api_auditor(): name="Monitor", description="show the current listeners and other monitoring data", dependencies=[Depends(check_admin)], + response_model=list[PublicTask], ) -async def api_monitor(): - return { - "invoice_listeners": list(invoice_listeners.keys()), - } +async def api_monitor() -> list[PublicTask]: + return task_manager.get_public_tasks() @admin_router.get( diff --git a/lnbits/core/views/asset_api.py b/lnbits/core/views/asset_api.py index afc0d1b00..86baf3ac7 100644 --- a/lnbits/core/views/asset_api.py +++ b/lnbits/core/views/asset_api.py @@ -16,7 +16,14 @@ from lnbits.core.crud.assets import ( from lnbits.core.models.assets import AssetFilters, AssetInfo, AssetUpdate from lnbits.core.models.misc import SimpleStatus from lnbits.core.models.users import AccountId -from lnbits.core.services.assets import create_user_asset +from lnbits.core.services.assets import ( + ASSET_SECURITY_HEADERS, + INLINE_ASSET_MIME_TYPES, + content_disposition, + create_user_asset, + normalize_media_type, + thumbnail_media_type, +) from lnbits.db import Filters, Page from lnbits.decorators import ( check_account_id_exists, @@ -75,11 +82,7 @@ async def api_get_asset_data( if not asset: raise HTTPException(HTTPStatus.NOT_FOUND, "Asset not found.") - return Response( - content=asset.data, - media_type=asset.mime_type, - headers={"Content-Disposition": f'inline; filename="{asset.name}"'}, - ) + return asset_response(asset.data, asset.mime_type, asset.name) @asset_router.get( @@ -101,14 +104,14 @@ async def api_get_asset_thumbnail( if not asset_info: raise HTTPException(HTTPStatus.NOT_FOUND, "Asset not found.") - return Response( + return asset_response( content=( base64.b64decode(asset_info.thumbnail_base64) if asset_info.thumbnail_base64 else b"" ), - media_type=asset_info.mime_type, - headers={"Content-Disposition": f'inline; filename="{asset_info.name}"'}, + media_type=thumbnail_media_type(), + filename=asset_info.name, ) @@ -172,3 +175,16 @@ async def api_delete_asset( await delete_user_asset(account_id.id, asset_id) return SimpleStatus(success=True, message="Asset deleted successfully.") + + +def asset_response(content: bytes, media_type: str, filename: str) -> Response: + media_type = normalize_media_type(media_type) + disposition = "inline" if media_type in INLINE_ASSET_MIME_TYPES else "attachment" + return Response( + content=content, + media_type=media_type, + headers={ + **ASSET_SECURITY_HEADERS, + "Content-Disposition": content_disposition(disposition, filename), + }, + ) diff --git a/lnbits/core/views/auth_api.py b/lnbits/core/views/auth_api.py index 38c8b2166..5a88c257f 100644 --- a/lnbits/core/views/auth_api.py +++ b/lnbits/core/views/auth_api.py @@ -12,6 +12,7 @@ from fastapi.responses import JSONResponse, RedirectResponse from fastapi_sso.sso.base import OpenID, SSOBase from loguru import logger +from lnbits.core.crud.settings import set_settings_field from lnbits.core.crud.users import ( get_user_access_control_lists, update_user_access_control_list, @@ -35,6 +36,7 @@ from lnbits.decorators import ( check_account_exists, check_admin, check_user_exists, + optional_user_id, ) from lnbits.helpers import ( create_access_token, @@ -154,9 +156,20 @@ async def impersonate_user( max_age = settings.auth_token_expire_minutes * 60 response.set_cookie( - "admin_access_token", cookie_access_token, httponly=True, max_age=max_age + "admin_access_token", + cookie_access_token, + httponly=True, + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, + ) + response.set_cookie( + "is_lnbits_user_impersonated", + "true", + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, ) - response.set_cookie("is_lnbits_user_impersonated", "true", max_age=max_age) return response @@ -177,7 +190,12 @@ async def stop_impersonate_user( ) max_age = settings.auth_token_expire_minutes * 60 response.set_cookie( - "cookie_access_token", admin_access_token, httponly=True, max_age=max_age + "cookie_access_token", + admin_access_token, + httponly=True, + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, ) response.delete_cookie("admin_access_token") response.delete_cookie("is_access_token_expired") @@ -277,7 +295,10 @@ async def api_create_user_api_token( account.username, api_token_id, data.expiration_time_minutes ) - acl.token_id_list.append(SimpleItem(id=api_token_id, name=data.token_name)) + expires_at = int(time()) + data.expiration_time_minutes * 60 + acl.token_id_list.append( + SimpleItem(id=api_token_id, name=data.token_name, expires_at=expires_at) + ) await update_user_access_control_list(acls) return ApiTokenResponse(id=api_token_id, api_token=api_token) @@ -303,7 +324,10 @@ async def api_delete_user_api_token( @auth_router.get("/{provider}", description="SSO Provider") async def login_with_sso_provider( - request: Request, provider: str, user_id: str | None = None + request: Request, + provider: str, + user_id: str | None = None, + auth_user_id: str | None = Depends(optional_user_id), ): provider_sso = _new_sso(provider) if not provider_sso: @@ -311,6 +335,8 @@ async def login_with_sso_provider( HTTPStatus.FORBIDDEN, f"Login by '{provider}' not allowed.", ) + if user_id and user_id != auth_user_id: + raise HTTPException(HTTPStatus.FORBIDDEN, "User ID mismatch.") provider_sso.redirect_uri = str(request.base_url) + f"api/v1/auth/{provider}/token" with provider_sso: @@ -331,7 +357,11 @@ async def handle_oauth_token(request: Request, provider: str) -> RedirectRespons userinfo = await provider_sso.verify_and_process(request) if not userinfo: raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid user info.") - user_id = decrypt_internal_message(provider_sso.state) + if provider_sso.state is None or provider_sso.state == "null": + user_id = None + else: + user_id = decrypt_internal_message(provider_sso.state) + request.session.pop("user", None) return await _handle_sso_login(userinfo, user_id) @@ -532,6 +562,13 @@ async def first_install(data: UpdateSuperuserPassword) -> JSONResponse: account.hash_password(data.password) await update_account(account) settings.first_install = False + + # only confrm it after the super user has been successfully updated + if settings.first_install_token: + settings.first_install_token_confirmed = data.first_install_token + await set_settings_field( + "first_install_token_confirmed", data.first_install_token + ) return _auth_success_response(account.username, account.id, account.email) @@ -560,7 +597,7 @@ async def _handle_sso_login(userinfo: OpenID, verified_user_id: str | None = Non id=uuid4().hex, email=email, extra=UserExtra(email_verified=True) ) await create_user_account(account) - return _auth_redirect_response(redirect_path, email) + return _auth_redirect_response(redirect_path, account.id, email) def _auth_success_response( @@ -575,9 +612,20 @@ def _auth_success_response( max_age = settings.auth_token_expire_minutes * 60 response = JSONResponse({"access_token": access_token, "token_type": "bearer"}) response.set_cookie( - "cookie_access_token", access_token, httponly=True, max_age=max_age + "cookie_access_token", + access_token, + httponly=True, + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, + ) + response.set_cookie( + "is_lnbits_user_authorized", + "true", + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, ) - response.set_cookie("is_lnbits_user_authorized", "true", max_age=max_age) response.delete_cookie("is_access_token_expired") return response @@ -594,15 +642,28 @@ def _auth_api_token_response( ) -def _auth_redirect_response(path: str, email: str) -> RedirectResponse: - payload = AccessTokenPayload(sub="" or "", email=email, auth_time=int(time())) +def _auth_redirect_response(path: str, user_id: str, email: str) -> RedirectResponse: + payload = AccessTokenPayload( + usr=user_id, sub="", email=email, auth_time=int(time()) + ) access_token = create_access_token(data=payload.dict()) max_age = settings.auth_token_expire_minutes * 60 response = RedirectResponse(path) response.set_cookie( - "cookie_access_token", access_token, httponly=True, max_age=max_age + "cookie_access_token", + access_token, + httponly=True, + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, + ) + response.set_cookie( + "is_lnbits_user_authorized", + "true", + secure=settings.auth_https_only, + samesite="lax", + max_age=max_age, ) - response.set_cookie("is_lnbits_user_authorized", "true", max_age=max_age) response.delete_cookie("is_access_token_expired") return response @@ -622,7 +683,10 @@ def _new_sso(provider: str) -> SSOBase | None: sso_provider_class = _find_auth_provider_class(provider) sso_provider = sso_provider_class( - client_id, client_secret, None, allow_insecure_http=True + client_id, + client_secret, + None, + allow_insecure_http=not settings.auth_https_only, ) if ( discovery_url diff --git a/lnbits/core/views/blockexplorer_api.py b/lnbits/core/views/blockexplorer_api.py new file mode 100644 index 000000000..e088988d3 --- /dev/null +++ b/lnbits/core/views/blockexplorer_api.py @@ -0,0 +1,170 @@ +import asyncio +from http import HTTPStatus +from typing import Annotated + +from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket +from pydantic.types import UUID4 + +from lnbits.core.services.blockexplorer import ( + address_event_to_response, + fetch_fee_estimates, + fetch_onchain_balance, + fetch_recent_blocks, + fetch_tip, + fetch_transaction, + fetch_utxos, +) +from lnbits.decorators import check_access_token, check_user_exists +from lnbits.settings import settings +from lnbits.task_manager import ( + OnchainAddressEvent, + OnchainTxEvent, + relay_ws_queue, + task_manager, +) +from lnbits.utils.electrum import ( + UTXO, + AddressResponse, + BlockHeader, + BlockInfo, + ElectrumError, + FeeResponse, + Transaction, + scripthash_from_address, +) + +blockexplorer_router = APIRouter( + tags=["Block Explorer"], + prefix="/blockexplorer/api/v1", +) + + +def _check_enabled() -> None: + if not settings.lnbits_blockexplorer_enabled: + raise HTTPException( + status_code=HTTPStatus.SERVICE_UNAVAILABLE, + detail="Block explorer is not enabled.", + ) + + +async def _check_api_access( + r: Request, + access_token: Annotated[str | None, Depends(check_access_token)], + usr: UUID4 | None = None, +) -> None: + _check_enabled() + if not settings.lnbits_blockexplorer_public_api: + await check_user_exists(r, access_token, usr) + + +# ---- REST ---- + + +@blockexplorer_router.get("/blocks", dependencies=[Depends(_check_api_access)]) +async def api_blocks() -> list[BlockInfo]: + try: + return await fetch_recent_blocks() + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +@blockexplorer_router.get("/tip", dependencies=[Depends(_check_api_access)]) +async def api_tip() -> BlockHeader: + try: + return await fetch_tip() + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +@blockexplorer_router.get("/fees", dependencies=[Depends(_check_api_access)]) +async def api_fees() -> FeeResponse: + try: + return await fetch_fee_estimates() + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +@blockexplorer_router.get("/tx/{txid}", dependencies=[Depends(_check_api_access)]) +async def api_tx(txid: str) -> Transaction: + try: + return await fetch_transaction(txid) + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +@blockexplorer_router.get( + "/address/{address}", dependencies=[Depends(_check_api_access)] +) +async def api_address(address: str) -> AddressResponse: + try: + scripthash_from_address(address) + except ValueError as e: + raise HTTPException(HTTPStatus.BAD_REQUEST, detail=str(e)) from e + try: + return await fetch_onchain_balance(address) + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +@blockexplorer_router.get("/utxos/{address}", dependencies=[Depends(_check_api_access)]) +async def api_utxos(address: str) -> list[UTXO]: + try: + scripthash_from_address(address) + except ValueError as e: + raise HTTPException(HTTPStatus.BAD_REQUEST, detail=str(e)) from e + try: + return await fetch_utxos(address) + except ElectrumError as e: + raise HTTPException(HTTPStatus.SERVICE_UNAVAILABLE, detail=str(e)) from e + + +# ---- WebSocket ---- + + +@blockexplorer_router.websocket("/ws/blocks") +async def ws_blocks(websocket: WebSocket) -> None: + if not settings.lnbits_blockexplorer_enabled: + await websocket.close(code=1008) + return + await websocket.accept() + + queue: asyncio.Queue[BlockInfo] = asyncio.Queue() + task_manager.register_ws_block_queue(queue) + try: + await relay_ws_queue(websocket, queue) + finally: + task_manager.unregister_ws_block_queue(queue) + + +@blockexplorer_router.websocket("/ws/address/{address}") +async def ws_address(websocket: WebSocket, address: str) -> None: + if not settings.lnbits_blockexplorer_enabled: + await websocket.close(code=1008) + return + await websocket.accept() + + queue: asyncio.Queue[OnchainAddressEvent] = asyncio.Queue() + try: + task_manager.register_ws_address_queue(address, queue) + except ValueError as e: + await websocket.close(code=1008, reason=str(e)) + return + try: + await relay_ws_queue(websocket, queue, serialize=address_event_to_response) + finally: + task_manager.unregister_ws_address_queue(address, queue) + + +@blockexplorer_router.websocket("/ws/tx/{txid}") +async def ws_tx(websocket: WebSocket, txid: str) -> None: + if not settings.lnbits_blockexplorer_enabled: + await websocket.close(code=1008) + return + await websocket.accept() + + queue: asyncio.Queue[OnchainTxEvent] = asyncio.Queue() + task_manager.register_ws_tx_queue(txid, queue) + try: + await relay_ws_queue(websocket, queue, stop_after=lambda e: e.confirmed) + finally: + task_manager.unregister_ws_tx_queue(txid, queue) diff --git a/lnbits/core/views/callback_api.py b/lnbits/core/views/callback_api.py index 75c7d02b4..80b7ed4c4 100644 --- a/lnbits/core/views/callback_api.py +++ b/lnbits/core/views/callback_api.py @@ -4,17 +4,30 @@ from fastapi import APIRouter, Request from loguru import logger from lnbits.core.crud.payments import ( + get_payments, get_standalone_payment, + update_payment, ) +from lnbits.core.models import Payment, PaymentFilters from lnbits.core.models.misc import SimpleStatus from lnbits.core.models.payments import CreateInvoice from lnbits.core.services.fiat_providers import ( check_fiat_status, + check_revolut_signature, + check_square_signature, check_stripe_signature, verify_paypal_webhook, ) -from lnbits.core.services.payments import create_fiat_invoice +from lnbits.core.services.payments import ( + create_fiat_invoice, + create_wallet_invoice, + service_fee_fiat, +) +from lnbits.db import Filter, Filters +from lnbits.fiat import get_fiat_provider from lnbits.fiat.base import FiatSubscriptionPaymentOptions +from lnbits.fiat.revolut import RevolutWallet +from lnbits.fiat.square import SquareWallet from lnbits.settings import settings callback_router = APIRouter(prefix="/api/v1/callback", tags=["callback"]) @@ -50,6 +63,41 @@ async def api_generic_webhook_handler( message=f"Callback received successfully from '{provider_name}'.", ) + if provider_name.lower() == "square": + payload = await request.body() + sig_header = request.headers.get("x-square-hmacsha256-signature") + check_square_signature( + payload, + sig_header, + settings.square_webhook_signature_key, + settings.square_payment_webhook_url, + ) + event = await request.json() + await handle_square_event(event) + + return SimpleStatus( + success=True, + message=f"Callback received successfully from '{provider_name}'.", + ) + + if provider_name.lower() == "revolut": + payload = await request.body() + sig_header = request.headers.get("Revolut-Signature") + timestamp_header = request.headers.get("Revolut-Request-Timestamp") + check_revolut_signature( + payload, + sig_header, + timestamp_header, + settings.revolut_webhook_signing_secret, + ) + event = await request.json() + await handle_revolut_event(event) + + return SimpleStatus( + success=True, + message=f"Callback received successfully from '{provider_name}'.", + ) + return SimpleStatus( success=False, message=f"Unknown fiat provider '{provider_name}'.", @@ -280,3 +328,382 @@ def _deserialize_paypal_metadata(custom_id: str) -> FiatSubscriptionPaymentOptio except (json.JSONDecodeError, IndexError) as e: logger.warning(f"Failed to deserialize PayPal metadata: {e}") return FiatSubscriptionPaymentOptions() + + +async def handle_square_event(event: dict): + event_id = event.get("event_id") or event.get("id", "") + event_type = event.get("type", "") + logger.info(f"Handling Square event: '{event_id}'. Type: '{event_type}'.") + + if event_type == "payment.updated": + await _handle_square_payment_event(event) + return + + if event_type == "invoice.payment_made": + await _handle_square_invoice_payment_made(event) + return + + logger.warning(f"Unhandled Square event type: '{event_type}'.") + + +async def handle_revolut_event(event: dict): + event_type = event.get("event", "") + order_id = event.get("order_id") + logger.info(f"Handling Revolut event: '{event_type}'. Order ID: '{order_id}'.") + + if event_type in ["ORDER_AUTHORISED", "ORDER_COMPLETED"]: + if not order_id: + logger.warning("Revolut event missing order_id.") + return + + payment = await get_standalone_payment(f"fiat_revolut_order_{order_id}") + if payment: + await check_fiat_status(payment) + return + + if event_type == "ORDER_COMPLETED": + logger.warning(f"No payment found for Revolut order: '{order_id}'.") + await _handle_revolut_subscription_order_paid(order_id) + return + + logger.info(f"Ignoring Revolut authorised order without payment: '{order_id}'.") + return + + if event_type == "SUBSCRIPTION_INITIATED": + logger.info("Revolut subscription initiated event received.") + return + + if event_type in [ + "SUBSCRIPTION_CANCELLED", + "SUBSCRIPTION_FINISHED", + "SUBSCRIPTION_OVERDUE", + ]: + logger.info(f"Revolut subscription lifecycle event received: '{event_type}'.") + return + + logger.warning(f"Unhandled Revolut event type: '{event_type}'.") + + +async def _get_revolut_provider() -> RevolutWallet | None: + fiat_provider = await get_fiat_provider("revolut") + if not isinstance(fiat_provider, RevolutWallet): + logger.warning("Revolut fiat provider is not configured.") + return None + return fiat_provider + + +async def _handle_revolut_subscription( + subscription: dict, + fiat_provider: RevolutWallet, + order_id: str | None = None, + order: dict | None = None, +): + subscription_id = subscription.get("id") + if not subscription_id: + logger.warning("Revolut subscription missing id.") + return + + reference = fiat_provider.deserialize_subscription_reference( + subscription.get("external_reference") + ) + if not reference: + logger.warning("Revolut subscription event missing LNbits metadata.") + return + + if not order_id: + cycle_id = subscription.get("current_cycle_id") + if not cycle_id: + logger.warning("Revolut subscription missing current_cycle_id.") + return + + cycle = await fiat_provider.get_subscription_cycle(subscription_id, cycle_id) + order_id = cycle.get("order_id") + if not order_id: + logger.warning("Revolut subscription cycle missing order_id.") + return + + existing_payment = await get_standalone_payment(f"fiat_revolut_order_{order_id}") + if existing_payment: + if existing_payment.external_id != subscription_id: + existing_payment.external_id = subscription_id + await update_payment(existing_payment) + await check_fiat_status(existing_payment) + return + + if not order: + order = await fiat_provider.get_order(order_id) + amount_minor = order.get("amount") + currency = (order.get("currency") or "").upper() + if amount_minor is None or not currency: + raise ValueError("Revolut subscription order missing amount or currency.") + + extra = { + **(reference.extra or {}), + "subscription_request_id": subscription_id, + "fiat_method": "subscription", + "tag": reference.tag, + "subscription": { + "checking_id": f"order_{order_id}", + "payment_request": order.get("checkout_url") or "", + }, + } + lnbits_payment = await _create_revolut_subscription_payment( + wallet_id=reference.wallet_id, + amount_minor=amount_minor, + currency=currency, + memo=reference.memo or "", + extra=extra, + order_id=order_id, + payment_request=order.get("checkout_url") or "", + subscription_id=subscription_id, + ) + + await check_fiat_status(lnbits_payment) + + +async def _handle_revolut_subscription_order_paid(order_id: str): + fiat_provider = await _get_revolut_provider() + if not fiat_provider: + return + + order = await fiat_provider.get_order(order_id) + order_type = (order.get("type") or "").lower() + order_state = (order.get("state") or "").upper() + if order_type != "payment" or order_state != "COMPLETED": + logger.warning(f"Revolut order is not a completed payment: '{order_id}'.") + return + + channel_data = order.get("channel_data") or {} + subscription_id = channel_data.get("subscription_id") + if not subscription_id: + logger.warning(f"Revolut order missing subscription_id: '{order_id}'.") + return + + subscription = await fiat_provider.get_subscription(subscription_id) + if subscription.get("state") != "active": + logger.warning(f"Revolut subscription is not active: '{subscription_id}'.") + return + + await _handle_revolut_subscription( + subscription, fiat_provider, order_id=order_id, order=order + ) + + +async def _create_revolut_subscription_payment( + wallet_id: str, + amount_minor: int, + currency: str, + memo: str, + extra: dict, + order_id: str, + payment_request: str, + subscription_id: str, +) -> Payment: + amount = RevolutWallet.minor_units_to_amount(amount_minor, currency) + payment = await create_wallet_invoice( + wallet_id, + CreateInvoice( + unit=currency, + amount=amount, + memo=memo, + extra=extra, + internal=True, + external_id=subscription_id, + ), + ) + payment.fee = -abs(service_fee_fiat(payment.msat, "revolut")) + payment.fiat_provider = "revolut" + payment.extra["fiat_checking_id"] = f"order_{order_id}" + payment.extra["fiat_payment_request"] = payment_request + checking_id = f"fiat_revolut_order_{order_id}" + await update_payment(payment, checking_id) + payment.checking_id = checking_id + return payment + + +async def _handle_square_payment_event(event: dict): + payment = _square_extract_payment(event) + payment_options = _deserialize_square_metadata(_square_payment_note(payment)) + if payment_options.wallet_id: + if not _square_payment_is_completed(payment): + logger.debug("Square subscription payment is not completed yet.") + return + await _handle_square_subscription_payment(payment, payment_options) + return + + order_id = payment.get("order_id") + if not order_id: + logger.warning("Square payment event missing order_id.") + return + + lnbits_payment = await get_standalone_payment(f"fiat_square_order_{order_id}") + if not lnbits_payment: + logger.warning(f"No payment found for Square order: '{order_id}'.") + return + + await check_fiat_status(lnbits_payment) + + +async def _handle_square_invoice_payment_made(event: dict): + invoice = event.get("data", {}).get("object", {}).get("invoice") or {} + order_id = invoice.get("order_id") + if not order_id: + logger.warning("Square invoice.payment_made event missing order_id.") + return + subscription_id = invoice.get("subscription_id") + + fiat_provider = await get_fiat_provider("square") + if not isinstance(fiat_provider, SquareWallet): + logger.warning("Square fiat provider is not configured.") + return + + payment = await fiat_provider.get_payment_for_order(order_id) + if not payment: + logger.warning(f"No Square payment found for invoice order: '{order_id}'.") + return + + payment_options = _deserialize_square_metadata(_square_payment_note(payment)) + if not payment_options.wallet_id: + payment_id = payment.get("id") + stored_payment = ( + await get_standalone_payment(f"fiat_square_payment_{payment_id}") + if payment_id + else None + ) + if not stored_payment and subscription_id: + stored_payments = await get_payments( + filters=Filters( + filters=[ + Filter.parse_query( + "external_id", [subscription_id], PaymentFilters + ) + ], + model=PaymentFilters, + sortby="created_at", + direction="desc", + limit=1, + ) + ) + stored_payment = stored_payments[0] if stored_payments else None + if stored_payment: + payment_options = _square_payment_options_from_payment(stored_payment) + else: + logger.warning("Square subscription payment missing LNbits metadata.") + return + + await _handle_square_subscription_payment( + payment, + payment_options, + invoice.get("public_url") or "", + square_subscription_id=subscription_id, + ) + + +async def _handle_square_subscription_payment( + payment: dict, + payment_options: FiatSubscriptionPaymentOptions, + payment_request: str = "", + square_subscription_id: str | None = None, +): + amount_money = payment.get("amount_money") or {} + amount = amount_money.get("amount") + currency = (amount_money.get("currency") or "").upper() + payment_id = payment.get("id") + if amount is None or not currency or not payment_id: + raise ValueError("Square subscription payment event missing payment amount.") + wallet_id = payment_options.wallet_id + if not wallet_id: + raise ValueError("Square subscription payment event missing wallet_id.") + + checking_id = f"payment_{payment_id}" + existing_payment = await get_standalone_payment(f"fiat_square_{checking_id}") + if existing_payment: + if ( + square_subscription_id + and existing_payment.external_id != square_subscription_id + ): + existing_payment.external_id = square_subscription_id + await update_payment(existing_payment) + await check_fiat_status(existing_payment) + return + + square_subscription_id = square_subscription_id or ( + payment_options.extra or {} + ).get("square_subscription_id") + extra = { + **(payment_options.extra or {}), + "subscription_request_id": payment_options.subscription_request_id, + "fiat_method": "subscription", + "tag": payment_options.tag, + "subscription": { + "checking_id": checking_id, + "payment_request": payment_request, + }, + } + + lnbits_payment = await create_fiat_invoice( + wallet_id=wallet_id, + invoice_data=CreateInvoice( + unit=currency, + amount=amount / 100, + memo=payment_options.memo or "", + extra=extra, + fiat_provider="square", + external_id=square_subscription_id, + ), + ) + + await check_fiat_status(lnbits_payment) + + +def _square_payment_options_from_payment( + payment: Payment, +) -> FiatSubscriptionPaymentOptions: + extra = payment.extra or {} + return FiatSubscriptionPaymentOptions( + wallet_id=payment.wallet_id, + tag=extra.get("tag") or payment.tag, + subscription_request_id=extra.get("subscription_request_id"), + extra=extra, + memo=payment.memo, + ) + + +def _square_extract_payment(event: dict) -> dict: + event_object = event.get("data", {}).get("object", {}) + return event_object.get("payment") or event_object + + +def _square_payment_is_completed(payment: dict) -> bool: + return (payment.get("status") or "").upper() == "COMPLETED" + + +def _square_payment_note(payment: dict) -> str: + return payment.get("note") or payment.get("payment_note") or "" + + +def _deserialize_square_metadata(custom_id: str) -> FiatSubscriptionPaymentOptions: + try: + meta = json.loads(custom_id) + if not isinstance(meta, list): + return FiatSubscriptionPaymentOptions() + wallet_id = meta[0] if len(meta) > 0 else None + tag = meta[1] if len(meta) > 1 else None + subscription_request_id = meta[2] if len(meta) > 2 else None + extra_link = meta[3] if len(meta) > 3 else None + memo = meta[4] if len(meta) > 4 else None + + extra = { + "link": extra_link, + "subscription_request_id": subscription_request_id, + } + + return FiatSubscriptionPaymentOptions( + wallet_id=wallet_id, + tag=tag, + subscription_request_id=subscription_request_id, + extra=extra, + memo=memo, + ) + except (json.JSONDecodeError, IndexError, TypeError): + return FiatSubscriptionPaymentOptions() diff --git a/lnbits/core/views/extension_api.py b/lnbits/core/views/extension_api.py index 3192b832c..8b2c6b1c1 100644 --- a/lnbits/core/views/extension_api.py +++ b/lnbits/core/views/extension_api.py @@ -1,3 +1,4 @@ +import json import sys import traceback from http import HTTPStatus @@ -9,7 +10,7 @@ from fastapi.requests import Request from loguru import logger from lnbits.core.crud.extensions import get_user_extensions -from lnbits.core.crud.wallets import get_wallets_ids +from lnbits.core.crud.wallets import get_wallet, get_wallets_ids from lnbits.core.db import db from lnbits.core.models import ( SimpleStatus, @@ -18,27 +19,54 @@ from lnbits.core.models.extensions import ( CreateExtension, CreateExtensionReview, Extension, + ExtensionArchiveValidationError, + ExtensionBackgroundPaymentDestinationPolicy, + ExtensionBackgroundPaymentGrant, + ExtensionBackgroundPaymentGrantRequest, ExtensionConfig, ExtensionMeta, + ExtensionPermissionCheckRequest, + ExtensionPermissionCheckResponse, + ExtensionPermissionCheckResult, + ExtensionPermissionsResponse, + ExtensionPermissionsUpdate, ExtensionRelease, ExtensionReview, ExtensionReviewPaymentRequest, ExtensionReviewsStatus, + ExtensionWalletPaymentsWatchGrant, + ExtensionWalletPaymentsWatchGrantRequest, InstallableExtension, PayToEnableInfo, ReleasePaymentInfo, UserExtension, UserExtensionInfo, + WasmInvocation, + WasmInvocationStats, + WasmRuntimeLimitsInfo, + WasmRuntimeLimitsUpdate, + wasm_extension_icon_url, ) from lnbits.core.models.users import Account, AccountId from lnbits.core.services import check_transaction_status, create_invoice from lnbits.core.services.extensions import ( activate_extension, deactivate_extension, + get_current_wasm_invocations, get_valid_extension, get_valid_extensions, + get_wasm_invocation_history, + get_wasm_invocation_summary, install_extension, + resolve_wasm_runtime_limits, + stop_wasm_invocation, uninstall_extension, + update_wasm_extension_runtime_limits, + validate_wasm_runtime_limit_overrides, +) +from lnbits.core.wasm_ext.api.permissions import ( + validate_extension_permissions, + validate_wasm_extension_permissions, ) from lnbits.db import Page from lnbits.decorators import ( @@ -66,6 +94,9 @@ extension_router = APIRouter( prefix="/api/v1/extension", ) +WALLET_PAY_INVOICE_BACKGROUND_PERMISSION = "wallet.pay_invoice_background" +WALLET_PAYMENTS_WATCH_PERMISSION = "wallet.payments.watch" + @extension_router.post("", dependencies=[Depends(check_admin)]) async def api_install_extension(data: CreateExtension): @@ -89,21 +120,39 @@ async def api_install_extension(data: CreateExtension): ) try: - extension = await install_extension(ext_info) + extension = await install_extension( + ext_info, + granted_permissions=data.permissions, + allow_admin_policy_overrides=True, + ) except Exception as exc: logger.warning(exc) etype, _, tb = sys.exc_info() traceback.print_exception(etype, exc, tb) - ext_info.clean_extension_files() + if isinstance(exc, ExtensionArchiveValidationError): + ext_info.zip_path.unlink(missing_ok=True) + else: + try: + archive_config = ext_info.load_archive_config() + except ValueError: + archive_config = {} + if archive_config.get("extension_type") == "wasm": + ext_info.clean_wasm_extension_files() + else: + ext_info.clean_extension_files() detail = ( str(exc) - if isinstance(exc, AssertionError) + if isinstance(exc, (AssertionError, ValueError)) else f"Failed to install extension '{ext_info.id}'." f"({ext_info.installed_version})." ) raise HTTPException( - status_code=HTTPStatus.INTERNAL_SERVER_ERROR, + status_code=( + HTTPStatus.BAD_REQUEST + if isinstance(exc, (AssertionError, ValueError)) + else HTTPStatus.INTERNAL_SERVER_ERROR + ), detail=detail, ) from exc @@ -124,6 +173,106 @@ async def api_install_extension(data: CreateExtension): ) from exc +@extension_router.get( + "/wasm/invocations/current", + dependencies=[Depends(check_admin)], +) +async def api_get_current_wasm_invocations( + extension_id: str | None = None, +) -> list[WasmInvocation]: + return get_current_wasm_invocations(extension_id=extension_id) + + +@extension_router.get( + "/wasm/invocations", + dependencies=[Depends(check_admin)], +) +async def api_get_wasm_invocations( + extension_id: str | None = None, + status: str | None = None, + limit: int = 100, + offset: int = 0, +) -> list[WasmInvocation]: + return await get_wasm_invocation_history( + extension_id=extension_id, + status=status, + limit=limit, + offset=offset, + ) + + +@extension_router.get( + "/wasm/invocations/stats", + dependencies=[Depends(check_admin)], +) +async def api_get_wasm_invocation_stats( + extension_id: str | None = None, + hours: int = 24, +) -> WasmInvocationStats: + return await get_wasm_invocation_summary(extension_id=extension_id, hours=hours) + + +@extension_router.post( + "/wasm/invocations/{invocation_id}/stop", + dependencies=[Depends(check_admin)], +) +async def api_stop_wasm_invocation(invocation_id: str) -> SimpleStatus: + await stop_wasm_invocation(invocation_id, reason="Stopped by admin.") + return SimpleStatus(success=True, message="WASM invocation stop requested.") + + +@extension_router.get( + "/wasm/runtime-limits/extensions", + dependencies=[Depends(check_admin)], +) +async def api_get_wasm_runtime_limit_extensions() -> list[WasmRuntimeLimitsInfo]: + installed_extensions = await get_installed_extensions() + return [ + WasmRuntimeLimitsInfo( + id=extension.id, + name=extension.name, + active=extension.active, + wasm_runtime_limits=validate_wasm_runtime_limit_overrides( + extension.wasm_runtime_limits, + strict=False, + ), + effective_wasm_runtime_limits=resolve_wasm_runtime_limits(extension), + ) + for extension in installed_extensions + if extension.is_wasm + ] + + +@extension_router.put( + "/wasm/runtime-limits/{ext_id}", + dependencies=[Depends(check_admin)], +) +async def api_update_wasm_runtime_limits( + ext_id: str, + data: WasmRuntimeLimitsUpdate, +) -> WasmRuntimeLimitsInfo: + try: + wasm_runtime_limits = await update_wasm_extension_runtime_limits( + ext_id, data.limits + ) + extension = await get_installed_extension(ext_id) + if not extension: + raise ValueError(f"Extension '{ext_id}' is not installed.") + extension.wasm_runtime_limits = wasm_runtime_limits + return WasmRuntimeLimitsInfo( + id=extension.id, + name=extension.name, + active=extension.active, + wasm_runtime_limits=wasm_runtime_limits, + effective_wasm_runtime_limits=resolve_wasm_runtime_limits(extension), + ) + except ValueError as exc: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(exc), + ) from exc + + @extension_router.get("/{ext_id}/details") async def api_extension_details( ext_id: str, @@ -247,6 +396,250 @@ async def api_disable_extension( return SimpleStatus(success=True, message=f"Extension '{ext_id}' disabled.") +@extension_router.post("/{ext_id}/permissions/background-payment") +async def api_grant_background_payment_permission( + ext_id: str, + data: ExtensionBackgroundPaymentGrantRequest, + account_id: AccountId = Depends(check_account_id_exists), +) -> dict: + installed_ext = await get_installed_extension(ext_id) + if not installed_ext or not installed_ext.active: + raise HTTPException( + HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' is not active." + ) + + installed_permission_ids = { + permission.id for permission in installed_ext.permissions or [] + } + if WALLET_PAY_INVOICE_BACKGROUND_PERMISSION not in installed_permission_ids: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' cannot request background payments.", + ) + + user_ext = await get_user_extension(account_id.id, ext_id) + if not user_ext or not user_ext.active: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' is not enabled for this user.", + ) + + wallet = await get_wallet(data.wallet_id) + if not wallet or wallet.user != account_id.id: + raise HTTPException(HTTPStatus.FORBIDDEN, "Not your wallet.") + if wallet.is_lightning_shared_wallet: + raise HTTPException( + HTTPStatus.BAD_REQUEST, + "Background payments are not allowed from shared wallets.", + ) + if not wallet.can_send_payments: + raise HTTPException( + HTTPStatus.BAD_REQUEST, + "This wallet cannot send payments.", + ) + + permissions = user_ext.permissions or {} + grant = data.to_grant( + _user_permission_grant_id_for_wallet( + permissions, + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, + data.wallet_id, + ) + ) + background_grants = [ + existing + for existing in permissions.get(WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, []) + if isinstance(existing, dict) and existing.get("wallet_id") != grant.wallet_id + ] + background_grants.append(json.loads(grant.json())) + permissions[WALLET_PAY_INVOICE_BACKGROUND_PERMISSION] = background_grants + user_ext.permissions = permissions + await update_user_extension(user_ext) + return {"permission": WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, "grant": grant} + + +@extension_router.post("/{ext_id}/permissions/wallet-payments-watch") +async def api_grant_wallet_payments_watch_permission( + ext_id: str, + data: ExtensionWalletPaymentsWatchGrantRequest, + account_id: AccountId = Depends(check_account_id_exists), +) -> dict: + installed_ext = await get_installed_extension(ext_id) + if not installed_ext or not installed_ext.active: + raise HTTPException( + HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' is not active." + ) + + installed_permission_ids = { + permission.id for permission in installed_ext.permissions or [] + } + if WALLET_PAYMENTS_WATCH_PERMISSION not in installed_permission_ids: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' cannot request wallet payment watch access.", + ) + + user_ext = await get_user_extension(account_id.id, ext_id) + if not user_ext or not user_ext.active: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' is not enabled for this user.", + ) + + wallet = await get_wallet(data.wallet_id) + if not wallet or wallet.user != account_id.id: + raise HTTPException(HTTPStatus.FORBIDDEN, "Not your wallet.") + + permissions = user_ext.permissions or {} + grant = data.to_grant( + _user_permission_grant_id_for_wallet( + permissions, + WALLET_PAYMENTS_WATCH_PERMISSION, + data.wallet_id, + ) + ) + watch_grants = [ + existing + for existing in permissions.get(WALLET_PAYMENTS_WATCH_PERMISSION, []) + if isinstance(existing, dict) and existing.get("wallet_id") != grant.wallet_id + ] + watch_grants.append(json.loads(grant.json())) + permissions[WALLET_PAYMENTS_WATCH_PERMISSION] = watch_grants + user_ext.permissions = permissions + await update_user_extension(user_ext) + return {"permission": WALLET_PAYMENTS_WATCH_PERMISSION, "grant": grant} + + +@extension_router.get("/{ext_id}/permissions") +async def api_get_extension_permissions( + ext_id: str, + account_id: AccountId = Depends(check_account_id_exists), +) -> ExtensionPermissionsResponse: + installed_ext = await _require_active_wasm_extension(ext_id) + extension_permissions = validate_extension_permissions( + installed_ext.id, installed_ext.permissions, strict=False + ) + user_ext = await get_user_extension(account_id.id, ext_id) + return ExtensionPermissionsResponse( + extension_permissions=extension_permissions, + user_permissions=_safe_user_extension_permissions( + user_ext.permissions if user_ext else {} + ), + ) + + +@extension_router.put("/{ext_id}/permissions", dependencies=[Depends(check_admin)]) +async def api_update_extension_permissions( + ext_id: str, + data: ExtensionPermissionsUpdate, +) -> ExtensionPermissionsResponse: + installed_ext = await get_installed_extension(ext_id) + if not installed_ext: + raise HTTPException( + HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' is not installed." + ) + if not installed_ext.is_wasm: + raise HTTPException( + HTTPStatus.BAD_REQUEST, f"Extension '{ext_id}' is not a WASM extension." + ) + + try: + extension_config = _load_installed_extension_config(installed_ext) + installed_ext.permissions = validate_wasm_extension_permissions( + installed_ext, + data.permissions, + extension_config, + allow_admin_policy_overrides=True, + ) + await update_installed_extension(installed_ext) + except ValueError as exc: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail=str(exc), + ) from exc + + return ExtensionPermissionsResponse( + extension_permissions=validate_extension_permissions( + installed_ext.id, installed_ext.permissions, strict=False + ) + ) + + +@extension_router.delete("/{ext_id}/permissions/user/{grant_id}") +async def api_delete_user_extension_permission( + ext_id: str, + grant_id: str, + account_id: AccountId = Depends(check_account_id_exists), +) -> SimpleStatus: + await _require_active_wasm_extension(ext_id) + + user_ext = await get_user_extension(account_id.id, ext_id) + if not user_ext: + return SimpleStatus(success=True, message="Permission grant removed.") + + user_ext.permissions = _remove_user_permission_grant( + user_ext.permissions or {}, grant_id + ) + await update_user_extension(user_ext) + return SimpleStatus(success=True, message="Permission grant removed.") + + +@extension_router.post("/{ext_id}/permissions/check") +async def api_check_extension_permissions( + ext_id: str, + data: ExtensionPermissionCheckRequest, + account_id: AccountId = Depends(check_account_id_exists), +) -> ExtensionPermissionCheckResponse: + installed_ext = await get_installed_extension(ext_id) + if not installed_ext or not installed_ext.active: + raise HTTPException( + HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' is not active." + ) + + installed_permission_ids = { + permission.id for permission in installed_ext.permissions or [] + } + + user_ext = await get_user_extension(account_id.id, ext_id) + if not user_ext or not user_ext.active: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' is not enabled for this user.", + ) + + results: list[ExtensionPermissionCheckResult] = [] + for permission in data.permissions: + if permission.id not in installed_permission_ids: + raise HTTPException( + HTTPStatus.FORBIDDEN, + f"Extension '{ext_id}' cannot request '{permission.id}'.", + ) + if permission.id == WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: + results.append( + await _check_background_payment_permission( + account_id.id, + user_ext.permissions or {}, + permission.grant, + ) + ) + continue + if permission.id == WALLET_PAYMENTS_WATCH_PERMISSION: + results.append( + await _check_wallet_payments_watch_permission( + account_id.id, + user_ext.permissions or {}, + permission.grant, + ) + ) + continue + raise HTTPException( + HTTPStatus.BAD_REQUEST, + f"Unsupported permission check '{permission.id}'.", + ) + + return ExtensionPermissionCheckResponse(permissions=results) + + @extension_router.put("/{ext_id}/activate", dependencies=[Depends(check_admin)]) async def api_activate_extension(ext_id: str) -> SimpleStatus: try: @@ -288,7 +681,6 @@ async def api_deactivate_extension(ext_id: str) -> SimpleStatus: @extension_router.delete("/{ext_id}", dependencies=[Depends(check_admin)]) async def api_uninstall_extension(ext_id: str) -> SimpleStatus: - extension = await get_installed_extension(ext_id) if not extension: raise HTTPException( @@ -332,6 +724,10 @@ async def get_extension_releases(ext_id: str) -> list[ExtensionRelease]: extension_releases: list[ExtensionRelease] = ( await InstallableExtension.get_extension_releases(ext_id) ) + for release in extension_releases: + release.permissions = validate_extension_permissions( + ext_id, release.permissions + ) installed_ext = await get_installed_extension(ext_id) if not installed_ext: @@ -456,11 +852,19 @@ async def get_extension_release(org: str, repo: str, tag_name: str): if not config: return {} + permissions = validate_extension_permissions(config.name, config.permissions) + return { "min_lnbits_version": config.min_lnbits_version, "is_version_compatible": config.is_version_compatible(), "warning": config.warning, + "extension_type": config.extension_type, + "permissions": [dict(permission) for permission in permissions], } + except ValueError as exc: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail=str(exc) + ) from exc except Exception as exc: raise HTTPException( status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(exc) @@ -532,9 +936,11 @@ async def extensions(account_id: AccountId = Depends(check_account_id_exists)): ) installable_exts_ids = [e.id for e in installable_exts] installable_exts += [e for e in installed_exts if e.id not in installable_exts_ids] + installable_exts.sort(key=lambda e: e.id) + installed_exts_by_id = {e.id: e for e in installed_exts} for e in installable_exts: - installed_ext = next((ie for ie in installed_exts if e.id == ie.id), None) + installed_ext = installed_exts_by_id.get(e.id) if installed_ext and installed_ext.meta: installed_release = installed_ext.meta.installed_release if installed_ext.meta.pay_to_enable and not account_id.is_admin_id: @@ -555,46 +961,60 @@ async def extensions(account_id: AccountId = Depends(check_account_id_exists)): e.short_description = installed_ext.short_description e.icon = installed_ext.icon - extension_data = [ - { - "id": ext.id, - "name": ext.name, - "icon": ext.icon, - "shortDescription": ext.short_description, - "stars": ext.stars, - "isFeatured": ext.meta.featured if ext.meta else False, - "dependencies": ext.meta.dependencies if ext.meta else "", - "isInstalled": ext.id in installed_exts_ids, - "hasDatabaseTables": next( - (True for version in db_versions if version.db == ext.id), False - ), - "isAvailable": ext.id in all_ext_ids, - "isAdminOnly": ext.id in settings.lnbits_admin_extensions, - "isActive": ext.id not in inactive_extensions, - "latestRelease": ( - dict(ext.meta.latest_release) - if ext.meta and ext.meta.latest_release - else None - ), - "hasPaidRelease": ext.meta.has_paid_release if ext.meta else False, - "hasFreeRelease": ext.meta.has_free_release if ext.meta else False, - "paidFeatures": ext.meta.paid_features if ext.meta else False, - "installedRelease": ( - dict(ext.meta.installed_release) - if ext.meta and ext.meta.installed_release - else None - ), - "payToEnable": ( - dict(ext.meta.pay_to_enable) - if ext.meta and ext.meta.pay_to_enable - else {} - ), - "isPaymentRequired": ext.requires_payment, - "inProgress": False, - "selectedForUpdate": False, - } - for ext in installable_exts - ] + extension_data = [] + for ext in installable_exts: + installed_ext = installed_exts_by_id.get(ext.id) + is_wasm = installed_ext.is_wasm if installed_ext else ext.is_wasm + icon = wasm_extension_icon_url(ext.id) if is_wasm else ext.icon + permissions = ( + validate_extension_permissions( + installed_ext.id, installed_ext.permissions, strict=False + ) + if installed_ext + else [] + ) + extension_data.append( + { + "id": ext.id, + "name": ext.name, + "icon": icon, + "shortDescription": ext.short_description, + "stars": ext.stars, + "isFeatured": ext.meta.featured if ext.meta else False, + "categories": ext.meta.categories if ext.meta else [], + "dependencies": ext.meta.dependencies if ext.meta else "", + "isInstalled": ext.id in installed_exts_ids, + "hasDatabaseTables": next( + (True for version in db_versions if version.db == ext.id), False + ), + "isAvailable": ext.id in all_ext_ids, + "isAdminOnly": ext.id in settings.lnbits_admin_extensions, + "isActive": ext.id not in inactive_extensions, + "latestRelease": ( + dict(ext.meta.latest_release) + if ext.meta and ext.meta.latest_release + else None + ), + "hasPaidRelease": ext.meta.has_paid_release if ext.meta else False, + "hasFreeRelease": ext.meta.has_free_release if ext.meta else False, + "paidFeatures": ext.meta.paid_features if ext.meta else False, + "installedRelease": ( + dict(ext.meta.installed_release) + if ext.meta and ext.meta.installed_release + else None + ), + "payToEnable": ( + dict(ext.meta.pay_to_enable) + if ext.meta and ext.meta.pay_to_enable + else {} + ), + "isPaymentRequired": ext.requires_payment, + "isWasm": is_wasm, + "permissions": [dict(permission) for permission in permissions], + "inProgress": False, + "selectedForUpdate": False, + } + ) return extension_data @@ -642,3 +1062,193 @@ async def create_extension_review( resp.raise_for_status() payment_request = resp.json() return ExtensionReviewPaymentRequest(**payment_request) + + +def _load_installed_extension_config(extension: InstallableExtension) -> dict: + ext_dir = extension.wasm_ext_dir if extension.is_wasm else extension.ext_dir + config_path = ext_dir / "config.json" + if not config_path.is_file(): + raise ValueError(f"Extension '{extension.id}' config file is missing.") + try: + with open(config_path, encoding="utf-8") as config_file: + config = json.load(config_file) + except Exception as exc: + raise ValueError(f"Cannot read extension config for '{extension.id}'.") from exc + if not isinstance(config, dict): + raise ValueError(f"Extension '{extension.id}' config file is invalid.") + return config + + +async def _require_active_wasm_extension(ext_id: str) -> InstallableExtension: + installed_ext = await get_installed_extension(ext_id) + if not installed_ext or not installed_ext.active: + raise HTTPException( + HTTPStatus.NOT_FOUND, f"Extension '{ext_id}' is not active." + ) + if not installed_ext.is_wasm: + raise HTTPException( + HTTPStatus.BAD_REQUEST, f"Extension '{ext_id}' is not a WASM extension." + ) + return installed_ext + + +def _safe_user_extension_permissions(permissions: dict | None) -> dict: + safe_permissions: dict[str, list[dict]] = {} + for permission_id, grants in (permissions or {}).items(): + if not isinstance(permission_id, str) or not isinstance(grants, list): + continue + safe_grants = [ + grant + for grant in grants + if isinstance(grant, dict) and isinstance(grant.get("id"), str) + ] + if safe_grants: + safe_permissions[permission_id] = safe_grants + return safe_permissions + + +def _user_permission_grant_id_for_wallet( + permissions: dict, permission_id: str, wallet_id: str +) -> str | None: + grants = permissions.get(permission_id) + if not isinstance(grants, list): + return None + + for grant in grants: + if not isinstance(grant, dict) or grant.get("wallet_id") != wallet_id: + continue + grant_id = grant.get("id") + return grant_id if isinstance(grant_id, str) and grant_id else None + return None + + +def _remove_user_permission_grant(permissions: dict, grant_id: str) -> dict: + updated_permissions = dict(permissions or {}) + for permission_id, grants in list(updated_permissions.items()): + if not isinstance(grants, list): + continue + + remaining_grants = [ + grant + for grant in grants + if not isinstance(grant, dict) or grant.get("id") != grant_id + ] + if remaining_grants: + updated_permissions[permission_id] = remaining_grants + else: + updated_permissions.pop(permission_id, None) + return updated_permissions + + +async def _check_background_payment_permission( + account_id: str, + permissions: dict, + grant_data: dict, +) -> ExtensionPermissionCheckResult: + try: + data = ExtensionBackgroundPaymentGrantRequest.parse_obj(grant_data) + except ValueError as exc: + raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc + + wallet = await get_wallet(data.wallet_id) + if not wallet or wallet.user != account_id: + raise HTTPException(HTTPStatus.FORBIDDEN, "Not your wallet.") + if wallet.is_lightning_shared_wallet: + raise HTTPException( + HTTPStatus.BAD_REQUEST, + "Background payments are not allowed from shared wallets.", + ) + if not wallet.can_send_payments: + raise HTTPException( + HTTPStatus.BAD_REQUEST, + "This wallet cannot send payments.", + ) + + requested_grant = data.to_grant() + existing_grant = _find_background_payment_grant( + permissions, requested_grant.wallet_id + ) + covered = ( + existing_grant is not None + and existing_grant.enabled + and existing_grant.max_amount >= requested_grant.max_amount + and _background_destination_policy_covers( + existing_grant.destination_policy, requested_grant.destination_policy + ) + ) + grant = existing_grant if covered and existing_grant else requested_grant + return ExtensionPermissionCheckResult( + id=WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, + approved=covered, + grant=json.loads(grant.json()), + ) + + +async def _check_wallet_payments_watch_permission( + account_id: str, + permissions: dict, + grant_data: dict, +) -> ExtensionPermissionCheckResult: + try: + data = ExtensionWalletPaymentsWatchGrantRequest.parse_obj(grant_data) + except ValueError as exc: + raise HTTPException(HTTPStatus.BAD_REQUEST, str(exc)) from exc + + wallet = await get_wallet(data.wallet_id) + if not wallet or wallet.user != account_id: + raise HTTPException(HTTPStatus.FORBIDDEN, "Not your wallet.") + + existing_grant = _find_wallet_payments_watch_grant(permissions, data.wallet_id) + covered = bool(existing_grant and existing_grant.enabled) + grant = existing_grant if covered and existing_grant else data.to_grant() + return ExtensionPermissionCheckResult( + id=WALLET_PAYMENTS_WATCH_PERMISSION, + approved=covered, + grant=json.loads(grant.json()), + ) + + +def _find_background_payment_grant( + permissions: dict, wallet_id: str +) -> ExtensionBackgroundPaymentGrant | None: + grants = permissions.get(WALLET_PAY_INVOICE_BACKGROUND_PERMISSION) + if not isinstance(grants, list): + return None + for grant_data in grants: + if not isinstance(grant_data, dict): + continue + try: + grant = ExtensionBackgroundPaymentGrant.parse_obj(grant_data) + except ValueError: + continue + if grant.wallet_id == wallet_id: + return grant + return None + + +def _find_wallet_payments_watch_grant( + permissions: dict, wallet_id: str +) -> ExtensionWalletPaymentsWatchGrant | None: + grants = permissions.get(WALLET_PAYMENTS_WATCH_PERMISSION) + if not isinstance(grants, list): + return None + for grant_data in grants: + if not isinstance(grant_data, dict): + continue + try: + grant = ExtensionWalletPaymentsWatchGrant.parse_obj(grant_data) + except ValueError: + continue + if grant.wallet_id == wallet_id: + return grant + return None + + +def _background_destination_policy_covers( + existing: ExtensionBackgroundPaymentDestinationPolicy, + requested: ExtensionBackgroundPaymentDestinationPolicy, +) -> bool: + return ( + existing == requested + or existing == ExtensionBackgroundPaymentDestinationPolicy.EXTERNAL_ALLOWED + ) diff --git a/lnbits/core/views/fiat_api.py b/lnbits/core/views/fiat_api.py index 9a59efe96..8dc2727ed 100644 --- a/lnbits/core/views/fiat_api.py +++ b/lnbits/core/views/fiat_api.py @@ -2,17 +2,35 @@ from http import HTTPStatus from fastapi import APIRouter, Depends, HTTPException from loguru import logger +from pydantic import BaseModel +from lnbits.core.crud.settings import set_settings_field from lnbits.core.models.misc import SimpleStatus from lnbits.core.models.wallets import WalletTypeInfo +from lnbits.core.services import update_cached_settings from lnbits.core.services.fiat_providers import test_connection from lnbits.decorators import check_admin, require_admin_key -from lnbits.fiat import StripeWallet, get_fiat_provider +from lnbits.fiat import RevolutWallet, StripeWallet, get_fiat_provider from lnbits.fiat.base import CreateFiatSubscription, FiatSubscriptionResponse fiat_router = APIRouter(tags=["Fiat API"], prefix="/api/v1/fiat") +class RevolutCreateWebhook(BaseModel): + url: str + endpoint: str | None = None + api_secret_key: str | None = None + api_version: str | None = None + + +class RevolutCreateWebhookResponse(BaseModel): + id: str | None = None + url: str + events: list[str] = [] + signing_secret: str + already_exists: bool = False + + @fiat_router.put( "/check/{provider}", status_code=HTTPStatus.OK, @@ -22,6 +40,54 @@ async def api_test_fiat_provider(provider: str) -> SimpleStatus: return await test_connection(provider) +@fiat_router.post( + "/revolut/webhook", + status_code=HTTPStatus.OK, + dependencies=[Depends(check_admin)], +) +async def api_create_revolut_webhook( + data: RevolutCreateWebhook, +) -> RevolutCreateWebhookResponse: + try: + webhook = await RevolutWallet.create_webhook( + url=data.url, + endpoint=data.endpoint, + api_secret_key=data.api_secret_key, + api_version=data.api_version, + ) + except ValueError as exc: + logger.warning(exc) + raise HTTPException(status_code=400, detail=str(exc)) from exc + except Exception as exc: + logger.warning(exc) + raise HTTPException( + status_code=500, detail="Failed to create Revolut webhook." + ) from exc + + signing_secret = webhook.get("signing_secret") + webhook_url = webhook.get("url") or data.url + if not signing_secret: + raise HTTPException( + status_code=502, detail="Revolut returned no webhook signing secret." + ) + + updated_settings = { + "revolut_payment_webhook_url": webhook_url, + "revolut_webhook_signing_secret": signing_secret, + } + for key, value in updated_settings.items(): + await set_settings_field(key, value) + update_cached_settings(updated_settings) + + return RevolutCreateWebhookResponse( + id=webhook.get("id"), + url=webhook_url, + events=webhook.get("events") or [], + signing_secret=signing_secret, + already_exists=webhook.get("already_exists", False), + ) + + @fiat_router.post( "/{provider}/subscription", status_code=HTTPStatus.OK, diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index d5fe0d45a..b0adee7c8 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -185,10 +185,15 @@ admin_ui_checks = [Depends(check_admin), Depends(check_admin_ui)] @generic_router.get("/wallets") @generic_router.get("/account") @generic_router.get("/extensions") +@generic_router.get("/blockexplorer") +@generic_router.get("/blockexplorer/{resource_type}/{resource}") @generic_router.get("/users", dependencies=admin_ui_checks) @generic_router.get("/audit", dependencies=admin_ui_checks) @generic_router.get("/node", dependencies=admin_ui_checks) @generic_router.get("/admin", dependencies=admin_ui_checks) +@generic_router.get("/admin/extensions/wasm", dependencies=admin_ui_checks) +@generic_router.get("/admin/extensions/wasm/limits", dependencies=admin_ui_checks) +@generic_router.get("/admin/extensions/wasm/{ext_id}", dependencies=admin_ui_checks) @generic_router.get( "/extensions/builder", dependencies=[Depends(check_extension_builder)] ) @@ -196,11 +201,13 @@ admin_ui_checks = [Depends(check_admin), Depends(check_admin_ui)] "/extensions/builder/preview", dependencies=[Depends(check_extension_builder)] ) async def index( - request: Request, user: User = Depends(check_user_exists) + request: Request, + ext_id: str | None = None, + user: User = Depends(check_user_exists), ) -> HTMLResponse: return template_renderer().TemplateResponse( request, - "index.html", + "base.html", { "user": user.json(), }, @@ -211,7 +218,7 @@ async def index( @generic_router.get("/node/public") @generic_router.get("/first_install", dependencies=[Depends(check_first_install)]) async def index_public(request: Request) -> HTMLResponse: - return template_renderer().TemplateResponse(request, "index.html", {"public": True}) + return template_renderer().TemplateResponse(request, "base.html", {"public": True}) @generic_router.get("/uuidv4/{hex_value}") diff --git a/lnbits/core/views/lnurl_api.py b/lnbits/core/views/lnurl_api.py index 21d34abca..23ca95f68 100644 --- a/lnbits/core/views/lnurl_api.py +++ b/lnbits/core/views/lnurl_api.py @@ -1,10 +1,13 @@ from http import HTTPStatus from typing import Any +import httpx from fastapi import ( APIRouter, Depends, HTTPException, + Query, + Request, ) from lnurl import ( LnurlAuthResponse, @@ -18,6 +21,7 @@ from lnurl import execute_login as lnurlauth from lnurl import handle as lnurl_handle from lnurl.models import LnurlResponseModel from loguru import logger +from pydantic import ValidationError from lnbits.core.models import Payment from lnbits.core.models.lnurl import CreateLnurlPayment, LnurlScan @@ -27,13 +31,50 @@ from lnbits.decorators import ( require_base_invoice_key, ) from lnbits.helpers import check_callback_url -from lnbits.settings import settings +from lnbits.settings import RedirectPath, settings from ..services import fetch_lnurl_pay_request, pay_invoice +from ..services.lightning_address import ( + wallet_lightning_address_callback, + wallet_lightning_address_response, +) lnurl_router = APIRouter(tags=["LNURL"]) +@lnurl_router.get( + "/.well-known/lnurlp/{username}", + name="lnurl.api_wallet_lightning_address_response", +) +async def api_wallet_lightning_address_response( + username: str, request: Request +) -> LnurlPayResponse | LnurlErrorResponse: + if settings.lnbits_ln_address_mode in ["extension_first", "extension_only"]: + req_headers = request["headers"] if "headers" in request else [] + redirect = settings.find_extension_redirect(request.url.path, req_headers) + if redirect: + resp = await _check_extension_well_known(redirect, request) + if resp and resp.ok: + return resp + + if settings.lnbits_ln_address_mode == "extension_only": + return LnurlErrorResponse( + reason="Lightning addresses are not supported on this instance." + ) + + return await wallet_lightning_address_response(username, request) + + +@lnurl_router.get( + "/api/v1/lnurl/wallet/{username}/cb", + name="lnurl.api_wallet_lightning_address_callback", +) +async def api_wallet_lightning_address_callback( + username: str, request: Request, amount: int = Query(...) +) -> LnurlErrorResponse | Any: + return await wallet_lightning_address_callback(username, request, amount) + + async def _handle(lnurl: str) -> LnurlResponseModel: try: if "@" in lnurl: # lower case lightning addresses @@ -137,3 +178,32 @@ async def api_payments_pay_lnurl( ) return payment + + +async def _check_extension_well_known( + redirect: RedirectPath, request: Request +) -> LnurlPayResponse | LnurlErrorResponse | None: + target_path = redirect.new_path_from(request.url.path) + + transport = httpx.ASGITransport(app=request.app) + try: + async with httpx.AsyncClient( + transport=transport, + base_url=str(request.base_url), + ) as client: + response = await client.get( + target_path, + headers={"accept": "application/json"}, + ) + + response.raise_for_status() + response_data = response.json() + try: + return LnurlPayResponse.parse_obj(response_data) + except ValidationError: + return LnurlErrorResponse.parse_obj(response_data) + except Exception as exc: + logger.warning( + f"Failed to fetch LNURL response Extension redirect {target_path}: {exc}" + ) + return None diff --git a/lnbits/core/views/payment_api.py b/lnbits/core/views/payment_api.py index 38d6e10df..5239c7454 100644 --- a/lnbits/core/views/payment_api.py +++ b/lnbits/core/views/payment_api.py @@ -1,5 +1,6 @@ from hashlib import sha256 from http import HTTPStatus +from secrets import token_hex from fastapi import ( APIRouter, @@ -14,6 +15,7 @@ from lnurl import url_decode from lnbits import bolt11 from lnbits.core.crud.payments import ( get_payment_count_stats, + get_wallet_payment_total_breakdown, get_wallets_stats, update_payment, ) @@ -31,13 +33,16 @@ from lnbits.core.models import ( PaymentDailyStats, PaymentFilters, PaymentHistoryPoint, + PaymentTotalBreakdown, PaymentWalletStats, SettleInvoice, SimpleStatus, + UpdatePaymentExtra, ) from lnbits.core.models.payments import UpdatePaymentLabels -from lnbits.core.models.users import AccountId +from lnbits.core.models.users import AccountId, UserLabel from lnbits.core.models.wallets import BaseWalletTypeInfo +from lnbits.core.services.users import update_user_account from lnbits.db import Filters, Page from lnbits.decorators import ( WalletTypeInfo, @@ -50,6 +55,7 @@ from lnbits.decorators import ( from lnbits.helpers import ( filter_dict_keys, generate_filter_params_openapi, + is_valid_label, ) from lnbits.wallets.base import InvoiceResponse @@ -130,6 +136,17 @@ async def api_payments_counting_stats( return await get_payment_count_stats(count_by, filters=filters, user_id=for_user_id) +@payment_router.get( + "/stats/breakdown", + name="Get wallet payment total breakdown", + response_model=list[PaymentTotalBreakdown], +) +async def api_payments_total_breakdown( + key_info: BaseWalletTypeInfo = Depends(require_base_invoice_key), +): + return await get_wallet_payment_total_breakdown(key_info.wallet.id) + + @payment_router.get( "/stats/wallets", name="Get payments history for all users", @@ -263,6 +280,7 @@ async def api_payments_create( payment_request=invoice_data.bolt11, extra=invoice_data.extra, labels=invoice_data.labels, + external_id=invoice_data.external_id, ) return payment @@ -289,13 +307,60 @@ async def api_update_payment_labels( if not account: raise HTTPException(HTTPStatus.NOT_FOUND, "Account does not exist.") - # only keep labels that belong to the user user_label_names = [label.name for label in account.extra.labels] - payment.labels = [label for label in data.labels if label in user_label_names] + updated_account = False + for label_name in data.labels: + if label_name not in user_label_names: + if not is_valid_label(label_name): + raise HTTPException( + HTTPStatus.BAD_REQUEST, f"Invalid label name: '{label_name}'." + ) + account.extra.labels.append( + UserLabel(name=label_name, color=f"#{token_hex(3)}") + ) + user_label_names.append(label_name) + updated_account = True + + if updated_account: + await update_user_account(account) + + payment.labels = data.labels await update_payment(payment) return SimpleStatus(success=True, message="Payment labels updated.") +@payment_router.patch( + "/extra", + name="Update payment extra", + description="Append new extra metadata to a payment.", + response_model=Payment, +) +async def api_update_payment_extra( + data: UpdatePaymentExtra, + key_type: WalletTypeInfo = Depends(require_admin_key), +) -> Payment: + payment = await get_standalone_payment( + data.payment_hash, wallet_id=key_type.wallet.id + ) + if payment is None: + raise HTTPException(HTTPStatus.NOT_FOUND, "Payment does not exist.") + if not payment.success: + raise HTTPException( + HTTPStatus.BAD_REQUEST, "Payment extra can only be updated after success." + ) + + duplicate_keys = sorted(set(payment.extra).intersection(data.extra)) + if duplicate_keys: + raise HTTPException( + HTTPStatus.BAD_REQUEST, + f"Extra keys already exist: {', '.join(duplicate_keys)}.", + ) + + payment.extra.update(data.extra) + await update_payment(payment) + return payment + + @payment_router.get("/fee-reserve") async def api_payments_fee_reserve(invoice: str = Query("invoice")) -> JSONResponse: invoice_obj = bolt11.decode(invoice) diff --git a/lnbits/core/views/user_api.py b/lnbits/core/views/user_api.py index dd500766b..28ad4cddc 100644 --- a/lnbits/core/views/user_api.py +++ b/lnbits/core/views/user_api.py @@ -41,6 +41,7 @@ from lnbits.core.services import ( update_user_extensions, update_wallet_balance, ) +from lnbits.core.services.lightning_address import set_wallet_lightning_address from lnbits.db import Filters, Page from lnbits.decorators import check_admin, check_super_user, parse_filters from lnbits.helpers import ( @@ -158,10 +159,6 @@ async def api_update_user( async def api_users_delete_user( user_id: str, account: Account = Depends(check_admin) ) -> SimpleStatus: - wallets = await get_wallets(user_id, deleted=False) - for wallet in wallets: - await delete_wallet_by_id(wallet.id) - if user_id == settings.super_user: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, @@ -173,6 +170,11 @@ async def api_users_delete_user( status_code=HTTPStatus.BAD_REQUEST, detail="Only super_user can delete admin user.", ) + + wallets = await get_wallets(user_id, deleted=False) + for wallet in wallets: + await delete_wallet_by_id(wallet.id) + await delete_account(user_id) return SimpleStatus(success=True, message="User deleted.") @@ -279,6 +281,34 @@ async def api_users_create_user_wallet( return wallet +@users_router.put( + "/user/{user_id}/wallet/{wallet}/lightning-address", + name="Set wallet Lightning Address", +) +async def api_users_set_wallet_lightning_address( + user_id: str, + wallet: str, + lightning_address: str = Body(..., embed=True), +) -> Wallet: + wal = await get_wallet(wallet) + if not wal: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, + detail="Wallet does not exist.", + ) + if user_id != wal.user: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, + detail="Wallet does not belong to user.", + ) + return await set_wallet_lightning_address( + wallet=wal, + local_part=lightning_address, + allow_blacklisted=True, + charge=False, + ) + + @users_router.put( "/user/{user_id}/wallet/{wallet}/undelete", name="Reactivate deleted wallet" ) diff --git a/lnbits/core/views/wallet_api.py b/lnbits/core/views/wallet_api.py index 3aa7b9934..79636325a 100644 --- a/lnbits/core/views/wallet_api.py +++ b/lnbits/core/views/wallet_api.py @@ -22,6 +22,7 @@ from lnbits.core.models.wallets import ( WalletSharePermission, WalletType, ) +from lnbits.core.services.lightning_address import set_wallet_lightning_address from lnbits.core.services.wallets import ( create_lightning_shared_wallet, delete_wallet_share, @@ -38,6 +39,7 @@ from lnbits.decorators import ( require_invoice_key, ) from lnbits.helpers import generate_filter_params_openapi +from lnbits.settings import settings from ..crud import ( delete_wallet, @@ -164,6 +166,7 @@ async def api_update_wallet( color: str | None = Body(None), currency: str | None = Body(None), pinned: bool | None = Body(None), + lightning_address: str | None = Body(None), key_info: WalletTypeInfo = Depends(require_admin_key), ) -> Wallet: wallet = await get_wallet(key_info.wallet.id) @@ -175,6 +178,20 @@ async def api_update_wallet( wallet.extra.pinned = pinned if pinned is not None else wallet.extra.pinned wallet.currency = currency if currency is not None else wallet.currency + if lightning_address and lightning_address != wallet.lightning_address: + if not settings.lnbits_allow_custom_wallet_lightning_addresses: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, + detail="Users cannot specify Lightning Addresses.", + ) + # too much logic here + wallet = await set_wallet_lightning_address( + wallet=wallet, + local_part=lightning_address, + charge=True, + ) + return wallet + await update_wallet(wallet) return wallet diff --git a/lnbits/core/views/websocket_api.py b/lnbits/core/views/websocket_api.py index 956e2cbda..ee817641f 100644 --- a/lnbits/core/views/websocket_api.py +++ b/lnbits/core/views/websocket_api.py @@ -1,8 +1,15 @@ -from fastapi import APIRouter, WebSocket +from fastapi import APIRouter, WebSocket, status + +from lnbits.core.crud import get_installed_extension +from lnbits.core.wasm_ext.api.websockets import wasm_extension_websocket_hub from ..services import websocket_manager websocket_router = APIRouter(prefix="/api/v1/ws", tags=["Websocket"]) +extension_websocket_router = APIRouter( + prefix="/api/v1/ext/ws", + tags=["Extension Websocket"], +) @websocket_router.websocket("/{item_id}") @@ -11,6 +18,35 @@ async def websocket_connect(websocket: WebSocket, item_id: str) -> None: await websocket_manager.listen(conn) +@extension_websocket_router.websocket("/{ext_id}/{item_id}") +async def extension_websocket_connect( + websocket: WebSocket, + ext_id: str, + item_id: str, +) -> None: + installed_ext = await get_installed_extension(ext_id) + installed_permission_ids = ( + {permission.id for permission in installed_ext.permissions or []} + if installed_ext + else set() + ) + if ( + not installed_ext + or not installed_ext.active + or not installed_ext.is_wasm + or "websocket.subscribe" not in installed_permission_ids + ): + await websocket.close(code=status.WS_1008_POLICY_VIOLATION) + return + + try: + conn = await wasm_extension_websocket_hub.connect(ext_id, item_id, websocket) + except ValueError: + await websocket.close(code=status.WS_1008_POLICY_VIOLATION) + return + await wasm_extension_websocket_hub.listen(conn) + + @websocket_router.post("/{item_id}") async def websocket_update_post(item_id: str, data: str): try: diff --git a/lnbits/core/wasm_ext/__init__.py b/lnbits/core/wasm_ext/__init__.py new file mode 100644 index 000000000..3ac850ed1 --- /dev/null +++ b/lnbits/core/wasm_ext/__init__.py @@ -0,0 +1,24 @@ +from .api.host import ExtensionHostAPI +from .api.models import ExtensionAPIMethod, ExtensionAPIMethodExport +from .api.registry import ( + extension_api_contract, + extension_api_method, + extension_api_permission_ids, + get_extension_api_method, + list_extension_api_methods, +) +from .api.runtime import ExtensionAPIHost +from .wasm.loader import WasmExtension + +__all__ = [ + "ExtensionAPIHost", + "ExtensionAPIMethod", + "ExtensionAPIMethodExport", + "ExtensionHostAPI", + "WasmExtension", + "extension_api_contract", + "extension_api_method", + "extension_api_permission_ids", + "get_extension_api_method", + "list_extension_api_methods", +] diff --git a/lnbits/core/wasm_ext/api/__init__.py b/lnbits/core/wasm_ext/api/__init__.py new file mode 100644 index 000000000..1ad668781 --- /dev/null +++ b/lnbits/core/wasm_ext/api/__init__.py @@ -0,0 +1,22 @@ +from .host import ExtensionHostAPI +from .models import ExtensionAPIMethod, ExtensionAPIMethodExport +from .registry import ( + extension_api_contract, + extension_api_method, + extension_api_permission_ids, + get_extension_api_method, + list_extension_api_methods, +) +from .runtime import ExtensionAPIHost + +__all__ = [ + "ExtensionAPIHost", + "ExtensionAPIMethod", + "ExtensionAPIMethodExport", + "ExtensionHostAPI", + "extension_api_contract", + "extension_api_method", + "extension_api_permission_ids", + "get_extension_api_method", + "list_extension_api_methods", +] diff --git a/lnbits/core/wasm_ext/api/background_payments.py b/lnbits/core/wasm_ext/api/background_payments.py new file mode 100644 index 000000000..640a3df52 --- /dev/null +++ b/lnbits/core/wasm_ext/api/background_payments.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from typing import Any, NoReturn + +from bolt11 import decode as bolt11_decode +from loguru import logger + +from lnbits.core.crud.extensions import get_user_extension +from lnbits.core.crud.payments import check_internal +from lnbits.core.crud.wallets import get_wallet +from lnbits.core.models.extensions import ( + ExtensionBackgroundPaymentDestinationPolicy, + ExtensionBackgroundPaymentGrant, +) +from lnbits.core.models.wallets import Wallet + +WALLET_PAY_INVOICE_BACKGROUND_PERMISSION = "wallet.pay_invoice_background" + + +async def background_payment_extra( + *, + extension_id: str, + wallet: Wallet, + payment_request: str, + amount_msat: int, +) -> dict[str, Any]: + grant = await _background_payment_grant(extension_id, wallet, amount_msat) + await _check_destination_policy(extension_id, wallet, grant, payment_request) + + return { + "tag": extension_id, + "extension": extension_id, + "background_payment": True, + "background_permission": WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, + "background_wallet_id": wallet.source_wallet_id, + "background_destination_policy": grant.destination_policy.value, + } + + +def invoice_amount_msat(payment_request: str) -> int: + invoice = bolt11_decode(payment_request) + amount_msat = int(invoice.amount_msat or 0) + if amount_msat <= 0: + raise PermissionError("Background payments require an invoice amount.") + return amount_msat + + +async def _background_payment_grant( + extension_id: str, + wallet: Wallet, + amount_msat: int, +) -> ExtensionBackgroundPaymentGrant: + if wallet.is_lightning_shared_wallet: + _deny(extension_id, wallet, amount_msat, "shared wallet") + if not wallet.can_send_payments: + _deny(extension_id, wallet, amount_msat, "wallet cannot send payments") + + user_extension = await get_user_extension(wallet.user, extension_id) + if not user_extension or not user_extension.active: + _deny(extension_id, wallet, amount_msat, "extension disabled for user") + + permissions = user_extension.permissions or {} + grants = permissions.get(WALLET_PAY_INVOICE_BACKGROUND_PERMISSION) + if not isinstance(grants, list): + _deny(extension_id, wallet, amount_msat, "missing background payment grant") + + grant = _find_wallet_grant(grants, wallet.id) + if not grant: + _deny(extension_id, wallet, amount_msat, "missing wallet background grant") + if not grant.enabled: + _deny(extension_id, wallet, amount_msat, "background grant disabled") + if amount_msat > grant.max_amount * 1000: + _deny(extension_id, wallet, amount_msat, "payment exceeds max amount") + return grant + + +def _find_wallet_grant( + grants: list[Any], wallet_id: str +) -> ExtensionBackgroundPaymentGrant | None: + for grant_data in grants: + if not isinstance(grant_data, dict): + continue + try: + grant = ExtensionBackgroundPaymentGrant.parse_obj(grant_data) + except ValueError: + continue + if grant.wallet_id == wallet_id: + return grant + return None + + +async def _check_destination_policy( + extension_id: str, + wallet: Wallet, + grant: ExtensionBackgroundPaymentGrant, + payment_request: str, +) -> None: + if ( + grant.destination_policy + == ExtensionBackgroundPaymentDestinationPolicy.EXTERNAL_ALLOWED + ): + return + + payment_hash = bolt11_decode(payment_request).payment_hash + internal_payment = await check_internal(payment_hash) + if not internal_payment: + _deny(extension_id, wallet, 0, "external destination not allowed") + + destination_wallet = await get_wallet(internal_payment.wallet_id) + if not destination_wallet or destination_wallet.user != wallet.user: + _deny(extension_id, wallet, 0, "destination wallet is not owned by user") + + +def _deny(extension_id: str, wallet: Wallet, amount_msat: int, reason: str) -> NoReturn: + logger.warning( + "WASM extension '{}' denied background payment from wallet '{}', " + "user '{}', amount_msat '{}': {}.", + extension_id, + wallet.id, + wallet.user, + amount_msat, + reason, + ) + raise PermissionError(reason) diff --git a/lnbits/core/wasm_ext/api/host.py b/lnbits/core/wasm_ext/api/host.py new file mode 100644 index 000000000..0cdcd09a1 --- /dev/null +++ b/lnbits/core/wasm_ext/api/host.py @@ -0,0 +1,1000 @@ +from __future__ import annotations + +import json +import logging +import secrets +import time +from collections.abc import Iterable, Mapping +from typing import Any + +from lnbits.helpers import sha256s + +from ..client.extensions import send_extension_api_request +from ..storage.crud import ( + OWNER_ID_FIELD, + storage_append_public_row, + storage_count_rows, + storage_delete_row, + storage_get_paginated_rows, + storage_get_public_paginated_rows, + storage_get_public_row, + storage_get_row, + storage_get_row_owner_id, + storage_set_row, +) +from .background_payments import ( + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, + background_payment_extra, + invoice_amount_msat, +) +from .models import ( + CreateInvoicePublicRequest, + CreateInvoiceRequest, + CreateInvoiceResponse, + EmptyRequest, + ExtensionApiRequest, + HttpRequest, + HttpResponse, + ListUserWalletsResponse, + LogRequest, + LogResponse, + NowResponse, + PayInvoiceRequest, + PayInvoiceResponse, + PayLnurlRequest, + RandomIdRequest, + RandomIdResponse, + StorageAppendPublicRequest, + StorageAppendPublicResponse, + StorageDeleteRequest, + StorageDeleteResponse, + StorageGetRequest, + StorageGetResponse, + StoragePaginatedRequest, + StoragePaginatedResponse, + StoragePublicPaginatedRequest, + StorageSetRequest, + StorageSetResponse, + UserWalletSummary, + WalletBalanceRequest, + WalletBalanceResponse, + WebsocketPublishRequest, + WebsocketPublishResponse, +) +from .registry import extension_api_method +from .websockets import scoped_websocket_item_id, wasm_extension_websocket_hub + +logger = logging.getLogger("lnbits.extensions") +PUBLIC_APPEND_DEFAULT_MAX_ROWS_PER_SOURCE = 10_000 + + +class ExtensionHostAPI: + def __init__( + self, + extension_id: str, + permissions: Iterable[Any], + *, + user_id: str | None = None, + access_token: str | None = None, + context: str = "user", + owner_id: str | None = None, + invocation_id: str | None = None, + runtime_limits: dict[str, int] | None = None, + ) -> None: + self.extension_id = extension_id + self.permissions, self.permission_policies = self._permission_data(permissions) + self.user_id = user_id + self.access_token = access_token + self.context = context + self.owner_id = sha256s(user_id) if user_id else owner_id + self.invocation_id = invocation_id + self.runtime_limits = runtime_limits or {} + from .utils import ExtensionAPIUtils + + self.utils = ExtensionAPIUtils( + self.extension_id, + self.permissions, + authenticated=self.has_authenticated_context(), + ) + + @extension_api_method( + method_id="storage.get", + namespace="storage", + name="Get storage row", + host_name="storage_get", + sdk_name="get", + description="Read one row from an extension storage table.", + required_permission="ext.storage.read", + require_auth=True, + ) + async def storage_get(self, request: StorageGetRequest) -> StorageGetResponse: + row = await storage_get_row( + self.extension_id, + request.table, + request.id, + self._require_owner_id(), + ) + return StorageGetResponse(data_json=json.dumps(row) if row else None) + + @extension_api_method( + method_id="storage.get_public", + namespace="storage", + name="Get public storage row", + host_name="storage_get_public", + sdk_name="getPublic", + description="Read one public row from an extension storage table.", + required_permission="ext.storage.read_public", + require_auth=False, + ) + async def storage_get_public( + self, request: StorageGetRequest + ) -> StorageGetResponse: + public_fields = self._public_storage_policy(request.table)["public_fields"] + row = await storage_get_public_row(self.extension_id, request.table, request.id) + if not row: + return StorageGetResponse() + public_row = { + field_name: value + for field_name, value in row.items() + if field_name in public_fields + } + # todo: check public fields filtering + return StorageGetResponse(data_json=json.dumps(public_row)) + + @extension_api_method( + method_id="storage.append_public", + namespace="storage", + name="Append public storage row", + host_name="storage_append_public", + sdk_name="appendPublic", + description="Append one public row to an extension storage table.", + required_permission="ext.storage.append_public", + require_auth=False, + ) + async def storage_append_public( + self, request: StorageAppendPublicRequest + ) -> StorageAppendPublicResponse: + policy, owner_id = await self._public_storage_append_policy( + request.table, request.source_id + ) + data = dict(request.data) + self._validate_public_append_data(policy, data) + + source_id_field = policy["source_id_field"] + current_rows = await storage_count_rows( + self.extension_id, + request.table, + {source_id_field: request.source_id}, + owner_id=owner_id, + ) + if current_rows >= policy["max_rows_per_source"]: + raise PermissionError( + f"Public storage append limit reached for '{request.table}'." + ) + + row_id = await storage_append_public_row( + self.extension_id, + request.table, + {**data, source_id_field: request.source_id}, + owner_id, + ) + return StorageAppendPublicResponse(id=row_id) + + @extension_api_method( + method_id="storage.set", + namespace="storage", + name="Set storage row", + host_name="storage_set", + sdk_name="set", + description="Create or update one row in an extension storage table.", + required_permission="ext.storage.write", + require_auth=True, + ) + async def storage_set(self, request: StorageSetRequest) -> StorageSetResponse: + await storage_set_row( + self.extension_id, + request.table, + request.data, + self._require_owner_id(), + ) + return StorageSetResponse() + + @extension_api_method( + method_id="storage.get_paginated", + namespace="storage", + name="Get paginated storage rows", + host_name="storage_get_paginated", + sdk_name="getPaginated", + description="Get filtered, searched, sorted, paginated storage rows.", + required_permission="ext.storage.read", + require_auth=True, + ) + async def storage_get_paginated( + self, request: StoragePaginatedRequest + ) -> StoragePaginatedResponse: + page = await storage_get_paginated_rows( + self.extension_id, + request.table, + request.filters, + owner_id=self._require_owner_id(), + search=request.search, + search_fields=request.search_fields, + sort_by=request.sort_by, + descending=request.descending, + limit=request.limit, + offset=request.offset, + ) + return StoragePaginatedResponse( + rows_json=json.dumps(page["data"]), + total=page["total"], + ) + + @extension_api_method( + method_id="storage.get_public_paginated", + namespace="storage", + name="Get paginated public storage rows", + host_name="storage_get_public_paginated", + sdk_name="getPublicPaginated", + description="Get filtered, searched, sorted, paginated public storage rows.", + required_permission="ext.storage.read_public", + require_auth=False, + ) + async def storage_get_public_paginated( + self, request: StoragePublicPaginatedRequest + ) -> StoragePaginatedResponse: + policy = self._public_storage_policy(request.table) + public_fields = policy["public_fields"] + source_id_field = policy["source_id_field"] + if not isinstance(source_id_field, str) or not source_id_field: + raise PermissionError( + "Public paginated storage reads require a source ID field policy." + ) + + filters = self._public_storage_paginated_filters( + request, public_fields, source_id_field + ) + page = await storage_get_public_paginated_rows( + self.extension_id, + request.table, + filters, + search=request.search, + search_fields=request.search_fields, + sort_by=request.sort_by, + descending=request.descending, + limit=request.limit, + offset=request.offset, + ) + return StoragePaginatedResponse( + rows_json=json.dumps( + [ + { + field_name: value + for field_name, value in row.items() + if field_name in public_fields + } + for row in page["data"] + ] + ), + total=page["total"], + ) + + @extension_api_method( + method_id="storage.delete", + namespace="storage", + name="Delete storage row", + host_name="storage_delete", + sdk_name="delete", + description="Delete one row from an extension storage table.", + required_permission="ext.storage.write", + require_auth=True, + ) + async def storage_delete( + self, request: StorageDeleteRequest + ) -> StorageDeleteResponse: + await storage_delete_row( + self.extension_id, + request.table, + request.id, + self._require_owner_id(), + ) + return StorageDeleteResponse() + + @extension_api_method( + method_id="websocket.publish", + namespace="websocket", + name="Publish websocket message", + host_name="websocket_publish", + sdk_name="publish", + description="Publish a JSON message on an extension-local websocket channel.", + required_permission="websocket.publish", + require_auth=False, + ) + async def websocket_publish( + self, request: WebsocketPublishRequest + ) -> WebsocketPublishResponse: + scoped_websocket_item_id(self.extension_id, request.item_id) + await wasm_extension_websocket_hub.publish( + self.extension_id, + request.item_id, + request.data_json, + max_messages_per_second=(self._websocket_publish_max_messages_per_second()), + ) + return WebsocketPublishResponse() + + @extension_api_method( + method_id="wallet.create_invoice", + namespace="wallet", + name="Create invoice", + host_name="create_invoice", + sdk_name="createInvoice", + description="Create an incoming Lightning invoice for an allowed wallet.", + required_permission="wallet.create_invoice", + require_auth=True, + ) + async def wallet_create_invoice( + self, request: CreateInvoiceRequest + ) -> CreateInvoiceResponse: + from lnbits.core.crud.wallets import get_wallet + from lnbits.core.models.payments import CreateInvoice + from lnbits.core.services.payments import create_payment_request + + if not self.user_id: + raise PermissionError( + "Creating an invoice for this wallet requires an " + "authenticated user context." + ) + wallet = await get_wallet(request.wallet_id) + if wallet is None or wallet.user != self.user_id: + raise PermissionError("Not your wallet.") + + payment = await create_payment_request( + request.wallet_id, + CreateInvoice( + amount=request.amount, + unit=request.currency, + memo=request.memo, + extra=request.extra, + extension=self.extension_id, + ), + ) + return CreateInvoiceResponse( + payment_hash=payment.payment_hash, + payment_request=payment.payment_request or payment.bolt11, + checking_id=payment.checking_id, + ) + + @extension_api_method( + method_id="wallet.create_invoice_public", + namespace="wallet", + name="Create public invoice", + host_name="create_invoice_public", + sdk_name="createInvoicePublic", + description="Create a public incoming Lightning invoice.", + required_permission="wallet.create_invoice_public", + require_auth=False, + ) + async def wallet_create_invoice_public( + self, request: CreateInvoicePublicRequest + ) -> CreateInvoiceResponse: + from lnbits.core.models.payments import CreateInvoice + from lnbits.core.services.payments import create_payment_request + + row: dict[str, Any] | None = None + wallet_field = "" + for policy in self._public_invoice_wallet_sources(): + row = await storage_get_public_row( + self.extension_id, + policy["table"], + request.source_id, + ) + if row: + wallet_field = policy["wallet_field"] + break + + if not row: + raise PermissionError("Public invoice source was not found.") + + wallet_id = row.get(wallet_field) + if not isinstance(wallet_id, str) or not wallet_id: + raise PermissionError("Public invoice source has no valid wallet.") + + payment = await create_payment_request( + wallet_id, + CreateInvoice( + amount=request.amount, + unit=request.currency, + memo=request.memo, + extra={ + "tag": self.extension_id, + "source_id": request.source_id, + f"extra_{self.extension_id}": request.extra, + }, + extension=self.extension_id, + ), + ) + return CreateInvoiceResponse( + payment_hash=payment.payment_hash, + payment_request=payment.payment_request or payment.bolt11, + checking_id=payment.checking_id, + ) + + @extension_api_method( + method_id="wallet.list_user_wallets", + namespace="wallet", + name="List user wallets", + host_name="list_user_wallets", + sdk_name="listUserWallets", + description="List wallets available to the authenticated extension user.", + required_permission="wallet.list", + ) + async def wallet_list_user_wallets( + self, request: EmptyRequest + ) -> ListUserWalletsResponse: + if not self.user_id: + raise PermissionError( + "Listing user wallets requires an authenticated user context." + ) + + from lnbits.core.crud.wallets import get_wallets + + user_wallets = await get_wallets(self.user_id) + if user_wallets is None: + raise PermissionError( + "Listing user wallets requires an authenticated user context." + ) + return ListUserWalletsResponse( + wallets=[ + UserWalletSummary(id=w.id, name=w.name, currency=w.currency) + for w in user_wallets + ] + ) + + @extension_api_method( + method_id="wallet.balance", + namespace="wallet", + name="Read wallet balance", + host_name="wallet_balance", + sdk_name="balance", + description="Read the balance of a wallet available to the user.", + required_permission="wallet.balance.read", + ) + async def wallet_balance( + self, request: WalletBalanceRequest + ) -> WalletBalanceResponse: + from lnbits.core.crud.wallets import get_wallet + + if not self.user_id: + raise PermissionError( + "Reading a wallet balance requires an authenticated user context." + ) + + wallet = await get_wallet(request.wallet_id) + if wallet is None or wallet.user != self.user_id: + raise PermissionError("Reading this wallet balance is not allowed.") + + withdrawable_msat = max(wallet.withdrawable_balance, 0) + fee_reserve_msat = max(wallet.balance_msat - withdrawable_msat, 0) + return WalletBalanceResponse( + wallet_id=wallet.id, + name=wallet.name, + currency=wallet.currency, + balance_msat=wallet.balance_msat, + balance_sat=wallet.balance, + withdrawable_msat=withdrawable_msat, + withdrawable_sat=withdrawable_msat // 1000, + fee_reserve_msat=fee_reserve_msat, + fee_reserve_sat=fee_reserve_msat // 1000, + can_send_payments=wallet.can_send_payments, + ) + + @extension_api_method( + method_id="wallet.pay_invoice", + namespace="wallet", + name="Pay invoice", + host_name="pay_invoice", + sdk_name="payInvoice", + description="Pay a Lightning invoice from a wallet available to the user.", + ) + async def wallet_pay_invoice( + self, request: PayInvoiceRequest + ) -> PayInvoiceResponse: + from lnbits.core.crud.wallets import get_wallet + from lnbits.core.services.payments import pay_invoice + from lnbits.exceptions import PaymentError + + wallet = await get_wallet(request.wallet_id) + if wallet is None: + raise PermissionError("Paying invoices from this wallet is not allowed.") + + try: + if self.user_id: + self.require_permission("wallet.pay_invoice") + if wallet.user != self.user_id: + raise PermissionError( + "Paying invoices from this wallet is not allowed." + ) + payment = await pay_invoice( + wallet_id=request.wallet_id, + payment_request=request.payment_request, + max_sat=request.max_sat, + extra={"tag": self.extension_id, **request.extra}, + description=request.description, + tag=self.extension_id, + ) + else: + self.require_permission(WALLET_PAY_INVOICE_BACKGROUND_PERMISSION) + amount_msat = invoice_amount_msat(request.payment_request) + extra = await background_payment_extra( + extension_id=self.extension_id, + wallet=wallet, + payment_request=request.payment_request, + amount_msat=amount_msat, + ) + payment = await pay_invoice( + wallet_id=request.wallet_id, + payment_request=request.payment_request, + max_sat=request.max_sat, + extra={**request.extra, **extra}, + description=request.description, + tag=self.extension_id, + ) + except (PaymentError, PermissionError, ValueError) as exc: + return PayInvoiceResponse(ok=False, error=str(exc)) + + return _pay_invoice_response(payment) + + @extension_api_method( + method_id="wallet.pay_lnurl", + namespace="wallet", + name="Pay LNURL", + host_name="pay_lnurl", + sdk_name="payLnurl", + description="Pay a Lightning Address or LNURL-pay request from a wallet.", + ) + async def wallet_pay_lnurl(self, request: PayLnurlRequest) -> PayInvoiceResponse: + from lnurl import LnAddressError, LnurlResponseException + + from lnbits.core.crud.wallets import get_wallet + from lnbits.core.models.lnurl import CreateLnurlPayment + from lnbits.core.services.lnurl import fetch_lnurl_pay_request + from lnbits.core.services.payments import pay_invoice + from lnbits.exceptions import PaymentError + + from .lnurl import ( + lnurl_for_core, + lnurl_pay_response_text, + lnurl_payment_amount_for_core, + lnurl_payment_unit_for_core, + ) + + wallet = await get_wallet(request.wallet_id) + if wallet is None: + raise PermissionError("Paying from this wallet is not allowed.") + + try: + if self.user_id: + self.require_permission("wallet.pay_invoice") + if wallet.user != self.user_id: + raise PermissionError("Paying from this wallet is not allowed.") + else: + self.require_permission(WALLET_PAY_INVOICE_BACKGROUND_PERMISSION) + + unit = lnurl_payment_unit_for_core(request.currency) + res, action = await fetch_lnurl_pay_request( + data=CreateLnurlPayment( + lnurl=lnurl_for_core(request.lnurl), + amount=lnurl_payment_amount_for_core(request.amount), + unit=unit, + comment=request.comment, + internal_memo=request.description or None, + ), + wallet=None, + ) + extra = {"tag": self.extension_id, **request.extra} + if action.successAction: + extra["success_action"] = action.successAction.json() + if request.comment: + extra["comment"] = request.comment + if unit != "sat": + extra["fiat_currency"] = unit + extra["fiat_amount"] = str(request.amount) + + if not self.user_id: + amount_msat = invoice_amount_msat(str(action.pr)) + extra = { + **extra, + **( + await background_payment_extra( + extension_id=self.extension_id, + wallet=wallet, + payment_request=str(action.pr), + amount_msat=amount_msat, + ) + ), + } + + payment = await pay_invoice( + wallet_id=request.wallet_id, + payment_request=str(action.pr), + max_sat=request.max_sat, + extra=extra, + description=request.description or lnurl_pay_response_text(res), + tag=self.extension_id, + ) + except ( + LnAddressError, + LnurlResponseException, + PaymentError, + PermissionError, + ValueError, + ) as exc: + return PayInvoiceResponse(ok=False, error=str(exc)) + + return _pay_invoice_response(payment) + + @extension_api_method( + method_id="http.request", + namespace="http", + name="HTTP request", + host_name="http_request", + sdk_name="request", + description="Make an outbound HTTP request to an allowed host.", + required_permission="http.request", + require_auth=True, + ) + async def http_request(self, request: HttpRequest) -> HttpResponse: + from ..client.http import send_extension_http_request + + policies = self.permission_policies.get("http.request") or [] + return await send_extension_http_request( + self.extension_id, + policies, + request, + timeout_ms=self.runtime_limits.get("wasm_runtime_http_timeout_ms"), + max_response_bytes=self.runtime_limits.get( + "wasm_runtime_max_http_response_bytes" + ), + ) + + @extension_api_method( + method_id="extension.api.request", + namespace="extension", + name="Extension API request", + host_name="extension_api_request", + sdk_name="request", + description="Call an allowed installed extension API.", + required_permission="extension.api.request", + require_auth=True, + ) + async def extension_api_request(self, request: ExtensionApiRequest) -> HttpResponse: + + policies = self.permission_policies.get("extension.api.request") or [] + return await send_extension_api_request( + self.extension_id, + policies, + self.user_id, + self.access_token, + request, + timeout_ms=self.runtime_limits.get("wasm_runtime_http_timeout_ms"), + max_response_bytes=self.runtime_limits.get( + "wasm_runtime_max_http_response_bytes" + ), + ) + + @extension_api_method( + method_id="system.random_id", + namespace="system", + name="Random ID", + host_name="random_id", + sdk_name="id", + description="Create a random extension-local identifier.", + require_auth=False, + ) + async def system_random_id(self, request: RandomIdRequest) -> RandomIdResponse: + return RandomIdResponse( + id=f"{request.prefix}_{secrets.token_urlsafe(12).replace('-', '_')}" + ) + + @extension_api_method( + method_id="system.now", + namespace="system", + name="Current timestamp", + host_name="now", + sdk_name="now", + description="Return the current Unix timestamp.", + require_auth=False, + ) + async def system_now(self, request: EmptyRequest) -> NowResponse: + return NowResponse(timestamp=int(time.time())) + + @extension_api_method( + method_id="system.log", + namespace="system", + name="Log message", + host_name="log", + sdk_name="log", + description="Write a bounded message to the extension log.", + require_auth=False, + ) + async def system_log(self, request: LogRequest) -> LogResponse: + log = getattr(logger, request.level) + log("extension:%s %s", self.extension_id, request.message) + return LogResponse() + + @staticmethod + def _permission_data( + permissions: Iterable[Any], + ) -> tuple[set[str], dict[str, list[Any]]]: + permission_ids: set[str] = set() + policies: dict[str, list[Any]] = {} + + for permission in permissions: + if isinstance(permission, str): + permission_ids.add(permission) + continue + + permission_id: str | None = None + permission_policies: Any = None + if isinstance(permission, Mapping): + permission_id = permission.get("id") # type: ignore[assignment] + permission_policies = permission.get("policies") + else: + permission_id = getattr(permission, "id", None) + permission_policies = getattr(permission, "policies", None) + + if not permission_id: + continue + permission_ids.add(permission_id) + if isinstance(permission_policies, list): + policies[permission_id] = permission_policies + + return permission_ids, policies + + def _public_storage_policy(self, table: str) -> dict[str, Any]: + tables = self.permission_policies.get("ext.storage.read_public") + if not isinstance(tables, list) or not tables: + raise PermissionError( + "Public storage reads require policies for " + "'ext.storage.read_public'." + ) + + for table_policy in tables: + if not isinstance(table_policy, dict): + continue + if table_policy.get("table_name") != table: + continue + public_fields = table_policy.get("public_fields") + if not isinstance(public_fields, list) or not all( + isinstance(field, str) and field for field in public_fields + ): + raise PermissionError( + f"Public storage table '{table}' has no valid public fields." + ) + source_id_field = table_policy.get("source_id_field") + if source_id_field is not None and ( + not isinstance(source_id_field, str) or not source_id_field + ): + raise PermissionError( + f"Public storage table '{table}' has no valid source ID field." + ) + return { + "public_fields": set(public_fields), + "source_id_field": source_id_field, + } + + raise PermissionError(f"Storage table '{table}' is not publicly readable.") + + def _validate_public_storage_query_fields( + self, + request: StoragePaginatedRequest, + public_fields: set[str], + allowed_private_fields: set[str] | None = None, + ) -> None: + allowed_private_fields = allowed_private_fields or set() + query_fields = set(request.filters) + query_fields.update(request.search_fields) + if request.sort_by: + query_fields.add(request.sort_by) + private_fields = sorted(query_fields - public_fields - allowed_private_fields) + if private_fields: + raise PermissionError( + "Public storage query uses non-public fields: " + + ", ".join(private_fields) + ) + + def _public_storage_paginated_filters( + self, + request: StoragePublicPaginatedRequest, + public_fields: set[str], + source_id_field: str, + ) -> dict[str, Any]: + self._validate_public_storage_query_fields( + request, public_fields, {source_id_field} + ) + filters = dict(request.filters) + requested_source_id = filters.get(source_id_field) + if requested_source_id is not None and requested_source_id != request.source_id: + raise PermissionError( + "Public storage source filter does not match source_id." + ) + filters[source_id_field] = request.source_id + return filters + + async def _public_storage_append_policy( + self, table: str, source_id: str + ) -> tuple[dict[str, Any], str]: + policies = self.permission_policies.get("ext.storage.append_public") + if not isinstance(policies, list) or not policies: + raise PermissionError( + "Public storage appends require policies for " + "'ext.storage.append_public'." + ) + + source_not_found = False + for raw_policy in policies: + policy = self._normalize_public_storage_append_policy(raw_policy) + if policy["table"] != table: + continue + owner_id = await storage_get_row_owner_id( + self.extension_id, + policy["source_table"], + source_id, + ) + if not owner_id: + source_not_found = True + continue + return policy, owner_id + + if source_not_found: + raise PermissionError("Public storage append source was not found.") + raise PermissionError(f"Storage table '{table}' is not publicly appendable.") + + def _normalize_public_storage_append_policy(self, policy: Any) -> dict[str, Any]: + if not isinstance(policy, dict): + raise PermissionError("Public storage append policies must be objects.") + + table = policy.get("table") + source_table = policy.get("source_table") + source_id_field = policy.get("source_id_field") + allowed_fields = policy.get("allowed_fields") + max_rows_per_source = policy.get( + "max_rows_per_source", PUBLIC_APPEND_DEFAULT_MAX_ROWS_PER_SOURCE + ) + + if not isinstance(table, str) or not table: + raise PermissionError("Public storage append requires a table policy.") + if not isinstance(source_table, str) or not source_table: + raise PermissionError( + "Public storage append requires a source table policy." + ) + if not isinstance(source_id_field, str) or not source_id_field: + raise PermissionError( + "Public storage append requires a source ID field policy." + ) + if source_id_field == "id": + raise PermissionError("Public storage append source field cannot be 'id'.") + if ( + not isinstance(allowed_fields, list) + or not all(isinstance(field, str) and field for field in allowed_fields) + or "id" in allowed_fields + or OWNER_ID_FIELD in allowed_fields + or source_id_field in allowed_fields + ): + raise PermissionError( + "Public storage append requires valid allowed fields." + ) + if ( + isinstance(max_rows_per_source, bool) + or not isinstance(max_rows_per_source, int) + or max_rows_per_source <= 0 + ): + raise PermissionError( + "Public storage append requires a positive row limit." + ) + + return { + "table": table, + "source_table": source_table, + "source_id_field": source_id_field, + "allowed_fields": set(allowed_fields), + "max_rows_per_source": max_rows_per_source, + } + + def _validate_public_append_data( + self, policy: dict[str, Any], data: dict[str, Any] + ) -> None: + if not isinstance(data, dict): + raise PermissionError("Public storage append data must be an object.") + unknown_fields = sorted(set(data) - policy["allowed_fields"]) + if unknown_fields: + raise PermissionError( + "Public storage append contains disallowed fields: " + + ", ".join(unknown_fields) + ) + + def _public_invoice_wallet_sources(self) -> list[dict[str, str]]: + policies = self.permission_policies.get("wallet.create_invoice_public") + if not isinstance(policies, list) or not policies: + raise PermissionError("Public invoice creation requires a policies list.") + + sources: list[dict[str, str]] = [] + for source_policy in policies: + if not isinstance(source_policy, dict): + raise PermissionError( + "Public invoice creation policies must be objects." + ) + table = source_policy.get("table") + wallet_field = source_policy.get("wallet_field") + if not isinstance(table, str) or not table: + raise PermissionError( + "Public invoice creation requires a storage table policy." + ) + if not isinstance(wallet_field, str) or not wallet_field: + raise PermissionError( + "Public invoice creation requires a wallet field policy." + ) + sources.append({"table": table, "wallet_field": wallet_field}) + + if not sources: + raise PermissionError( + "Public invoice creation requires at least one valid policy." + ) + return sources + + def _websocket_publish_max_messages_per_second(self) -> int: + policies = self.permission_policies.get("websocket.publish") + if not isinstance(policies, list) or len(policies) != 1: + raise PermissionError( + "Websocket publishing requires a max messages per second policy." + ) + policy = policies[0] + if not isinstance(policy, dict): + raise PermissionError( + "Websocket publishing requires a max messages per second policy." + ) + max_messages_per_second = policy.get("max_messages_per_second") + if ( + isinstance(max_messages_per_second, bool) + or not isinstance(max_messages_per_second, int) + or max_messages_per_second <= 0 + ): + raise PermissionError( + "Websocket publishing requires a valid max messages per second policy." + ) + return max_messages_per_second + + def require_permission(self, permission: str | None) -> None: + if permission and permission not in self.permissions: + raise PermissionError( + f"Extension '{self.extension_id}' is missing permission '{permission}'." + ) + + def has_authenticated_context(self) -> bool: + return bool(self.user_id) or self.context == "event" + + def _require_owner_id(self) -> str: + if not self.owner_id: + raise PermissionError("Extension API method requires an owner context.") + return self.owner_id + + def __repr__(self) -> str: + return ( + "ExtensionHostAPI(" + f"extension_id={self.extension_id!r}, " + f"context={self.context!r}, " + f"owner_id={self.owner_id!r}" + ")" + ) + + +def _pay_invoice_response(payment: Any) -> PayInvoiceResponse: + return PayInvoiceResponse( + ok=True, + checking_id=payment.checking_id, + payment_hash=payment.payment_hash, + status=payment.status, + amount_msat=abs(payment.amount), + fee_msat=abs(payment.fee), + pending=payment.pending, + success=payment.success, + ) diff --git a/lnbits/core/wasm_ext/api/lnurl.py b/lnbits/core/wasm_ext/api/lnurl.py new file mode 100644 index 000000000..22f78f829 --- /dev/null +++ b/lnbits/core/wasm_ext/api/lnurl.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +import json +from typing import Any + +from lnurl import LnAddress, Lnurl + + +def normalize_lnurl(value: str) -> str: + normalized = value.strip() + if normalized.lower().startswith("lightning:"): + normalized = normalized[len("lightning:") :] + if "@" in normalized: + normalized = normalized.lower() + if not normalized: + raise ValueError("LNURL is required.") + return normalized + + +def lnurl_for_core(value: str) -> Lnurl | LnAddress: + normalized = normalize_lnurl(value) + if "@" in normalized: + return LnAddress(normalized) + return Lnurl(normalized) + + +def lnurl_payment_amount_for_core(amount: float) -> int: + if amount <= 0: + raise ValueError("Amount must be greater than zero.") + return round(amount * 1000) + + +def lnurl_payment_unit_for_core(currency: str) -> str: + unit = currency.strip().lower() + if not unit: + raise ValueError("Currency is required.") + if unit in {"sat", "sats"}: + return "sat" + return unit.upper() + + +def lnurl_pay_response_metadata_json(response: Any) -> str: + metadata = getattr(response, "metadata", None) + if metadata is None: + return "[]" + + metadata_list = getattr(metadata, "list", None) + try: + if callable(metadata_list): + return json.dumps(metadata_list()) + return json.dumps(metadata) + except TypeError: + return json.dumps(str(metadata)) + + +def lnurl_pay_response_text(response: Any) -> str: + description = getattr(response, "description", None) + if description is not None: + return str(description) + + metadata = getattr(response, "metadata", None) + text = getattr(metadata, "text", None) + return str(text) if text is not None else "" + + +def lnurl_pay_response_int(response: Any, snake_name: str, camel_name: str) -> int: + value = getattr(response, snake_name, None) + if value is None: + value = getattr(response, camel_name, 0) + return int(value or 0) diff --git a/lnbits/core/wasm_ext/api/models.py b/lnbits/core/wasm_ext/api/models.py new file mode 100644 index 000000000..de518af11 --- /dev/null +++ b/lnbits/core/wasm_ext/api/models.py @@ -0,0 +1,440 @@ +import json +from dataclasses import dataclass +from typing import Any, Literal + +from pydantic import BaseModel, Field, root_validator + + +@dataclass(frozen=True) +class ExtensionAPIMethodExport: + method_id: str + namespace: str + name: str + host_interface: str + host_name: str + sdk_name: str + description: str + required_permission: str | None = None + require_auth: bool = True + + +@dataclass(frozen=True) +class ExtensionAPIMethod: + method_id: str + namespace: str + name: str + python_name: str + host_interface: str + host_name: str + sdk_name: str + description: str + request_model: type[BaseModel] + response_model: type[BaseModel] + required_permission: str | None = None + require_auth: bool = True + + @property + def sdk_qualified_name(self) -> str: + return f"{self.namespace}.{self.sdk_name}" + + +class EmptyRequest(BaseModel): + pass + + +class StorageGetRequest(BaseModel): + table: str = Field(..., min_length=1, max_length=128) + id: str = Field(..., min_length=1, max_length=512) + + +class StorageGetResponse(BaseModel): + data_json: str | None = None + + +class StorageSetRequest(BaseModel): + table: str = Field(..., min_length=1, max_length=128) + data: dict[str, Any] = Field(default_factory=dict) + + @root_validator(pre=True) + def parse_data_json(cls, values: dict[str, Any]) -> dict[str, Any]: + data_json = values.get("data_json") + if data_json is not None and "data" not in values: + values["data"] = json.loads(data_json) + return values + + +class StorageSetResponse(BaseModel): + ok: bool = True + + +class StorageAppendPublicRequest(BaseModel): + table: str = Field(..., min_length=1, max_length=128) + source_id: str = Field(..., min_length=1, max_length=512) + data: dict[str, Any] = Field(default_factory=dict) + + @root_validator(pre=True) + def parse_data_json(cls, values: dict[str, Any]) -> dict[str, Any]: + data_json = values.get("data_json") + if data_json is not None and "data" not in values: + values["data"] = json.loads(data_json) + return values + + +class StorageAppendPublicResponse(BaseModel): + id: str + + +class StoragePaginatedRequest(BaseModel): + table: str = Field(..., min_length=1, max_length=128) + filters: dict[str, Any] = Field(default_factory=dict) + search: str | None = Field(None, max_length=256) + search_fields: list[str] = Field(default_factory=list) + sort_by: str | None = Field(None, min_length=1, max_length=128) + descending: bool = False + limit: int = Field(25, ge=1, le=1000) + offset: int = Field(0, ge=0) + + @root_validator(pre=True) + def parse_json_fields(cls, values: dict[str, Any]) -> dict[str, Any]: + filters_json = values.get("filters_json") + if filters_json is not None and "filters" not in values: + values["filters"] = json.loads(filters_json) + + search_fields_json = values.get("search_fields_json") + if search_fields_json is not None and "search_fields" not in values: + values["search_fields"] = json.loads(search_fields_json) + + if values.get("sort_by") == "": + values["sort_by"] = None + return values + + +class StoragePublicPaginatedRequest(StoragePaginatedRequest): + source_id: str = Field(..., min_length=1, max_length=512) + + +class StoragePaginatedResponse(BaseModel): + rows_json: str = "[]" + total: int = 0 + + +class WebsocketPublishRequest(BaseModel): + item_id: str = Field(..., min_length=1, max_length=128) + data: Any = Field(default_factory=dict) + + @root_validator(pre=True) + def parse_data_json(cls, values: dict[str, Any]) -> dict[str, Any]: + data_json = values.get("data_json") + if data_json is not None and "data" not in values: + values["data"] = json.loads(data_json) + return values + + @root_validator + def validate_data_size(cls, values: dict[str, Any]) -> dict[str, Any]: + data = values.get("data") + try: + encoded = json.dumps(data, separators=(",", ":")) + except TypeError as exc: + raise ValueError("websocket data must be JSON serializable.") from exc + if len(encoded.encode()) > 65536: + raise ValueError("websocket data must not exceed 65536 bytes.") + values["data"] = data + return values + + @property + def data_json(self) -> str: + return json.dumps(self.data, separators=(",", ":")) + + +class WebsocketPublishResponse(BaseModel): + sent: bool = True + + +class StorageDeleteRequest(BaseModel): + table: str = Field(..., min_length=1, max_length=128) + id: str = Field(..., min_length=1, max_length=512) + + +class StorageDeleteResponse(BaseModel): + ok: bool = True + + +class CreateInvoiceRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + amount: float = Field(..., gt=0) + currency: str = Field("sat", min_length=1, max_length=8) + memo: str = Field(..., max_length=512) + tag: str = Field(..., min_length=1, max_length=64) + extra: dict[str, str] = Field(default_factory=dict) + + +class CreateInvoicePublicRequest(BaseModel): + source_id: str = Field( + ..., + min_length=1, + max_length=512, + description="The source ID (entry id) of the wallet to create the invoice for.", + ) + amount: float = Field(..., gt=0) + currency: str = Field(..., min_length=1, max_length=8) + memo: str = Field("", max_length=512) + extra: dict[str, Any] = Field(default_factory=dict) + + @root_validator + def validate_extra_size(cls, values: dict[str, Any]) -> dict[str, Any]: + extra = values.get("extra") or {} + try: + encoded = json.dumps(extra, separators=(",", ":")) + except TypeError as exc: + raise ValueError("extra must be JSON serializable.") from exc + if len(encoded.encode()) > 4096: + raise ValueError("extra must not exceed 4096 bytes.") + values["extra"] = extra + return values + + +class CreateInvoiceResponse(BaseModel): + payment_hash: str + payment_request: str + checking_id: str + + +class UserWalletSummary(BaseModel): + id: str + name: str + currency: str | None = None + + +class ListUserWalletsResponse(BaseModel): + wallets: list[UserWalletSummary] = Field(default_factory=list) + + +class WalletBalanceRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + + +class WalletBalanceResponse(BaseModel): + wallet_id: str + name: str + currency: str | None = None + balance_msat: int + balance_sat: int + withdrawable_msat: int + withdrawable_sat: int + fee_reserve_msat: int + fee_reserve_sat: int + can_send_payments: bool + + +class PayInvoiceRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + payment_request: str = Field(..., min_length=1, max_length=8192) + max_sat: int | None = Field(None, gt=0) + description: str = Field("", max_length=512) + extra: dict[str, str] = Field(default_factory=dict) + + +class PayLnurlRequest(BaseModel): + wallet_id: str = Field(..., min_length=1, max_length=128) + lnurl: str = Field(..., min_length=1, max_length=2048) + amount: float = Field(..., gt=0) + currency: str = Field("sat", min_length=1, max_length=8) + comment: str | None = Field(None, max_length=512) + description: str = Field("", max_length=512) + max_sat: int | None = Field(None, gt=0) + extra: dict[str, str] = Field(default_factory=dict) + + +class PayInvoiceResponse(BaseModel): + ok: bool = True + error: str | None = None + checking_id: str | None = None + payment_hash: str | None = None + status: str | None = None + amount_msat: int = 0 + fee_msat: int = 0 + pending: bool = False + success: bool = False + + +class HttpRequest(BaseModel): + method: Literal["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"] = "GET" + url: str = Field(..., min_length=1, max_length=2048) + headers: dict[str, str] = Field(default_factory=dict) + body: str | None = Field(None, max_length=65536) + + @root_validator(pre=True) + def normalize_method(cls, values: dict[str, Any]) -> dict[str, Any]: + method = values.get("method") + if isinstance(method, str): + values["method"] = method.upper() + return values + + @root_validator + def validate_headers_size(cls, values: dict[str, Any]) -> dict[str, Any]: + headers = values.get("headers") or {} + if len(headers) > 32: + raise ValueError("headers must not contain more than 32 entries.") + for key, value in headers.items(): + if len(key) > 128 or len(value) > 4096: + raise ValueError("headers are too large.") + values["headers"] = headers + return values + + +class HttpResponse(BaseModel): + status_code: int + headers: dict[str, str] = Field(default_factory=dict) + body: str = "" + + +class ExtensionApiRequest(BaseModel): + extension_id: str = Field(..., min_length=1, max_length=128) + method: Literal["DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"] = "GET" + path: str = Field(..., min_length=1, max_length=2048) + body: str | None = Field(None, max_length=65536) + + @root_validator(pre=True) + def normalize_method(cls, values: dict[str, Any]) -> dict[str, Any]: + method = values.get("method") + if isinstance(method, str): + values["method"] = method.upper() + return values + + +class CurrencyListResponse(BaseModel): + currencies: list[str] = Field(default_factory=list) + + +class CurrencyRateRequest(BaseModel): + currency: str = Field(..., min_length=1, max_length=8) + + +class CurrencyRateResponse(BaseModel): + rate: float + price: float + + +class CurrencyConvertRequest(BaseModel): + amount: float = Field(..., gt=0) + from_currency: str = Field(..., alias="from", min_length=1, max_length=8) + to: str = Field(..., min_length=1, max_length=256) + + class Config: + allow_population_by_field_name = True + + +class CurrencyConvertResponse(BaseModel): + amounts: list[tuple[str, float]] = Field(default_factory=list) + + +class FiatToSatsRequest(BaseModel): + amount: float = Field(..., gt=0) + currency: str = Field(..., min_length=1, max_length=8) + + +class FiatToSatsResponse(BaseModel): + amount_sat: int + + +class SatsToFiatRequest(BaseModel): + amount: float = Field(..., gt=0) + currency: str = Field(..., min_length=1, max_length=8) + + +class SatsToFiatResponse(BaseModel): + amount: float + + +class LnurlResolveRequest(BaseModel): + lnurl: str = Field(..., min_length=1, max_length=2048) + + +class LnurlResolveResponse(BaseModel): + lnurl: str + domain: str | None = None + description: str = "" + min_sendable_msat: int + max_sendable_msat: int + comment_allowed: int = 0 + fixed: bool = False + image: str | None = None + metadata_json: str = "[]" + + +class ServerHealthResponse(BaseModel): + server_time: int + up_time: str + + +class Bolt11Request(BaseModel): + bolt11: str = Field(..., min_length=1, max_length=8192) + + +class DecodeInvoiceResponse(BaseModel): + valid: bool = True + payment_hash: str | None = None + amount_msat: int | None = None + expiry: int | None = None + expires_at: int | None = None + memo: str | None = None + + +class ValidateInvoiceResponse(BaseModel): + valid: bool + error: str | None = None + + +class InvoicePaymentHashResponse(BaseModel): + payment_hash: str + + +class InvoiceAmountMsatResponse(BaseModel): + amount_msat: int | None = None + + +class InvoiceExpiryResponse(BaseModel): + expires_at: int | None = None + + +class InvoiceMemoResponse(BaseModel): + memo: str | None = None + + +class VerifyPreimageRequest(BaseModel): + preimage: str = Field(..., min_length=64, max_length=64) + payment_hash: str = Field(..., min_length=64, max_length=64) + + +class VerifyPreimageResponse(BaseModel): + valid: bool + + +class RandomSecretAndHashRequest(BaseModel): + length: int = Field(32, ge=16, le=64) + + +class RandomSecretAndHashResponse(BaseModel): + secret: str + hash: str + + +class RandomIdRequest(BaseModel): + prefix: str = Field(..., min_length=1, max_length=32) + + +class RandomIdResponse(BaseModel): + id: str + + +class NowResponse(BaseModel): + timestamp: int + + +class LogRequest(BaseModel): + level: Literal["debug", "info", "warning", "error"] = "info" + message: str = Field(..., min_length=1, max_length=2048) + + +class LogResponse(BaseModel): + ok: bool = True diff --git a/lnbits/core/wasm_ext/api/permissions.py b/lnbits/core/wasm_ext/api/permissions.py new file mode 100644 index 000000000..837e77954 --- /dev/null +++ b/lnbits/core/wasm_ext/api/permissions.py @@ -0,0 +1,412 @@ +from collections.abc import Iterable +from typing import Any + +from lnbits.core.models.extensions import ExtensionPermission, InstallableExtension +from lnbits.core.wasm_ext.api.registry import extension_api_permission_ids +from lnbits.core.wasm_ext.api.websockets import ( + WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT, +) +from lnbits.core.wasm_ext.client.http import _request_origin +from lnbits.core.wasm_ext.wasm.config import ( + WasmExtensionConfig, + parse_wasm_extension_config, +) + +_POLICY_AWARE_PERMISSION_IDS = { + "ext.storage.append_public", + "ext.storage.read_public", + "extension.api.request", + "http.request", + "wallet.create_invoice_public", + "websocket.publish", +} +_OWNER_ID_FIELD = "__lnbits_owner_id__" +_PUBLIC_APPEND_DEFAULT_MAX_ROWS_PER_SOURCE = 10_000 +PUBLIC_APPEND_MAX_ROWS_PER_SOURCE_LIMIT = 1_000_000 + + +def validate_extension_permissions( + ext_id: str, + permissions: Iterable[ExtensionPermission], + *, + strict: bool = True, +) -> list[ExtensionPermission]: + known_permission_ids = extension_api_permission_ids() + normalized_permissions: list[ExtensionPermission] = [] + unknown_ids: list[str] = [] + + for permission in permissions: + if permission.id not in known_permission_ids: + unknown_ids.append(permission.id) + if strict: + continue + normalized_permissions.append(permission.copy()) + + if unknown_ids and strict: + raise ValueError( + f"Extension '{ext_id}' requests unknown permissions: " + + ", ".join(sorted(set(unknown_ids))) + ) + + return normalized_permissions + + +def validate_wasm_extension_permissions( + ext_info: InstallableExtension, + granted_permissions: list[ExtensionPermission] | None, + extension_config: dict[str, Any] | WasmExtensionConfig, + *, + allow_admin_policy_overrides: bool = False, +) -> list[ExtensionPermission]: + if isinstance(extension_config, WasmExtensionConfig): + config = extension_config + elif extension_config.get("extension_type") != "wasm": + return [] + else: + config = parse_wasm_extension_config(ext_info.id, extension_config) + + requested_permissions = validate_extension_permissions( + ext_info.id, config.permissions + ) + _validate_requested_permission_policies(ext_info.id, requested_permissions) + if not requested_permissions: + return [] + + if granted_permissions is None: + raise ValueError(f"Extension '{ext_info.id}' requires permission approval.") + + granted_permissions = validate_extension_permissions( + ext_info.id, + granted_permissions, + ) + requested_by_id = _permission_index(ext_info.id, requested_permissions, "requested") + granted_by_id = _permission_index(ext_info.id, granted_permissions, "granted") + + extra_granted_ids = sorted(set(granted_by_id) - set(requested_by_id)) + if extra_granted_ids: + raise ValueError( + f"Extension '{ext_info.id}' was granted unrequested permissions: " + + ", ".join(extra_granted_ids) + ) + + effective_permissions: list[ExtensionPermission] = [] + for permission_id, granted_permission in granted_by_id.items(): + requested_permission = requested_by_id[permission_id] + if not _permission_grant_is_subset( + requested_permission, + granted_permission, + allow_admin_policy_overrides=allow_admin_policy_overrides, + ): + raise ValueError( + f"Extension '{ext_info.id}' was granted broader policies for " + f"permission '{permission_id}'." + ) + effective_permissions.append( + requested_permission.copy(update={"policies": granted_permission.policies}) + ) + + return effective_permissions + + +def _permission_index( + ext_id: str, + permissions: Iterable[ExtensionPermission], + source: str, +) -> dict[str, ExtensionPermission]: + indexed: dict[str, ExtensionPermission] = {} + duplicate_ids: list[str] = [] + + for permission in permissions: + if permission.id in indexed: + duplicate_ids.append(permission.id) + continue + indexed[permission.id] = permission + + if duplicate_ids: + raise ValueError( + f"Extension '{ext_id}' has duplicate {source} permissions: " + + ", ".join(sorted(set(duplicate_ids))) + ) + return indexed + + +def _permission_grant_is_subset( + requested: ExtensionPermission, + granted: ExtensionPermission, + *, + allow_admin_policy_overrides: bool = False, +) -> bool: + if requested.id != granted.id: + return False + if requested.id not in _POLICY_AWARE_PERMISSION_IDS: + return True + if requested.id == "http.request": + return _http_request_grant_is_subset(requested.policies, granted.policies) + if requested.id == "extension.api.request": + return _extension_api_grant_is_subset(requested.policies, granted.policies) + if requested.id == "ext.storage.append_public": + return _public_storage_append_grant_is_subset( + requested.policies, + granted.policies, + allow_max_rows_per_source_override=allow_admin_policy_overrides, + ) + if requested.id == "ext.storage.read_public": + return _public_storage_grant_is_subset(requested.policies, granted.policies) + if requested.id == "wallet.create_invoice_public": + return _public_invoice_grant_is_subset(requested.policies, granted.policies) + if requested.id == "websocket.publish": + return _websocket_publish_grant_is_subset( + requested.policies, + granted.policies, + allow_max_messages_per_second_override=allow_admin_policy_overrides, + ) + return False + + +def _validate_requested_permission_policies( + ext_id: str, + permissions: Iterable[ExtensionPermission], +) -> None: + for permission in permissions: + if permission.id != "websocket.publish": + continue + if _websocket_publish_policy(permission.policies) is None: + raise ValueError( + f"Extension '{ext_id}' requests invalid policies for permission " + "'websocket.publish'." + ) + + +def _policy_list(policies: list[Any] | None) -> list[Any]: + return policies if isinstance(policies, list) else [] + + +def _http_request_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, +) -> bool: + return _http_origins(granted_policies).issubset(_http_origins(requested_policies)) + + +def _http_origins(policies: list[Any] | None) -> set[str]: + origins: set[str] = set() + for policy in _policy_list(policies): + host = policy.get("host") if isinstance(policy, dict) else policy + if not isinstance(host, str) or not host: + continue + try: + origins.add(_request_origin(host)) + except PermissionError: + continue + return origins + + +def _extension_api_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, +) -> bool: + requested_targets = _extension_api_targets(requested_policies) + granted_targets = _extension_api_targets(granted_policies) + for extension_id, granted_access in granted_targets.items(): + requested_access = requested_targets.get(extension_id) + if requested_access is None or not granted_access.issubset(requested_access): + return False + return True + + +def _extension_api_targets(policies: list[Any] | None) -> dict[str, set[str]]: + targets: dict[str, set[str]] = {} + for policy in _policy_list(policies): + extension_id: str | None = None + access: list[Any] = [] + if isinstance(policy, str): + extension_id = policy + access = ["read"] + elif isinstance(policy, dict): + raw_extension_id = policy.get("id") + raw_access = policy.get("access") + if isinstance(raw_extension_id, str) and isinstance(raw_access, list): + extension_id = raw_extension_id + access = raw_access + if not extension_id or extension_id in targets: + continue + clean_access = { + item + for item in access + if isinstance(item, str) and item in {"read", "write"} + } + if clean_access: + targets[extension_id] = clean_access + return targets + + +def _public_storage_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, +) -> bool: + requested_tables = _public_storage_tables(requested_policies) + granted_tables = _public_storage_tables(granted_policies) + for table_name, granted_policy in granted_tables.items(): + requested_policy = requested_tables.get(table_name) + if requested_policy is None: + return False + if not granted_policy["public_fields"].issubset( + requested_policy["public_fields"] + ): + return False + requested_source_id_field = requested_policy["source_id_field"] + if ( + requested_source_id_field + and granted_policy["source_id_field"] != requested_source_id_field + ): + return False + return True + + +def _public_storage_tables(policies: list[Any] | None) -> dict[str, dict[str, Any]]: + tables: dict[str, dict[str, Any]] = {} + for policy in _policy_list(policies): + if not isinstance(policy, dict): + continue + table_name = policy.get("table_name") + public_fields = policy.get("public_fields") + source_id_field = policy.get("source_id_field") + if ( + not isinstance(table_name, str) + or table_name in tables + or not isinstance(public_fields, list) + or ( + source_id_field is not None + and (not isinstance(source_id_field, str) or not source_id_field) + ) + ): + continue + fields = {field for field in public_fields if isinstance(field, str) and field} + if fields: + tables[table_name] = { + "public_fields": fields, + "source_id_field": source_id_field, + } + return tables + + +def _public_storage_append_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, + *, + allow_max_rows_per_source_override: bool = False, +) -> bool: + requested_targets = _public_storage_append_targets(requested_policies) + granted_targets = _public_storage_append_targets(granted_policies) + if len(granted_targets) != len(_policy_list(granted_policies)): + return False + for target, granted_policy in granted_targets.items(): + requested_policy = requested_targets.get(target) + if requested_policy is None: + return False + if not granted_policy["allowed_fields"].issubset( + requested_policy["allowed_fields"] + ): + return False + if ( + granted_policy["max_rows_per_source"] + > requested_policy["max_rows_per_source"] + and not allow_max_rows_per_source_override + ): + return False + return True + + +def _public_storage_append_targets(policies: list[Any] | None) -> dict[Any, dict]: + targets: dict[Any, dict] = {} + for policy in _policy_list(policies): + if not isinstance(policy, dict): + continue + table = policy.get("table") + source_table = policy.get("source_table") + source_id_field = policy.get("source_id_field") + allowed_fields = policy.get("allowed_fields") + max_rows_per_source = policy.get( + "max_rows_per_source", _PUBLIC_APPEND_DEFAULT_MAX_ROWS_PER_SOURCE + ) + if ( + not isinstance(table, str) + or not table + or not isinstance(source_table, str) + or not source_table + or not isinstance(source_id_field, str) + or not source_id_field + or source_id_field == "id" + or not isinstance(allowed_fields, list) + or isinstance(max_rows_per_source, bool) + or not isinstance(max_rows_per_source, int) + or max_rows_per_source <= 0 + or max_rows_per_source > PUBLIC_APPEND_MAX_ROWS_PER_SOURCE_LIMIT + ): + continue + fields = {field for field in allowed_fields if isinstance(field, str) and field} + if "id" in fields or _OWNER_ID_FIELD in fields or source_id_field in fields: + continue + targets[(table, source_table, source_id_field)] = { + "allowed_fields": fields, + "max_rows_per_source": max_rows_per_source, + } + return targets + + +def _public_invoice_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, +) -> bool: + return _public_invoice_sources(granted_policies).issubset( + _public_invoice_sources(requested_policies) + ) + + +def _public_invoice_sources(policies: list[Any] | None) -> set[tuple[str, str]]: + sources: set[tuple[str, str]] = set() + for policy in _policy_list(policies): + if not isinstance(policy, dict): + continue + table = policy.get("table") + wallet_field = policy.get("wallet_field") + if isinstance(table, str) and table and isinstance(wallet_field, str): + sources.add((table, wallet_field)) + return sources + + +def _websocket_publish_grant_is_subset( + requested_policies: list[Any] | None, + granted_policies: list[Any] | None, + *, + allow_max_messages_per_second_override: bool = False, +) -> bool: + requested_policy = _websocket_publish_policy(requested_policies) + granted_policy = _websocket_publish_policy(granted_policies) + if requested_policy is None or granted_policy is None: + return False + if ( + granted_policy["max_messages_per_second"] + > requested_policy["max_messages_per_second"] + and not allow_max_messages_per_second_override + ): + return False + return True + + +def _websocket_publish_policy(policies: list[Any] | None) -> dict[str, int] | None: + policy_list = _policy_list(policies) + if len(policy_list) != 1: + return None + policy = policy_list[0] + if not isinstance(policy, dict): + return None + max_messages_per_second = policy.get("max_messages_per_second") + if ( + isinstance(max_messages_per_second, bool) + or not isinstance(max_messages_per_second, int) + or max_messages_per_second <= 0 + or max_messages_per_second > WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT + ): + return None + return {"max_messages_per_second": max_messages_per_second} diff --git a/lnbits/core/wasm_ext/api/registry.py b/lnbits/core/wasm_ext/api/registry.py new file mode 100644 index 000000000..2dcddc55f --- /dev/null +++ b/lnbits/core/wasm_ext/api/registry.py @@ -0,0 +1,205 @@ +from __future__ import annotations + +import inspect +from collections.abc import Awaitable, Callable +from functools import wraps +from typing import Any, TypeVar, cast, get_type_hints + +from pydantic import BaseModel + +from .models import ExtensionAPIMethod, ExtensionAPIMethodExport + +_EXTENSION_API_METHOD_ATTR = "__lnbits_extension_api_method__" +_EXTENSION_RUNTIME_PERMISSION_IDS = { + "ui.camera.scan_qr", + "wallet.pay_invoice", + "wallet.pay_invoice_background", + "wallet.payments.watch", + "websocket.subscribe", +} +_RequestModel = TypeVar("_RequestModel", bound=BaseModel) +_ResponseModel = TypeVar("_ResponseModel", bound=BaseModel) + + +def extension_api_method( + *, + method_id: str, + namespace: str, + name: str, + host_name: str, + sdk_name: str, + description: str, + host_interface: str = "host", + required_permission: str | None = None, + require_auth: bool = True, +) -> Callable[ + [Callable[[Any, _RequestModel], Awaitable[_ResponseModel]]], + Callable[[Any, _RequestModel], Awaitable[_ResponseModel]], +]: + export = ExtensionAPIMethodExport( + method_id=method_id, + namespace=namespace, + name=name, + host_interface=host_interface, + host_name=host_name, + sdk_name=sdk_name, + description=description, + required_permission=required_permission, + require_auth=require_auth, + ) + + def decorator( + function: Callable[[Any, _RequestModel], Awaitable[_ResponseModel]], + ) -> Callable[[Any, _RequestModel], Awaitable[_ResponseModel]]: + @wraps(function) + async def wrapper(self: Any, request: _RequestModel) -> _ResponseModel: + api = getattr(self, "api", self) + if require_auth and not api.has_authenticated_context(): + raise PermissionError( + f"Extension API method '{method_id}' requires authentication." + ) + api.require_permission(required_permission) + return await function(self, request) + + setattr(wrapper, _EXTENSION_API_METHOD_ATTR, export) + return wrapper + + return decorator + + +def list_extension_api_methods( + api_cls: type[Any] | None = None, +) -> list[ExtensionAPIMethod]: + api_cls = _default_api_cls(api_cls) + methods: list[ExtensionAPIMethod] = [] + + for prefix, method_cls in _extension_api_method_sources(api_cls): + for python_name, function in inspect.getmembers(method_cls, inspect.isfunction): + export = getattr(function, _EXTENSION_API_METHOD_ATTR, None) + if not export: + continue + + request_model, response_model = _get_method_models(function) + methods.append( + ExtensionAPIMethod( + method_id=export.method_id, + namespace=export.namespace, + name=export.name, + python_name=f"{prefix}.{python_name}" if prefix else python_name, + host_interface=export.host_interface, + host_name=export.host_name, + sdk_name=export.sdk_name, + description=export.description, + request_model=request_model, + response_model=response_model, + required_permission=export.required_permission, + require_auth=export.require_auth, + ) + ) + + return sorted(methods, key=lambda method: method.method_id) + + +def extension_api_permission_ids(api_cls: type[Any] | None = None) -> set[str]: + permissions = { + method.required_permission + for method in list_extension_api_methods(api_cls) + if method.required_permission + } + permissions.update(_EXTENSION_RUNTIME_PERMISSION_IDS) + return permissions + + +def get_extension_api_method( + method_id: str, + api_cls: type[Any] | None = None, +) -> ExtensionAPIMethod: + for method in list_extension_api_methods(api_cls): + if method.method_id == method_id: + return method + raise KeyError(f"Unknown extension API method '{method_id}'.") + + +def extension_api_contract(api_cls: type[Any] | None = None) -> dict[str, object]: + return { + "version": 1, + "methods": [ + { + "id": method.method_id, + "namespace": method.namespace, + "name": method.name, + "python_name": method.python_name, + "host_interface": method.host_interface, + "host_name": method.host_name, + "sdk_name": method.sdk_name, + "sdk_qualified_name": method.sdk_qualified_name, + "description": method.description, + "required_permission": method.required_permission, + "require_auth": method.require_auth, + "request_schema": method.request_model.schema( + ref_template="#/definitions/{model}" + ), + "response_schema": method.response_model.schema( + ref_template="#/definitions/{model}" + ), + } + for method in list_extension_api_methods(api_cls) + ], + } + + +def _default_api_cls(api_cls: type[Any] | None) -> type[Any]: + if api_cls is not None: + return api_cls + + from .host import ExtensionHostAPI + + return ExtensionHostAPI + + +def _extension_api_method_sources( + api_cls: type[Any], +) -> list[tuple[str, type[Any]]]: + sources: list[tuple[str, type[Any]]] = [("", api_cls)] + + from .host import ExtensionHostAPI + + if issubclass(api_cls, ExtensionHostAPI): + from .utils import extension_api_utils_method_classes + + sources.extend(extension_api_utils_method_classes().items()) + return sources + + +def _get_method_models( + function: Callable[..., object], +) -> tuple[type[BaseModel], type[BaseModel]]: + signature = inspect.signature(function) + request_parameters = [ + parameter + for parameter in signature.parameters.values() + if parameter.name != "self" + ] + if len(request_parameters) != 1: + raise TypeError( + f"Extension API method '{function.__name__}' must accept one request model." + ) + + hints = get_type_hints(function) + request_model = hints.get(request_parameters[0].name) + response_model = hints.get("return") + + if not _is_pydantic_model(request_model): + raise TypeError( + f"Extension API method '{function.__name__}' request must be a BaseModel." + ) + if not _is_pydantic_model(response_model): + raise TypeError( + f"Extension API method '{function.__name__}' response must be a BaseModel." + ) + + return cast(type[BaseModel], request_model), cast(type[BaseModel], response_model) + + +def _is_pydantic_model(value: object) -> bool: + return isinstance(value, type) and issubclass(value, BaseModel) diff --git a/lnbits/core/wasm_ext/api/runtime.py b/lnbits/core/wasm_ext/api/runtime.py new file mode 100644 index 000000000..e4a62a666 --- /dev/null +++ b/lnbits/core/wasm_ext/api/runtime.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +import inspect +import re +from collections.abc import Awaitable, Callable, Mapping +from typing import Any + +from pydantic import BaseModel + +from .host import ExtensionHostAPI +from .models import ExtensionAPIMethod +from .registry import list_extension_api_methods + +HostImport = Callable[..., Awaitable[dict[str, Any]]] + + +class ExtensionAPIHost: + def __init__( + self, + api: ExtensionHostAPI, + *, + api_cls: type[ExtensionHostAPI] = ExtensionHostAPI, + ) -> None: + self.api = api + self.methods = list_extension_api_methods(api_cls) + self._methods_by_host_name = self._index_methods(self.methods) + + async def invoke( + self, + host_name: str, + payload: Mapping[str, Any] | BaseModel | None = None, + ) -> dict[str, Any]: + method = self._require_method(host_name) + from lnbits.core.services.extensions import record_wasm_invocation_host_call + + record_wasm_invocation_host_call(self.api.invocation_id, method.method_id) + request = self._request_model(method, payload) + handler = _resolve_attr_path(self.api, method.python_name) + response = handler(request) + if inspect.isawaitable(response): + response = await response + return self._response_payload(method, response) + + def imports(self) -> dict[str, HostImport]: + return self.imports_for_interface("host") + + def import_object(self) -> dict[str, dict[str, HostImport]]: + interfaces = sorted({method.host_interface for method in self.methods}) + return { + f"lnbits:extension/{interface}": self.imports_for_interface(interface) + for interface in interfaces + } + + def imports_for_interface(self, host_interface: str) -> dict[str, HostImport]: + return { + _snake_to_camel(method.host_name): self._make_import(method) + for method in self.methods + if method.host_interface == host_interface + } + + def _make_import(self, method: ExtensionAPIMethod) -> HostImport: + async def host_import( + payload: Mapping[str, Any] | BaseModel | None = None, + ) -> dict[str, Any]: + return await self.invoke(method.method_id, payload) + + return host_import + + def _require_method(self, host_name: str) -> ExtensionAPIMethod: + method = self._methods_by_host_name.get(host_name) + if not method: + raise KeyError(f"Unknown extension host function '{host_name}'.") + return method + + @staticmethod + def _index_methods( + methods: list[ExtensionAPIMethod], + ) -> dict[str, ExtensionAPIMethod]: + index: dict[str, ExtensionAPIMethod] = {} + for method in methods: + for host_name in { + method.method_id, + f"{method.host_interface}:{method.host_name}", + method.host_name, + _snake_to_camel(method.host_name), + method.host_name.replace("_", "-"), + }: + index[host_name] = method + return index + + @staticmethod + def _request_model( + method: ExtensionAPIMethod, + payload: Mapping[str, Any] | BaseModel | None, + ) -> BaseModel: + if isinstance(payload, method.request_model): + return payload + if isinstance(payload, BaseModel): + payload = payload.dict() + if payload is None: + payload = {} + if not isinstance(payload, Mapping): + raise TypeError( + f"Host function '{method.host_name}' expects an object payload." + ) + data = {_to_snake(key): value for key, value in payload.items()} + if isinstance(data.get("extra"), list): + data["extra"] = dict(data["extra"]) + if isinstance(data.get("headers"), list): + data["headers"] = dict(data["headers"]) + return method.request_model.parse_obj(data) + + @staticmethod + def _response_payload( + method: ExtensionAPIMethod, + response: Any, + ) -> dict[str, Any]: + if not isinstance(response, method.response_model): + response = method.response_model.parse_obj(response) + payload = response.dict() + if method.method_id in {"http.request", "extension.api.request"} and isinstance( + payload.get("headers"), Mapping + ): + payload["headers"] = list(payload["headers"].items()) + return {_snake_to_camel(key): value for key, value in payload.items()} + + +def _snake_to_camel(value: str) -> str: + head, *tail = value.split("_") + return head + "".join(part.capitalize() for part in tail) + + +def _to_snake(value: str) -> str: + value = value.replace("-", "_") + return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", value).lower() + + +def _resolve_attr_path(value: Any, path: str) -> Any: + for part in path.split("."): + value = getattr(value, part) + return value diff --git a/lnbits/core/wasm_ext/api/utils.py b/lnbits/core/wasm_ext/api/utils.py new file mode 100644 index 000000000..bb664b168 --- /dev/null +++ b/lnbits/core/wasm_ext/api/utils.py @@ -0,0 +1,475 @@ +from __future__ import annotations + +import time +from collections.abc import Iterable +from datetime import datetime +from typing import Any + +from lnurl import LnurlErrorResponse, LnurlPayResponse, LnurlResponseException +from lnurl import handle as lnurl_handle + +from lnbits import bolt11 +from lnbits.settings import settings +from lnbits.utils.crypto import random_secret_and_hash, verify_preimage +from lnbits.utils.exchange_rates import ( + allowed_currencies, + fiat_amount_as_satoshis, + get_fiat_rate_and_price_satoshis, + satoshis_amount_as_fiat, +) + +from .lnurl import ( + lnurl_pay_response_int, + lnurl_pay_response_metadata_json, + lnurl_pay_response_text, + normalize_lnurl, +) +from .models import ( + Bolt11Request, + CurrencyConvertRequest, + CurrencyConvertResponse, + CurrencyListResponse, + CurrencyRateRequest, + CurrencyRateResponse, + DecodeInvoiceResponse, + EmptyRequest, + FiatToSatsRequest, + FiatToSatsResponse, + InvoiceAmountMsatResponse, + InvoiceExpiryResponse, + InvoiceMemoResponse, + InvoicePaymentHashResponse, + LnurlResolveRequest, + LnurlResolveResponse, + RandomSecretAndHashRequest, + RandomSecretAndHashResponse, + SatsToFiatRequest, + SatsToFiatResponse, + ServerHealthResponse, + ValidateInvoiceResponse, + VerifyPreimageRequest, + VerifyPreimageResponse, +) +from .registry import extension_api_method + + +class ExtensionAPIUtils: + def __init__( + self, + extension_id: str, + permissions: Iterable[str], + *, + authenticated: bool = False, + ) -> None: + permission_set = set(permissions) + self.currencies = ExtensionCurrencyUtils( + extension_id, permission_set, authenticated=authenticated + ) + self.server = ExtensionServerUtils( + extension_id, permission_set, authenticated=authenticated + ) + self.lightning = ExtensionLightningUtils( + extension_id, permission_set, authenticated=authenticated + ) + self.lnurl = ExtensionLnurlUtils( + extension_id, permission_set, authenticated=authenticated + ) + + +class _ExtensionAPIUtilsGroup: + def __init__( + self, + extension_id: str, + permissions: Iterable[str], + *, + authenticated: bool = False, + ) -> None: + self.extension_id = extension_id + self.permissions = set(permissions) + self.authenticated = authenticated + + def require_permission(self, permission: str | None) -> None: + if permission and permission not in self.permissions: + raise PermissionError( + f"Extension '{self.extension_id}' is missing permission '{permission}'." + ) + + def has_authenticated_context(self) -> bool: + return self.authenticated + + +class ExtensionCurrencyUtils(_ExtensionAPIUtilsGroup): + @extension_api_method( + method_id="utils.currencies.list", + namespace="utils.currencies", + name="List currencies", + host_interface="utils-currencies", + host_name="list_currencies", + sdk_name="list", + description="List currencies supported by LNbits exchange-rate conversion.", + required_permission="utils.basic", + require_auth=False, + ) + async def list(self, request: EmptyRequest) -> CurrencyListResponse: + + return CurrencyListResponse(currencies=allowed_currencies()) + + @extension_api_method( + method_id="utils.currencies.rate", + namespace="utils.currencies", + name="Get currency rate", + host_interface="utils-currencies", + host_name="rate", + sdk_name="rate", + description="Get sats-per-fiat and BTC price for a currency.", + required_permission="utils.basic", + require_auth=False, + ) + async def rate(self, request: CurrencyRateRequest) -> CurrencyRateResponse: + + rate, price = await get_fiat_rate_and_price_satoshis(request.currency) + return CurrencyRateResponse(rate=rate, price=price) + + @extension_api_method( + method_id="utils.currencies.convert", + namespace="utils.currencies", + name="Convert currency amount", + host_interface="utils-currencies", + host_name="convert", + sdk_name="convert", + description="Convert between sats, BTC, and supported fiat currencies.", + required_permission="utils.basic", + require_auth=False, + ) + async def convert(self, request: CurrencyConvertRequest) -> CurrencyConvertResponse: + + from_currency = request.from_currency + if from_currency == "sats": + from_currency = "sat" + + amounts: list[tuple[str, float]] = [] + if from_currency == "sat": + sats = int(request.amount) + amounts.append(("BTC", sats / 100_000_000)) + amounts.append(("sats", sats)) + for currency in request.to.split(","): + currency = currency.strip() + if currency: + amounts.append( + ( + currency.upper(), + await satoshis_amount_as_fiat(sats, currency), + ) + ) + else: + sats = await fiat_amount_as_satoshis(request.amount, from_currency) + amounts.append((from_currency.upper(), request.amount)) + amounts.append(("sats", sats)) + amounts.append(("BTC", sats / 100_000_000)) + return CurrencyConvertResponse(amounts=amounts) + + @extension_api_method( + method_id="utils.currencies.fiat_to_sats", + namespace="utils.currencies", + name="Convert fiat to sats", + host_interface="utils-currencies", + host_name="fiat_to_sats", + sdk_name="fiatToSats", + description="Convert a fiat amount to sats.", + required_permission="utils.basic", + require_auth=False, + ) + async def fiat_to_sats(self, request: FiatToSatsRequest) -> FiatToSatsResponse: + + return FiatToSatsResponse( + amount_sat=await fiat_amount_as_satoshis( + request.amount, + request.currency, + ) + ) + + @extension_api_method( + method_id="utils.currencies.sats_to_fiat", + namespace="utils.currencies", + name="Convert sats to fiat", + host_interface="utils-currencies", + host_name="sats_to_fiat", + sdk_name="satsToFiat", + description="Convert a sats amount to fiat.", + required_permission="utils.basic", + require_auth=False, + ) + async def sats_to_fiat(self, request: SatsToFiatRequest) -> SatsToFiatResponse: + + return SatsToFiatResponse( + amount=await satoshis_amount_as_fiat(request.amount, request.currency) + ) + + +class ExtensionServerUtils(_ExtensionAPIUtilsGroup): + @extension_api_method( + method_id="utils.server.health", + namespace="utils.server", + name="Server health", + host_interface="utils-server", + host_name="health", + sdk_name="health", + description="Return basic public LNbits server health data.", + required_permission="utils.basic", + require_auth=False, + ) + async def health(self, request: EmptyRequest) -> ServerHealthResponse: + + return ServerHealthResponse( + server_time=int(time.time()), + up_time=settings.lnbits_server_up_time, + ) + + +class ExtensionLnurlUtils(_ExtensionAPIUtilsGroup): + @extension_api_method( + method_id="utils.lnurl.resolve", + namespace="utils.lnurl", + name="Resolve LNURL-pay", + host_interface="utils-lnurl", + host_name="resolve", + sdk_name="resolve", + description="Resolve a Lightning Address or LNURL-pay request.", + required_permission="wallet.pay_invoice", + require_auth=True, + ) + async def resolve(self, request: LnurlResolveRequest) -> LnurlResolveResponse: + normalized_lnurl = normalize_lnurl(request.lnurl) + response = await lnurl_handle( + normalized_lnurl, + user_agent=settings.user_agent, + timeout=5, + ) + if isinstance(response, LnurlErrorResponse): + raise LnurlResponseException(response.reason) + if not isinstance(response, LnurlPayResponse): + raise LnurlResponseException( + "Invalid LNURL response. Expected LnurlPayResponse." + ) + + min_sendable_msat = lnurl_pay_response_int( + response, "min_sendable", "minSendable" + ) + max_sendable_msat = lnurl_pay_response_int( + response, "max_sendable", "maxSendable" + ) + image = getattr(response, "image", None) + return LnurlResolveResponse( + lnurl=normalized_lnurl, + domain=getattr(response, "domain", None), + description=lnurl_pay_response_text(response), + min_sendable_msat=min_sendable_msat, + max_sendable_msat=max_sendable_msat, + comment_allowed=lnurl_pay_response_int( + response, "comment_allowed", "commentAllowed" + ), + fixed=bool( + getattr( + response, + "fixed", + min_sendable_msat == max_sendable_msat, + ) + ), + image=str(image) if image is not None else None, + metadata_json=lnurl_pay_response_metadata_json(response), + ) + + +class ExtensionLightningUtils(_ExtensionAPIUtilsGroup): + @extension_api_method( + method_id="utils.lightning.decode_invoice", + namespace="utils.lightning", + name="Decode Lightning invoice", + host_interface="utils-lightning", + host_name="decode_invoice", + sdk_name="decodeInvoice", + description="Decode a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def decode_invoice(self, request: Bolt11Request) -> DecodeInvoiceResponse: + invoice = _decode_bolt11(request.bolt11) + return _decoded_invoice_response(invoice) + + @extension_api_method( + method_id="utils.lightning.validate_invoice", + namespace="utils.lightning", + name="Validate Lightning invoice", + host_interface="utils-lightning", + host_name="validate_invoice", + sdk_name="validateInvoice", + description="Validate whether a string is a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def validate_invoice(self, request: Bolt11Request) -> ValidateInvoiceResponse: + try: + _decode_bolt11(request.bolt11) + return ValidateInvoiceResponse(valid=True) + except Exception as exc: + return ValidateInvoiceResponse(valid=False, error=str(exc)) + + @extension_api_method( + method_id="utils.lightning.invoice_payment_hash", + namespace="utils.lightning", + name="Get Lightning invoice payment hash", + host_interface="utils-lightning", + host_name="invoice_payment_hash", + sdk_name="invoicePaymentHash", + description="Get the payment hash from a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def invoice_payment_hash( + self, request: Bolt11Request + ) -> InvoicePaymentHashResponse: + return InvoicePaymentHashResponse( + payment_hash=str(_decode_bolt11(request.bolt11).payment_hash) + ) + + @extension_api_method( + method_id="utils.lightning.invoice_amount_msat", + namespace="utils.lightning", + name="Get Lightning invoice amount", + host_interface="utils-lightning", + host_name="invoice_amount_msat", + sdk_name="invoiceAmountMsat", + description="Get the amount in msat from a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def invoice_amount_msat( + self, request: Bolt11Request + ) -> InvoiceAmountMsatResponse: + return InvoiceAmountMsatResponse( + amount_msat=_invoice_amount_msat(_decode_bolt11(request.bolt11)) + ) + + @extension_api_method( + method_id="utils.lightning.invoice_expiry", + namespace="utils.lightning", + name="Get Lightning invoice expiry", + host_interface="utils-lightning", + host_name="invoice_expiry", + sdk_name="invoiceExpiry", + description="Get the expiry timestamp from a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def invoice_expiry(self, request: Bolt11Request) -> InvoiceExpiryResponse: + return InvoiceExpiryResponse( + expires_at=_invoice_expires_at(_decode_bolt11(request.bolt11)) + ) + + @extension_api_method( + method_id="utils.lightning.invoice_memo", + namespace="utils.lightning", + name="Get Lightning invoice memo", + host_interface="utils-lightning", + host_name="invoice_memo", + sdk_name="invoiceMemo", + description="Get the memo from a BOLT11 Lightning invoice.", + required_permission="utils.basic", + require_auth=False, + ) + async def invoice_memo(self, request: Bolt11Request) -> InvoiceMemoResponse: + return InvoiceMemoResponse(memo=_invoice_memo(_decode_bolt11(request.bolt11))) + + @extension_api_method( + method_id="utils.lightning.verify_preimage", + namespace="utils.lightning", + name="Verify Lightning preimage", + host_interface="utils-lightning", + host_name="verify_preimage", + sdk_name="verifyPreimage", + description="Verify that a preimage matches a payment hash.", + required_permission="utils.basic", + require_auth=False, + ) + async def verify_preimage( + self, request: VerifyPreimageRequest + ) -> VerifyPreimageResponse: + + return VerifyPreimageResponse( + valid=verify_preimage(request.preimage, request.payment_hash) + ) + + @extension_api_method( + method_id="utils.lightning.random_secret_and_hash", + namespace="utils.lightning", + name="Random Lightning secret and hash", + host_interface="utils-lightning", + host_name="random_secret_and_hash", + sdk_name="randomSecretAndHash", + description="Create a random secret and matching SHA256 hash.", + required_permission="utils.basic", + require_auth=False, + ) + async def random_secret_and_hash( + self, request: RandomSecretAndHashRequest + ) -> RandomSecretAndHashResponse: + + secret, payment_hash = random_secret_and_hash(request.length) + return RandomSecretAndHashResponse(secret=secret, hash=payment_hash) + + +def extension_api_utils_method_classes() -> dict[str, type[_ExtensionAPIUtilsGroup]]: + return { + "utils.currencies": ExtensionCurrencyUtils, + "utils.server": ExtensionServerUtils, + "utils.lnurl": ExtensionLnurlUtils, + "utils.lightning": ExtensionLightningUtils, + } + + +def _decode_bolt11(payment_request: str) -> Any: + + return bolt11.decode(payment_request) + + +def _decoded_invoice_response(invoice: Any) -> DecodeInvoiceResponse: + return DecodeInvoiceResponse( + payment_hash=str(getattr(invoice, "payment_hash", "")) or None, + amount_msat=_invoice_amount_msat(invoice), + expiry=_invoice_expiry(invoice), + expires_at=_invoice_expires_at(invoice), + memo=_invoice_memo(invoice), + ) + + +def _invoice_amount_msat(invoice: Any) -> int | None: + amount_msat = getattr(invoice, "amount_msat", None) + if amount_msat is None: + return None + return int(amount_msat) + + +def _invoice_expiry(invoice: Any) -> int | None: + expiry = getattr(invoice, "expiry", None) + if expiry is None: + return None + return int(expiry) + + +def _invoice_expires_at(invoice: Any) -> int | None: + expiry_date = getattr(invoice, "expiry_date", None) + if isinstance(expiry_date, datetime): + return int(expiry_date.timestamp()) + + date = getattr(invoice, "date", None) + expiry = getattr(invoice, "expiry", None) + if isinstance(date, datetime) and expiry is not None: + return int(date.timestamp() + int(expiry)) + if isinstance(date, (int, float)) and expiry is not None: + return int(date + int(expiry)) + return None + + +def _invoice_memo(invoice: Any) -> str | None: + memo = getattr(invoice, "description", None) + return str(memo) if memo is not None else None diff --git a/lnbits/core/wasm_ext/api/websockets.py b/lnbits/core/wasm_ext/api/websockets.py new file mode 100644 index 000000000..a53c9943c --- /dev/null +++ b/lnbits/core/wasm_ext/api/websockets.py @@ -0,0 +1,176 @@ +from __future__ import annotations + +import re +import time +from collections import deque +from dataclasses import dataclass + +from fastapi import WebSocket, WebSocketDisconnect +from loguru import logger + +from lnbits.settings import settings + +_EXTENSION_ID_RE = re.compile(r"^[A-Za-z0-9_-]{1,128}$") +_LOCAL_ITEM_ID_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9:_-]{0,127}$") +WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT = 100 +WEBSOCKET_CLIENT_MAX_MESSAGES_PER_SECOND = 60 +WEBSOCKET_CLIENT_MAX_MESSAGE_BYTES = 8192 + + +@dataclass +class WasmExtensionWebsocketConnection: + extension_id: str + item_id: str + websocket: WebSocket + + +class WasmExtensionWebsocketRateLimitError(PermissionError): + pass + + +def scoped_websocket_item_id(extension_id: str, item_id: str) -> str: + if not _EXTENSION_ID_RE.fullmatch(extension_id): + raise ValueError("Extension websocket namespace is invalid.") + if not _LOCAL_ITEM_ID_RE.fullmatch(item_id): + raise ValueError( + "Extension websocket item ID must be 1-128 characters and contain " + "only letters, numbers, colon, underscore, or dash." + ) + return f"ext:{extension_id}:{item_id}" + + +class WasmExtensionWebsocketHub: + def __init__(self) -> None: + self.active_connections: list[WasmExtensionWebsocketConnection] = [] + self.publish_timestamps: dict[tuple[str, str], deque[float]] = {} + self.client_timestamps: dict[int, deque[float]] = {} + + async def connect( + self, extension_id: str, item_id: str, websocket: WebSocket + ) -> WasmExtensionWebsocketConnection: + scoped_websocket_item_id(extension_id, item_id) + logger.debug(f"WASM websocket connected to {extension_id}:{item_id}") + await websocket.accept() + conn = WasmExtensionWebsocketConnection( + extension_id=extension_id, + item_id=item_id, + websocket=websocket, + ) + self.active_connections.append(conn) + return conn + + async def listen(self, conn: WasmExtensionWebsocketConnection) -> None: + while settings.lnbits_running: + try: + data = await conn.websocket.receive_text() + if len(data.encode()) > WEBSOCKET_CLIENT_MAX_MESSAGE_BYTES: + await conn.websocket.close(code=1009) + self.disconnect(conn) + break + self._check_client_rate(conn) + await self._broadcast_client_message(conn, data) + except WebSocketDisconnect: + self.disconnect(conn) + break + except WasmExtensionWebsocketRateLimitError: + await conn.websocket.close(code=1008) + self.disconnect(conn) + break + + def disconnect(self, conn: WasmExtensionWebsocketConnection) -> None: + self.active_connections = [ + active_conn + for active_conn in self.active_connections + if active_conn.websocket != conn.websocket + ] + self.client_timestamps.pop(id(conn.websocket), None) + logger.debug( + f"WASM websocket disconnected from {conn.extension_id}:{conn.item_id}" + ) + + def get_connections( + self, extension_id: str, item_id: str + ) -> list[WasmExtensionWebsocketConnection]: + return [ + conn + for conn in self.active_connections + if conn.extension_id == extension_id and conn.item_id == item_id + ] + + async def publish( + self, + extension_id: str, + item_id: str, + data: str, + *, + max_messages_per_second: int, + ) -> None: + scoped_websocket_item_id(extension_id, item_id) + self._check_publish_rate( + extension_id, + item_id, + max_messages_per_second=max_messages_per_second, + ) + for conn in self.get_connections(extension_id, item_id): + await self._send_to_connection(conn, data) + + def _check_publish_rate( + self, + extension_id: str, + item_id: str, + *, + max_messages_per_second: int, + ) -> None: + if ( + isinstance(max_messages_per_second, bool) + or not isinstance(max_messages_per_second, int) + or max_messages_per_second <= 0 + or max_messages_per_second > WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT + ): + raise ValueError("Invalid websocket publish rate limit.") + + now = time.monotonic() + channel = (extension_id, item_id) + timestamps = self.publish_timestamps.setdefault(channel, deque()) + while timestamps and now - timestamps[0] >= 1: + timestamps.popleft() + if len(timestamps) >= max_messages_per_second: + raise WasmExtensionWebsocketRateLimitError( + "WASM websocket publish rate limit exceeded." + ) + timestamps.append(now) + + def _check_client_rate(self, conn: WasmExtensionWebsocketConnection) -> None: + now = time.monotonic() + key = id(conn.websocket) + timestamps = self.client_timestamps.setdefault(key, deque()) + while timestamps and now - timestamps[0] >= 1: + timestamps.popleft() + if len(timestamps) >= WEBSOCKET_CLIENT_MAX_MESSAGES_PER_SECOND: + raise WasmExtensionWebsocketRateLimitError( + "WASM websocket client rate limit exceeded." + ) + timestamps.append(now) + + async def _broadcast_client_message( + self, + conn: WasmExtensionWebsocketConnection, + data: str, + ) -> None: + for active_conn in self.get_connections(conn.extension_id, conn.item_id): + if active_conn.websocket == conn.websocket: + continue + await self._send_to_connection(active_conn, data) + + async def _send_to_connection( + self, + conn: WasmExtensionWebsocketConnection, + data: str, + ) -> None: + try: + await conn.websocket.send_text(data) + except (RuntimeError, WebSocketDisconnect): + self.disconnect(conn) + + +wasm_extension_websocket_hub = WasmExtensionWebsocketHub() diff --git a/lnbits/core/wasm_ext/client/__init__.py b/lnbits/core/wasm_ext/client/__init__.py new file mode 100644 index 000000000..42d836d84 --- /dev/null +++ b/lnbits/core/wasm_ext/client/__init__.py @@ -0,0 +1,4 @@ +from .extensions import send_extension_api_request +from .http import send_extension_http_request + +__all__ = ["send_extension_api_request", "send_extension_http_request"] diff --git a/lnbits/core/wasm_ext/client/extensions.py b/lnbits/core/wasm_ext/client/extensions.py new file mode 100644 index 000000000..b40484f14 --- /dev/null +++ b/lnbits/core/wasm_ext/client/extensions.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +import posixpath +import re +from typing import Any +from urllib.parse import unquote, urlsplit, urlunsplit + +import httpx + +from lnbits.core.crud.extensions import ( + get_installed_extension, + get_user_active_extensions_ids, +) +from lnbits.settings import settings + +from ..api.models import ExtensionApiRequest, HttpResponse + +EXTENSION_API_TIMEOUT_SECONDS = 10.0 +EXTENSION_API_MAX_RESPONSE_BYTES = 262_144 + +_READ_METHODS = {"GET", "HEAD"} +_WRITE_METHODS = {"DELETE", "PATCH", "POST", "PUT"} +_EXTENSION_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$") +_FORBIDDEN_RESPONSE_HEADERS = { + "connection", + "content-length", + "set-cookie", + "transfer-encoding", +} + + +async def send_extension_api_request( + caller_extension_id: str, + policies: list[Any], + user_id: str | None, + access_token: str | None, + request: ExtensionApiRequest, + *, + timeout_ms: int | None = None, + max_response_bytes: int | None = None, +) -> HttpResponse: + if not user_id: + raise PermissionError("Extension API requests require authentication.") + if not access_token: + raise PermissionError("Extension API requests require an account access token.") + + target_extension_id = _target_extension_id(request.extension_id) + access = _target_extension_access(policies, target_extension_id) + _require_method_access(caller_extension_id, target_extension_id, access, request) + await _require_enabled_extension(target_extension_id, user_id) + + path = _extension_api_path(request.path) + body = request.body.encode() if request.body is not None else b"" + if len(body) > 65_536: + raise ValueError("Extension API request body is too large.") + + url = f"http://{settings.host}:{settings.port}/{target_extension_id}{path}" + try: + async with httpx.AsyncClient( + follow_redirects=False, + timeout=_timeout_seconds(timeout_ms, EXTENSION_API_TIMEOUT_SECONDS), + trust_env=False, + ) as client: + async with client.stream( + request.method, + url, + headers={"Authorization": f"Bearer {access_token}"}, + content=body, + ) as response: + response_body = await _read_limited_response( + response, + max_response_bytes=max_response_bytes, + ) + return HttpResponse( + status_code=response.status_code, + headers=_response_headers(dict(response.headers)), + body=response_body.decode(response.encoding or "utf-8", "replace"), + ) + except httpx.RequestError as exc: + raise ValueError("Extension API request failed.") from exc + + +def _target_extension_id(extension_id: str) -> str: + target = extension_id.strip() + if not target or not _EXTENSION_ID_RE.match(target): + raise PermissionError("Extension API request has an invalid target extension.") + return target + + +def _target_extension_access(policies: list[Any], target_extension_id: str) -> set[str]: + if not isinstance(policies, list) or not policies: + raise PermissionError( + "Extension API requests require a non-empty extensions policy." + ) + + for extension in policies: + if isinstance(extension, str): + extension_id = extension + access = ["read"] + elif isinstance(extension, dict): + raw_extension_id = extension.get("id") + raw_access = extension.get("access") + if not isinstance(raw_extension_id, str): + continue + if not isinstance(raw_access, list): + raise PermissionError( + f"Extension API target '{target_extension_id}' " + "has no access policy." + ) + extension_id = raw_extension_id + access = raw_access + else: + continue + + if extension_id != target_extension_id: + continue + clean_access = { + item + for item in access + if isinstance(item, str) and item in {"read", "write"} + } + if clean_access: + return clean_access + break + + raise PermissionError( + f"Extension API target '{target_extension_id}' is not allowed." + ) + + +def _require_method_access( + caller_extension_id: str, + target_extension_id: str, + access: set[str], + request: ExtensionApiRequest, +) -> None: + if request.method in _READ_METHODS: + required_access = "read" + elif request.method in _WRITE_METHODS: + required_access = "write" + else: + raise PermissionError("Extension API request method is not allowed.") + + if required_access not in access: + raise PermissionError( + f"Extension '{caller_extension_id}' cannot {required_access} " + f"extension '{target_extension_id}'." + ) + + +async def _require_enabled_extension(target_extension_id: str, user_id: str) -> None: + extension = await get_installed_extension(target_extension_id) + if not extension or not extension.active: + raise PermissionError( + f"Target extension '{target_extension_id}' is not installed or enabled." + ) + + active_extensions = await get_user_active_extensions_ids(user_id) + if target_extension_id not in active_extensions: + raise PermissionError( + f"Target extension '{target_extension_id}' is not active for this user." + ) + + +def _extension_api_path(path: str) -> str: + parts = urlsplit(path) + if parts.scheme or parts.netloc: + raise PermissionError("Extension API request path must be relative.") + if parts.fragment: + raise PermissionError("Extension API request path cannot include a fragment.") + if not parts.path.startswith("/api/"): + raise PermissionError("Extension API request path must start with '/api/'.") + + decoded_path = unquote(parts.path) + path_parts = decoded_path.split("/") + if any(part == ".." for part in path_parts): + raise PermissionError("Extension API request path cannot traverse directories.") + + normalized = posixpath.normpath(decoded_path) + if normalized != decoded_path.rstrip("/") or not normalized.startswith("/api/"): + raise PermissionError("Extension API request path is invalid.") + + return urlunsplit(("", "", parts.path, parts.query, "")) + + +async def _read_limited_response( + response: httpx.Response, + *, + max_response_bytes: int | None = None, +) -> bytes: + limit = ( + EXTENSION_API_MAX_RESPONSE_BYTES + if max_response_bytes is None + else max_response_bytes + ) + chunks: list[bytes] = [] + size = 0 + async for chunk in response.aiter_bytes(): + size += len(chunk) + if limit > 0 and size > limit: + raise ValueError("Extension API response is too large.") + chunks.append(chunk) + return b"".join(chunks) + + +def _timeout_seconds(timeout_ms: int | None, default: float) -> float | None: + if timeout_ms is None: + return default + if timeout_ms <= 0: + return None + return timeout_ms / 1000 + + +def _response_headers(headers: dict[str, str]) -> dict[str, str]: + return { + key: value + for key, value in headers.items() + if key.lower() not in _FORBIDDEN_RESPONSE_HEADERS + } diff --git a/lnbits/core/wasm_ext/client/http.py b/lnbits/core/wasm_ext/client/http.py new file mode 100644 index 000000000..e3876d9b6 --- /dev/null +++ b/lnbits/core/wasm_ext/client/http.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import ipaddress +import socket +from typing import Any +from urllib.parse import urlparse + +import httpx + +from ..api.models import HttpRequest, HttpResponse + +HTTP_REQUEST_TIMEOUT_SECONDS = 10.0 +HTTP_MAX_RESPONSE_BYTES = 262_144 + +_FORBIDDEN_REQUEST_HEADERS = { + "connection", + "content-length", + "cookie", + "host", + "proxy-authorization", + "transfer-encoding", +} +_FORBIDDEN_RESPONSE_HEADERS = { + "connection", + "content-length", + "set-cookie", + "transfer-encoding", +} + + +async def send_extension_http_request( + extension_id: str, + policies: list[Any], + request: HttpRequest, + *, + timeout_ms: int | None = None, + max_response_bytes: int | None = None, +) -> HttpResponse: + allowed_origins = _allowed_origins(policies) + origin = _request_origin(request.url) + if origin not in allowed_origins: + raise PermissionError( + f"Extension '{extension_id}' is not allowed to request '{origin}'." + ) + + await _reject_internal_host(request.url) + headers = _request_headers(request.headers) + body = request.body.encode() if request.body is not None else b"" + if len(body) > 65_536: + raise ValueError("HTTP request body is too large.") + + try: + async with httpx.AsyncClient( + follow_redirects=False, + timeout=_timeout_seconds(timeout_ms, HTTP_REQUEST_TIMEOUT_SECONDS), + trust_env=False, + ) as client: + async with client.stream( + request.method, + request.url, + headers=headers, + content=body, + ) as response: + response_body = await _read_limited_response( + response, + max_response_bytes=max_response_bytes, + ) + return HttpResponse( + status_code=response.status_code, + headers=_response_headers(dict(response.headers)), + body=response_body.decode(response.encoding or "utf-8", "replace"), + ) + except httpx.RequestError as exc: + raise ValueError("HTTP request failed.") from exc + + +def _allowed_origins(policies: list[Any]) -> set[str]: + if not isinstance(policies, list) or not policies: + raise PermissionError("HTTP requests require a non-empty hosts policy.") + + origins: set[str] = set() + for policy in policies: + host = policy.get("host") if isinstance(policy, dict) else policy + if not isinstance(host, str) or not host: + continue + origins.add(_request_origin(host)) + if not origins: + raise PermissionError("HTTP requests require at least one valid host.") + return origins + + +def _request_origin(url: str) -> str: + parsed = urlparse(url) + if parsed.scheme != "https": + raise PermissionError("HTTP requests require https URLs.") + if parsed.username or parsed.password: + raise PermissionError("HTTP requests cannot include credentials in URLs.") + if not parsed.hostname: + raise PermissionError("HTTP requests require a hostname.") + + hostname = parsed.hostname.lower() + port = _url_port(parsed) + if port is None or port == 443: + return f"https://{hostname}" + return f"https://{hostname}:{port}" + + +def _url_port(parsed: Any) -> int | None: + try: + return parsed.port + except ValueError as exc: + raise PermissionError("HTTP request URL has an invalid port.") from exc + + +async def _reject_internal_host(url: str) -> None: + parsed = urlparse(url) + hostname = parsed.hostname + if not hostname: + raise PermissionError("HTTP requests require a hostname.") + if hostname == "localhost" or hostname.endswith(".localhost"): + raise PermissionError("HTTP requests cannot target localhost.") + + try: + address = ipaddress.ip_address(hostname) + _reject_internal_address(address) + return + except ValueError: + pass + + for address in await _resolve_host(hostname): + _reject_internal_address(address) + + +async def _resolve_host( + hostname: str, +) -> list[ipaddress.IPv4Address | ipaddress.IPv6Address]: + import asyncio + + def resolve() -> list[ipaddress.IPv4Address | ipaddress.IPv6Address]: + try: + infos = socket.getaddrinfo(hostname, None, type=socket.SOCK_STREAM) + except socket.gaierror as exc: + raise PermissionError("HTTP request host could not be resolved.") from exc + + addresses: list[ipaddress.IPv4Address | ipaddress.IPv6Address] = [] + for info in infos: + sockaddr = info[4] + addresses.append(ipaddress.ip_address(sockaddr[0])) + return addresses + + return await asyncio.to_thread(resolve) + + +def _reject_internal_address( + address: ipaddress.IPv4Address | ipaddress.IPv6Address, +) -> None: + if not address.is_global: + raise PermissionError("HTTP requests cannot target internal network addresses.") + + +def _request_headers(headers: dict[str, str]) -> dict[str, str]: + clean: dict[str, str] = {} + for key, value in headers.items(): + header = key.strip() + if not header: + continue + if header.lower() in _FORBIDDEN_REQUEST_HEADERS: + continue + clean[header] = value + return clean + + +async def _read_limited_response( + response: httpx.Response, + *, + max_response_bytes: int | None = None, +) -> bytes: + limit = ( + HTTP_MAX_RESPONSE_BYTES if max_response_bytes is None else max_response_bytes + ) + chunks: list[bytes] = [] + size = 0 + async for chunk in response.aiter_bytes(): + size += len(chunk) + if limit > 0 and size > limit: + raise ValueError("HTTP response is too large.") + chunks.append(chunk) + return b"".join(chunks) + + +def _timeout_seconds(timeout_ms: int | None, default: float) -> float | None: + if timeout_ms is None: + return default + if timeout_ms <= 0: + return None + return timeout_ms / 1000 + + +def _response_headers(headers: dict[str, str]) -> dict[str, str]: + return { + key: value + for key, value in headers.items() + if key.lower() not in _FORBIDDEN_RESPONSE_HEADERS + } diff --git a/lnbits/core/wasm_ext/routes/__init__.py b/lnbits/core/wasm_ext/routes/__init__.py new file mode 100644 index 000000000..c2b8497dd --- /dev/null +++ b/lnbits/core/wasm_ext/routes/__init__.py @@ -0,0 +1,3 @@ +from .register import register_wasm_extension, unregister_wasm_extension + +__all__ = ["register_wasm_extension", "unregister_wasm_extension"] diff --git a/lnbits/core/wasm_ext/routes/api.py b/lnbits/core/wasm_ext/routes/api.py new file mode 100644 index 000000000..df695e9ec --- /dev/null +++ b/lnbits/core/wasm_ext/routes/api.py @@ -0,0 +1,396 @@ +from __future__ import annotations + +import json +import re +from dataclasses import dataclass +from typing import Annotated, Any + +from fastapi import Depends, FastAPI, HTTPException, Request + +from lnbits.core.models import Account +from lnbits.core.services.extensions import get_wasm_runtime_limits_for_extension +from lnbits.core.wasm_ext.storage.crud import storage_get_row_owner_id +from lnbits.decorators import check_access_token, check_account_exists +from lnbits.settings import settings + +from ..wasm.config import WasmAPIRouteConfig +from ..wasm.invoke import invoke_wasm_extension_export +from ..wasm.loader import WasmExtension +from .open_api import wasm_extension_api_openapi_metadata, wasm_extension_api_tag + +_WASM_EXTENSION_API_METHODS = {"GET", "POST", "PUT", "PATCH", "DELETE"} + + +class WasmRequestBodyTooLargeError(ValueError): + pass + + +@dataclass(frozen=True) +class WasmRoutePayload: + data: dict[str, Any] + request_bytes: int | None + + +@dataclass(frozen=True) +class WasmAPIRouteRegistration: + route_config: WasmAPIRouteConfig + method: str + route_path: str + export_name: str + path_params: dict[str, str] + auth: str + route_name: str + + +def register_wasm_extension_api_routes(app: FastAPI, extension: WasmExtension) -> None: + route_registrations = [ + _wasm_extension_api_route_registration(extension, route_config) + for route_config in extension.config.api_routes + ] + + openapi_schema_changed = _remove_wasm_extension_api_routes(app, extension.id) + for route_registration in route_registrations: + if _add_wasm_extension_api_route(app, extension, route_registration): + openapi_schema_changed = True + if openapi_schema_changed: + app.openapi_schema = None + + +def unregister_wasm_extension_api_routes(app: FastAPI, ext_id: str) -> bool: + openapi_schema_changed = _remove_wasm_extension_api_routes(app, ext_id) + if openapi_schema_changed: + app.openapi_schema = None + return openapi_schema_changed + + +def _add_wasm_extension_api_route( + app: FastAPI, + extension: WasmExtension, + route_registration: WasmAPIRouteRegistration, +) -> bool: + method = route_registration.method + route_path = route_registration.route_path + export_name = route_registration.export_name + path_params = route_registration.path_params + auth = route_registration.auth + route_name = route_registration.route_name + route_config = route_registration.route_config + openapi = wasm_extension_api_openapi_metadata(extension, route_config, method) + + if not _prepare_wasm_extension_api_route(app, route_path, method, route_name): + return False + + async def invoke_wasm_api_request( + request: Request, + account: Account | None = None, + access_token: str | None = None, + ) -> dict[str, Any]: + try: + limits = await get_wasm_runtime_limits_for_extension(extension.id) + payload = await _read_api_payload( + request, + path_params, + max_body_bytes=limits["wasm_runtime_max_request_bytes"], + ) + owner_id = await _wasm_route_owner_id(extension, route_config, payload) + return await invoke_wasm_extension_export( + extension.id, + export_name, + payload.data, + user=account, + access_token=access_token, + context="event" if owner_id else "user", + owner_id=owner_id, + trigger_type="http", + method=request.method, + path=request.url.path, + request_id=request.headers.get("x-request-id"), + request_bytes=payload.request_bytes, + context_data={"origin": _request_origin(request)}, + ) + except WasmRequestBodyTooLargeError as exc: + raise HTTPException(status_code=413, detail=str(exc)) from exc + except KeyError as exc: + raise HTTPException(status_code=404, detail=str(exc)) from exc + except PermissionError as exc: + raise HTTPException(status_code=403, detail=str(exc)) from exc + except (TypeError, ValueError) as exc: + raise HTTPException(status_code=400, detail=str(exc)) from exc + + async def invoke_private_wasm_extension_export( + request: Request, + access_token: Annotated[str | None, Depends(check_access_token)], + account: Account = Depends(check_account_exists), + ) -> dict[str, Any]: + return await invoke_wasm_api_request(request, account, access_token) + + async def invoke_public_wasm_extension_export(request: Request) -> dict[str, Any]: + return await invoke_wasm_api_request(request) + + app.add_api_route( + route_path, + ( + invoke_public_wasm_extension_export + if auth == "public" + else invoke_private_wasm_extension_export + ), + methods=[method], + name=route_name, + tags=[wasm_extension_api_tag(extension)], + summary=openapi.summary, + description=openapi.description, + operation_id=openapi.operation_id, + openapi_extra=openapi.openapi_extra, + include_in_schema=True, + ) + return True + + +async def _read_api_payload( + request: Request, + path_params: dict[str, str], + *, + max_body_bytes: int, +) -> WasmRoutePayload: + payload = _read_api_path_params(request, path_params) + payload.update(_read_api_query_params(request)) + request_bytes: int | None = None + if request.method in {"POST", "PUT", "PATCH"}: + body, request_bytes = await _read_json_object_with_size( + request, + max_body_bytes=max_body_bytes, + ) + payload.update(body) + return WasmRoutePayload(payload, request_bytes) + + +async def _wasm_route_owner_id( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, + payload: WasmRoutePayload, +) -> str | None: + owner_context = route_config.owner_context + if not owner_context: + return None + source_id = payload.data.get(owner_context.id_param) + if not isinstance(source_id, str) or not source_id: + raise PermissionError("WASM owner-context route source is missing.") + owner_id = await storage_get_row_owner_id( + extension.id, + owner_context.table, + source_id, + ) + if not owner_id: + raise PermissionError("WASM owner-context route source was not found.") + return owner_id + + +async def _read_json_object( + request: Request, + *, + max_body_bytes: int | None = None, +) -> dict[str, Any]: + body, _ = await _read_json_object_with_size( + request, + max_body_bytes=( + settings.wasm_runtime_max_request_bytes + if max_body_bytes is None + else max_body_bytes + ), + ) + return body + + +async def _read_json_object_with_size( + request: Request, + *, + max_body_bytes: int, +) -> tuple[dict[str, Any], int]: + body = await _read_limited_body(request, max_body_bytes=max_body_bytes) + if not body: + return {}, 0 + value = json.loads(body) + if not isinstance(value, dict): + raise TypeError("WASM extension API payload must be a JSON object.") + return value, len(body) + + +async def _read_limited_body(request: Request, *, max_body_bytes: int) -> bytes: + content_length = _request_content_length(request) + if _wasm_request_too_large(content_length, max_body_bytes): + raise WasmRequestBodyTooLargeError( + f"WASM extension request is too large: {content_length} bytes." + ) + + chunks: list[bytes] = [] + size = 0 + async for chunk in request.stream(): + if not chunk: + continue + size += len(chunk) + if _wasm_request_too_large(size, max_body_bytes): + raise WasmRequestBodyTooLargeError( + f"WASM extension request is too large: {size} bytes." + ) + chunks.append(chunk) + return b"".join(chunks) + + +def _read_api_path_params( + request: Request, + path_params: dict[str, str], +) -> dict[str, Any]: + payload: dict[str, Any] = {} + for key, value in request.path_params.items(): + target = path_params.get(key) or _snake_to_camel(key) + payload[target] = value + return payload + + +def _read_api_query_params(request: Request) -> dict[str, Any]: + return {_snake_to_camel(key): value for key, value in request.query_params.items()} + + +def _request_content_length(request: Request) -> int | None: + content_length = request.headers.get("content-length") + if content_length and content_length.isdigit(): + return int(content_length) + return None + + +def _wasm_request_too_large(size: int | None, max_body_bytes: int) -> bool: + return size is not None and max_body_bytes > 0 and size > max_body_bytes + + +def _request_origin(request: Request) -> str | None: + origin = request.headers.get("origin") + if not origin: + return None + return origin[:256] + + +def _wasm_extension_api_export(extension: WasmExtension, export_name: Any) -> str: + if not isinstance(export_name, str) or not export_name: + raise ValueError(f"Invalid API export for WASM extension '{extension.id}'.") + + for export in extension.exports: + if export.name != export_name: + continue + if export.visibility in {"public", "authenticated"}: + return export_name + raise PermissionError(f"WASM export '{export_name}' is not callable over HTTP.") + raise KeyError(f"WASM extension '{extension.id}' has no export '{export_name}'.") + + +def _wasm_extension_api_method(extension: WasmExtension, method: Any) -> str: + if not isinstance(method, str): + raise ValueError(f"Invalid API method for WASM extension '{extension.id}'.") + method = method.upper() + if method not in _WASM_EXTENSION_API_METHODS: + raise ValueError(f"Unsupported API method for WASM extension '{extension.id}'.") + return method + + +def _wasm_extension_api_path(extension: WasmExtension, path: Any) -> str: + if not isinstance(path, str) or not path.startswith("/"): + raise ValueError(f"Invalid API path for WASM extension '{extension.id}'.") + if path == "/": + return f"/api/v1/ext/{extension.id}" + return f"/api/v1/ext/{extension.id}{path}" + + +def _wasm_extension_route_auth(extension: WasmExtension, auth: Any) -> str: + if auth in {"public", "user"}: + return auth + raise ValueError(f"Invalid route auth for WASM extension '{extension.id}'.") + + +def _has_route(app: FastAPI, route_path: str, method: str) -> bool: + for route in app.routes: + if getattr(route, "path", None) != route_path: + continue + methods = getattr(route, "methods", set()) or set() + if method in methods: + return True + return False + + +def _wasm_extension_api_route_registration( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, +) -> WasmAPIRouteRegistration: + method = _wasm_extension_api_method(extension, route_config.method) + route_path = _wasm_extension_api_path(extension, route_config.path) + return WasmAPIRouteRegistration( + route_config=route_config, + method=method, + route_path=route_path, + export_name=_wasm_extension_api_export(extension, route_config.export), + path_params=route_config.path_params, + auth=_wasm_extension_route_auth(extension, route_config.auth), + route_name=_wasm_extension_api_route_name(extension.id, method, route_path), + ) + + +def _remove_wasm_extension_api_routes(app: FastAPI, ext_id: str) -> bool: + removed = False + for route in list(app.router.routes): + if not _is_wasm_extension_api_route(route, ext_id): + continue + app.router.routes.remove(route) + removed = True + return removed + + +def _is_wasm_extension_api_route(route: Any, ext_id: str) -> bool: + route_name = getattr(route, "name", None) + if not isinstance(route_name, str) or not route_name.startswith(f"{ext_id}:"): + return False + route_name_parts = route_name.split(":", 2) + if len(route_name_parts) != 3: + return False + _, route_method, named_route_path = route_name_parts + if route_method not in _WASM_EXTENSION_API_METHODS: + return False + + route_path = getattr(route, "path", None) + if not isinstance(route_path, str): + return False + + route_prefix = f"/api/v1/ext/{ext_id}" + if route_path != route_prefix and not route_path.startswith(f"{route_prefix}/"): + return False + return named_route_path == route_path + + +def _prepare_wasm_extension_api_route( + app: FastAPI, + route_path: str, + method: str, + route_name: str, +) -> bool: + for route in list(app.router.routes): + if getattr(route, "path", None) != route_path: + continue + methods = getattr(route, "methods", set()) or set() + if method not in methods: + continue + if getattr(route, "name", None) != route_name: + return False + app.router.routes.remove(route) + return True + return True + + +def _wasm_extension_api_route_name(ext_id: str, method: str, route_path: str) -> str: + return f"{ext_id}:{method}:{route_path}" + + +def _snake_to_camel(value: str) -> str: + head, *tail = value.split("_") + return head + "".join(part.capitalize() for part in tail) + + +def _path_template_pattern(path: str) -> str: + pattern = re.sub(r"\\{[^/{}]+\\}", r"[^/]+", re.escape(path)) + return f"^{pattern}$" diff --git a/lnbits/core/wasm_ext/routes/assets.py b/lnbits/core/wasm_ext/routes/assets.py new file mode 100644 index 000000000..709786718 --- /dev/null +++ b/lnbits/core/wasm_ext/routes/assets.py @@ -0,0 +1,140 @@ +from __future__ import annotations + +import os +from pathlib import Path + +from fastapi import FastAPI, HTTPException +from fastapi.responses import FileResponse, Response +from fastapi.staticfiles import StaticFiles +from starlette.staticfiles import PathLike as StaticFilesPathLike +from starlette.types import Scope + +from lnbits.settings import settings + +from ..wasm.loader import WasmExtension + +WASM_EXTENSION_CORE_ASSET_PREFIX = "_lnbits" +WASM_EXTENSION_CORE_STATIC_ASSETS = { + "bundle.min.css": ("static/bundle.min.css", "text/css; charset=utf-8"), + "material-icons-v50.woff2": ( + "static/fonts/material-icons-v50.woff2", + "font/woff2", + ), + "quasar.css": ("static/vendor/quasar.css", "text/css; charset=utf-8"), + "quasar.umd.prod.js": ( + "static/vendor/quasar.umd.prod.js", + "text/javascript; charset=utf-8", + ), + "qrcode.vue.browser.js": ( + "static/vendor/qrcode.vue.browser.js", + "text/javascript; charset=utf-8", + ), + "vue.global.prod.js": ( + "static/vendor/vue.global.prod.js", + "text/javascript; charset=utf-8", + ), +} +WASM_EXTENSION_GENERATED_CORE_ASSETS = { + "material-icons.css": ( + """ + @font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url('./material-icons-v50.woff2') format('woff2'); + } + """, + "text/css; charset=utf-8", + ) +} +WASM_EXTENSION_STATIC_MIME_TYPES = { + ".css": "text/css; charset=utf-8", + ".gif": "image/gif", + ".ico": "image/x-icon", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".js": "text/javascript; charset=utf-8", + ".ogg": "audio/ogg", + ".png": "image/png", + ".webp": "image/webp", + ".woff": "font/woff", + ".woff2": "font/woff2", +} +WASM_EXTENSION_TEXT_STATIC_EXTENSIONS = {".css", ".js"} +WASM_EXTENSION_HTML_PREFIXES = (b" Response: + if path.startswith(f"{WASM_EXTENSION_CORE_ASSET_PREFIX}/"): + return _wasm_extension_core_asset_response(path) + if Path(path).suffix.lower() not in WASM_EXTENSION_STATIC_MIME_TYPES: + raise HTTPException(status_code=404) + return await super().get_response(path, scope) + + def file_response( + self, + full_path: StaticFilesPathLike, + stat_result: os.stat_result, + scope: Scope, + status_code: int = 200, + ) -> Response: + suffix = Path(full_path).suffix.lower() + if suffix in WASM_EXTENSION_TEXT_STATIC_EXTENSIONS: + _reject_html_like_wasm_static_asset(Path(full_path)) + + response = super().file_response(full_path, stat_result, scope, status_code) + response.headers["Content-Type"] = WASM_EXTENSION_STATIC_MIME_TYPES[suffix] + response.headers["X-Content-Type-Options"] = "nosniff" + response.headers["Cache-Control"] = "no-store" + return response + + +def mount_wasm_extension_static(app: FastAPI, extension: WasmExtension) -> None: + static_path = extension.root_path / "static" + + mount_path = f"/ext-assets/{extension.id}" + if any(getattr(route, "path", None) == mount_path for route in app.routes): + return + + app.mount( + mount_path, + GuardedWasmExtensionStaticFiles(directory=static_path, check_dir=False), + name=f"{extension.id}-static", + ) + + +def _reject_html_like_wasm_static_asset(path: Path) -> None: + with path.open("rb") as asset_file: + prefix = asset_file.read(512).lstrip().lower() + if prefix.startswith(WASM_EXTENSION_HTML_PREFIXES): + raise HTTPException(status_code=404) + + +def _wasm_extension_core_asset_response(path: str) -> Response: + asset_name = path.removeprefix(f"{WASM_EXTENSION_CORE_ASSET_PREFIX}/") + if not asset_name or "/" in asset_name or "\\" in asset_name: + raise HTTPException(status_code=404) + + generated_asset = WASM_EXTENSION_GENERATED_CORE_ASSETS.get(asset_name) + if generated_asset: + content, content_type = generated_asset + response = Response(content=content, media_type=content_type) + response.headers["X-Content-Type-Options"] = "nosniff" + response.headers["Cache-Control"] = "no-store" + return response + + asset_config = WASM_EXTENSION_CORE_STATIC_ASSETS.get(asset_name) + if not asset_config: + raise HTTPException(status_code=404) + + relative_path, content_type = asset_config + asset_path = Path(settings.lnbits_path, relative_path) + if not asset_path.is_file(): + raise HTTPException(status_code=404) + + response = FileResponse(asset_path) + response.headers["Content-Type"] = content_type + response.headers["X-Content-Type-Options"] = "nosniff" + response.headers["Cache-Control"] = "no-store" + return response diff --git a/lnbits/core/wasm_ext/routes/open_api.py b/lnbits/core/wasm_ext/routes/open_api.py new file mode 100644 index 000000000..d3c0da8af --- /dev/null +++ b/lnbits/core/wasm_ext/routes/open_api.py @@ -0,0 +1,356 @@ +from __future__ import annotations + +import json +import re +from copy import deepcopy +from dataclasses import dataclass +from typing import Any + +from loguru import logger + +from ..wasm.config import WasmAPIRouteConfig +from ..wasm.loader import WasmExtension + + +@dataclass(frozen=True) +class WasmOpenAPIMetadata: + summary: str + description: str | None + operation_id: str + openapi_extra: dict[str, Any] | None + + +_MISSING_OPENAPI_EXAMPLE = object() + + +def wasm_extension_api_tag(extension: WasmExtension) -> str: + return extension.name.strip() or extension.id + + +def wasm_extension_api_openapi_metadata( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, + method: str, +) -> WasmOpenAPIMetadata: + operation = _load_wasm_extension_openapi_operation( + extension, + route_config, + ) + summary = _openapi_string(operation.pop("summary", None)) or ( + f"{method} {route_config.path}" + ) + description = _openapi_string(operation.pop("description", None)) + operation_id = ( + _openapi_string(operation.pop("operationId", None)) + or _openapi_string(operation.pop("operation_id", None)) + or _wasm_extension_default_operation_id(extension, route_config, method) + ) + operation.pop("tags", None) + _add_wasm_openapi_success_examples(operation) + return WasmOpenAPIMetadata( + summary=summary, + description=description, + operation_id=operation_id, + openapi_extra=operation or None, + ) + + +def _load_wasm_extension_openapi_operation( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, +) -> dict[str, Any]: + try: + openapi_refs = _wasm_extension_openapi_refs(extension, route_config) + except Exception as exc: + logger.warning( + f"Ignoring OpenAPI metadata for WASM extension '{extension.id}' " + f"route '{route_config.path}': {exc}" + ) + return {} + if not openapi_refs: + return {} + + errors: list[Exception] = [] + for openapi_ref in openapi_refs: + try: + document_path, pointer = _wasm_openapi_ref_parts(openapi_ref) + document = _load_wasm_openapi_document(extension, document_path) + operation = _resolve_json_pointer(document, pointer) + if not isinstance(operation, dict): + raise TypeError("OpenAPI route fragment must resolve to an object.") + return _inline_wasm_openapi_refs(deepcopy(operation), document) + except Exception as exc: + errors.append(exc) + + logger.warning( + f"Ignoring OpenAPI metadata for WASM extension '{extension.id}' " + f"route '{route_config.path}': {errors[-1]}" + ) + return {} + + +def _wasm_extension_openapi_refs( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, +) -> list[str]: + if route_config.openapi: + return [ + _wasm_openapi_resolved_ref( + extension.config.openapi, + route_config.openapi, + ) + ] + + document_path = extension.config.openapi + if not document_path: + return [] + + document_path = _wasm_openapi_document_path(document_path) + route_keys = [route_config.export, _wasm_openapi_route_key(route_config.export)] + return [ + f"{document_path}#/routes/{_json_pointer_token(route_key)}" + for route_key in dict.fromkeys(route_keys) + ] + + +def _wasm_openapi_resolved_ref( + base_ref: str | None, + route_ref: str, +) -> str: + if not route_ref.startswith("#"): + return route_ref + if not base_ref: + raise ValueError("OpenAPI metadata reference must include a JSON file path.") + return f"{_wasm_openapi_document_path(base_ref)}{route_ref}" + + +def _wasm_openapi_document_path(openapi_ref: str) -> str: + document_path, _, _ = openapi_ref.partition("#") + if not document_path: + raise ValueError("OpenAPI metadata reference must include a JSON file path.") + return document_path + + +def _wasm_openapi_route_key(export_name: str) -> str: + return re.sub(r"[^A-Za-z0-9]+", "_", export_name).strip("_").lower() + + +def _json_pointer_token(value: str) -> str: + return value.replace("~", "~0").replace("/", "~1") + + +def _wasm_openapi_ref_parts(openapi_ref: str) -> tuple[str, str]: + document_path, _, pointer = openapi_ref.partition("#") + if not document_path: + raise ValueError("OpenAPI metadata reference must include a JSON file path.") + return document_path, pointer + + +def _load_wasm_openapi_document( + extension: WasmExtension, + document_path: str, +) -> dict[str, Any]: + if "://" in document_path or document_path.startswith(("/", "\\")): + raise ValueError("OpenAPI metadata reference must be a local relative path.") + if not document_path.lower().endswith(".json"): + raise ValueError("OpenAPI metadata reference must point to a JSON file.") + + extension_root = extension.root_path.resolve() + path = (extension_root / document_path).resolve() + if not path.is_relative_to(extension_root): + raise ValueError("OpenAPI metadata reference escapes the extension root.") + if not path.is_file(): + raise FileNotFoundError(f"OpenAPI metadata file not found: {document_path}") + + with path.open("r", encoding="utf-8") as openapi_file: + document = json.load(openapi_file) + if not isinstance(document, dict): + raise TypeError("OpenAPI metadata file must contain a JSON object.") + return document + + +def _resolve_json_pointer(document: Any, pointer: str) -> Any: + if not pointer: + return document + if not pointer.startswith("/"): + raise ValueError("OpenAPI metadata reference must use a JSON pointer.") + + value = document + for raw_token in pointer[1:].split("/"): + token = raw_token.replace("~1", "/").replace("~0", "~") + if isinstance(value, dict): + value = value[token] + elif isinstance(value, list): + value = value[int(token)] + else: + raise KeyError(token) + return value + + +def _inline_wasm_openapi_refs( + value: Any, + document: dict[str, Any], + seen_refs: tuple[str, ...] = (), +) -> Any: + if isinstance(value, list): + return [_inline_wasm_openapi_refs(item, document, seen_refs) for item in value] + if not isinstance(value, dict): + return value + + ref = value.get("$ref") + if isinstance(ref, str) and ref.startswith("#/") and ref not in seen_refs: + try: + resolved = _inline_wasm_openapi_refs( + deepcopy(_resolve_json_pointer(document, ref[1:])), + document, + (*seen_refs, ref), + ) + except Exception: + resolved = None + + if resolved is not None: + overrides = { + key: _inline_wasm_openapi_refs(item, document, seen_refs) + for key, item in value.items() + if key != "$ref" + } + if isinstance(resolved, dict): + return {**resolved, **overrides} + if not overrides: + return resolved + + return { + key: _inline_wasm_openapi_refs(item, document, seen_refs) + for key, item in value.items() + } + + +def _add_wasm_openapi_success_examples(operation: dict[str, Any]) -> None: + responses = operation.get("responses") + if not isinstance(responses, dict): + return + + for response in responses.values(): + if not isinstance(response, dict): + continue + content = response.get("content") + if not isinstance(content, dict): + continue + json_content = content.get("application/json") + if not isinstance(json_content, dict): + continue + if "example" in json_content or "examples" in json_content: + continue + + schema = json_content.get("schema") + example = _wasm_openapi_success_example(schema) + if example is not None: + json_content["example"] = example + + +def _wasm_openapi_success_example(schema: Any) -> Any | None: + if not isinstance(schema, dict): + return None + + for keyword in ("oneOf", "anyOf"): + variants = schema.get(keyword) + if not isinstance(variants, list): + continue + for variant in variants: + if _wasm_openapi_schema_has_ok_value(variant, True): + return _wasm_openapi_schema_example(variant) + return None + + +def _wasm_openapi_schema_has_ok_value(schema: Any, ok_value: bool) -> bool: + if not isinstance(schema, dict): + return False + properties = schema.get("properties") + if isinstance(properties, dict): + ok_schema = properties.get("ok") + if isinstance(ok_schema, dict): + enum = ok_schema.get("enum") + return isinstance(enum, list) and ok_value in enum + all_of = schema.get("allOf") + return isinstance(all_of, list) and any( + _wasm_openapi_schema_has_ok_value(item, ok_value) for item in all_of + ) + + +def _wasm_openapi_schema_example(schema: Any) -> Any: + if not isinstance(schema, dict): + return None + + explicit_example = _wasm_openapi_explicit_schema_example(schema) + if explicit_example is not _MISSING_OPENAPI_EXAMPLE: + return explicit_example + + composed_example = _wasm_openapi_composed_schema_example(schema) + if composed_example is not _MISSING_OPENAPI_EXAMPLE: + return composed_example + + return _wasm_openapi_type_schema_example(schema) + + +def _wasm_openapi_explicit_schema_example(schema: dict[str, Any]) -> Any: + if "example" in schema: + return schema["example"] + enum = schema.get("enum") + if isinstance(enum, list) and enum: + return enum[0] + return _MISSING_OPENAPI_EXAMPLE + + +def _wasm_openapi_composed_schema_example(schema: dict[str, Any]) -> Any: + all_of = schema.get("allOf") + if isinstance(all_of, list): + example: dict[str, Any] = {} + for item in all_of: + item_example = _wasm_openapi_schema_example(item) + if isinstance(item_example, dict): + example.update(item_example) + return example + + for keyword in ("oneOf", "anyOf"): + variants = schema.get(keyword) + if isinstance(variants, list) and variants: + return _wasm_openapi_schema_example(variants[0]) + return _MISSING_OPENAPI_EXAMPLE + + +def _wasm_openapi_type_schema_example(schema: dict[str, Any]) -> Any: + schema_type = schema.get("type") + if schema_type == "object" or isinstance(schema.get("properties"), dict): + properties = schema.get("properties") + if not isinstance(properties, dict): + return {} + return { + name: _wasm_openapi_schema_example(property_schema) + for name, property_schema in properties.items() + } + if schema_type == "array": + return [_wasm_openapi_schema_example(schema.get("items"))] + if schema_type == "integer": + return 0 + if schema_type == "number": + return 0 + if schema_type == "boolean": + return True + return "string" + + +def _openapi_string(value: Any) -> str | None: + if not isinstance(value, str): + return None + value = value.strip() + return value or None + + +def _wasm_extension_default_operation_id( + extension: WasmExtension, + route_config: WasmAPIRouteConfig, + method: str, +) -> str: + value = f"{extension.id}_{method}_{route_config.path}" + value = re.sub(r"[^A-Za-z0-9]+", "_", value).strip("_").lower() + return value or f"{extension.id}_{method.lower()}" diff --git a/lnbits/core/wasm_ext/routes/register.py b/lnbits/core/wasm_ext/routes/register.py new file mode 100644 index 000000000..a6c43b6ba --- /dev/null +++ b/lnbits/core/wasm_ext/routes/register.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +from time import perf_counter + +from fastapi import FastAPI +from loguru import logger + +from lnbits.core.db import core_app_extra +from lnbits.settings import settings + +from ..wasm.component import warm_wasm_extension +from ..wasm.loader import WasmExtension, load_wasm_extension +from .api import ( + register_wasm_extension_api_routes, + unregister_wasm_extension_api_routes, +) +from .assets import mount_wasm_extension_static +from .ui import register_wasm_extension_ui_routes + + +def register_wasm_extension(app: FastAPI, ext_id: str) -> WasmExtension: + load_started_at = perf_counter() + loaded = load_wasm_extension(ext_id) + core_app_extra.wasm_extension_registry.require_available(loaded) + + warm_wasm_extension(loaded) + mount_wasm_extension_static(app, loaded) + register_wasm_extension_ui_routes(app, loaded) + register_wasm_extension_api_routes(app, loaded) + + core_app_extra.wasm_extension_registry.register(loaded) + + settings.activate_extension_paths(ext_id, []) + module_size = _format_wasm_extension_size(loaded.module_path.stat().st_size) + load_seconds = perf_counter() - load_started_at + logger.info( + f"Loaded WASM extension '{loaded.id}' " + f"({module_size}) in {load_seconds:.2f} s." + ) + return loaded + + +def unregister_wasm_extension(app: FastAPI, ext_id: str) -> None: + routes_removed = unregister_wasm_extension_api_routes(app, ext_id) + core_app_extra.wasm_extension_registry.unregister(ext_id) + if routes_removed: + logger.info(f"Unloaded WASM extension API routes for '{ext_id}'.") + + +def _format_wasm_extension_size(size_bytes: int) -> str: + if size_bytes >= 1_000_000: + return f"{size_bytes / 1_000_000:,.2f} MB" + return f"{size_bytes / 1_000:,.2f} KB" diff --git a/lnbits/core/wasm_ext/routes/security.py b/lnbits/core/wasm_ext/routes/security.py new file mode 100644 index 000000000..016f37faf --- /dev/null +++ b/lnbits/core/wasm_ext/routes/security.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from typing import Any, NoReturn +from uuid import uuid4 + +from fastapi import HTTPException, Request +from loguru import logger + +from lnbits.helpers import template_renderer +from lnbits.utils.cache import cache + +from ..wasm.loader import WasmExtension + +WASM_FRAME_TOKEN_EXPIRY_SECONDS = 60 + + +def wasm_extension_wrapper_response( + request: Request, + extension: WasmExtension, + auth: str, + user_json: str | None, +) -> Any: + public = auth == "public" + response = template_renderer().TemplateResponse( + request, + "wasm_extension.html", + { + "extension": extension, + "public": public, + "user": user_json, + }, + ) + response.headers["Content-Security-Policy"] = "frame-ancestors 'self'" + response.headers["X-Frame-Options"] = "SAMEORIGIN" + return response + + +def wasm_extension_frame_csp(request: Request, extension: WasmExtension) -> str: + origin = str(request.base_url).rstrip("/") + extension_assets = f"{origin}/ext-assets/{extension.id}/" + return ( + "sandbox allow-scripts allow-pointer-lock; " + "default-src 'none'; " + f"script-src {extension_assets}; " + "script-src-attr 'none'; " + f"style-src {extension_assets}; " + "style-src-attr 'none'; " + f"img-src {extension_assets} data:; " + f"font-src {extension_assets}; " + "connect-src 'none'; " + "form-action 'none'; " + "object-src 'none'; " + "base-uri 'none'; " + "frame-src 'none'; " + "worker-src 'none'; " + f"media-src {extension_assets}; " + "manifest-src 'none'; " + "frame-ancestors 'self'" + ) + + +def wasm_extension_frame_url( + extension: WasmExtension, frame_path: str, user_id: str | None +) -> str: + token = _create_wasm_extension_frame_token(extension, frame_path, user_id) + return f"{frame_path}?frame_token={token}" + + +def consume_wasm_extension_frame_token( + request: Request, + extension: WasmExtension, + frame_path: str, + user_id: str | None, +) -> None: + token = request.query_params.get("frame_token") + if not token: + _raise_wasm_extension_frame_not_found(extension, frame_path, "missing") + + cache_key = _wasm_extension_frame_token_cache_key(token) + token_data = cache.get(cache_key) + if ( + not isinstance(token_data, dict) + or token_data.get("extension_id") != extension.id + or token_data.get("frame_path") != frame_path + ): + _raise_wasm_extension_frame_not_found( + extension, frame_path, "unknown or expired" + ) + + token_user_id = token_data.get("user_id") + if token_user_id and token_user_id != user_id: + _raise_wasm_extension_frame_not_found(extension, frame_path, "wrong user") + + cache.pop(cache_key) + + +def _create_wasm_extension_frame_token( + extension: WasmExtension, + frame_path: str, + user_id: str | None, +) -> str: + token = uuid4().hex + cache.set( + _wasm_extension_frame_token_cache_key(token), + { + "extension_id": extension.id, + "frame_path": frame_path, + "user_id": user_id, + }, + expiry=WASM_FRAME_TOKEN_EXPIRY_SECONDS, + ) + return token + + +def _wasm_extension_frame_token_cache_key(token: str) -> str: + return f"wasm-frame-token:{token}" + + +def _raise_wasm_extension_frame_not_found( + extension: WasmExtension, + frame_path: str, + reason: str, +) -> NoReturn: + logger.warning( + f"WASM frame token {reason} for extension '{extension.id}' at '{frame_path}'." + ) + raise HTTPException(status_code=404, detail="Not found") diff --git a/lnbits/core/wasm_ext/routes/ui.py b/lnbits/core/wasm_ext/routes/ui.py new file mode 100644 index 000000000..d0d4362f1 --- /dev/null +++ b/lnbits/core/wasm_ext/routes/ui.py @@ -0,0 +1,369 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Annotated, Any + +from fastapi import Depends, FastAPI, HTTPException, Request +from fastapi.responses import FileResponse +from pydantic import UUID4 + +from lnbits.core.crud import get_installed_extension, get_user_from_account +from lnbits.core.models import Account +from lnbits.decorators import ( + check_access_token, + check_account_exists, + optional_user_id, +) + +from ..wasm.loader import WasmExtension +from .api import ( + WasmRequestBodyTooLargeError, + _has_route, + _path_template_pattern, + _read_json_object, + _snake_to_camel, + _wasm_extension_api_export, + _wasm_extension_api_method, + _wasm_extension_api_path, + _wasm_extension_route_auth, +) +from .security import ( + consume_wasm_extension_frame_token, + wasm_extension_frame_csp, + wasm_extension_frame_url, + wasm_extension_wrapper_response, +) + + +def register_wasm_extension_ui_routes(app: FastAPI, extension: WasmExtension) -> None: + _add_wasm_extension_frame_config_route(app, extension) + + for route_index, route_config in enumerate(extension.config.ui_routes): + route_path = _wasm_extension_ui_route_path(extension, route_config.path) + entrypoint = _wasm_extension_entrypoint(extension, route_config.entrypoint) + frame_path = f"/ext-frame/{extension.id}/{route_index}" + auth = _wasm_extension_route_auth(extension, route_config.auth) + _add_wasm_extension_frame_route(app, extension, frame_path, entrypoint) + _add_wasm_extension_wrapper_route( + app, + extension, + route_path, + auth, + ) + + +def _add_wasm_extension_frame_config_route( + app: FastAPI, + extension: WasmExtension, +) -> None: + route_path = _wasm_extension_frame_config_path(extension) + if _has_route(app, route_path, "POST"): + return + + async def create_wasm_extension_frame_config( + request: Request, + access_token: Annotated[str | None, Depends(check_access_token)], + usr: UUID4 | None = None, + ) -> dict[str, Any]: + try: + body = await _read_json_object(request) + except WasmRequestBodyTooLargeError as exc: + raise HTTPException(status_code=413, detail=str(exc)) from exc + except (TypeError, ValueError) as exc: + raise HTTPException(status_code=400, detail=str(exc)) from exc + + ui_route = _match_wasm_extension_ui_route(extension, body.get("path")) + auth = ui_route["auth"] + + if auth == "user": + account = await check_account_exists(request, access_token, usr) + user_id: str | None = account.id + else: + user_id = await _optional_wasm_user_id(request, access_token, usr) + + granted_permission_ids = await _wasm_extension_granted_permission_ids(extension) + + return _wasm_extension_frame_config( + extension, + ui_route["frame_path"], + auth, + ui_route["path_params"], + ui_route["route_params"], + _read_wasm_extension_route_query(body.get("query")), + user_id, + granted_permission_ids, + ) + + app.add_api_route( + route_path, + create_wasm_extension_frame_config, + methods=["POST"], + name=f"{extension.id}:frame-config", + include_in_schema=False, + ) + + +def _add_wasm_extension_wrapper_route( + app: FastAPI, + extension: WasmExtension, + route_path: str, + auth: str, +) -> None: + if _has_route(app, route_path, "GET"): + return + + async def serve_private_wasm_extension_page( + request: Request, + account: Account = Depends(check_account_exists), + ) -> Any: + user = await get_user_from_account(account) + return wasm_extension_wrapper_response( + request, + extension, + auth, + user.json() if user else None, + ) + + async def serve_public_wasm_extension_page(request: Request) -> Any: + return wasm_extension_wrapper_response( + request, + extension, + auth, + None, + ) + + app.add_api_route( + route_path, + ( + serve_public_wasm_extension_page + if auth == "public" + else serve_private_wasm_extension_page + ), + methods=["GET"], + name=f"{extension.id}:{route_path}", + include_in_schema=False, + ) + + +def _add_wasm_extension_frame_route( + app: FastAPI, + extension: WasmExtension, + frame_path: str, + entrypoint: Path, +) -> None: + if _has_route(app, frame_path, "GET"): + return + + async def serve_wasm_extension_frame( + request: Request, + user_id: str | None = Depends(_optional_wasm_user_id), + ) -> FileResponse: + consume_wasm_extension_frame_token(request, extension, frame_path, user_id) + response = FileResponse(entrypoint) + response.headers["Content-Security-Policy"] = wasm_extension_frame_csp( + request, extension + ) + response.headers["Cache-Control"] = "no-store" + response.headers["Cross-Origin-Opener-Policy"] = "same-origin" + response.headers["Cross-Origin-Resource-Policy"] = "same-origin" + # Extension access goes through the parent bridge. + response.headers["Permissions-Policy"] = ( + "camera=(), microphone=(), geolocation=(), payment=(), " + "clipboard-read=(), usb=()" + ) + response.headers["Referrer-Policy"] = "no-referrer" + response.headers["X-Content-Type-Options"] = "nosniff" + return response + + app.add_api_route( + frame_path, + serve_wasm_extension_frame, + methods=["GET"], + name=f"{extension.id}:frame:{frame_path}", + include_in_schema=False, + ) + + +def _wasm_extension_bridge_api_routes( + extension: WasmExtension, + public: bool, +) -> list[dict[str, str]]: + routes: list[dict[str, str]] = [] + for route_config in extension.config.api_routes: + auth = _wasm_extension_route_auth(extension, route_config.auth) + if public and auth != "public": + continue + method = _wasm_extension_api_method(extension, route_config.method) + path = _wasm_extension_api_path(extension, route_config.path) + _wasm_extension_api_export(extension, route_config.export) + routes.append( + { + "method": method, + "path": path, + "pattern": _path_template_pattern(path), + } + ) + return routes + + +def _wasm_extension_frame_config_path(extension: WasmExtension) -> str: + return f"/api/v1/ext/{extension.id}/_ui/frame" + + +def _match_wasm_extension_ui_route( + extension: WasmExtension, + path: Any, +) -> dict[str, Any]: + if not isinstance(path, str) or not path.startswith("/"): + raise HTTPException(status_code=404, detail="Not found") + + for route_index, route_config in enumerate(extension.config.ui_routes): + route_path = _wasm_extension_ui_route_path(extension, route_config.path) + route_params = _path_template_params(route_path, path) + if route_params is None: + continue + + return { + "frame_path": f"/ext-frame/{extension.id}/{route_index}", + "auth": _wasm_extension_route_auth(extension, route_config.auth), + "path_params": route_config.path_params, + "route_params": route_params, + } + + raise HTTPException(status_code=404, detail="Not found") + + +def _path_template_params(template: str, path: str) -> dict[str, str] | None: + template_parts = _path_parts(template) + path_parts = _path_parts(path) + if len(template_parts) != len(path_parts): + return None + + params: dict[str, str] = {} + for template_part, path_part in zip(template_parts, path_parts, strict=False): + if template_part.startswith("{") and template_part.endswith("}"): + param_name = template_part[1:-1] + if not param_name: + return None + params[param_name] = path_part + continue + + if template_part != path_part: + return None + + return params + + +def _path_parts(path: str) -> list[str]: + return [part for part in path.strip("/").split("/") if part] + + +def _wasm_extension_frame_config( + extension: WasmExtension, + frame_path: str, + auth: str, + path_params: dict[str, str], + route_params: dict[str, str], + query: dict[str, Any], + user_id: str | None, + permissions: set[str], +) -> dict[str, Any]: + public = auth == "public" + return { + "extension": { + "id": extension.id, + "name": extension.name, + }, + "frameUrl": wasm_extension_frame_url(extension, frame_path, user_id), + "bridge": { + "extensionId": extension.id, + "public": public, + "routeParams": _map_wasm_extension_route_params(route_params, path_params), + "query": query, + "permissions": sorted(permissions), + "apiRoutes": _wasm_extension_bridge_api_routes(extension, public), + }, + } + + +async def _wasm_extension_granted_permission_ids( + extension: WasmExtension, +) -> set[str]: + installed_extension = await get_installed_extension(extension.id) + if not installed_extension: + return set() + return {permission.id for permission in installed_extension.permissions} + + +def _map_wasm_extension_route_params( + route_params: dict[str, str], + path_params: dict[str, str], +) -> dict[str, str]: + payload: dict[str, str] = {} + for key, value in route_params.items(): + target = path_params.get(key) or _snake_to_camel(key) + payload[target] = value + return payload + + +def _read_wasm_extension_route_query(query: Any) -> dict[str, Any]: + if not isinstance(query, dict): + return {} + + payload: dict[str, Any] = {} + for key, value in query.items(): + if value is None: + continue + payload[_snake_to_camel(str(key))] = value + return payload + + +async def _optional_wasm_user_id( + request: Request, + access_token: Annotated[str | None, Depends(check_access_token)], + usr: UUID4 | None = None, +) -> str | None: + try: + return await optional_user_id(request, access_token, usr) + except HTTPException: + return None + + +def _wasm_extension_ui_route_path(extension: WasmExtension, path: Any) -> str: + if not isinstance(path, str) or not path.startswith("/"): + raise ValueError(f"Invalid route path for WASM extension '{extension.id}'.") + if path == "/": + return "/ext" + return f"/ext{path}" + + +def _wasm_extension_entrypoint(extension: WasmExtension, entrypoint: Any) -> Path: + if not isinstance(entrypoint, str) or not entrypoint: + raise ValueError( + f"Invalid route entrypoint for WASM extension '{extension.id}'." + ) + if entrypoint.startswith("/"): + raise ValueError( + f"Route entrypoint for WASM extension '{extension.id}' must be a " + "relative extension path." + ) + + path = (extension.root_path / entrypoint).resolve() + root_path = extension.root_path.resolve() + if path != root_path and root_path not in path.parents: + raise ValueError(f"Route entrypoint escapes extension root: {entrypoint}") + + static_path = (extension.root_path / "static").resolve() + if path == static_path or static_path in path.parents: + raise ValueError( + f"Route entrypoint for WASM extension '{extension.id}' must not be " + "inside the static asset directory." + ) + if path.suffix.lower() != ".html": + raise ValueError( + f"Route entrypoint for WASM extension '{extension.id}' must be " + "an HTML file." + ) + if not path.is_file(): + raise FileNotFoundError(f"Route entrypoint not found: {path}") + return path diff --git a/lnbits/core/wasm_ext/storage/__init__.py b/lnbits/core/wasm_ext/storage/__init__.py new file mode 100644 index 000000000..031dfd3d3 --- /dev/null +++ b/lnbits/core/wasm_ext/storage/__init__.py @@ -0,0 +1,25 @@ +from .crud import ( + migrate_wasm_extension_database, + storage_append_public_row, + storage_count_rows, + storage_delete_row, + storage_get_paginated_rows, + storage_get_public_paginated_rows, + storage_get_public_row, + storage_get_row, + storage_get_row_owner_id, + storage_set_row, +) + +__all__ = [ + "migrate_wasm_extension_database", + "storage_append_public_row", + "storage_count_rows", + "storage_delete_row", + "storage_get_paginated_rows", + "storage_get_public_paginated_rows", + "storage_get_public_row", + "storage_get_row", + "storage_get_row_owner_id", + "storage_set_row", +] diff --git a/lnbits/core/wasm_ext/storage/crud.py b/lnbits/core/wasm_ext/storage/crud.py new file mode 100644 index 000000000..4c17f5c35 --- /dev/null +++ b/lnbits/core/wasm_ext/storage/crud.py @@ -0,0 +1,720 @@ +from __future__ import annotations + +import json +import re +from datetime import datetime, timezone +from pathlib import Path +from typing import Any +from uuid import uuid4 + +from loguru import logger + +from lnbits.core.crud import update_migration_version +from lnbits.core.db import db as core_db +from lnbits.core.models import DbVersion +from lnbits.core.models.extensions import InstallableExtension +from lnbits.db import POSTGRES, SQLITE, Compat, Connection, Database +from lnbits.settings import settings + +_MIGRATION_FILE_RE = re.compile(r"^(\d+)_.*\.json$") +_SQL_IDENTIFIER_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") +OWNER_ID_FIELD = "__lnbits_owner_id__" + + +async def storage_get_row( + ext_id: str, + table: str, + row_id: str, + owner_id: str, +) -> dict[str, Any] | None: + table_schema = _load_table_schema(ext_id, table) + query = f""" + SELECT * FROM {_table_ref_for_schema(ext_id, table)} + WHERE id = :id AND {OWNER_ID_FIELD} = :owner_id + """ # noqa: S608 + async with Database(f"ext_{ext_id}").connect() as conn: + row = await conn.fetchone(query, {"id": row_id, "owner_id": owner_id}) + return _row_from_db(table_schema, row) if row else None + + +async def storage_get_public_row( + ext_id: str, + table: str, + row_id: str, +) -> dict[str, Any] | None: + table_schema = _load_table_schema(ext_id, table) + query = f""" + SELECT * FROM {_table_ref_for_schema(ext_id, table)} + WHERE id = :id + """ # noqa: S608 + async with Database(f"ext_{ext_id}").connect() as conn: + row = await conn.fetchone(query, {"id": row_id}) + return _row_from_db(table_schema, row) if row else None + + +async def storage_get_row_owner_id( + ext_id: str, + table: str, + row_id: str, +) -> str | None: + _load_table_schema(ext_id, table) + query = f""" + SELECT {OWNER_ID_FIELD} FROM {_table_ref_for_schema(ext_id, table)} + WHERE id = :id + """ # noqa: S608 + async with Database(f"ext_{ext_id}").connect() as conn: + row = await conn.fetchone(query, {"id": row_id}) + + owner_id = row[OWNER_ID_FIELD] if row else None + return owner_id if isinstance(owner_id, str) and owner_id else None + + +async def storage_set_row( + ext_id: str, + table: str, + data: dict[str, Any], + owner_id: str, +) -> None: + table_schema = _load_table_schema(ext_id, table) + clean_data = _data_to_db(table_schema, data, require_id=True) + columns = list(clean_data.keys()) + database = Database(f"ext_{ext_id}") + fields = _fields_by_name(table_schema) + placeholders = [ + _value_placeholder(database, fields[column], column) for column in columns + ] + + clean_data[OWNER_ID_FIELD] = owner_id + columns.append(OWNER_ID_FIELD) + placeholders.append(f":{OWNER_ID_FIELD}") + updates = [ + f"{column} = excluded.{column}" + for column in columns + if column not in ("id", OWNER_ID_FIELD) + ] + conflict_sql = ( + "DO UPDATE SET " + + ", ".join(updates) + + f" WHERE storage_row.{OWNER_ID_FIELD} = :{OWNER_ID_FIELD}" + if updates + else "DO NOTHING" + ) + query = f""" + INSERT INTO {_table_ref_for_schema(ext_id, table)} AS storage_row + ({", ".join(columns)}) + VALUES + ({", ".join(placeholders)}) + ON CONFLICT (id) {conflict_sql} + """ # noqa: S608 + + async with database.connect() as conn: + await conn.execute(query, clean_data) + + +async def storage_append_public_row( + ext_id: str, + table: str, + data: dict[str, Any], + owner_id: str, +) -> str: + row_id = uuid4().hex + await storage_set_row(ext_id, table, {**data, "id": row_id}, owner_id) + return row_id + + +async def storage_count_rows( + ext_id: str, + table: str, + filters: dict[str, Any], + *, + owner_id: str, +) -> int: + table_schema = _load_table_schema(ext_id, table) + database = Database(f"ext_{ext_id}") + where_sql, values = _where_sql(database, table_schema, filters, None, []) + where_sql = _append_owner_where_sql(where_sql) + values[OWNER_ID_FIELD] = owner_id + + query = f""" + SELECT COUNT(*) AS count FROM {_table_ref_for_schema(ext_id, table)} + {where_sql} + """ # noqa: S608 + async with database.connect() as conn: + row = await conn.fetchone(query, values) + return int(row["count"]) if row else 0 + + +async def storage_get_paginated_rows( + ext_id: str, + table: str, + filters: dict[str, Any], + *, + owner_id: str, + search: str | None, + search_fields: list[str], + sort_by: str | None, + descending: bool, + limit: int, + offset: int, +) -> dict[str, Any]: + table_schema = _load_table_schema(ext_id, table) + database = Database(f"ext_{ext_id}") + where_sql, values = _where_sql( + database, table_schema, filters, search, search_fields + ) + where_sql = _append_owner_where_sql(where_sql) + values[OWNER_ID_FIELD] = owner_id + order_sql = _order_sql(table_schema, sort_by, descending) + count_values = dict(values) + values.update({"limit": min(limit, 1000), "offset": offset}) + + table_ref = _table_ref_for_schema(ext_id, table) + rows_query = f""" + SELECT * FROM {table_ref} + {where_sql} + {order_sql} + LIMIT :limit + OFFSET :offset + """ # noqa: S608 + count_query = f""" + SELECT COUNT(*) AS count FROM {table_ref} + {where_sql} + """ # noqa: S608 + + async with database.connect() as conn: + rows = await conn.fetchall(rows_query, values) + count_row = await conn.fetchone(count_query, count_values) + + return { + "data": [_row_from_db(table_schema, row) for row in rows], + "total": int(count_row["count"]) if count_row else 0, + } + + +async def storage_get_public_paginated_rows( + ext_id: str, + table: str, + filters: dict[str, Any], + *, + search: str | None, + search_fields: list[str], + sort_by: str | None, + descending: bool, + limit: int, + offset: int, +) -> dict[str, Any]: + table_schema = _load_table_schema(ext_id, table) + database = Database(f"ext_{ext_id}") + where_sql, values = _where_sql( + database, table_schema, filters, search, search_fields + ) + order_sql = _order_sql(table_schema, sort_by, descending) + count_values = dict(values) + values.update({"limit": min(limit, 1000), "offset": offset}) + + table_ref = _table_ref_for_schema(ext_id, table) + rows_query = f""" + SELECT * FROM {table_ref} + {where_sql} + {order_sql} + LIMIT :limit + OFFSET :offset + """ # noqa: S608 + count_query = f""" + SELECT COUNT(*) AS count FROM {table_ref} + {where_sql} + """ # noqa: S608 + + async with database.connect() as conn: + rows = await conn.fetchall(rows_query, values) + count_row = await conn.fetchone(count_query, count_values) + + return { + "data": [_row_from_db(table_schema, row) for row in rows], + "total": int(count_row["count"]) if count_row else 0, + } + + +async def storage_delete_row( + ext_id: str, + table: str, + row_id: str, + owner_id: str, +) -> None: + _load_table_schema(ext_id, table) + query = f""" + DELETE FROM {_table_ref_for_schema(ext_id, table)} + WHERE id = :id AND {OWNER_ID_FIELD} = :owner_id + """ # noqa: S608 + async with Database(f"ext_{ext_id}").connect() as conn: + await conn.execute(query, {"id": row_id, "owner_id": owner_id}) + + +async def migrate_wasm_extension_database( + ext: InstallableExtension, + current_version: DbVersion | None = None, +) -> None: + migrations_dir = ext.wasm_ext_dir / "storage" / "migrations" + migration_files = _migration_files(migrations_dir) + if not migration_files: + logger.debug(f"No storage migrations for WASM extension '{ext.id}'.") + return + + ext_db = Database(f"ext_{ext.id}") + async with ext_db.connect() as conn: + for version, path in migration_files: + if current_version and version <= current_version.version: + continue + logger.debug(f"running WASM storage migration {ext.id}.{version}") + print(f"running migration {ext.id}.{version}") + await _run_storage_migration(conn, path) + await _update_wasm_migration_version(conn, ext.id, version) + + +def _migration_files(migrations_dir: Path) -> list[tuple[int, Path]]: + if not migrations_dir.is_dir(): + return [] + + files: list[tuple[int, Path]] = [] + for path in migrations_dir.glob("*.json"): + match = _MIGRATION_FILE_RE.match(path.name) + if not match: + raise ValueError(f"Invalid WASM storage migration filename: {path.name}") + files.append((int(match.group(1)), path)) + return sorted(files) + + +async def _run_storage_migration(db: Connection, path: Path) -> None: + migration = _load_json(path) + operations = migration.get("operations") + if not isinstance(operations, list): + raise ValueError(f"WASM storage migration '{path}' has no operations list.") + + for operation in operations: + if not isinstance(operation, dict): + raise ValueError(f"WASM storage migration '{path}' has invalid operation.") + sql = _operation_sql(db, operation) + await db.execute(sql) + + +def _operation_sql(db: Connection, operation: dict[str, Any]) -> str: + op = operation.get("op") + if op == "create_table": + return _create_table_sql(db, operation) + if op == "add_field": + return _add_field_sql(db, operation) + if op == "create_index": + return _create_index_sql(db, operation) + raise ValueError(f"Unsupported WASM storage migration operation: {op}") + + +def _create_table_sql(db: Connection, operation: dict[str, Any]) -> str: + table = _require_identifier(operation, "table") + fields = _require_fields(operation) + if not any(field.get("name") == "id" for field in fields): + raise ValueError(f"WASM storage table '{table}' must define an id field.") + if any(field.get("name") == OWNER_ID_FIELD for field in fields): + raise ValueError( + f"WASM storage table '{table}' defines reserved field '{OWNER_ID_FIELD}'." + ) + + columns = [ + _column_sql(db, field, primary_key=field.get("name") == "id") + for field in fields + ] + columns.append(f"{OWNER_ID_FIELD} TEXT NOT NULL") + return f""" + CREATE TABLE IF NOT EXISTS {_table_ref(db, table)} ( + {", ".join(columns)} + ); + """ + + +def _add_field_sql(db: Connection, operation: dict[str, Any]) -> str: + table = _require_identifier(operation, "table") + field = _field_from_add_field_operation(operation) + if field["name"] == OWNER_ID_FIELD: + raise ValueError( + f"WASM storage table '{table}' cannot add reserved field " + f"'{OWNER_ID_FIELD}'." + ) + return f""" + ALTER TABLE {_table_ref(db, table)} + ADD COLUMN {_column_sql(db, field)}; + """ + + +def _create_index_sql(db: Connection, operation: dict[str, Any]) -> str: + table = _require_identifier(operation, "table") + name = _require_identifier(operation, "name") + field = _require_identifier(operation, "field") + if field == OWNER_ID_FIELD: + raise ValueError( + f"WASM storage table '{table}' cannot index reserved field " + f"'{OWNER_ID_FIELD}'." + ) + + if db.type == SQLITE and db.schema: + return f""" + CREATE INDEX IF NOT EXISTS {_schema_ref(db, name)} + ON {table} ({field}); + """ + + return f""" + CREATE INDEX IF NOT EXISTS {name} + ON {_table_ref(db, table)} ({field}); + """ + + +def _column_sql( + db: Connection, + field: dict[str, Any], + *, + primary_key: bool = False, +) -> str: + name = _require_identifier(field, "name") + column_type = _field_type_sql(db, field) + parts = [name, column_type] + + if primary_key: + parts.append("PRIMARY KEY") + elif not field.get("nullable", False): + parts.append("NOT NULL") + + if "default" in field: + parts.append(f"DEFAULT {_default_sql(field['default'])}") + + return " ".join(parts) + + +def _field_type_sql(db: Connection, field: dict[str, Any]) -> str: + if field.get("list") is True: + return "TEXT" + + field_type = field.get("type") + if field_type == "string": + return "TEXT" + if field_type == "integer": + return db.big_int + if field_type == "number": + return "DOUBLE PRECISION" if db.type == POSTGRES else "REAL" + if field_type == "boolean": + return "BOOLEAN" + if field_type == "datetime": + return "TIMESTAMP" + raise ValueError(f"Unsupported WASM storage field type: {field_type}") + + +def _load_table_schema(ext_id: str, table: str) -> dict[str, Any]: + schema = _load_storage_schema(ext_id) + tables = schema.get("tables") + if not isinstance(tables, dict): + raise ValueError(f"WASM extension '{ext_id}' has no storage tables schema.") + + _require_identifier({"table": table}, "table") + table_schema = tables.get(table) + if not isinstance(table_schema, dict): + raise ValueError(f"WASM extension '{ext_id}' has no storage table '{table}'.") + + fields = table_schema.get("fields") + if not isinstance(fields, list) or not fields: + raise ValueError(f"WASM storage table '{table}' has no fields schema.") + + for field in fields: + if not isinstance(field, dict): + raise ValueError(f"WASM storage table '{table}' has invalid field schema.") + _require_identifier(field, "name") + if field["name"] == OWNER_ID_FIELD: + raise ValueError( + f"WASM storage table '{table}' defines reserved field " + f"'{OWNER_ID_FIELD}'." + ) + return table_schema + + +def _load_storage_schema(ext_id: str) -> dict[str, Any]: + schema_path = settings.wasm_extensions_dir / ext_id / "storage" / "schema.json" + if not schema_path.is_file(): + raise ValueError(f"WASM extension '{ext_id}' has no storage schema.") + return _load_json(schema_path) + + +def _data_to_db( + table_schema: dict[str, Any], + data: dict[str, Any], + *, + require_id: bool, +) -> dict[str, Any]: + if not isinstance(data, dict): + raise ValueError("WASM storage row data must be an object.") + if require_id and not data.get("id"): + raise ValueError("WASM storage row data must include an id.") + _reject_reserved_owner_field(data, "row") + + fields = _fields_by_name(table_schema) + unknown_fields = sorted(set(data) - set(fields)) + if unknown_fields: + raise ValueError( + "WASM storage row has unknown fields: " + ", ".join(unknown_fields) + ) + + return { + field_name: _value_to_db(fields[field_name], value) + for field_name, value in data.items() + } + + +def _filters_to_db( + table_schema: dict[str, Any], + filters: dict[str, Any], +) -> dict[str, Any]: + if not isinstance(filters, dict): + raise ValueError("WASM storage filters must be an object.") + _reject_reserved_owner_field(filters, "filters") + + fields = _fields_by_name(table_schema) + unknown_fields = sorted(set(filters) - set(fields)) + if unknown_fields: + raise ValueError( + "WASM storage filters have unknown fields: " + ", ".join(unknown_fields) + ) + + return { + field_name: _value_to_db(fields[field_name], value) + for field_name, value in filters.items() + } + + +def _value_placeholder(db: Compat, field: dict[str, Any], key: str) -> str: + if field.get("type") == "datetime" and not field.get("list"): + return db.timestamp_placeholder(key) + return f":{key}" + + +def _where_sql( + db: Compat, + table_schema: dict[str, Any], + filters: dict[str, Any], + search: str | None, + search_fields: list[str], +) -> tuple[str, dict[str, Any]]: + clean_filters = _filters_to_db(table_schema, filters) + fields = _fields_by_name(table_schema) + clauses = [ + f"{field} = {_value_placeholder(db, fields[field], f'filter_{field}')}" + for field in clean_filters + ] + values = {f"filter_{field}": value for field, value in clean_filters.items()} + + clean_search = search.strip().lower() if search else "" + if clean_search: + fields = _fields_by_name(table_schema) + invalid_fields = sorted(set(search_fields) - set(fields)) + if invalid_fields: + raise ValueError( + "WASM storage search has unknown fields: " + ", ".join(invalid_fields) + ) + if search_fields: + search_clause = " OR ".join( + f"LOWER(CAST({field} AS TEXT)) LIKE :search" for field in search_fields + ) + clauses.append(f"({search_clause})") + values["search"] = f"%{clean_search}%" + + return ("WHERE " + " AND ".join(clauses), values) if clauses else ("", values) + + +def _append_owner_where_sql(where_sql: str) -> str: + owner_clause = f"{OWNER_ID_FIELD} = :{OWNER_ID_FIELD}" + if where_sql: + return f"{where_sql} AND {owner_clause}" + return f"WHERE {owner_clause}" + + +def _order_sql( + table_schema: dict[str, Any], + sort_by: str | None, + descending: bool, +) -> str: + if not sort_by: + return "" + fields = _fields_by_name(table_schema) + if sort_by not in fields: + raise ValueError(f"WASM storage sort field is unknown: {sort_by}") + direction = "DESC" if descending else "ASC" + return f"ORDER BY {sort_by} {direction}" + + +def _row_from_db( + table_schema: dict[str, Any], + row: dict[str, Any], +) -> dict[str, Any]: + fields = _fields_by_name(table_schema) + return { + field_name: _value_from_db(fields[field_name], value) + for field_name, value in dict(row).items() + if field_name in fields + } + + +def _fields_by_name(table_schema: dict[str, Any]) -> dict[str, dict[str, Any]]: + fields = table_schema.get("fields") + if not isinstance(fields, list): + raise ValueError("WASM storage table schema fields must be a list.") + return {field["name"]: field for field in fields} + + +def _reject_reserved_owner_field(data: dict[str, Any], value_name: str) -> None: + if OWNER_ID_FIELD in data: + raise ValueError(f"WASM storage {value_name} includes a reserved owner field.") + + +def _value_to_db(field: dict[str, Any], value: Any) -> Any: # noqa: C901 + if value is None: + if field.get("nullable", False): + return None + raise ValueError(f"WASM storage field '{field['name']}' cannot be null.") + + if field.get("list") is True: + if not isinstance(value, list): + raise ValueError(f"WASM storage field '{field['name']}' must be a list.") + return json.dumps(value) + + field_type = field.get("type") + if field_type == "string": + if not isinstance(value, str): + raise ValueError(f"WASM storage field '{field['name']}' must be a string.") + return value + if field_type == "integer": + if isinstance(value, bool) or not isinstance(value, int): + raise ValueError( + f"WASM storage field '{field['name']}' must be an integer." + ) + return value + if field_type == "number": + if isinstance(value, bool) or not isinstance(value, int | float): + raise ValueError(f"WASM storage field '{field['name']}' must be a number.") + return value + if field_type == "boolean": + if not isinstance(value, bool): + raise ValueError(f"WASM storage field '{field['name']}' must be a boolean.") + return value + if field_type == "datetime": + if isinstance(value, int | float): + return datetime.fromtimestamp(value, tz=timezone.utc) + if isinstance(value, datetime): + return value + raise ValueError( + f"WASM storage field '{field['name']}' must be a Unix timestamp." + ) + raise ValueError(f"Unsupported WASM storage field type: {field_type}") + + +def _value_from_db(field: dict[str, Any], value: Any) -> Any: + if value is None: + return None + + if field.get("list") is True: + if isinstance(value, str): + return json.loads(value) + return value + + field_type = field.get("type") + if field_type == "boolean": + return bool(value) + if field_type == "datetime": + if isinstance(value, datetime): + return int(value.replace(tzinfo=timezone.utc).timestamp()) + if isinstance(value, int | float): + return int(value) + if isinstance(value, str): + try: + return int(datetime.fromisoformat(value).timestamp()) + except ValueError: + return value + return value + + +def _default_sql(value: Any) -> str: + if value is None: + return "NULL" + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, int | float): + return str(value) + if isinstance(value, str): + return _quote_sql_string(value) + if isinstance(value, list | dict): + return _quote_sql_string(json.dumps(value)) + raise ValueError(f"Unsupported WASM storage default value: {value}") + + +def _field_from_add_field_operation(operation: dict[str, Any]) -> dict[str, Any]: + field = { + "name": operation.get("field"), + "type": operation.get("type"), + } + for key in ("default", "list", "nullable"): + if key in operation: + field[key] = operation[key] + return field + + +def _require_fields(operation: dict[str, Any]) -> list[dict[str, Any]]: + fields = operation.get("fields") + if not isinstance(fields, list) or not fields: + raise ValueError("WASM storage create_table operation requires fields.") + if not all(isinstance(field, dict) for field in fields): + raise ValueError("WASM storage fields must be objects.") + return fields + + +def _require_identifier(data: dict[str, Any], key: str) -> str: + value = data.get(key) + if not isinstance(value, str) or not _SQL_IDENTIFIER_RE.match(value): + raise ValueError(f"Invalid WASM storage SQL identifier for '{key}': {value}") + return value + + +def _table_ref(db: Connection, table: str) -> str: + if db.schema: + return f"{_schema_ref(db, table)}" + return table + + +def _table_ref_for_schema(ext_id: str, table: str) -> str: + _require_identifier({"schema": ext_id}, "schema") + _require_identifier({"table": table}, "table") + return f"{ext_id}.{table}" + + +def _schema_ref(db: Connection, name: str) -> str: + if not db.schema: + return name + if not _SQL_IDENTIFIER_RE.match(db.schema): + raise ValueError(f"Invalid WASM extension storage schema: {db.schema}") + return f"{db.schema}.{name}" + + +def _quote_sql_string(value: str) -> str: + return "'" + value.replace("'", "''") + "'" + + +def _load_json(path: Path) -> dict[str, Any]: + with open(path, encoding="utf-8") as json_file: + data = json.load(json_file) + if not isinstance(data, dict): + raise ValueError(f"WASM storage migration '{path}' must be a JSON object.") + return data + + +async def _update_wasm_migration_version( + db: Connection, + ext_id: str, + version: int, +) -> None: + if db.schema is None: + await update_migration_version(db, ext_id, version) + else: + async with core_db.connect() as conn: + await update_migration_version(conn, ext_id, version) diff --git a/lnbits/core/wasm_ext/wasm/__init__.py b/lnbits/core/wasm_ext/wasm/__init__.py new file mode 100644 index 000000000..9d61f30d0 --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/__init__.py @@ -0,0 +1,13 @@ +from .component import warm_wasm_extension +from .events import dispatch_wasm_invoice_paid +from .invoke import invoke_wasm_extension_export +from .loader import WasmExtension, is_wasm_extension_dir, is_wasm_extension_id + +__all__ = [ + "WasmExtension", + "dispatch_wasm_invoice_paid", + "invoke_wasm_extension_export", + "is_wasm_extension_dir", + "is_wasm_extension_id", + "warm_wasm_extension", +] diff --git a/lnbits/core/wasm_ext/wasm/component.py b/lnbits/core/wasm_ext/wasm/component.py new file mode 100644 index 000000000..e95ec9fe2 --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/component.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from functools import lru_cache +from typing import Any + +from wasmtime import Config, Engine + +from lnbits.settings import settings + +from .loader import WasmExtension + + +def warm_wasm_extension(extension: WasmExtension) -> None: + _wasm_component(extension) + + +@lru_cache(maxsize=8) +def _wasm_engine(max_wasm_stack_bytes: int | None = None) -> Any: + config = Config() + config.wasm_component_model = True + config.epoch_interruption = True + config.consume_fuel = True + stack_limit = ( + settings.wasm_runtime_max_wasm_stack_bytes + if max_wasm_stack_bytes is None + else max_wasm_stack_bytes + ) + if stack_limit > 0: + config.max_wasm_stack = stack_limit + return Engine(config) + + +def _wasm_component( + extension: WasmExtension, + limits: dict[str, int] | None = None, +) -> Any: + stat = extension.module_path.stat() + max_wasm_stack_bytes = ( + limits["wasm_runtime_max_wasm_stack_bytes"] + if limits + else settings.wasm_runtime_max_wasm_stack_bytes + ) + return _cached_wasm_component( + str(extension.module_path), + stat.st_mtime_ns, + stat.st_size, + max_wasm_stack_bytes, + ) + + +@lru_cache(maxsize=32) +def _cached_wasm_component( + module_path: str, + mtime_ns: int, + size: int, + max_wasm_stack_bytes: int, +) -> Any: + from wasmtime import component + + return component.Component.from_file( + _wasm_engine(max_wasm_stack_bytes), module_path + ) diff --git a/lnbits/core/wasm_ext/wasm/config.py b/lnbits/core/wasm_ext/wasm/config.py new file mode 100644 index 000000000..947b3a513 --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/config.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +import re +from typing import Any, Literal + +from pydantic import ( + BaseModel, + Field, + StrictBool, + StrictStr, + ValidationError, +) + +from lnbits.core.models.extensions import ExtensionPermission + +_EXTENSION_ID_RE = re.compile(r"^[A-Za-z0-9_-]+$") + + +class _StrictWasmModel(BaseModel): + class Config: + extra = "ignore" + allow_population_by_field_name = True + + +class WasmExtensionExport(_StrictWasmModel): + name: StrictStr + visibility: Literal["authenticated", "event", "public"] + + +class WasmRuntimeConfig(_StrictWasmModel): + module: StrictStr + wit: StrictStr | None = None + world: StrictStr = "" + exports: list[WasmExtensionExport] = Field(default_factory=list) + + +class WasmUIConfig(_StrictWasmModel): + entrypoint: StrictStr | None = None + sandbox: StrictBool | None = None + + +class WasmSDKConfig(_StrictWasmModel): + frontend_js: StrictStr | None = None + + +class WasmUIRouteConfig(_StrictWasmModel): + path: StrictStr + entrypoint: StrictStr + auth: Literal["public", "user"] + path_params: dict[str, StrictStr] = Field(default_factory=dict) + + +class WasmRouteOwnerContext(_StrictWasmModel): + table: StrictStr + id_param: StrictStr = Field(..., alias="idParam") + + +class WasmAPIRouteConfig(_StrictWasmModel): + method: Literal["DELETE", "GET", "PATCH", "POST", "PUT"] + path: StrictStr + export: StrictStr + auth: Literal["public", "user"] + path_params: dict[str, StrictStr] = Field(default_factory=dict) + owner_context: WasmRouteOwnerContext | None = Field(None, alias="ownerContext") + openapi: StrictStr | None = None + + +class WasmEventsConfig(_StrictWasmModel): + on_invoice_paid: StrictStr | None = Field(None, alias="onInvoicePaid") + + +class WasmExtensionConfig(_StrictWasmModel): + id: StrictStr + name: StrictStr + short_description: StrictStr + tile: StrictStr | None = None + version: StrictStr + min_lnbits_version: StrictStr | None = None + max_lnbits_version: StrictStr | None = None + extension_type: Literal["wasm"] + wasm: WasmRuntimeConfig + events: WasmEventsConfig = Field( + default_factory=lambda: WasmEventsConfig.parse_obj({}) + ) + ui: WasmUIConfig | None = None + sdk: WasmSDKConfig | None = None + openapi: StrictStr | None = None + ui_routes: list[WasmUIRouteConfig] = Field(default_factory=list) + api_routes: list[WasmAPIRouteConfig] = Field(default_factory=list) + permissions: list[ExtensionPermission] = Field(default_factory=list) + + +def parse_wasm_extension_config( + ext_id: str, + config: dict[str, Any], +) -> WasmExtensionConfig: + validate_wasm_extension_config_id(ext_id, config) + try: + return WasmExtensionConfig.parse_obj(config) + except ValidationError as exc: + raise ValueError( + f"Invalid WASM extension config for '{ext_id}': {exc}" + ) from exc + + +def validate_wasm_extension_config_id( + ext_id: str, + config: dict[str, Any] | WasmExtensionConfig, +) -> str: + if not _EXTENSION_ID_RE.fullmatch(ext_id): + raise ValueError(f"Invalid WASM extension id '{ext_id}'.") + + config_id = ( + config.id if isinstance(config, WasmExtensionConfig) else config.get("id") + ) + if not isinstance(config_id, str) or not config_id: + raise ValueError(f"WASM extension '{ext_id}' config must define id.") + if config_id != ext_id: + raise ValueError( + f"WASM extension id mismatch: installed as '{ext_id}' " + f"but config declares '{config_id}'." + ) + return config_id diff --git a/lnbits/core/wasm_ext/wasm/events.py b/lnbits/core/wasm_ext/wasm/events.py new file mode 100644 index 000000000..6a86b1dee --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/events.py @@ -0,0 +1,256 @@ +import json +from collections.abc import Iterable +from typing import Any + +from loguru import logger + +from lnbits.core.crud.extensions import get_installed_extension, get_user_extensions +from lnbits.core.crud.wallets import get_wallet +from lnbits.core.db import core_app_extra +from lnbits.core.models.extensions import ExtensionWalletPaymentsWatchGrant +from lnbits.core.wasm_ext.storage.crud import storage_get_row_owner_id +from lnbits.core.wasm_ext.wasm.invoke import invoke_wasm_extension_export +from lnbits.helpers import sha256s + +WALLET_PAYMENTS_WATCH_PERMISSION = "wallet.payments.watch" + + +async def dispatch_wasm_invoice_paid(payment: Any) -> None: + targets: dict[str, tuple[Any, str | None]] = {} + extension_id = _payment_extension_id(payment) + if extension_id: + extension = core_app_extra.wasm_extension_registry.get(extension_id) + if extension: + targets[extension_id] = ( + extension, + await _wasm_invoice_paid_owner_id(extension, payment), + ) + + wallet = await _payment_wallet(payment) + if wallet: + wallet_owner_id = sha256s(wallet.user) + for watch_extension_id in await _wallet_watch_extension_ids( + wallet.user, wallet.id + ): + extension = core_app_extra.wasm_extension_registry.get(watch_extension_id) + if not extension: + continue + if watch_extension_id in targets: + existing_extension, existing_owner_id = targets[watch_extension_id] + targets[watch_extension_id] = ( + existing_extension, + existing_owner_id or wallet_owner_id, + ) + continue + targets[watch_extension_id] = (extension, wallet_owner_id) + + for extension, owner_id in targets.values(): + await _dispatch_wasm_invoice_paid_to_extension(extension, payment, owner_id) + + +async def _dispatch_wasm_invoice_paid_to_extension( + extension: Any, payment: Any, owner_id: str | None +) -> None: + export_name = _wasm_invoice_paid_export(extension.config) + if not export_name: + return + + if not _is_wasm_event_export(extension, export_name): + logger.warning( + f"WASM extension '{extension.id}' declares invalid onInvoicePaid " + f"export '{export_name}'." + ) + return + + try: + await invoke_wasm_extension_export( + extension.id, + export_name, + _wasm_invoice_paid_payload(payment), + context="event", + owner_id=owner_id, + trigger_type="event", + event_type="invoice_paid", + wallet_id=payment.wallet_id, + payment_hash=payment.payment_hash, + checking_id=payment.checking_id, + ) + except Exception as exc: + logger.warning( + f"WASM extension '{extension.id}' failed to handle paid invoice " + f"'{payment.payment_hash}': {exc!s}" + ) + + +async def _payment_wallet(payment: Any) -> Any | None: + wallet_id = getattr(payment, "wallet_id", None) + if not isinstance(wallet_id, str) or not wallet_id: + return None + try: + return await get_wallet(wallet_id) + except Exception as exc: + logger.warning(f"Could not fetch wallet '{wallet_id}' for WASM event: {exc!s}") + return None + + +async def _wallet_watch_extension_ids(user_id: str, wallet_id: str) -> list[str]: + try: + user_extensions = await get_user_extensions(user_id) + except Exception as exc: + logger.warning( + f"Could not fetch extensions for wallet payment watch user " + f"'{user_id}': {exc!s}" + ) + return [] + extension_ids: list[str] = [] + + for user_extension in user_extensions: + if not user_extension.active: + continue + if not _has_wallet_watch_grant(user_extension, wallet_id): + continue + if not core_app_extra.wasm_extension_registry.get(user_extension.extension): + continue + try: + installed_extension = await get_installed_extension( + user_extension.extension + ) + except Exception as exc: + logger.warning( + f"Could not fetch installed extension '{user_extension.extension}' " + f"for wallet payment watch: {exc!s}" + ) + continue + if not installed_extension or not installed_extension.active: + continue + if not _extension_has_permission( + installed_extension, WALLET_PAYMENTS_WATCH_PERMISSION + ): + continue + extension_ids.append(user_extension.extension) + + return extension_ids + + +def _has_wallet_watch_grant(user_extension: Any, wallet_id: str) -> bool: + permissions = user_extension.permissions or {} + grants = permissions.get(WALLET_PAYMENTS_WATCH_PERMISSION) + if not isinstance(grants, list): + return False + + for grant_data in grants: + if not isinstance(grant_data, dict): + continue + try: + grant = ExtensionWalletPaymentsWatchGrant.parse_obj(grant_data) + except ValueError: + continue + if grant.enabled and grant.wallet_id == wallet_id: + return True + return False + + +def _extension_has_permission(extension: Any, permission_id: str) -> bool: + return any( + ( + permission.get("id") + if isinstance(permission, dict) + else getattr(permission, "id", None) + ) + == permission_id + for permission in (extension.permissions or []) + ) + + +def _payment_extension_id(payment: Any) -> str | None: + if isinstance(payment.extension, str) and payment.extension: + return payment.extension + + extra = payment.extra or {} + tag = extra.get("tag") or payment.tag + return tag if isinstance(tag, str) and tag else None + + +async def _wasm_invoice_paid_owner_id(extension: Any, payment: Any) -> str | None: + source_id = _payment_source_id(payment) + source_tables = await _wasm_public_invoice_source_tables(extension.id) + if not source_id or not source_tables: + return None + + for source_table in source_tables: + owner_id = await storage_get_row_owner_id(extension.id, source_table, source_id) + if owner_id: + return owner_id + return None + + +def _payment_source_id(payment: Any) -> str | None: + extra = payment.extra or {} + source_id = extra.get("source_id") + return source_id if isinstance(source_id, str) and source_id else None + + +async def _wasm_public_invoice_source_tables(extension_id: str) -> list[str]: + installed_extension = await get_installed_extension(extension_id) + if not installed_extension: + return [] + return _wasm_public_invoice_source_tables_from_permissions( + installed_extension.permissions + ) + + +def _wasm_public_invoice_source_tables_from_permissions( + permissions: Iterable[Any], +) -> list[str]: + for permission in permissions: + permission_id = ( + permission.get("id") + if isinstance(permission, dict) + else getattr(permission, "id", None) + ) + if permission_id != "wallet.create_invoice_public": + continue + policies = ( + permission.get("policies") + if isinstance(permission, dict) + else getattr(permission, "policies", None) + ) + if not isinstance(policies, list): + return [] + return [ + source_policy["table"] + for source_policy in policies + if isinstance(source_policy, dict) + and isinstance(source_policy.get("table"), str) + and source_policy["table"] + ] + return [] + + +def _wasm_invoice_paid_export(config: Any) -> str | None: + return config.events.on_invoice_paid + + +def _is_wasm_event_export(extension: Any, export_name: str) -> bool: + for export in extension.exports: + if export.name == export_name: + return export.visibility == "event" + return False + + +def _wasm_invoice_paid_payload(payment: Any) -> dict[str, Any]: + return { + "checkingId": payment.checking_id, + "paymentHash": payment.payment_hash, + "walletId": payment.wallet_id, + "amount": payment.amount, + "fee": payment.fee, + "bolt11": payment.bolt11, + "memo": payment.memo, + "pending": payment.pending, + "status": payment.status, + "tag": payment.tag, + "extension": payment.extension, + "extra": payment.extra or {}, + "payment": json.loads(payment.json()), + } diff --git a/lnbits/core/wasm_ext/wasm/host.py b/lnbits/core/wasm_ext/wasm/host.py new file mode 100644 index 000000000..e89779a70 --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/host.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import asyncio +import re +from collections.abc import Mapping +from typing import Any + +from wasmtime import component + +from ..api.models import EmptyRequest +from ..api.registry import list_extension_api_methods +from ..api.runtime import ExtensionAPIHost + + +def add_extension_host_imports( + linker: Any, + api_host: ExtensionAPIHost, + event_loop: asyncio.AbstractEventLoop, +) -> None: + with linker.root() as root: + methods_by_interface: dict[str, list[Any]] = {} + for method in list_extension_api_methods(): + methods_by_interface.setdefault(method.host_interface, []).append(method) + + for host_interface, methods in methods_by_interface.items(): + with root.add_instance(f"lnbits:extension/{host_interface}") as host: + for method in methods: + host.add_func( + method.host_name.replace("_", "-"), + _make_host_import( + api_host, + method.method_id, + method.request_model is EmptyRequest, + event_loop, + ), + ) + + +def _make_host_import( + api_host: ExtensionAPIHost, + host_name: str, + empty_request: bool, + event_loop: asyncio.AbstractEventLoop, +) -> Any: + if empty_request: + + def empty_host_import(_store: Any) -> Any: + future = asyncio.run_coroutine_threadsafe( + api_host.invoke(host_name), event_loop + ) + response = future.result() + return _dict_to_component_record(response) + + return empty_host_import + + def host_import(_store: Any, request: Any = None) -> Any: + payload = _component_payload_to_dict(request) + future = asyncio.run_coroutine_threadsafe( + api_host.invoke(host_name, payload), event_loop + ) + response = future.result() + return _dict_to_component_record(response) + + return host_import + + +def _component_payload_to_dict(value: Any) -> dict[str, Any]: + if value is None: + return {} + if hasattr(value, "__dict__"): + return dict(value.__dict__) + if isinstance(value, Mapping): + return dict(value) + raise TypeError("WASM host function payload must be a record.") + + +def _dict_to_component_record(value: Mapping[str, Any]) -> Any: + + record = component.Record() + for key, item in value.items(): + setattr(record, _camel_to_kebab(key), _to_component_value(item)) + return record + + +def _to_component_value(value: Any) -> Any: + if isinstance(value, Mapping): + return _dict_to_component_record(value) + if isinstance(value, list): + return [_to_component_value(item) for item in value] + return value + + +def _camel_to_kebab(value: str) -> str: + return re.sub(r"([a-z0-9])([A-Z])", r"\1-\2", value).replace("_", "-").lower() diff --git a/lnbits/core/wasm_ext/wasm/invoke.py b/lnbits/core/wasm_ext/wasm/invoke.py new file mode 100644 index 000000000..a13c968be --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/invoke.py @@ -0,0 +1,279 @@ +from __future__ import annotations + +import asyncio +import json +from collections.abc import Mapping +from typing import Any + +from wasmtime import Store, WasiConfig, component + +from lnbits.core.crud.extensions import get_installed_extension +from lnbits.core.db import core_app_extra +from lnbits.settings import settings + +from ..api.host import ExtensionHostAPI +from ..api.runtime import ExtensionAPIHost +from .component import _wasm_component, _wasm_engine +from .host import add_extension_host_imports +from .loader import WasmExtension + +_WASM_EPOCH_DEADLINE_TICKS = 1_000_000_000 +_WASM_UNLIMITED_FUEL = 2**63 - 1 + + +async def invoke_wasm_extension_export( + ext_id: str, + export_name: str, + payload: Mapping[str, Any] | None = None, + *, + user: Any | None = None, + access_token: str | None = None, + context: str = "user", + owner_id: str | None = None, + trigger_type: str = "unknown", + request_id: str | None = None, + method: str | None = None, + path: str | None = None, + event_type: str | None = None, + wallet_id: str | None = None, + payment_hash: str | None = None, + checking_id: str | None = None, + request_bytes: int | None = None, + context_data: dict | None = None, +) -> dict[str, Any]: + from lnbits.core.services.extensions import ( + finish_wasm_invocation, + get_wasm_invocation_stop_reason, + resolve_wasm_runtime_limits, + start_wasm_invocation, + stop_wasm_invocation, + wasm_invocation_stop_requested, + ) + + extension = _get_registered_extension(ext_id) + installed_extension = await _active_installed_extension(extension) + permissions = installed_extension.permissions + limits = resolve_wasm_runtime_limits(installed_extension) + payload = payload or {} + payload_size = _json_size(payload) + effective_request_bytes = ( + request_bytes if request_bytes is not None else payload_size + ) + _check_wasm_request_size(effective_request_bytes, limits) + invocation = await start_wasm_invocation( + extension_id=extension.id, + export_name=export_name, + trigger_type=trigger_type, + user_id=_user_id(user) or owner_id, + wallet_id=wallet_id, + request_id=request_id, + method=method, + path=path, + event_type=event_type, + payment_hash=payment_hash, + checking_id=checking_id, + request_bytes=effective_request_bytes, + context={"host_context": context, **(context_data or {})}, + runtime_limits=limits, + ) + api = ExtensionHostAPI( + extension.id, + permissions, + user_id=_user_id(user), + access_token=access_token, + context=context, + owner_id=owner_id, + invocation_id=invocation.id, + runtime_limits=limits, + ) + event_loop = asyncio.get_running_loop() + thread_task = asyncio.create_task( + asyncio.to_thread( + _invoke_wasm_extension_export_sync, + extension, + export_name, + payload, + api, + event_loop, + invocation.id, + limits, + ) + ) + max_execution_ms = limits["wasm_runtime_max_execution_ms"] + timed_out = False + finished = False + + try: + try: + if max_execution_ms > 0: + result = await asyncio.wait_for( + asyncio.shield(thread_task), + timeout=max_execution_ms / 1000, + ) + else: + result = await thread_task + except asyncio.TimeoutError as exc: + timed_out = True + stop_reason = "WASM execution time limit exceeded." + await stop_wasm_invocation(invocation.id, reason=stop_reason) + try: + result = await asyncio.wait_for( + asyncio.shield(thread_task), + timeout=2, + ) + except asyncio.TimeoutError: + await finish_wasm_invocation( + invocation.id, + status="timeout", + error_type="TimeoutError", + error_message=stop_reason, + stop_reason=stop_reason, + ) + finished = True + raise TimeoutError(stop_reason) from exc + + status = ( + "timeout" + if timed_out + else ( + "stopped" + if wasm_invocation_stop_requested(invocation.id) + else "completed" + ) + ) + await finish_wasm_invocation( + invocation.id, + status=status, + response_bytes=_json_size(result), + stop_reason=get_wasm_invocation_stop_reason(invocation.id), + ) + finished = True + return result + except Exception as exc: + if not finished: + await finish_wasm_invocation( + invocation.id, + status=( + "timeout" + if timed_out + else ( + "stopped" + if wasm_invocation_stop_requested(invocation.id) + else "failed" + ) + ), + error_type=exc.__class__.__name__, + error_message=str(exc), + stop_reason=get_wasm_invocation_stop_reason(invocation.id), + ) + raise + + +def _invoke_wasm_extension_export_sync( + extension: WasmExtension, + export_name: str, + payload: Mapping[str, Any], + api: ExtensionHostAPI, + event_loop: asyncio.AbstractEventLoop, + invocation_id: str, + limits: dict[str, int], +) -> dict[str, Any]: + from lnbits.core.services.extensions import attach_wasm_invocation_runtime + + engine = _wasm_engine(limits["wasm_runtime_max_wasm_stack_bytes"]) + store = Store(engine) + _set_store_limits(store, limits) + _set_store_fuel(store, limits) + store.set_epoch_deadline(_WASM_EPOCH_DEADLINE_TICKS) + attach_wasm_invocation_runtime(invocation_id, engine=engine, store=store) + store.set_wasi(WasiConfig()) + + linker = component.Linker(engine) + linker.add_wasip2() + add_extension_host_imports(linker, ExtensionAPIHost(api), event_loop) + + wasm_component = _wasm_component(extension, limits) + instance = linker.instantiate(store, wasm_component) + function = instance.get_func(store, export_name) + if not function: + raise KeyError( + f"WASM extension '{extension.id}' has no export '{export_name}'." + ) + + result = function(store, json.dumps(payload)) + function.post_return(store) + return _parse_wasm_export_result(result, limits) + + +def _parse_wasm_export_result(value: Any, limits: dict[str, int]) -> dict[str, Any]: + if isinstance(value, bytes): + value = value.decode() + if not isinstance(value, str): + return {"ok": True, "data": value} + + max_response_bytes = limits["wasm_runtime_max_response_bytes"] + if max_response_bytes > 0: + response_size = len(value.encode()) + if response_size > max_response_bytes: + raise ValueError( + f"WASM extension response is too large: {response_size} bytes." + ) + + parsed = json.loads(value) + if isinstance(parsed, dict): + return parsed + return {"ok": True, "data": parsed} + + +def _get_registered_extension(ext_id: str) -> WasmExtension: + extension = core_app_extra.wasm_extension_registry.get(ext_id) + if extension: + return extension + raise RuntimeError(f"WASM extension '{ext_id}' is not registered.") + + +async def _active_installed_extension(extension: WasmExtension) -> Any: + installed_extension = await get_installed_extension(extension.id) + if ( + not installed_extension + or settings.lnbits_extensions_deactivate_all + or not installed_extension.active + ): + raise PermissionError(f"WASM extension '{extension.id}' is deactivated.") + return installed_extension + + +def _user_id(user: Any | None) -> str | None: + return getattr(user, "id", None) if user else None + + +def _set_store_limits(store: Any, limits: dict[str, int]) -> None: + store.set_limits( + memory_size=_wasm_limit(limits["wasm_runtime_max_memory_bytes"]), + table_elements=_wasm_limit(limits["wasm_runtime_max_table_elements"]), + instances=_wasm_limit(limits["wasm_runtime_max_instances"]), + tables=_wasm_limit(limits["wasm_runtime_max_tables"]), + memories=_wasm_limit(limits["wasm_runtime_max_memories"]), + ) + + +def _set_store_fuel(store: Any, limits: dict[str, int]) -> None: + store.set_fuel( + limits["wasm_runtime_max_fuel"] + if limits["wasm_runtime_max_fuel"] > 0 + else _WASM_UNLIMITED_FUEL + ) + + +def _check_wasm_request_size(request_bytes: int, limits: dict[str, int]) -> None: + max_request_bytes = limits["wasm_runtime_max_request_bytes"] + if max_request_bytes > 0 and request_bytes > max_request_bytes: + raise ValueError(f"WASM extension request is too large: {request_bytes} bytes.") + + +def _wasm_limit(value: int) -> int: + return value if value > 0 else -1 + + +def _json_size(value: Any) -> int: + return len(json.dumps(value, default=str).encode()) diff --git a/lnbits/core/wasm_ext/wasm/loader.py b/lnbits/core/wasm_ext/wasm/loader.py new file mode 100644 index 000000000..c62f03a06 --- /dev/null +++ b/lnbits/core/wasm_ext/wasm/loader.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +import json +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +from lnbits.core.wasm_ext.wasm.config import ( + WasmExtensionConfig, + WasmExtensionExport, + parse_wasm_extension_config, +) +from lnbits.settings import settings + + +@dataclass(frozen=True) +class WasmExtension: + id: str + name: str + version: str + root_path: Path + module_path: Path + wit_path: Path | None + world: str + exports: list[WasmExtensionExport] + config: WasmExtensionConfig + + +def is_wasm_extension_id(ext_id: str) -> bool: + ext_dir = Path(settings.wasm_extensions_dir, ext_id) + config = _load_json(ext_dir / "config.json") + return bool(config and config.get("extension_type") == "wasm") + + +def is_wasm_extension_dir(ext_dir: Path) -> bool: + config = _load_json(ext_dir / "config.json") + return bool(config and config.get("extension_type") == "wasm") + + +def load_wasm_extension_config(ext_id: str) -> WasmExtensionConfig | None: + ext_dir = Path(settings.wasm_extensions_dir, ext_id) + config = _load_json(ext_dir / "config.json") + if not config or config.get("extension_type") != "wasm": + return None + return parse_wasm_extension_config(ext_id, config) + + +def load_wasm_extension(ext_id: str) -> WasmExtension: + ext_dir = Path(settings.wasm_extensions_dir, ext_id) + raw_config = _load_json(ext_dir / "config.json") + if not raw_config: + raise FileNotFoundError(f"Missing WASM extension config for '{ext_id}'.") + if raw_config.get("extension_type") != "wasm": + raise ValueError(f"Extension '{ext_id}' is not a WASM extension.") + config = parse_wasm_extension_config(ext_id, raw_config) + + module_path = _extension_path(ext_dir, config.wasm.module) + wit_path = _optional_extension_path(ext_dir, config.wasm.wit) + _check_wasm_module(module_path) + if wit_path and not wit_path.is_file(): + raise FileNotFoundError(f"WIT file not found: {wit_path}") + + return WasmExtension( + id=config.id, + name=config.name, + version=config.version, + root_path=ext_dir, + module_path=module_path, + wit_path=wit_path, + world=config.wasm.world, + exports=config.wasm.exports, + config=config, + ) + + +def _load_json(path: Path) -> dict[str, Any] | None: + if not path.is_file(): + return None + with path.open("r", encoding="utf-8") as config_file: + value = json.load(config_file) + if not isinstance(value, dict): + raise ValueError(f"Expected JSON object in '{path}'.") + return value + + +def _extension_path(ext_dir: Path, value: Any) -> Path: + if not isinstance(value, str) or not value: + raise ValueError(f"Missing relative path for extension '{ext_dir.name}'.") + path = (ext_dir / value).resolve() + if ext_dir.resolve() not in path.parents: + raise ValueError(f"Extension path escapes extension root: {value}") + return path + + +def _optional_extension_path(ext_dir: Path, value: Any) -> Path | None: + if value is None: + return None + return _extension_path(ext_dir, value) + + +def _check_wasm_module(path: Path) -> None: + if not path.is_file(): + raise FileNotFoundError(f"WASM module not found: {path}") + with path.open("rb") as wasm_file: + magic = wasm_file.read(4) + if magic != b"\0asm": + raise ValueError(f"Invalid WASM module: {path}") diff --git a/lnbits/db.py b/lnbits/db.py index e6315d294..dc50b36ce 100644 --- a/lnbits/db.py +++ b/lnbits/db.py @@ -35,7 +35,7 @@ if settings.lnbits_database_url: else: if not database_uri.startswith("postgres://"): raise ValueError( - "Please use the 'postgres://...' " "format for the database URL." + "Please use the 'postgres://...' format for the database URL." ) DB_TYPE = POSTGRES @@ -497,7 +497,7 @@ class Filter(BaseModel, Generic[TFilterModel]): validated, errors = compare_field.validate(raw_value, {}, loc="none") if errors: raise ValidationError(errors=[errors], model=model) - values[f"{field}__{index}"] = validated + values[f"{field}__{i}_{index}"] = validated else: raise ValueError("Unknown filter field") @@ -510,11 +510,12 @@ class Filter(BaseModel, Generic[TFilterModel]): for key in self.values.keys() if self.values else []: if self.model and self.model.__fields__[self.field].type_ == datetime: placeholder = compat_timestamp_placeholder(key) - stmt.append(f"{prefix}{self.field} {self.op.as_sql} {placeholder}") - if self.op in {Operator.INCLUDE, Operator.EXCLUDE}: - stmt.append(f":{key}") else: - stmt.append(f"{prefix}{self.field} {self.op.as_sql} :{key}") + placeholder = f":{key}" + if self.op in {Operator.INCLUDE, Operator.EXCLUDE}: + stmt.append(placeholder) + else: + stmt.append(f"{prefix}{self.field} {self.op.as_sql} {placeholder}") if self.op in {Operator.INCLUDE, Operator.EXCLUDE}: statement = f"{prefix}{self.field} {self.op.as_sql} ({', '.join(stmt)})" @@ -560,7 +561,9 @@ class Filters(BaseModel, Generic[TFilterModel]): def pagination(self) -> str: stmt = "" - self.limit = self.limit or 10 + if self.limit == 0: + self.limit = 1000 + self.limit = 10 if self.limit is None else self.limit stmt += f"LIMIT {min(1000, self.limit)} " if self.offset: stmt += f"OFFSET {self.offset}" @@ -613,6 +616,12 @@ class Filters(BaseModel, Generic[TFilterModel]): for page_filter in self.filters: page_filter.table_name = table_name + def get_filter_by_field(self, field: str) -> Filter[TFilterModel] | None: + return next((f for f in self.filters if f.field == field), None) + + def remove_filter_by_field(self, field: str) -> None: + self.filters = [f for f in self.filters if f.field != field] + class DbJsonEncoder(json.JSONEncoder): def default(self, o): @@ -717,20 +726,20 @@ def dict_to_model(_row: dict, model: type[TModel]) -> TModel: # noqa: C901 if get_origin(outertype_) is list: _items = _safe_load_json(value) if isinstance(value, str) else value _dict[key] = [ - dict_to_submodel(type_, v) if issubclass(type_, BaseModel) else v + dict_to_submodel(type_, v) if _is_subclass(type_, BaseModel) else v for v in _items ] continue - if issubclass(type_, bool): + if _is_subclass(type_, bool): _dict[key] = bool(value) continue - if issubclass(type_, datetime): + if _is_subclass(type_, datetime): if DB_TYPE == SQLITE: _dict[key] = datetime.fromtimestamp(value, timezone.utc) else: _dict[key] = value.replace(tzinfo=timezone.utc) continue - if issubclass(type_, BaseModel): + if _is_subclass(type_, BaseModel): _dict[key] = dict_to_submodel(type_, value) continue # TODO: remove this when all sub models are migrated to Pydantic @@ -755,6 +764,13 @@ def _safe_load_json(value: str) -> dict: return {} +def _is_subclass(type_: Any, class_or_tuple: type | tuple[type, ...]) -> bool: + try: + return issubclass(type_, class_or_tuple) + except TypeError: + return False + + def _valid_sql_name(name: str) -> bool: """Check if a SQL name is valid (alphanumeric and underscores only)""" return ( diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 1673b860f..a8b82d49c 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -448,7 +448,7 @@ async def _check_user_access(r: Request, user_id: str, conn: Connection | None = async def _check_user_extension_access( user_id: str, path: str, conn: Connection | None = None ): - ext_id = path_segments(path)[0] + ext_id = _extension_id_from_request_path(path) status = await check_user_extension_access(user_id, ext_id, conn=conn) if not status.success: raise HTTPException( @@ -457,6 +457,15 @@ async def _check_user_extension_access( ) +def _extension_id_from_request_path(path: str) -> str: + segments = path_segments(path) + if len(segments) >= 2 and segments[0] == "ext": + return segments[1] + if len(segments) >= 4 and segments[:3] == ["api", "v1", "ext"]: + return segments[3] + return segments[0] + + async def _get_account_from_token( access_token: str, path: str, method: str, conn: Connection | None = None ) -> Account | None: diff --git a/lnbits/fiat/__init__.py b/lnbits/fiat/__init__.py index 09cc96935..5d46256fd 100644 --- a/lnbits/fiat/__init__.py +++ b/lnbits/fiat/__init__.py @@ -9,6 +9,8 @@ from lnbits.fiat.base import FiatProvider from lnbits.settings import settings from .paypal import PayPalWallet +from .revolut import RevolutWallet +from .square import SquareWallet from .stripe import StripeWallet fiat_module = importlib.import_module("lnbits.fiat") @@ -17,6 +19,8 @@ fiat_module = importlib.import_module("lnbits.fiat") class FiatProviderType(Enum): stripe = "StripeWallet" paypal = "PayPalWallet" + square = "SquareWallet" + revolut = "RevolutWallet" async def get_fiat_provider(name: str) -> FiatProvider | None: @@ -52,5 +56,7 @@ fiat_providers: dict[str, FiatProvider] = {} __all__ = [ "PayPalWallet", + "RevolutWallet", + "SquareWallet", "StripeWallet", ] diff --git a/lnbits/fiat/base.py b/lnbits/fiat/base.py index 162ed85bb..15e39fb3b 100644 --- a/lnbits/fiat/base.py +++ b/lnbits/fiat/base.py @@ -95,6 +95,10 @@ class FiatSubscriptionPaymentOptions(BaseModel): description="Unique ID that can be used to identify the subscription request." "If not provided, one will be generated.", ) + customer_email: str | None = Field( + default=None, + description="The customer email to use for the subscription.", + ) tag: str | None = Field( default=None, description="Payments created by the recurring subscription" @@ -127,15 +131,15 @@ class FiatSubscriptionResponse(BaseModel): class FiatPaymentSuccessStatus(FiatPaymentStatus): - paid = True + paid = True # type: ignore[reportIncompatibleVariableOverride] class FiatPaymentFailedStatus(FiatPaymentStatus): - paid = False + paid = False # type: ignore[reportIncompatibleVariableOverride] class FiatPaymentPendingStatus(FiatPaymentStatus): - paid = None + paid = None # type: ignore[reportIncompatibleVariableOverride] class FiatProvider(ABC): diff --git a/lnbits/fiat/revolut.py b/lnbits/fiat/revolut.py new file mode 100644 index 000000000..fd3454f07 --- /dev/null +++ b/lnbits/fiat/revolut.py @@ -0,0 +1,646 @@ +import asyncio +import ipaddress +import json +from collections.abc import AsyncGenerator +from decimal import ROUND_HALF_UP, Decimal +from typing import Any +from urllib.parse import urlparse + +import httpx +from loguru import logger +from pydantic import BaseModel, Field, ValidationError + +from lnbits.helpers import normalize_endpoint, urlsafe_short_hash +from lnbits.settings import settings + +from .base import ( + FiatInvoiceResponse, + FiatPaymentFailedStatus, + FiatPaymentPendingStatus, + FiatPaymentResponse, + FiatPaymentStatus, + FiatPaymentSuccessStatus, + FiatProvider, + FiatStatusResponse, + FiatSubscriptionPaymentOptions, + FiatSubscriptionResponse, +) + + +class RevolutCheckoutOptions(BaseModel): + class Config: + extra = "ignore" + + success_url: str | None = None + metadata: dict[str, Any] = Field(default_factory=dict) + description: str | None = None + + +class RevolutCreateInvoiceOptions(BaseModel): + class Config: + extra = "ignore" + + checkout: RevolutCheckoutOptions | None = None + + +class RevolutSubscriptionReference(BaseModel): + wallet_id: str + tag: str | None = None + subscription_request_id: str | None = None + extra: dict[str, Any] | None = None + memo: str | None = None + + +REVOLUT_WEBHOOK_EVENTS = [ + "ORDER_AUTHORISED", + "ORDER_COMPLETED", + "SUBSCRIPTION_INITIATED", +] + +ZERO_DECIMAL_CURRENCIES = { + "BIF", + "CLP", + "DJF", + "GNF", + "ISK", + "JPY", + "KMF", + "KRW", + "PYG", + "RWF", + "UGX", + "VND", + "VUV", + "XAF", + "XOF", + "XPF", +} +THREE_DECIMAL_CURRENCIES = { + "BHD", + "IQD", + "JOD", + "KWD", + "LYD", + "OMR", + "TND", +} +REVOLUT_CUSTOMER_LIST_LIMIT = 500 +REVOLUT_CUSTOMER_LIST_MAX_PAGES = 20 +REVOLUT_REQUEST_TIMEOUT = 30 + + +class RevolutWallet(FiatProvider): + """https://developer.revolut.com/docs/merchant""" + + def __init__(self): + logger.debug("Initializing RevolutWallet") + self._settings_fields = self._settings_connection_fields() + if not settings.revolut_api_endpoint: + raise ValueError("Cannot initialize RevolutWallet: missing endpoint.") + if not settings.revolut_api_secret_key: + raise ValueError("Cannot initialize RevolutWallet: missing API secret key.") + + self.endpoint = normalize_endpoint(settings.revolut_api_endpoint) + self.headers = { + "Authorization": f"Bearer {settings.revolut_api_secret_key}", + "Revolut-Api-Version": settings.revolut_api_version, + "Content-Type": "application/json", + "User-Agent": settings.user_agent, + } + self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers) + logger.info("RevolutWallet initialized.") + + async def cleanup(self): + try: + await self.client.aclose() + except RuntimeError as e: + logger.warning(f"Error closing Revolut wallet connection: {e}") + + async def status( + self, only_check_settings: bool | None = False + ) -> FiatStatusResponse: + if only_check_settings: + if self._settings_fields != self._settings_connection_fields(): + return FiatStatusResponse("Connection settings have changed.", 0) + return FiatStatusResponse(balance=0) + + try: + r = await self.client.get( + "/api/orders", + params={"limit": 1}, + timeout=REVOLUT_REQUEST_TIMEOUT, + ) + r.raise_for_status() + _ = r.json() + return FiatStatusResponse(balance=0) + except json.JSONDecodeError: + return FiatStatusResponse("Server error: 'invalid json response'", 0) + except Exception as exc: + logger.warning(exc) + return FiatStatusResponse(f"Unable to connect to {self.endpoint}.", 0) + + async def create_invoice( + self, + amount: float, + payment_hash: str, + currency: str, + memo: str | None = None, + extra: dict[str, Any] | None = None, + **kwargs, + ) -> FiatInvoiceResponse: + opts = self._parse_create_opts(extra or {}) + if opts is None: + return FiatInvoiceResponse( + ok=False, error_message="Invalid Revolut options" + ) + + amount_minor = self.amount_to_minor_units(amount, currency) + checkout = opts.checkout or RevolutCheckoutOptions() + success_url = ( + checkout.success_url + or settings.revolut_payment_success_url + or "https://lnbits.com" + ) + + payload = { + "amount": amount_minor, + "currency": currency.upper(), + "description": checkout.description or memo or "LNbits Invoice", + "redirect_url": success_url, + "metadata": { + **checkout.metadata, + "payment_hash": payment_hash, + "alan_action": "invoice", + }, + } + + try: + r = await self.client.post( + "/api/orders", json=payload, timeout=REVOLUT_REQUEST_TIMEOUT + ) + r.raise_for_status() + data = r.json() + order_id = data.get("id") + checkout_url = data.get("checkout_url") + if not order_id or not checkout_url: + return FiatInvoiceResponse( + ok=False, error_message="Server error: missing order id or url" + ) + return FiatInvoiceResponse( + ok=True, + checking_id=f"order_{order_id}", + payment_request=checkout_url, + ) + except json.JSONDecodeError: + return FiatInvoiceResponse( + ok=False, error_message="Server error: invalid json response" + ) + except Exception as exc: + logger.warning(exc) + return FiatInvoiceResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + + async def create_subscription( + self, + subscription_id: str, + quantity: int, + payment_options: FiatSubscriptionPaymentOptions, + **kwargs, + ) -> FiatSubscriptionResponse: + if quantity != 1: + return FiatSubscriptionResponse( + ok=False, + error_message="Revolut subscriptions do not support quantity.", + ) + + wallet_id = payment_options.wallet_id + if not wallet_id: + return FiatSubscriptionResponse( + ok=False, error_message="Wallet ID is required." + ) + + extra = payment_options.extra or {} + if not payment_options.subscription_request_id: + payment_options.subscription_request_id = urlsafe_short_hash() + + reference = RevolutSubscriptionReference( + wallet_id=wallet_id, + tag=payment_options.tag, + subscription_request_id=payment_options.subscription_request_id, + extra=extra, + memo=payment_options.memo, + ) + payload: dict[str, Any] = { + "plan_variation_id": subscription_id, + "external_reference": self._serialize_subscription_reference(reference), + "setup_order_redirect_url": ( + payment_options.success_url + or settings.revolut_payment_success_url + or "https://lnbits.com" + ), + } + if extra.get("trial_duration"): + payload["trial_duration"] = extra["trial_duration"] + + headers = { + **self.headers, + "Idempotency-Key": payment_options.subscription_request_id, + } + + try: + customer_id, customer_error = await self._get_subscription_customer_id( + payment_options + ) + if not customer_id: + return FiatSubscriptionResponse(ok=False, error_message=customer_error) + payload["customer_id"] = customer_id + r = await self.client.post( + "/api/subscriptions", + json=payload, + headers=headers, + timeout=REVOLUT_REQUEST_TIMEOUT, + ) + r.raise_for_status() + data = r.json() + revolut_subscription_id = data.get("id") + setup_order_id = data.get("setup_order_id") + if not revolut_subscription_id or not setup_order_id: + return FiatSubscriptionResponse( + ok=False, + error_message=( + "Server error: missing subscription id or setup order id" + ), + ) + + setup_order = await self.get_order(setup_order_id) + checkout_url = setup_order.get("checkout_url") + if not checkout_url: + return FiatSubscriptionResponse( + ok=False, error_message="Server error: missing setup checkout url" + ) + + return FiatSubscriptionResponse( + ok=True, + checkout_session_url=checkout_url, + subscription_request_id=revolut_subscription_id, + ) + except json.JSONDecodeError: + return FiatSubscriptionResponse( + ok=False, error_message="Server error: invalid json response" + ) + except Exception as exc: + logger.warning(exc) + return FiatSubscriptionResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + + async def cancel_subscription( + self, + subscription_id: str, + correlation_id: str, + **kwargs, + ) -> FiatSubscriptionResponse: + try: + subscription = await self.get_subscription(subscription_id) + reference = self.deserialize_subscription_reference( + subscription.get("external_reference") + ) + if not reference or reference.wallet_id != correlation_id: + return FiatSubscriptionResponse( + ok=False, error_message="Subscription not found." + ) + + r = await self.client.post( + f"/api/subscriptions/{subscription_id}/cancel", + timeout=REVOLUT_REQUEST_TIMEOUT, + ) + r.raise_for_status() + return FiatSubscriptionResponse(ok=True) + except Exception as exc: + logger.warning(exc) + return FiatSubscriptionResponse( + ok=False, error_message="Unable to cancel subscription." + ) + + async def pay_invoice(self, payment_request: str) -> FiatPaymentResponse: + raise NotImplementedError("Revolut does not support paying invoices directly.") + + async def get_invoice_status(self, checking_id: str) -> FiatPaymentStatus: + try: + order_id = self._normalize_revolut_id(checking_id) + return self._status_from_order(await self.get_order(order_id)) + except Exception as exc: + logger.debug(f"Error getting Revolut invoice status: {exc}") + return FiatPaymentPendingStatus() + + async def get_payment_status(self, checking_id: str) -> FiatPaymentStatus: + raise NotImplementedError("Revolut does not support outgoing payments.") + + async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: + logger.warning( + "Revolut does not support paid invoices stream. Use webhooks instead." + ) + mock_queue: asyncio.Queue[str] = asyncio.Queue(0) + while settings.lnbits_running: + value = await mock_queue.get() + yield value + + def _normalize_revolut_id(self, checking_id: str) -> str: + value = ( + checking_id.replace("fiat_revolut_", "", 1) + if checking_id.startswith("fiat_revolut_") + else checking_id + ) + return value.replace("order_", "", 1) if value.startswith("order_") else value + + async def get_order(self, order_id: str) -> dict[str, Any]: + r = await self.client.get( + f"/api/orders/{order_id}", timeout=REVOLUT_REQUEST_TIMEOUT + ) + r.raise_for_status() + return r.json() + + async def get_subscription(self, subscription_id: str) -> dict[str, Any]: + r = await self.client.get( + f"/api/subscriptions/{subscription_id}", timeout=REVOLUT_REQUEST_TIMEOUT + ) + r.raise_for_status() + return r.json() + + async def get_subscription_cycle( + self, subscription_id: str, cycle_id: str + ) -> dict[str, Any]: + r = await self.client.get( + f"/api/subscriptions/{subscription_id}/cycles/{cycle_id}", + timeout=REVOLUT_REQUEST_TIMEOUT, + ) + r.raise_for_status() + return r.json() + + async def _get_subscription_customer_id( + self, payment_options: FiatSubscriptionPaymentOptions + ) -> tuple[str | None, str | None]: + if not payment_options.customer_email: + return ( + None, + "Revolut subscriptions require customer_email.", + ) + + customer = await self._get_customer_by_email(payment_options.customer_email) + customer_id = customer.get("id") if customer else None + if customer_id: + return customer_id, None + + customer = await self._create_customer(payment_options.customer_email) + customer_id = customer.get("id") + if not customer_id: + return None, "Server error: missing customer id" + return customer_id, None + + async def _get_customer_by_email(self, email: str) -> dict[str, Any] | None: + page_token = None + for _ in range(REVOLUT_CUSTOMER_LIST_MAX_PAGES): + customer_page = await self._list_customers(page_token=page_token) + customer = _find_customer_by_email(customer_page["customers"], email) + if customer: + return customer + + page_token = customer_page.get("next_page_token") + if not page_token: + return None + return None + + async def _list_customers(self, page_token: str | None = None) -> dict[str, Any]: + params: dict[str, Any] = {"limit": REVOLUT_CUSTOMER_LIST_LIMIT} + if page_token: + params["page_token"] = page_token + r = await self.client.get( + "/api/customers", params=params, timeout=REVOLUT_REQUEST_TIMEOUT + ) + r.raise_for_status() + return _extract_customer_page(r.json()) + + async def _create_customer(self, email: str) -> dict[str, Any]: + r = await self.client.post( + "/api/customers", + json={"email": email}, + timeout=REVOLUT_REQUEST_TIMEOUT, + ) + r.raise_for_status() + return r.json() + + @classmethod + async def create_webhook( + cls, + url: str, + endpoint: str | None = None, + api_secret_key: str | None = None, + api_version: str | None = None, + ) -> dict[str, Any]: + if not url: + raise ValueError("Missing Revolut webhook URL.") + cls._validate_webhook_url(url) + if not endpoint and not settings.revolut_api_endpoint: + raise ValueError("Missing Revolut API endpoint.") + if not api_secret_key and not settings.revolut_api_secret_key: + raise ValueError("Missing Revolut API secret key.") + + base_url = normalize_endpoint(endpoint or settings.revolut_api_endpoint) + secret_key = api_secret_key or settings.revolut_api_secret_key + headers = { + "Authorization": f"Bearer {secret_key}", + "Revolut-Api-Version": api_version or settings.revolut_api_version, + "Content-Type": "application/json", + "User-Agent": settings.user_agent, + } + payload = {"url": url, "events": REVOLUT_WEBHOOK_EVENTS} + async with httpx.AsyncClient(base_url=base_url, headers=headers) as client: + webhooks = await cls._list_webhooks(client) + existing = await cls._get_existing_webhook(client, webhooks, url) + if existing: + existing["already_exists"] = True + return existing + + response = await client.post( + "/api/webhooks", json=payload, timeout=REVOLUT_REQUEST_TIMEOUT + ) + response.raise_for_status() + return response.json() + + @classmethod + async def _list_webhooks(cls, client: httpx.AsyncClient) -> list[dict[str, Any]]: + response = await client.get("/api/webhooks", timeout=REVOLUT_REQUEST_TIMEOUT) + response.raise_for_status() + data = response.json() + if isinstance(data, list): + return data + if isinstance(data, dict): + for field in ["webhooks", "data", "items"]: + if isinstance(data.get(field), list): + return data[field] + return [] + + @classmethod + async def _get_existing_webhook( + cls, client: httpx.AsyncClient, webhooks: list[dict[str, Any]], url: str + ) -> dict[str, Any] | None: + for webhook in webhooks: + if cls._normalize_webhook_url(webhook.get("url")) != ( + cls._normalize_webhook_url(url) + ): + continue + + webhook_id = webhook.get("id") + if webhook_id and ( + not webhook.get("events") or not webhook.get("signing_secret") + ): + response = await client.get( + f"/api/webhooks/{webhook_id}", timeout=REVOLUT_REQUEST_TIMEOUT + ) + response.raise_for_status() + webhook = response.json() + + events = set(webhook.get("events") or []) + missing_events = set(REVOLUT_WEBHOOK_EVENTS) - events + if missing_events: + raise ValueError( + "A Revolut webhook already exists for this URL, but it is " + f"missing required events: {', '.join(sorted(missing_events))}." + ) + + if not webhook.get("signing_secret"): + raise ValueError( + "A Revolut webhook already exists for this URL, but Revolut " + "did not return a signing secret." + ) + + return webhook + return None + + @classmethod + def _normalize_webhook_url(cls, url: str | None) -> str: + return (url or "").strip().rstrip("/") + + @classmethod + def _validate_webhook_url(cls, url: str) -> None: + parsed = urlparse(url) + hostname = parsed.hostname + if parsed.scheme not in ["http", "https"] or not hostname: + raise ValueError("Revolut webhook URL must be a clearnet URL.") + + host = hostname.lower() + if host == "localhost" or host.endswith(".localhost"): + raise ValueError("Revolut webhook URL must be a clearnet URL.") + if host.endswith(".local") or host.endswith(".onion"): + raise ValueError("Revolut webhook URL must be a clearnet URL.") + + try: + ip = ipaddress.ip_address(host) + except ValueError: + return + + if ( + ip.is_loopback + or ip.is_private + or ip.is_link_local + or ip.is_reserved + or ip.is_unspecified + ): + raise ValueError("Revolut webhook URL must be a clearnet URL.") + + def _status_from_order(self, order: dict[str, Any]) -> FiatPaymentStatus: + status = (order.get("state") or "").upper() + if status == "COMPLETED": + return FiatPaymentSuccessStatus() + if status in ["CANCELLED", "FAILED"]: + return FiatPaymentFailedStatus() + return FiatPaymentPendingStatus() + + @classmethod + def amount_to_minor_units(cls, amount: float | Decimal, currency: str) -> int: + scale = Decimal(10) ** cls.currency_exponent(currency) + return int((Decimal(str(amount)) * scale).quantize(Decimal("1"), ROUND_HALF_UP)) + + @classmethod + def minor_units_to_amount(cls, amount: int, currency: str) -> float: + scale = Decimal(10) ** cls.currency_exponent(currency) + return float(Decimal(amount) / scale) + + @classmethod + def currency_exponent(cls, currency: str) -> int: + normalized = currency.upper() + if normalized in ZERO_DECIMAL_CURRENCIES: + return 0 + if normalized in THREE_DECIMAL_CURRENCIES: + return 3 + return 2 + + def _parse_create_opts( + self, raw_opts: dict[str, Any] + ) -> RevolutCreateInvoiceOptions | None: + try: + return RevolutCreateInvoiceOptions.parse_obj(raw_opts) + except ValidationError as e: + logger.warning(f"Invalid Revolut options: {e}") + return None + + def _serialize_subscription_reference( + self, reference: RevolutSubscriptionReference + ) -> str: + payload = reference.dict(exclude_none=True) + serialized = json.dumps(payload, separators=(",", ":")) + if len(serialized) > 1024: + raise ValueError("Revolut subscription external_reference is too long.") + return serialized + + def deserialize_subscription_reference( + self, external_reference: str | None + ) -> RevolutSubscriptionReference | None: + if not external_reference: + return None + try: + return RevolutSubscriptionReference.parse_obj( + json.loads(external_reference) + ) + except (json.JSONDecodeError, ValidationError) as exc: + logger.warning(exc) + return None + + def _settings_connection_fields(self) -> str: + return "-".join( + [ + str(settings.revolut_api_endpoint), + str(settings.revolut_api_secret_key), + str(settings.revolut_api_version), + str(settings.revolut_webhook_signing_secret), + ] + ) + + +def _extract_customer_page(data: Any) -> dict[str, Any]: + if isinstance(data, list): + return {"customers": _filter_customer_list(data)} + if isinstance(data, dict): + for field in ["customers", "data", "items"]: + customers = data.get(field) + if isinstance(customers, list): + return { + "customers": _filter_customer_list(customers), + "next_page_token": data.get("next_page_token"), + } + return {"customers": []} + + +def _filter_customer_list(customers: list[Any]) -> list[dict[str, Any]]: + return [customer for customer in customers if isinstance(customer, dict)] + + +def _find_customer_by_email( + customers: list[dict[str, Any]], email: str +) -> dict[str, Any] | None: + normalized_email = email.casefold() + for customer in customers: + if str(customer.get("email") or "").casefold() == normalized_email: + return customer + return None diff --git a/lnbits/fiat/square.py b/lnbits/fiat/square.py new file mode 100644 index 000000000..9481660de --- /dev/null +++ b/lnbits/fiat/square.py @@ -0,0 +1,620 @@ +import asyncio +import json +from collections.abc import AsyncGenerator +from typing import Any, Literal + +import httpx +from loguru import logger +from pydantic import BaseModel, Field, ValidationError + +from lnbits.helpers import normalize_endpoint, urlsafe_short_hash +from lnbits.settings import settings + +from .base import ( + FiatInvoiceResponse, + FiatPaymentFailedStatus, + FiatPaymentPendingStatus, + FiatPaymentResponse, + FiatPaymentStatus, + FiatPaymentSuccessStatus, + FiatProvider, + FiatStatusResponse, + FiatSubscriptionPaymentOptions, + FiatSubscriptionResponse, +) + +FiatMethod = Literal["checkout", "subscription"] + + +class SquareCheckoutOptions(BaseModel): + class Config: + extra = "ignore" + + success_url: str | None = None + metadata: dict[str, str] = Field(default_factory=dict) + line_item_name: str | None = None + + +class SquareSubscriptionOptions(BaseModel): + class Config: + extra = "ignore" + + checking_id: str | None = None + payment_request: str | None = None + + +class SquareCreateInvoiceOptions(BaseModel): + class Config: + extra = "ignore" + + fiat_method: FiatMethod = "checkout" + checkout: SquareCheckoutOptions | None = None + subscription: SquareSubscriptionOptions | None = None + + +class SquareSubscriptionCheckoutInfo(BaseModel): + plan_variation_id: str + price_money: dict[str, Any] + + +class SquareWallet(FiatProvider): + """https://developer.squareup.com/reference/square""" + + def __init__(self): + logger.debug("Initializing SquareWallet") + self._settings_fields = self._settings_connection_fields() + if not settings.square_api_endpoint: + raise ValueError("Cannot initialize SquareWallet: missing endpoint.") + if not settings.square_access_token: + raise ValueError("Cannot initialize SquareWallet: missing access token.") + if not settings.square_location_id: + raise ValueError("Cannot initialize SquareWallet: missing location ID.") + + self.endpoint = normalize_endpoint(settings.square_api_endpoint) + self.location_id = settings.square_location_id + self.headers = { + "Authorization": f"Bearer {settings.square_access_token}", + "Square-Version": settings.square_api_version, + "Content-Type": "application/json", + "User-Agent": settings.user_agent, + } + self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers) + logger.info("SquareWallet initialized.") + + async def cleanup(self): + try: + await self.client.aclose() + except RuntimeError as e: + logger.warning(f"Error closing Square wallet connection: {e}") + + async def status( + self, only_check_settings: bool | None = False + ) -> FiatStatusResponse: + if only_check_settings: + if self._settings_fields != self._settings_connection_fields(): + return FiatStatusResponse("Connection settings have changed.", 0) + return FiatStatusResponse(balance=0) + + try: + r = await self.client.get(f"/v2/locations/{self.location_id}", timeout=15) + r.raise_for_status() + _ = r.json() + return FiatStatusResponse(balance=0) + except json.JSONDecodeError: + return FiatStatusResponse("Server error: 'invalid json response'", 0) + except Exception as exc: + logger.warning(exc) + return FiatStatusResponse(f"Unable to connect to {self.endpoint}.", 0) + + async def create_invoice( + self, + amount: float, + payment_hash: str, + currency: str, + memo: str | None = None, + extra: dict[str, Any] | None = None, + **kwargs, + ) -> FiatInvoiceResponse: + opts = self._parse_create_opts(extra or {}) + if not opts: + return FiatInvoiceResponse(ok=False, error_message="Invalid Square options") + + if opts.fiat_method == "subscription": + return self._create_subscription_invoice(opts.subscription) + + return await self._create_checkout_invoice( + amount=amount, + payment_hash=payment_hash, + currency=currency, + opts=opts, + memo=memo, + ) + + async def create_subscription( + self, + subscription_id: str, + quantity: int, + payment_options: FiatSubscriptionPaymentOptions, + **kwargs, + ) -> FiatSubscriptionResponse: + if settings.lnbits_running: + return FiatSubscriptionResponse( + ok=False, error_message="Subscription not supported for Square." + ) + success_url = ( + payment_options.success_url + or settings.square_payment_success_url + or "https://lnbits.com" + ) + + if not payment_options.subscription_request_id: + payment_options.subscription_request_id = urlsafe_short_hash() + payment_options.extra = payment_options.extra or {} + payment_options.extra["subscription_request_id"] = ( + payment_options.subscription_request_id + ) + try: + checkout_info = await self._get_subscription_checkout_info(subscription_id) + metadata = self._serialize_metadata(payment_options) + payload = { + "idempotency_key": payment_options.subscription_request_id, + "description": metadata, + "quick_pay": { + "name": (payment_options.memo or "LNbits Subscription")[:255], + "price_money": checkout_info.price_money, + "location_id": self.location_id, + }, + "checkout_options": { + "redirect_url": success_url, + "subscription_plan_id": checkout_info.plan_variation_id, + }, + "payment_note": metadata, + } + r = await self.client.post( + "/v2/online-checkout/payment-links", json=payload + ) + r.raise_for_status() + data = r.json() + payment_link = data.get("payment_link") or {} + url = payment_link.get("url") + if not url: + return FiatSubscriptionResponse( + ok=False, error_message="Server error: missing url" + ) + return FiatSubscriptionResponse( + ok=True, + checkout_session_url=url, + subscription_request_id=payment_options.subscription_request_id, + ) + except json.JSONDecodeError as exc: + logger.warning(exc) + return FiatSubscriptionResponse( + ok=False, error_message="Server error: invalid json response" + ) + except Exception as exc: + logger.warning(exc) + return FiatSubscriptionResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + + async def cancel_subscription( + self, + subscription_id: str, + correlation_id: str, + **kwargs, + ) -> FiatSubscriptionResponse: + try: + square_subscription_id = await self._get_square_subscription_id( + subscription_id, correlation_id + ) + r = await self.client.post( + f"/v2/subscriptions/{square_subscription_id}/cancel" + ) + r.raise_for_status() + return FiatSubscriptionResponse(ok=True) + except Exception as exc: + logger.warning(exc) + return FiatSubscriptionResponse( + ok=False, error_message="Unable to cancel subscription." + ) + + async def pay_invoice(self, payment_request: str) -> FiatPaymentResponse: + raise NotImplementedError("Square does not support paying invoices directly.") + + async def get_invoice_status(self, checking_id: str) -> FiatPaymentStatus: + try: + square_id = self._normalize_square_id(checking_id) + if square_id.startswith("payment_"): + payment_id = square_id.replace("payment_", "", 1) + return await self._get_payment_status(payment_id) + + order_id = ( + square_id.replace("order_", "", 1) + if square_id.startswith("order_") + else square_id + ) + return await self._get_order_status(order_id) + except Exception as exc: + logger.debug(f"Error getting Square invoice status: {exc}") + return FiatPaymentPendingStatus() + + async def get_payment_status(self, checking_id: str) -> FiatPaymentStatus: + raise NotImplementedError("Square does not support outgoing payments.") + + async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: + logger.warning( + "Square does not support paid invoices stream. Use webhooks instead." + ) + mock_queue: asyncio.Queue[str] = asyncio.Queue(0) + while settings.lnbits_running: + value = await mock_queue.get() + yield value + + async def _get_order_status(self, order_id: str) -> FiatPaymentStatus: + order = await self._get_order(order_id) + payment_id = self._payment_id_from_order(order) + if payment_id: + return await self._get_payment_status(payment_id) + + if (order.get("state") or "").upper() == "CANCELED": + return FiatPaymentFailedStatus() + return FiatPaymentPendingStatus() + + async def _get_order(self, order_id: str) -> dict[str, Any]: + r = await self.client.get(f"/v2/orders/{order_id}") + r.raise_for_status() + return r.json().get("order") or {} + + async def get_payment_for_order(self, order_id: str) -> dict[str, Any] | None: + order = await self._get_order(order_id) + payment_id = self._payment_id_from_order(order) + if not payment_id: + return None + return await self._get_payment(payment_id) + + def _payment_id_from_order(self, order: dict[str, Any]) -> str | None: + tenders = order.get("tenders") or [] + for tender in tenders: + payment_id = tender.get("payment_id") + if payment_id: + return payment_id + return None + + async def _get_payment_status(self, payment_id: str) -> FiatPaymentStatus: + return self._status_from_payment(await self._get_payment(payment_id)) + + async def _get_payment(self, payment_id: str) -> dict[str, Any]: + r = await self.client.get(f"/v2/payments/{payment_id}") + r.raise_for_status() + return r.json().get("payment") or {} + + async def _get_subscription_checkout_info( + self, subscription_plan_id: str + ) -> SquareSubscriptionCheckoutInfo: + catalog_object = await self._get_catalog_object(subscription_plan_id) + if catalog_object.get("type") == "SUBSCRIPTION_PLAN": + return await self._get_plan_checkout_info(catalog_object) + + if catalog_object.get("type") == "SUBSCRIPTION_PLAN_VARIATION": + price_money = await self._get_subscription_price_money( + catalog_object, + ) + plan_variation_id = catalog_object.get("id") + if not plan_variation_id: + raise ValueError("Square subscription plan variation is missing an ID.") + return SquareSubscriptionCheckoutInfo( + plan_variation_id=plan_variation_id, + price_money=price_money, + ) + + raise ValueError( + "Square subscription ID must be a plan ID or plan variation ID." + ) + + async def _get_plan_checkout_info( + self, catalog_object: dict[str, Any] + ) -> SquareSubscriptionCheckoutInfo: + plan_data = catalog_object.get("subscription_plan_data") or {} + plan_variations = plan_data.get("subscription_plan_variations") or [] + eligible_item_ids = plan_data.get("eligible_item_ids") or [] + plan_variation = next( + ( + variation + for variation in plan_variations + if not variation.get("is_deleted") + ), + None, + ) + if not plan_variation: + raise ValueError("Square subscription plan is missing a variation.") + + price_money = await self._get_subscription_price_money( + plan_variation, + eligible_item_ids=eligible_item_ids, + ) + plan_variation_id = plan_variation.get("id") + if not plan_variation_id: + raise ValueError("Square subscription plan variation is missing an ID.") + + return SquareSubscriptionCheckoutInfo( + plan_variation_id=plan_variation_id, + price_money=price_money, + ) + + async def _get_catalog_object(self, object_id: str) -> dict[str, Any]: + r = await self.client.get(f"/v2/catalog/object/{object_id}") + r.raise_for_status() + return r.json().get("object") or {} + + async def _get_subscription_price_money( + self, + plan_variation: dict[str, Any], + eligible_item_ids: list[str] | None = None, + ) -> dict[str, Any]: + variation_data = plan_variation.get("subscription_plan_variation_data") or {} + phases = variation_data.get("phases") or [] + for phase in phases: + pricing = phase.get("pricing") or {} + price_money = pricing.get("price_money") or phase.get( + "recurring_price_money" + ) + parsed_price_money = self._parse_price_money(price_money) + if parsed_price_money: + return parsed_price_money + + if pricing.get("type") == "RELATIVE": + return await self._get_relative_subscription_price_money( + eligible_item_ids or [] + ) + + raise ValueError("Square subscription plan variation is missing price_money.") + + async def _get_relative_subscription_price_money( + self, eligible_item_ids: list[str] + ) -> dict[str, Any]: + if len(eligible_item_ids) != 1: + raise ValueError( + "Square relative subscription plan must have exactly one item." + ) + + item = await self._get_catalog_object(eligible_item_ids[0]) + item_variations: list[dict[str, Any]] = [] + if item.get("type") == "ITEM": + item_variations = (item.get("item_data") or {}).get("variations") or [] + elif item.get("type") == "ITEM_VARIATION": + item_variations = [item] + + item_variation = next( + ( + variation + for variation in item_variations + if not variation.get("is_deleted") + ), + None, + ) + if not item_variation: + raise ValueError("Square subscription item is missing a variation.") + + price_money = self._parse_price_money( + (item_variation.get("item_variation_data") or {}).get("price_money") + ) + if price_money: + return price_money + + raise ValueError("Square subscription item variation is missing price_money.") + + def _parse_price_money( + self, price_money: dict[str, Any] | None + ) -> dict[str, Any] | None: + if ( + price_money + and price_money.get("amount") is not None + and price_money.get("currency") + ): + return { + "amount": int(price_money["amount"]), + "currency": price_money["currency"].upper(), + } + return None + + def _status_from_payment(self, payment: dict[str, Any]) -> FiatPaymentStatus: + status = (payment.get("status") or "").upper() + if status == "COMPLETED": + return FiatPaymentSuccessStatus() + if status in ["CANCELED", "FAILED"]: + return FiatPaymentFailedStatus() + return FiatPaymentPendingStatus() + + async def _create_checkout_invoice( + self, + amount: float, + payment_hash: str, + currency: str, + opts: SquareCreateInvoiceOptions, + memo: str | None = None, + ) -> FiatInvoiceResponse: + amount_cents = int(amount * 100) + co = opts.checkout or SquareCheckoutOptions() + success_url = ( + co.success_url + or settings.square_payment_success_url + or "https://lnbits.com" + ) + line_item_name = (co.line_item_name or memo or "LNbits Invoice")[:255] + metadata = { + **co.metadata, + "payment_hash": payment_hash, + "alan_action": "invoice", + } + + payload = { + "idempotency_key": payment_hash, + "order": { + "location_id": self.location_id, + "metadata": metadata, + "line_items": [ + { + "name": line_item_name, + "quantity": "1", + "base_price_money": { + "amount": amount_cents, + "currency": currency.upper(), + }, + } + ], + }, + "checkout_options": {"redirect_url": success_url}, + } + if memo: + payload["payment_note"] = memo[:500] + + try: + r = await self.client.post( + "/v2/online-checkout/payment-links", json=payload + ) + r.raise_for_status() + data = r.json() + payment_link = data.get("payment_link") or {} + order_id = payment_link.get("order_id") + url = payment_link.get("url") + if not order_id or not url: + return FiatInvoiceResponse( + ok=False, error_message="Server error: missing order id or url" + ) + return FiatInvoiceResponse( + ok=True, + checking_id=f"order_{order_id}", + payment_request=url, + ) + except json.JSONDecodeError: + return FiatInvoiceResponse( + ok=False, error_message="Server error: invalid json response" + ) + except Exception as exc: + logger.warning(exc) + return FiatInvoiceResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + + def _create_subscription_invoice( + self, opts: SquareSubscriptionOptions | None + ) -> FiatInvoiceResponse: + term = opts or SquareSubscriptionOptions() + checking_id = term.checking_id or f"payment_{urlsafe_short_hash()}" + return FiatInvoiceResponse( + ok=True, + checking_id=checking_id, + payment_request=term.payment_request or "", + ) + + def _normalize_square_id(self, checking_id: str) -> str: + return ( + checking_id.replace("fiat_square_", "", 1) + if checking_id.startswith("fiat_square_") + else checking_id + ) + + def _parse_create_opts( + self, raw_opts: dict[str, Any] + ) -> SquareCreateInvoiceOptions | None: + try: + return SquareCreateInvoiceOptions.parse_obj(raw_opts) + except ValidationError as e: + logger.warning(f"Invalid Square options: {e}") + return None + + def _serialize_metadata( + self, payment_options: FiatSubscriptionPaymentOptions + ) -> str: + extra_link = None + if payment_options.extra: + raw_link = payment_options.extra.get("link") + extra_link = str(raw_link)[:200] if raw_link else None + + meta = [ + payment_options.wallet_id, + payment_options.tag, + payment_options.subscription_request_id, + extra_link, + ] + + memo_limit = 493 - len(json.dumps(meta, separators=(",", ":"))) + if memo_limit > 0 and payment_options.memo: + meta.append(payment_options.memo[:memo_limit]) + else: + meta.append(None) + + metadata = json.dumps(meta, separators=(",", ":")) + if len(metadata) > 500: + raise ValueError("Square subscription metadata is too long.") + return metadata + + async def _get_square_subscription_id( + self, subscription_id: str, wallet_id: str + ) -> str: + try: + from lnbits.core.crud.payments import get_payments + from lnbits.core.models import PaymentFilters + from lnbits.db import Filter, Filters + + payments = await get_payments( + wallet_id=wallet_id, + filters=Filters( + filters=[ + Filter.parse_query( + "external_id", [subscription_id], PaymentFilters + ) + ], + model=PaymentFilters, + sortby="created_at", + direction="desc", + limit=1, + ), + ) + payment = next( + ( + payment + for payment in payments + if payment.external_id and payment.fiat_provider == "square" + ), + None, + ) + if payment and payment.external_id: + return payment.external_id + + payments = await get_payments( + wallet_id=wallet_id, + incoming=True, + filters=Filters( + model=PaymentFilters, + sortby="created_at", + direction="desc", + ), + ) + payment = next( + ( + payment + for payment in payments + if payment.external_id + and payment.fiat_provider == "square" + and (payment.extra or {}).get("subscription_request_id") + == subscription_id + ), + None, + ) + if payment and payment.external_id: + return payment.external_id + except Exception as exc: + logger.warning(exc) + + return subscription_id + + def _settings_connection_fields(self) -> str: + return "-".join( + [ + str(settings.square_api_endpoint), + str(settings.square_access_token), + str(settings.square_location_id), + str(settings.square_api_version), + ] + ) diff --git a/lnbits/helpers.py b/lnbits/helpers.py index 8bcb2a013..1dc5b7aa3 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -13,6 +13,7 @@ from fastapi.routing import APIRoute from loguru import logger from packaging import version from pydantic.schema import field_schema +from random_username.generate import generate_username # type: ignore[import-untyped] from starlette.templating import Jinja2Templates from lnbits.settings import settings @@ -22,6 +23,10 @@ from lnbits.utils.exchange_rates import currencies from .db import FilterModel +def generate_ln_address() -> str: + return generate_username(1)[0].lower() + + def get_db_vendor_name(): db_url = settings.lnbits_database_url return ( @@ -55,7 +60,6 @@ def static_url_for(static: str, path: str) -> str: def template_renderer(additional_folders: list | None = None) -> Jinja2Templates: folders = [ "lnbits/templates", - "lnbits/core/templates", settings.extension_builder_working_dir_path.as_posix(), ] @@ -311,12 +315,7 @@ def get_api_routes(routes: list) -> dict[str, str]: def path_segments(path: str) -> list[str]: path = path.strip("/") - segments = path.split("/") - if len(segments) < 2: - return segments - if segments[0] == "upgrades": - return segments[2:] - return segments[0:] + return path.split("/") def normalize_path(path: str | None) -> str: @@ -373,3 +372,13 @@ def sha256s(value: str) -> str: Returns the hex as a string. """ return hashlib.sha256(value.encode("utf-8")).hexdigest() + + +def daystart_timestamp(dt: datetime | None = None) -> int: + """ + Returns the timestamp of the start of the day for the given + datetime (or now in UTC if not provided). + """ + dt = dt or datetime.now(timezone.utc) + day_start = dt.replace(hour=0, minute=0, second=0, microsecond=0) + return int(day_start.timestamp()) diff --git a/lnbits/llms_txt.py b/lnbits/llms_txt.py new file mode 100644 index 000000000..13816c4b5 --- /dev/null +++ b/lnbits/llms_txt.py @@ -0,0 +1,78 @@ +"""Generate llms.txt markdown from FastAPI OpenAPI schema for AI agents.""" + +from typing import Any + +from fastapi import FastAPI +from fastapi.responses import PlainTextResponse + + +def generate_llms_txt(app: FastAPI) -> str: + """Convert an OpenAPI schema to llms.txt markdown format.""" + openapi_schema = app.openapi() + lines: list[str] = [] + + # H1: API Title + info = openapi_schema.get("info", {}) + title = info.get("title", "API") + lines.append(f"# {title}") + lines.append("") + + # Blockquote: Description + description = info.get("description") + if description: + for line in description.strip().split("\n"): + lines.append(f"> {line}") + lines.append("") + + # Group endpoints by tag + paths = openapi_schema.get("paths", {}) + endpoints_by_tag: dict[str, list[dict[str, Any]]] = {} + + for path, path_item in paths.items(): + for method in ["get", "post", "put", "patch", "delete", "head", "options"]: + if method not in path_item: + continue + operation = path_item[method] + tags = operation.get("tags", ["Endpoints"]) + tag = tags[0] if tags else "Endpoints" + if tag not in endpoints_by_tag: + endpoints_by_tag[tag] = [] + endpoints_by_tag[tag].append( + { + "path": path, + "method": method.upper(), + "operation": operation, + } + ) + + # Generate sections by tag + for tag, endpoints in endpoints_by_tag.items(): + lines.append(f"## {tag}") + lines.append("") + for endpoint in endpoints: + method = endpoint["method"] + path = endpoint["path"] + operation = endpoint["operation"] + summary = operation.get("summary", "") + if summary: + lines.append(f"### `{method} {path}` - {summary}") + else: + lines.append(f"### `{method} {path}`") + lines.append("") + lines.append("") + + return "\n".join(lines).strip() + "\n" + + +def create_llms_txt_route(app: FastAPI) -> None: + """Add a /llms.txt endpoint to the app.""" + + @app.get( + "/llms.txt", + response_class=PlainTextResponse, + include_in_schema=False, + summary="Get LLM-friendly API documentation", + ) + async def get_llms_txt() -> str: + """Return the API documentation in llms.txt markdown format.""" + return generate_llms_txt(app) diff --git a/lnbits/middleware.py b/lnbits/middleware.py index 8f6cf0eab..d216786ac 100644 --- a/lnbits/middleware.py +++ b/lnbits/middleware.py @@ -7,6 +7,7 @@ from typing import Any from fastapi import FastAPI, Request, Response from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from loguru import logger +from pyinstrument import Profiler from slowapi import _rate_limit_exceeded_handler from slowapi.errors import RateLimitExceeded from slowapi.middleware import SlowAPIMiddleware @@ -50,14 +51,6 @@ class InstalledExtensionMiddleware: await self.app(scope, receive, send) return - # re-route all trafic if the extension has been upgraded - if top_path in settings.lnbits_upgraded_extensions: - upgrade_path = ( - f"""{settings.lnbits_upgraded_extensions[top_path]}/{top_path}""" - ) - tail = "/".join(rest) - scope["path"] = f"/upgrades/{upgrade_path}/{tail}" - await self.app(scope, receive, send) def _response_by_accepted_type( @@ -111,7 +104,7 @@ class ExtensionsRedirectMiddleware: req_headers = scope["headers"] if "headers" in scope else [] redirect = settings.find_extension_redirect(scope["path"], req_headers) - if redirect: + if redirect and not redirect.is_duplicate_well_known(): scope["path"] = redirect.new_path_from(scope["path"]) await self.app(scope, receive, send) @@ -246,3 +239,16 @@ def add_first_install_middleware(app: FastAPI): ): return RedirectResponse("/first_install") return await call_next(request) + + +def add_profiler_middleware(app: FastAPI): + @app.middleware("http") + async def profile_middleware(request: Request, call_next): + profiling = request.query_params.get("profiler", False) + if profiling: + profiler = Profiler(async_mode="enabled") + profiler.start() + _ = await call_next(request) + profiler.stop() + return HTMLResponse(profiler.output_html()) + return await call_next(request) diff --git a/lnbits/server.py b/lnbits/server.py index 51a26d3eb..6fbf078c7 100644 --- a/lnbits/server.py +++ b/lnbits/server.py @@ -27,6 +27,8 @@ from lnbits.settings import set_cli_settings, settings @click.option( "--reload", is_flag=True, default=False, help="Enable auto-reload for development" ) +@click.option("--ws-max-queue", default=128, help="Websocket max queue size") +@click.option("--ws-ping-timeout", default=60.0, help="Websocket ping timeout") def main( port: int, host: str, @@ -34,6 +36,8 @@ def main( ssl_keyfile: str, ssl_certfile: str, reload: bool, + ws_max_queue: int, + ws_ping_timeout: float, ): """Launched with `uv run lnbits` at root level""" @@ -45,6 +49,7 @@ def main( Path(settings.lnbits_extensions_path, "extensions").mkdir( parents=True, exist_ok=True ) + settings.wasm_extensions_dir.mkdir(parents=True, exist_ok=True) set_cli_settings(host=host, port=port, forwarded_allow_ips=forwarded_allow_ips) @@ -58,6 +63,8 @@ def main( ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, reload=reload or False, + ws_ping_timeout=ws_ping_timeout, + ws_max_queue=ws_max_queue, ) server = uvicorn.Server(config=config) diff --git a/lnbits/settings.py b/lnbits/settings.py index eb031c9df..7727d0c11 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -11,12 +11,16 @@ from enum import Enum from os import path from pathlib import Path from time import gmtime, strftime, time -from typing import Any +from typing import Any, Literal from uuid import uuid4 from loguru import logger from pydantic import BaseModel, BaseSettings, Extra, Field, validator +DEFAULT_WASM_MANIFESTS = [ + "https://raw.githubusercontent.com/lnbits/lnbits-extensions-wasm/refs/heads/main/extensions.json" +] + def list_parse_fallback(v: str): v = v.replace(" ", "") @@ -41,6 +45,16 @@ class UsersSettings(LNbitsSettings): lnbits_admin_users: list[str] = Field(default=[]) lnbits_allowed_users: list[str] = Field(default=[]) lnbits_allow_new_accounts: bool = Field(default=True) + + lnbits_ln_address_mode: Literal[ + "core_first", "extension_first", "extension_only" + ] = Field(default="extension_first") + lnbits_allow_custom_wallet_lightning_addresses: bool = Field(default=False) + lnbits_charge_wallet_lightning_addresses: bool = Field(default=False) + lnbits_wallet_lightning_address_price_sats: int = Field(default=1000, ge=0) + lnbits_wallet_lightning_address_blacklist: list[str] = Field( + default=["admin", "info", "support", "help", "security"] + ) lnbits_require_user_activation: bool = Field(default=False) lnbits_user_activation_by_email: bool = Field(default=False) @@ -54,12 +68,17 @@ class UsersSettings(LNbitsSettings): def new_accounts_allowed(self) -> bool: return self.lnbits_allow_new_accounts and len(self.lnbits_allowed_users) == 0 + @property + def ln_address_creation_allowed(self) -> bool: + return self.lnbits_ln_address_mode != "extension_only" + class ExtensionsSettings(LNbitsSettings): lnbits_admin_extensions: list[str] = Field(default=[]) lnbits_user_default_extensions: list[str] = Field(default=[]) lnbits_extensions_deactivate_all: bool = Field(default=False) lnbits_extensions_builder_activate_non_admins: bool = Field(default=False) + lnbits_wasm_invocation_retention_days: int = Field(default=7, ge=0) lnbits_extensions_reviews_url: str = Field( default="https://demo.lnbits.com/paidreviews/api/v1/AdFzLjzuKFLsdk4Bcnff6r", description=""" @@ -72,6 +91,7 @@ class ExtensionsSettings(LNbitsSettings): "https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json" ] ) + lnbits_wasm_extensions_manifests: list[str] = Field(default=DEFAULT_WASM_MANIFESTS) lnbits_extensions_builder_manifest_url: str = Field( default="https://raw.githubusercontent.com/lnbits/extension_builder_stub/refs/heads/main/manifest.json" ) @@ -81,6 +101,33 @@ class ExtensionsSettings(LNbitsSettings): return Path(settings.lnbits_data_folder, "extensions_builder") +class WasmRuntimeLimits(LNbitsSettings): + # 0 disables the limit. Installed WASM extensions may override these defaults. + wasm_runtime_max_memory_bytes: int = Field(default=64 * 1024 * 1024, ge=0) + wasm_runtime_max_execution_ms: int = Field(default=5_000, ge=0) + wasm_runtime_max_fuel: int = Field(default=100_000_000, ge=0) + wasm_runtime_max_response_bytes: int = Field(default=1024 * 1024, ge=0) + wasm_runtime_max_request_bytes: int = Field(default=1024 * 1024, ge=0) + wasm_runtime_max_wasm_stack_bytes: int = Field(default=1024 * 1024, ge=0) + + wasm_runtime_max_table_elements: int = Field(default=10_000, ge=0) + wasm_runtime_max_instances: int = Field(default=8, ge=0) + wasm_runtime_max_tables: int = Field(default=10, ge=0) + wasm_runtime_max_memories: int = Field(default=1, ge=0) + + wasm_runtime_max_concurrent_invocations: int = Field(default=16, ge=0) + wasm_runtime_max_concurrent_invocations_per_extension: int = Field(default=4, ge=0) + wasm_runtime_max_concurrent_invocations_per_user: int = Field(default=4, ge=0) + + wasm_runtime_max_host_calls: int = Field(default=1_000, ge=0) + wasm_runtime_max_http_calls: int = Field(default=20, ge=0) + wasm_runtime_max_storage_calls: int = Field(default=100, ge=0) + wasm_runtime_max_wallet_calls: int = Field(default=20, ge=0) + + wasm_runtime_http_timeout_ms: int = Field(default=5_000, ge=0) + wasm_runtime_max_http_response_bytes: int = Field(default=1024 * 1024, ge=0) + + class ExtensionsInstallSettings(LNbitsSettings): lnbits_extensions_default_install: list[str] = Field(default=[]) # required due to GitHUb rate-limit @@ -93,6 +140,9 @@ class RedirectPath(BaseModel): redirect_to_path: str header_filters: dict = {} + def is_duplicate_well_known(self) -> bool: + return self.from_path in ["/.well-known/lnurlp"] + def in_conflict(self, other: RedirectPath) -> bool: if self.ext_id == other.ext_id: return False @@ -166,8 +216,6 @@ class ExchangeRateProvider(BaseModel): class InstalledExtensionsSettings(LNbitsSettings): # installed extensions that have been deactivated lnbits_deactivated_extensions: set[str] = Field(default=set()) - # upgraded extensions that require API redirects - lnbits_upgraded_extensions: dict[str, str] = Field(default={}) # list of redirects that extensions want to perform lnbits_extensions_redirects: list[RedirectPath] = Field(default=[]) @@ -190,18 +238,10 @@ class InstalledExtensionsSettings(LNbitsSettings): def activate_extension_paths( self, ext_id: str, - upgrade_hash: str | None = None, ext_redirects: list[dict] | None = None, ): self.lnbits_deactivated_extensions.discard(ext_id) - """ - Update the list of upgraded extensions. The middleware will perform - redirects based on this - """ - if upgrade_hash: - self.lnbits_upgraded_extensions[ext_id] = upgrade_hash - if ext_redirects: self._activate_extension_redirects(ext_id, ext_redirects) @@ -211,9 +251,6 @@ class InstalledExtensionsSettings(LNbitsSettings): self.lnbits_deactivated_extensions.add(ext_id) self._remove_extension_redirects(ext_id) - def extension_upgrade_hash(self, ext_id: str) -> str: - return settings.lnbits_upgraded_extensions.get(ext_id, "") - def _activate_extension_redirects(self, ext_id: str, ext_redirects: list[dict]): ext_redirect_paths = [ RedirectPath(**{"ext_id": ext_id, **er}) for er in ext_redirects @@ -284,7 +321,7 @@ class ThemesSettings(LNbitsSettings): lnbits_custom_image: str | None = Field(default="/static/images/logos/lnbits.svg") lnbits_ad_space_title: str = Field(default="Supported by") lnbits_ad_space: str = Field( - default="https://shop.lnbits.com/;/static/images/bitcoin-shop-banner.png;/static/images/bitcoin-shop-banner.png,https://affil.trezor.io/aff_c?offer_id=169&aff_id=33845;/static/images/bitcoin-hardware-wallet.png;/static/images/bitcoin-hardware-wallet.png,https://firefish.io/?ref=lnbits;/static/images/firefish.png;/static/images/firefish.png,https://opensats.org/;/static/images/open-sats.png;/static/images/open-sats.png" + default="https://shop.lnbits.com/;/static/images/bitcoin-shop-banner.png;/static/images/bitcoin-shop-banner.png,https://affil.trezor.io/aff_c?offer_id=169&aff_id=33845;/static/images/bitcoin-hardware-wallet.png;/static/images/bitcoin-hardware-wallet.png,https://firefish.io/?ref=lnbits;/static/images/firefish.png;/static/images/firefish.png" ) # sneaky sneaky lnbits_ad_space_enabled: bool = Field(default=False) lnbits_allowed_currencies: list[str] = Field(default=[]) @@ -300,6 +337,7 @@ class ThemesSettings(LNbitsSettings): lnbits_default_card_rounded: bool = Field(default=True) lnbits_default_card_gradient: bool = Field(default=True) lnbits_default_card_shadow: bool = Field(default=False) + lnbits_default_burger_menu_background: bool = Field(default=True) class OpsSettings(LNbitsSettings): @@ -323,10 +361,6 @@ class AssetSettings(LNbitsSettings): "heic", "heif", "heics", - "text/plain", - "text/json" "text/xml", - "application/json", - "application/pdf", ] ) lnbits_asset_thumbnail_width: int = Field(default=128, ge=0) @@ -362,9 +396,11 @@ class FeeSettings(LNbitsSettings): class ExchangeProvidersSettings(LNbitsSettings): - lnbits_exchange_rate_cache_seconds: int = Field(default=30, ge=0) + lnbits_exchange_rate_cache_seconds: int = Field(default=60, ge=0) lnbits_exchange_history_size: int = Field(default=60, ge=0) lnbits_exchange_history_refresh_interval_seconds: int = Field(default=300, ge=0) + lnbits_price_aggregator_enabled: bool = Field(default=True) + lnbits_price_aggregator_url: str = Field(default="https://price.lnbits.com") lnbits_exchange_rate_providers: list[ExchangeRateProvider] = Field( default=[ @@ -447,6 +483,7 @@ class SecuritySettings(LNbitsSettings): lnbits_max_outgoing_payment_amount_sats: int = Field(default=10_000_000, ge=0) lnbits_max_incoming_payment_amount_sats: int = Field(default=10_000_000, ge=0) + first_install_token_confirmed: str | None = Field(default=None) def is_wallet_max_balance_exceeded(self, amount): return ( @@ -496,6 +533,11 @@ class NotificationsSettings(LNbitsSettings): and self.lnbits_telegram_notifications_access_token is not None ) + def is_email_notifications_configured(self) -> bool: + return self.lnbits_email_notifications_enabled and bool( + self.lnbits_email_notifications_email + ) + class FakeWalletFundingSource(LNbitsSettings): fake_wallet_secret: str = Field(default="ToTheMoon1") @@ -564,6 +606,7 @@ class LndGrpcFundingSource(LNbitsSettings): lnd_grpc_invoice_macaroon: str | None = Field(default=None) lnd_grpc_macaroon: str | None = Field(default=None) lnd_grpc_macaroon_encrypted: str | None = Field(default=None) + lnd_grpc_allow_self_payment: bool = Field(default=False) class LnPayFundingSource(LNbitsSettings): @@ -577,6 +620,10 @@ class BlinkFundingSource(LNbitsSettings): blink_api_endpoint: str | None = Field(default="https://api.blink.sv/graphql") blink_ws_endpoint: str | None = Field(default="wss://ws.blink.sv/graphql") blink_token: str | None = Field(default=None) + # If probing fails or is unsupported by the destination (e.g. fedimints), + # send the payment anyway. Blink reserves its max fee and reconciles any + # excess separately. If disabled, payments that cannot be probed will fail. + blink_send_without_probe: bool = Field(default=True) class ZBDFundingSource(LNbitsSettings): @@ -587,6 +634,9 @@ class ZBDFundingSource(LNbitsSettings): class PhoenixdFundingSource(LNbitsSettings): phoenixd_api_endpoint: str | None = Field(default="http://localhost:9740/") phoenixd_api_password: str | None = Field(default=None) + phoenixd_data_dir: str | None = Field(default=None) + phoenixd_mnemonic: str | None = Field(default=None) + phoenixd_mnemonic_backup_confirmed: bool = Field(default=False) class AlbyFundingSource(LNbitsSettings): @@ -606,11 +656,17 @@ class SparkFundingSource(LNbitsSettings): spark_token: str | None = Field(default=None) +class BarkFundingSource(LNbitsSettings): + bark_api_endpoint: str | None = Field(default="http://localhost:3000") + bark_api_token: str | None = Field(default=None) + + class SparkL2FundingSource(LNbitsSettings): spark_l2_network: str = Field(default="MAINNET") spark_l2_external_endpoint: str | None = Field(default="http://localhost:8765") spark_l2_external_api_key: str | None = Field(default=None) spark_l2_mnemonic: str | None = Field(default=None) + spark_l2_mnemonic_backup_confirmed: bool = Field(default=False) spark_l2_pay_wait_ms: int = Field(default=4000, ge=0) spark_l2_pay_poll_ms: int = Field(default=500, ge=0) spark_l2_stream_keepalive_ms: int = Field(default=15000, ge=0) @@ -648,6 +704,7 @@ class BoltzFundingSource(LNbitsSettings): boltz_client_password: str = Field(default="") boltz_client_cert: str | None = Field(default=None) boltz_mnemonic: str | None = Field(default=None) + boltz_mnemonic_backup_confirmed: bool = Field(default=False) class StrikeFundingSource(LNbitsSettings): @@ -699,6 +756,35 @@ class PayPalFiatProvider(LNbitsSettings): paypal_limits: FiatProviderLimits = Field(default_factory=FiatProviderLimits) +class SquareFiatProvider(LNbitsSettings): + square_enabled: bool = Field(default=False) + square_api_endpoint: str = Field(default="https://connect.squareup.com") + square_access_token: str | None = Field(default=None) + square_location_id: str | None = Field(default=None) + square_api_version: str = Field(default="2026-01-22") + square_payment_success_url: str = Field(default="https://lnbits.com") + square_payment_webhook_url: str = Field( + default="https://your-lnbits-domain-here.com/api/v1/callback/square" + ) + square_webhook_signature_key: str | None = Field(default=None) + + square_limits: FiatProviderLimits = Field(default_factory=FiatProviderLimits) + + +class RevolutFiatProvider(LNbitsSettings): + revolut_enabled: bool = Field(default=False) + revolut_api_endpoint: str = Field(default="https://merchant.revolut.com") + revolut_api_secret_key: str | None = Field(default=None) + revolut_api_version: str = Field(default="2026-04-20") + revolut_payment_success_url: str = Field(default="https://lnbits.com") + revolut_payment_webhook_url: str = Field( + default="https://your-lnbits-domain-here.com/api/v1/callback/revolut" + ) + revolut_webhook_signing_secret: str | None = Field(default=None) + + revolut_limits: FiatProviderLimits = Field(default_factory=FiatProviderLimits) + + class LightningSettings(LNbitsSettings): lightning_invoice_expiry: int = Field(default=3600, gt=0) @@ -721,6 +807,7 @@ class FundingSourcesSettings( PhoenixdFundingSource, OpenNodeFundingSource, SparkFundingSource, + BarkFundingSource, SparkL2FundingSource, LnTipsFundingSource, NWCFundingSource, @@ -732,10 +819,16 @@ class FundingSourcesSettings( # How long to wait for the payment to be confirmed before returning a pending status # It will not fail the payment, it will make it return pending after the timeout lnbits_funding_source_pay_invoice_wait_seconds: int = Field(default=5, ge=0) + lnbits_funding_source_pending_interval_seconds: int = Field(default=1800, ge=0) funding_source_max_retries: int = Field(default=4, ge=0) -class FiatProvidersSettings(StripeFiatProvider, PayPalFiatProvider): +class FiatProvidersSettings( + StripeFiatProvider, + PayPalFiatProvider, + SquareFiatProvider, + RevolutFiatProvider, +): def is_fiat_provider_enabled(self, provider: str | None) -> bool: """ Checks if a specific fiat provider is enabled. @@ -746,6 +839,10 @@ class FiatProvidersSettings(StripeFiatProvider, PayPalFiatProvider): return self.stripe_enabled if provider == "paypal": return self.paypal_enabled + if provider == "square": + return self.square_enabled + if provider == "revolut": + return self.revolut_enabled return False def get_fiat_providers_for_user(self, user_id: str) -> list[str]: @@ -765,6 +862,18 @@ class FiatProvidersSettings(StripeFiatProvider, PayPalFiatProvider): ): allowed_providers.append("paypal") + if self.square_enabled and ( + not self.square_limits.allowed_users + or user_id in self.square_limits.allowed_users + ): + allowed_providers.append("square") + + if self.revolut_enabled and ( + not self.revolut_limits.allowed_users + or user_id in self.revolut_limits.allowed_users + ): + allowed_providers.append("revolut") + return allowed_providers def get_fiat_provider_limits(self, provider_name: str) -> FiatProviderLimits | None: @@ -789,6 +898,16 @@ class NodeUISettings(LNbitsSettings): lnbits_node_ui_transactions: bool = Field(default=False) +class BlockExplorerSettings(LNbitsSettings): + lnbits_blockexplorer_enabled: bool = Field(default=False) + lnbits_blockexplorer_public_api: bool = Field(default=False) + lnbits_blockexplorer_electrum_url: str = Field( + default="ssl://electrum.blockstream.info:50002" + ) + # one of: main, test, regtest, signet (see embit.networks.NETWORKS) + lnbits_blockexplorer_network: str = Field(default="main") + + class AuthMethods(Enum): user_id_only = "user-id-only" username_and_password = "username-password" # noqa: S105 @@ -796,6 +915,7 @@ class AuthMethods(Enum): google_auth = "google-auth" github_auth = "github-auth" keycloak_auth = "keycloak-auth" + oidc_auth = "oidc-auth" @classmethod def all(cls): @@ -806,6 +926,7 @@ class AuthMethods(Enum): AuthMethods.google_auth.value, AuthMethods.github_auth.value, AuthMethods.keycloak_auth.value, + AuthMethods.oidc_auth.value, ] @@ -851,6 +972,14 @@ class KeycloakAuthSettings(LNbitsSettings): keycloak_client_custom_icon: str | None = Field(default=None) +class OidcAuthSettings(LNbitsSettings): + oidc_discovery_url: str = Field(default="") + oidc_client_id: str = Field(default="") + oidc_client_secret: str = Field(default="") + oidc_client_custom_org: str | None = Field(default=None) + oidc_client_custom_icon: str | None = Field(default=None) + + class AuditSettings(LNbitsSettings): lnbits_audit_enabled: bool = Field(default=True) @@ -940,6 +1069,7 @@ class AuditSettings(LNbitsSettings): class EditableSettings( UsersSettings, ExtensionsSettings, + WasmRuntimeLimits, ThemesSettings, OpsSettings, AssetSettings, @@ -952,18 +1082,23 @@ class EditableSettings( LightningSettings, WebPushSettings, NodeUISettings, + BlockExplorerSettings, AuditSettings, AuthSettings, NostrAuthSettings, GoogleAuthSettings, GitHubAuthSettings, KeycloakAuthSettings, + OidcAuthSettings, ): @validator( "lnbits_admin_users", "lnbits_allowed_users", + "lnbits_wallet_lightning_address_blacklist", "lnbits_theme_options", "lnbits_admin_extensions", + "lnbits_extensions_manifests", + "lnbits_wasm_extensions_manifests", pre=True, ) @classmethod @@ -985,7 +1120,7 @@ class EditableSettings( class UpdateSettings(EditableSettings): - class Config: + class Config(EditableSettings.Config): extra = Extra.forbid @@ -993,6 +1128,9 @@ class EnvSettings(LNbitsSettings): debug: bool = Field(default=False) debug_database: bool = Field(default=False) bundle_assets: bool = Field(default=True) + profiler: bool = Field(default=False) + # When enabled, auth cookies require HTTPS and SSO will reject insecure HTTP. + auth_https_only: bool = Field(default=True) host: str = Field(default="127.0.0.1") port: int = Field(default=5000, gt=0) forwarded_allow_ips: str = Field(default="*") @@ -1007,14 +1145,24 @@ class EnvSettings(LNbitsSettings): log_rotation: str = Field(default="100 MB") log_retention: str = Field(default="3 months") first_install_token: str | None = Field(default=None) - cleanup_wallets_days: int = Field(default=90, ge=0) funding_source_max_retries: int = Field(default=4, ge=0) + lnbits_max_users: int = Field(default=0, ge=0) + lnbits_max_extensions: int = Field(default=0, ge=0) + task_heart_beat_verbose: bool = Field(default=False) + task_heart_beat_interval: int = Field(default=30) @property def has_default_extension_path(self) -> bool: return self.lnbits_extensions_path == "lnbits" + def has_first_install_token_changed(self) -> bool: + if not self.first_install_token: + return False + if not settings.first_install_token_confirmed: + return False + return self.first_install_token != settings.first_install_token_confirmed + def check_auth_secret_key(self): if self.auth_secret_key: return @@ -1033,12 +1181,39 @@ class EnvSettings(LNbitsSettings): class PersistenceSettings(LNbitsSettings): lnbits_data_folder: str = Field(default="./data") lnbits_database_url: str | None = Field(default=None) + lnbits_wasm_extensions_path: str = Field(default="") + + @validator("lnbits_wasm_extensions_path", pre=True, always=True) + @classmethod + def validate_wasm_extensions_path(cls, value, values) -> str: + if value: + return str(value) + return str(Path(values.get("lnbits_data_folder", "./data"), "wasm_extensions")) + + @property + def wasm_extensions_dir(self) -> Path: + wasm_dir = Path(self.lnbits_wasm_extensions_path) + importable_dirs = ( + Path(getattr(self, "lnbits_extensions_path", "lnbits"), "extensions"), + Path(self.lnbits_data_folder, "upgrades"), + ) + resolved_wasm_dir = wasm_dir.resolve() + if any( + resolved_dir == resolved_wasm_dir + or resolved_dir in resolved_wasm_dir.parents + for resolved_dir in (path.resolve() for path in importable_dirs) + ): + raise ValueError( + "WASM extensions path must be outside importable extension directories." + ) + return wasm_dir class SuperUserSettings(LNbitsSettings): lnbits_allowed_funding_sources: list[str] = Field( default=[ "AlbyWallet", + "BarkWallet", "BoltzWallet", "BlinkWallet", "BreezSdkWallet", @@ -1124,11 +1299,11 @@ class ReadOnlySettings( class Settings(EditableSettings, ReadOnlySettings, TransientSettings, BaseSettings): - class Config: + class Config(EditableSettings.Config, BaseSettings.Config): # type: ignore[misc] env_file = ".env" env_file_encoding = "utf-8" case_sensitive = False - json_loads = list_parse_fallback + json_loads = list_parse_fallback # type: ignore[assignment] def is_user_allowed(self, user_id: str) -> bool: return ( @@ -1174,6 +1349,8 @@ class PublicSettings(BaseModel): auth_methods: list[str] = Field(alias="authMethods") keycloak_org: str | None = Field(alias="keycloakOrg") keycloak_icon: str | None = Field(alias="keycloakIcon") + oidc_org: str | None = Field(alias="oidcOrg") + oidc_icon: str | None = Field(alias="oidcIcon") has_holdinvoice: bool = Field(alias="hasHoldinvoice") has_nodemanager: bool = Field(alias="hasNodemanager") show_nodemanager: bool = Field(alias="showNodemanager") @@ -1186,6 +1363,7 @@ class PublicSettings(BaseModel): webpush_pubkey: str | None = Field(alias="webpushPubkey") show_extensions: bool = Field(alias="showExtensions") show_audit: bool = Field(alias="showAudit") + show_block_explorer: bool = Field(alias="showBlockExplorer") show_admin: bool = Field(alias="showAdmin") ad_space: list[list[str]] = Field(alias="adSpace") ad_space_title: str = Field(alias="adSpaceTitle") @@ -1206,16 +1384,30 @@ class PublicSettings(BaseModel): default_card_rounded: bool = Field(alias="defaultCardRounded") default_card_gradient: bool = Field(alias="defaultCardGradient") default_card_shadow: bool = Field(alias="defaultCardShadow") + default_burger_menu_background: bool = Field(alias="defaultBurgerMenuBackground") denomination: str | None = Field() extensions: list[str] = Field() allowed_currencies: list[str] = Field(alias="allowedCurrencies") extensions_reviews_url: str = Field(alias="extensionsReviewsUrl") ext_builder: bool = Field(alias="extBuilder") nostr_configured: bool = Field(alias="nostrConfigured") + email_configured: bool = Field(alias="emailConfigured") telegram_configured: bool = Field(alias="telegramConfigured") wallet_featured_button_label: str | None = Field(alias="walletFeaturedButtonLabel") wallet_featured_button_url: str | None = Field(alias="walletFeaturedButtonUrl") wallet_featured_button_icon: str | None = Field(alias="walletFeaturedButtonIcon") + enable_wallet_lightning_addresses: bool = Field( + alias="enableWalletLightningAddresses" + ) + allow_custom_wallet_lightning_addresses: bool = Field( + alias="allowCustomWalletLightningAddresses" + ) + charge_wallet_lightning_addresses: bool = Field( + alias="chargeWalletLightningAddresses" + ) + wallet_lightning_address_price_sats: int = Field( + alias="walletLightningAddressPriceSats" + ) lnbits_user_activation_by_email: bool = Field(alias="userActivationByEmail") lnbits_user_activation_by_payment: bool = Field(alias="userActivationByPayment") lnbits_user_activation_by_invitation_code: bool = Field( @@ -1238,6 +1430,8 @@ class PublicSettings(BaseModel): authMethods=settings.auth_allowed_methods, keycloakOrg=settings.keycloak_client_custom_org, keycloakIcon=settings.keycloak_client_custom_icon, + oidcOrg=settings.oidc_client_custom_org, + oidcIcon=settings.oidc_client_custom_icon, hasHoldinvoice=settings.has_holdinvoice, hasNodemanager=settings.has_nodemanager, showNodemanager=settings.lnbits_node_ui and settings.has_nodemanager, @@ -1250,6 +1444,7 @@ class PublicSettings(BaseModel): webpushPubkey=settings.lnbits_webpush_pubkey, showExtensions=not settings.lnbits_extensions_deactivate_all, showAudit=settings.lnbits_audit_enabled, + showBlockExplorer=settings.lnbits_blockexplorer_enabled, showAdmin=settings.lnbits_admin_ui, customImage=settings.lnbits_custom_image, customBadge=settings.lnbits_custom_badge, @@ -1267,16 +1462,28 @@ class PublicSettings(BaseModel): defaultCardRounded=settings.lnbits_default_card_rounded, defaultCardGradient=settings.lnbits_default_card_gradient, defaultCardShadow=settings.lnbits_default_card_shadow, + defaultBurgerMenuBackground=settings.lnbits_default_burger_menu_background, denomination=settings.lnbits_denomination, extensions=list(settings.lnbits_installed_extensions_ids), allowedCurrencies=settings.lnbits_allowed_currencies, extensionsReviewsUrl=settings.lnbits_extensions_reviews_url, extBuilder=settings.lnbits_extensions_builder_activate_non_admins, nostrConfigured=settings.is_nostr_notifications_configured(), + emailConfigured=settings.is_email_notifications_configured(), telegramConfigured=settings.is_telegram_notifications_configured(), walletFeaturedButtonLabel=settings.lnbits_wallet_featured_button_label, walletFeaturedButtonUrl=settings.lnbits_wallet_featured_button_url, walletFeaturedButtonIcon=settings.lnbits_wallet_featured_button_icon, + enableWalletLightningAddresses=settings.ln_address_creation_allowed, + allowCustomWalletLightningAddresses=( + settings.lnbits_allow_custom_wallet_lightning_addresses + ), + chargeWalletLightningAddresses=( + settings.lnbits_charge_wallet_lightning_addresses + ), + walletLightningAddressPriceSats=( + settings.lnbits_wallet_lightning_address_price_sats + ), userActivationByEmail=settings.lnbits_user_activation_by_email, userActivationByPayment=settings.lnbits_user_activation_by_payment, userActivationByInvitationCode=settings.lnbits_user_activation_by_invitation_code, diff --git a/lnbits/static/bundle-components.min.js b/lnbits/static/bundle-components.min.js index 97a150e06..5c38feff2 100644 --- a/lnbits/static/bundle-components.min.js +++ b/lnbits/static/bundle-components.min.js @@ -1 +1 @@ -window.PageError={template:"#page-error"},window.PageHome={template:"#page-home",data:()=>({lnurl:"",authAction:"login",authMethod:"username-password",usr:"",username:"",reset_key:"",email:"",password:"",passwordRepeat:"",invitationCode:"",walletName:"",signup:!1}),computed:{showClaimLnurl(){return""!==this.lnurl&&this.g.settings.allowRegister&&"user-id-only"in this.g.settings.authMethods},formatDescription(){return LNbits.utils.convertMarkdown(this.g.settings.siteDescription)},isAccessTokenExpired(){return this.$q.cookies.get("is_access_token_expired")}},methods:{showLogin(e){this.authAction="login",this.authMethod=e},showRegister(e){this.user="",this.username=null,this.password=null,this.passwordRepeat=null,this.invitationCode=null,this.authAction="register",this.authMethod=e},async register(){try{await LNbits.api.register(this.username,this.email,this.password,this.passwordRepeat,this.invitationCode),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async reset(){try{await LNbits.api.reset(this.reset_key,this.password,this.passwordRepeat),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async login(){try{await LNbits.api.login(this.username,this.password),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async loginUsr(){try{await LNbits.api.loginUsr(this.usr),this.refreshAuthUser()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async refreshAuthUser(){try{const e=await LNbits.api.getAuthUser();this.g.user=LNbits.map.user(e.data),this.g.isPublicPage=!1,this.$router.push(`/wallet/${this.g.user.wallets[0].id}`)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},createWallet(){LNbits.api.createAccount(this.walletName).then(e=>{this.$router.push(`/wallet/${e.data.id}`)})},processing(){Quasar.Notify.create({timeout:0,message:"Processing...",icon:null})}},created(){if(this.g.isUserAuthorized)return this.refreshAuthUser();const e=new URLSearchParams(window.location.search);this.reset_key=e.get("reset_key"),this.reset_key&&(this.authAction="reset"),e.has("lightning")&&(this.lnurl=e.get("lightning"))}},window.PageExtensionBuilder={template:"#page-extension-builder",data:()=>({step:1,previewStepNames:{2:"settings",3:"owner_data",4:"client_data",5:"public_page"},extensionDataCleanString:"",extensionData:{id:"",name:"",stub_version:"",short_description:"",description:"",public_page:{has_public_page:!0,owner_data_fields:{name:"",description:""},client_data_fields:{public_inputs:[]},action_fields:{generate_action:!0,generate_payment_logic:!1,wallet_id:"",currency:"",amount:"",paid_flag:""}},preview_action:{is_preview_mode:!1,is_settings_preview:!1,is_owner_data_preview:!1,is_client_data_preview:!1,is_public_page_preview:!1},settings_data:{name:"Settings",enabled:!0,type:"user",fields:[]},owner_data:{name:"OwnerData",fields:[]},client_data:{enabled:!0,name:"ClientData",fields:[]}},sampleField:{name:"name",type:"str",label:"Name",hint:"",optional:!0,editable:!0,searchable:!0,sortable:!0},settingsTypes:[{label:"User Settings",value:"user"},{label:"Admin Settings",value:"admin"}],amountSource:[{label:"Client Data",value:"client_data"},{label:"Owner Data",value:"owner_data"}],extensionStubVersions:[]}),watch:{"extensionData.public_page.action_fields.amount_source":function(e,t){t&&e!==t&&(this.extensionData.public_page.action_fields.amount="")}},computed:{paymentActionAmountFields(){const e=this.extensionData.public_page.action_fields.amount_source;return e?"owner_data"===e?[""].concat(this.extensionData.owner_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):"client_data"===e?[""].concat(this.extensionData.client_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):void 0:[""]}},methods:{saveState(){this.$q.localStorage.set("lnbits.extension.builder.data",JSON.stringify(this.extensionData)),this.$q.localStorage.set("lnbits.extension.builder.step",this.step)},nextStep(){this.saveState(),this.$refs.stepper.next(),this.refreshPreview()},previousStep(){this.saveState(),this.$refs.stepper.previous(),this.refreshPreview()},onStepChange(){this.saveState(),this.refreshPreview()},clearAllData(){LNbits.utils.confirmDialog("Are you sure you want to clear all data? This action cannot be undone.").onOk(()=>{this.extensionData=JSON.parse(this.extensionDataCleanString),this.$q.localStorage.remove("lnbits.extension.builder.data"),this.$refs.stepper.set(1)})},exportJsonData(){!0!==Quasar.exportFile(`${this.extensionData.id||"data-export"}.json`,JSON.stringify(this.extensionData,null,2),"text/json")?Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null}):Quasar.Notify.create({message:"File downloaded!",color:"positive",icon:"file_download"})},onJsonDataInput(e){const t=e.target.files[0],a=new FileReader;a.onload=e=>{this.extensionData={...this.extensionData,...JSON.parse(e.target.result)},this.$refs.extensionDataInput.value=null,Quasar.Notify.create({message:"File loaded!",color:"positive",icon:"file_upload"})},a.readAsText(t)},async buildExtension(){try{const e={responseType:"blob"},t=await LNbits.api.request("POST","/api/v1/extension/builder/zip",null,this.extensionData,e),a=window.URL.createObjectURL(new Blob([t.data])),s=document.createElement("a");s.href=a,s.download=`${this.extensionData.id||"lnbits-extension"}.zip`,document.body.appendChild(s),s.click(),s.remove(),window.URL.revokeObjectURL(a)}catch(e){LNbits.utils.notifyApiError(e)}},async buildExtensionAndDeploy(){try{const{data:e}=await LNbits.api.request("POST","/api/v1/extension/builder/deploy",null,this.extensionData);Quasar.Notify.create({message:e.message||"Extension deployed!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async cleanCacheData(){LNbits.utils.confirmDialog("Are you sure you want to clean the cache data? This action cannot be undone.","Clean Cache Data").onOk(async()=>{try{const{data:e}=await LNbits.api.request("DELETE","/api/v1/extension/builder",null,{});Quasar.Notify.create({message:e.message||"Cache data cleaned!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})},async previewExtension(e){this.saveState();try{await LNbits.api.request("POST","/api/v1/extension/builder/preview",null,{...this.extensionData,preview_action:{is_preview_mode:!!e,is_settings_preview:"settings"===e,is_owner_data_preview:"owner_data"===e,is_client_data_preview:"client_data"===e,is_public_page_preview:"public_page"===e}}),this.refreshIframe(e)}catch(e){LNbits.utils.notifyApiError(e)}},async refreshPreview(){setTimeout(()=>{const e=this.previewStepNames[`${this.step}`]||"";e&&this.previewExtension(e)},100)},async getStubExtensionReleases(){try{const e="extension_builder_stub",{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e}/releases`);this.extensionStubVersions=t;const a=t.filter(e=>e.is_version_compatible);this.extensionData.stub_version=a[0]?a[0].version:""}catch(e){LNbits.utils.notifyApiError(e)}},refreshIframe(e=""){const t=this.$refs[`iframeStep${this.step}`];if(!t)return void console.warn("Extension Builder Preview iframe not loaded yet.");t.onload=()=>{const e=t.contentDocument||t.contentWindow.document;e.body.style.transform="scale(0.8)",e.body.style.transformOrigin="center top"};let a="Page"+this.extensionData.id.toLowerCase().split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("");"public_page"===e&&(a+="Public"),t.src=`/extensions/builder/preview?ext_id=${this.extensionData.id}&page=${e}&component=${a}`},initBasicData(){this.extensionData.owner_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.client_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.settings_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionDataCleanString=JSON.stringify(this.extensionData)}},created(){this.initBasicData();const e=this.$q.localStorage.getItem("lnbits.extension.builder.data");e&&(this.extensionData={...this.extensionData,...JSON.parse(e)});const t=+this.$q.localStorage.getItem("lnbits.extension.builder.step");t&&(this.step=t),this.g.user.admin&&this.getStubExtensionReleases(),setTimeout(()=>{this.refreshIframe()},1e3)}},window.PageExtensionBuilder={template:"#page-extension-builder",data:()=>({step:1,previewStepNames:{2:"settings",3:"owner_data",4:"client_data",5:"public_page"},extensionDataCleanString:"",extensionData:{id:"",name:"",stub_version:"",short_description:"",description:"",public_page:{has_public_page:!0,owner_data_fields:{name:"",description:""},client_data_fields:{public_inputs:[]},action_fields:{generate_action:!0,generate_payment_logic:!1,wallet_id:"",currency:"",amount:"",paid_flag:""}},preview_action:{is_preview_mode:!1,is_settings_preview:!1,is_owner_data_preview:!1,is_client_data_preview:!1,is_public_page_preview:!1},settings_data:{name:"Settings",enabled:!0,type:"user",fields:[]},owner_data:{name:"OwnerData",fields:[]},client_data:{enabled:!0,name:"ClientData",fields:[]}},sampleField:{name:"name",type:"str",label:"Name",hint:"",optional:!0,editable:!0,searchable:!0,sortable:!0},settingsTypes:[{label:"User Settings",value:"user"},{label:"Admin Settings",value:"admin"}],amountSource:[{label:"Client Data",value:"client_data"},{label:"Owner Data",value:"owner_data"}],extensionStubVersions:[]}),watch:{"extensionData.public_page.action_fields.amount_source":function(e,t){t&&e!==t&&(this.extensionData.public_page.action_fields.amount="")}},computed:{paymentActionAmountFields(){const e=this.extensionData.public_page.action_fields.amount_source;return e?"owner_data"===e?[""].concat(this.extensionData.owner_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):"client_data"===e?[""].concat(this.extensionData.client_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):void 0:[""]}},methods:{saveState(){this.$q.localStorage.set("lnbits.extension.builder.data",JSON.stringify(this.extensionData)),this.$q.localStorage.set("lnbits.extension.builder.step",this.step)},nextStep(){this.saveState(),this.$refs.stepper.next(),this.refreshPreview()},previousStep(){this.saveState(),this.$refs.stepper.previous(),this.refreshPreview()},onStepChange(){this.saveState(),this.refreshPreview()},clearAllData(){LNbits.utils.confirmDialog("Are you sure you want to clear all data? This action cannot be undone.").onOk(()=>{this.extensionData=JSON.parse(this.extensionDataCleanString),this.$q.localStorage.remove("lnbits.extension.builder.data"),this.$refs.stepper.set(1)})},exportJsonData(){!0!==Quasar.exportFile(`${this.extensionData.id||"data-export"}.json`,JSON.stringify(this.extensionData,null,2),"text/json")?Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null}):Quasar.Notify.create({message:"File downloaded!",color:"positive",icon:"file_download"})},onJsonDataInput(e){const t=e.target.files[0],a=new FileReader;a.onload=e=>{this.extensionData={...this.extensionData,...JSON.parse(e.target.result)},this.$refs.extensionDataInput.value=null,Quasar.Notify.create({message:"File loaded!",color:"positive",icon:"file_upload"})},a.readAsText(t)},async buildExtension(){try{const e={responseType:"blob"},t=await LNbits.api.request("POST","/api/v1/extension/builder/zip",null,this.extensionData,e),a=window.URL.createObjectURL(new Blob([t.data])),s=document.createElement("a");s.href=a,s.download=`${this.extensionData.id||"lnbits-extension"}.zip`,document.body.appendChild(s),s.click(),s.remove(),window.URL.revokeObjectURL(a)}catch(e){LNbits.utils.notifyApiError(e)}},async buildExtensionAndDeploy(){try{const{data:e}=await LNbits.api.request("POST","/api/v1/extension/builder/deploy",null,this.extensionData);Quasar.Notify.create({message:e.message||"Extension deployed!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async cleanCacheData(){LNbits.utils.confirmDialog("Are you sure you want to clean the cache data? This action cannot be undone.","Clean Cache Data").onOk(async()=>{try{const{data:e}=await LNbits.api.request("DELETE","/api/v1/extension/builder",null,{});Quasar.Notify.create({message:e.message||"Cache data cleaned!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})},async previewExtension(e){this.saveState();try{await LNbits.api.request("POST","/api/v1/extension/builder/preview",null,{...this.extensionData,preview_action:{is_preview_mode:!!e,is_settings_preview:"settings"===e,is_owner_data_preview:"owner_data"===e,is_client_data_preview:"client_data"===e,is_public_page_preview:"public_page"===e}}),this.refreshIframe(e)}catch(e){LNbits.utils.notifyApiError(e)}},async refreshPreview(){setTimeout(()=>{const e=this.previewStepNames[`${this.step}`]||"";e&&this.previewExtension(e)},100)},async getStubExtensionReleases(){try{const e="extension_builder_stub",{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e}/releases`);this.extensionStubVersions=t;const a=t.filter(e=>e.is_version_compatible);this.extensionData.stub_version=a[0]?a[0].version:""}catch(e){LNbits.utils.notifyApiError(e)}},refreshIframe(e=""){const t=this.$refs[`iframeStep${this.step}`];if(!t)return void console.warn("Extension Builder Preview iframe not loaded yet.");t.onload=()=>{const e=t.contentDocument||t.contentWindow.document;e.body.style.transform="scale(0.8)",e.body.style.transformOrigin="center top"};let a="Page"+this.extensionData.id.toLowerCase().split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("");"public_page"===e&&(a+="Public"),t.src=`/extensions/builder/preview?ext_id=${this.extensionData.id}&page=${e}&component=${a}`},initBasicData(){this.extensionData.owner_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.client_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.settings_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionDataCleanString=JSON.stringify(this.extensionData)}},created(){this.initBasicData();const e=this.$q.localStorage.getItem("lnbits.extension.builder.data");e&&(this.extensionData={...this.extensionData,...JSON.parse(e)});const t=+this.$q.localStorage.getItem("lnbits.extension.builder.step");t&&(this.step=t),this.g.user.admin&&this.getStubExtensionReleases(),setTimeout(()=>{this.refreshIframe()},1e3)}},window.PageExtensionBuilderPreview={template:"#page-extension-builder-preview",mixins:[windowMixin],watch:{name:"reload"},data:()=>({extId:"",pageName:"",componentName:null}),methods:{async reload(){await LNbits.utils.loadTemplate(`/extensions/builder/preview/${this.extId}/template?page_name=${this.pageName}`),await LNbits.utils.loadScript(`/extensions/builder/preview/${this.extId}/component?page_name=${this.pageName}`),this._component=window[this.componentName],console.log("LNbits preview reloaded componentName:",this.componentName,!!this._component),this.$forceUpdate()}},async created(){const e=new URLSearchParams(window.location.search);this.extId=e.get("ext_id")||"",this.pageName=e.get("page")||"",this.componentName=e.get("component")||"",await this.reload()},render(){return this._component?Vue.h(this._component):Vue.h("div","Loading...")}},window.PageExtensions={template:"#page-extensions",data(){return{extbuilderEnabled:!1,slide:0,fullscreen:!1,autoplay:!0,searchTerm:"",tab:"installed",manageExtensionTab:"releases",filteredExtensions:[],updatableExtensions:[],showUninstallDialog:!1,showManageExtensionDialog:!1,showExtensionDetailsDialog:!1,showDropDbDialog:!1,showPayToEnableDialog:!1,showUpdateAllDialog:!1,dropDbExtensionId:"",selectedExtension:null,selectedImage:null,selectedExtensionDetails:null,selectedExtensionRepos:null,selectedRelease:null,uninstallAndDropDb:!1,maxStars:5,paylinkWebsocket:null,searchToggle:!1,reviewsUrl:null,reviewsDialog:{show:!1,extension:null,loading:!1,submitting:!1,form:{name:"",rating:0,comment:""},error:null},reviews:[],reviewsTable:{loading:!1,columns:[{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"comment",align:"left",label:this.$t("Comment"),field:"comment"},{name:"created_at",align:"left",label:this.$t("Date"),field:"created_at"},{name:"rating",align:"right",label:"Rating",field:"rating"}],pagination:{rowsPerPage:5,sortBy:"created_at",descending:!0,page:1}},paymentDialog:{show:!1,invoice:"",hash:""}}},watch:{searchTerm(e){this.filterExtensions(e,this.tab)},tab(e){this.filterExtensions(this.searchTerm,e)}},methods:{filterExtensions(e,t){var a;this.filteredExtensions=this.extensions.filter(e=>"all"!==t||!e.isInstalled).filter(e=>"installed"!==t||e.isInstalled).filter(e=>"installed"!==t||(!!e.isActive||!!this.g.user.admin)).filter(e=>"featured"!==t||e.isFeatured).filter((a=e,function(e){return e.name.toLowerCase().includes(a.toLowerCase())||e.shortDescription?.toLowerCase().includes(a.toLowerCase())})).map(e=>({...e,details_link:e.installedRelease?.details_link||e.latestRelease?.details_link}))},async installExtension(e){this.unsubscribeFromPaylinkWs(),this.selectedExtension.inProgress=!0,this.showManageExtensionDialog=!1,e.payment_hash=e.payment_hash||this.getPaylinkHash(e.pay_link),LNbits.api.request("POST","/api/v1/extension",this.g.user.wallets[0].adminkey,{ext_id:this.selectedExtension.id,archive:e.archive,source_repo:e.source_repo,payment_hash:e.payment_hash,version:e.version}).then(t=>{this.selectedExtension.inProgress=!1;const a=this.extensions.find(e=>e.id===this.selectedExtension.id);a.isAvailable=!0,a.isInstalled=!0,a.installedRelease=e,this.toggleExtension(a),a.inProgress=!1,this.selectedExtension=a,this.extensions=this.extensions.concat([]),this.tab="installed"}).catch(e=>{console.warn(e),this.selectedExtension.inProgress=!1,LNbits.utils.notifyApiError(e)})},async uninstallExtension(){this.showManageExtensionDialog=!1,this.showUninstallDialog=!1,this.selectedExtension.inProgress=!0,LNbits.api.request("DELETE",`/api/v1/extension/${this.selectedExtension.id}`,this.g.user.wallets[0].adminkey).then(e=>{const t=this.extensions.find(e=>e.id===this.selectedExtension.id);t.isAvailable=!1,t.isInstalled=!1,t.inProgress=!1,t.installedRelease=null,this.filteredExtensions=this.filteredExtensions.filter(e=>e.id!==t.id),Quasar.Notify.create({type:"positive",message:"Extension uninstalled!"}),this.uninstallAndDropDb&&this.showDropDb()}).catch(e=>{LNbits.utils.notifyApiError(e),extension.inProgress=!1})},async dropExtensionDb(){const e=this.selectedExtension;this.showManageExtensionDialog=!1,this.showDropDbDialog=!1,this.dropDbExtensionId="",e.inProgress=!0,LNbits.api.request("DELETE",`/api/v1/extension/${e.id}/db`,this.g.user.wallets[0].adminkey).then(t=>{e.installedRelease=null,e.inProgress=!1,e.hasDatabaseTables=!1,Quasar.Notify.create({type:"positive",message:"Extension DB deleted!"})}).catch(t=>{LNbits.utils.notifyApiError(t),e.inProgress=!1})},toggleExtension(e){const t=e.isActive?"activate":"deactivate";LNbits.api.request("PUT",`/api/v1/extension/${e.id}/${t}`,this.g.user.wallets[0].adminkey).then(a=>{Quasar.Notify.create({timeout:2e3,type:"positive",message:`Extension '${e.id}' ${t}d!`})}).catch(t=>{LNbits.utils.notifyApiError(t),e.isActive=!1,e.inProgress=!1})},async enableExtensionForUser(e){e.isPaymentRequired?this.showPayToEnable(e):this.enableExtension(e)},async enableExtension(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/enable`,this.g.user.wallets[0].adminkey).then(t=>{this.g.user.extensions=this.g.user.extensions.concat([e.id]),Quasar.Notify.create({type:"positive",message:"Extension enabled!"})}).catch(e=>{console.warn(e),LNbits.utils.notifyApiError(e)})},disableExtension(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/disable`,this.g.user.wallets[0].adminkey).then(t=>{this.g.user.extensions=this.g.user.extensions.filter(t=>t!==e.id),Quasar.Notify.create({type:"positive",message:"Extension disabled!"})}).catch(e=>{console.warn(error),LNbits.utils.notifyApiError(e)})},showPayToEnable(e){this.selectedExtension=e,this.selectedExtension.payToEnable.paidAmount=e.payToEnable.amount,this.selectedExtension.payToEnable.showQRCode=!1,this.showPayToEnableDialog=!0},updatePayToInstallData(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/sell`,this.g.user.wallets[0].adminkey,{required:e.payToEnable.required,amount:e.payToEnable.amount,wallet:e.payToEnable.wallet}).then(e=>{Quasar.Notify.create({type:"positive",message:"Payment info updated!"}),this.showManageExtensionDialog=!1}).catch(t=>{LNbits.utils.notifyApiError(t),e.inProgress=!1})},showUninstall(){this.showManageExtensionDialog=!1,this.showUninstallDialog=!0,this.uninstallAndDropDb=!1},showDropDb(){this.showDropDbDialog=!0},async showManageExtension(e){this.selectedExtension=e,this.selectedRelease=null,this.selectedExtensionRepos=null,this.manageExtensionTab="releases",this.showManageExtensionDialog=!0;try{const{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e.id}/releases`);this.selectedExtensionRepos=t.reduce((e,t)=>(e[t.source_repo]=e[t.source_repo]||{releases:[],isInstalled:!1,repo:t.repo},t.inProgress=!1,t.error=null,t.loaded=!1,t.isInstalled=this.isInstalledVersion(this.selectedExtension,t),t.isInstalled&&(e[t.source_repo].isInstalled=!0),t.pay_link&&(t.requiresPayment=!0,t.paidAmount=t.cost_sats,t.payment_hash=this.getPaylinkHash(t.pay_link)),e[t.source_repo].releases.push(t),e),{})}catch(t){LNbits.utils.notifyApiError(t),e.inProgress=!1}},async showExtensionDetails(e,t){if(t){this.selectedExtension=this.extensions.find(t=>t.id===e)||this.selectedExtension,this.selectedExtensionDetails=null,this.showExtensionDetailsDialog=!0,this.slide=0,this.fullscreen=!1;try{const{data:a}=await LNbits.api.request("GET",`/api/v1/extension/${e}/details?details_link=${t}`);this.selectedExtensionDetails=a,this.selectedExtensionDetails.description_md=LNbits.utils.convertMarkdown(a.description_md)}catch(e){console.warn(e)}}},async payAndInstall(e){try{this.selectedExtension.inProgress=!0,this.showManageExtensionDialog=!1;const t=await this.requestPaymentForInstall(this.selectedExtension.id,e);this.rememberPaylinkHash(e.pay_link,t.payment_hash);const a=this.g.user.wallets.find(t=>t.id===e.wallet),{data:s}=await LNbits.api.payInvoice(a,t.payment_request);e.payment_hash=s.payment_hash,await this.installExtension(e)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.selectedExtension.inProgress=!1}},async payAndEnable(e){try{const t=await this.requestPaymentForEnable(e.id,e.payToEnable.paidAmount),a=this.g.user.wallets.find(t=>t.id===e.payToEnable.paymentWallet),{data:s}=await LNbits.api.payInvoice(a,t.payment_request);this.enableExtension(e),this.showPayToEnableDialog=!1}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async showInstallQRCode(e){this.selectedRelease=e;try{const t=await this.requestPaymentForInstall(this.selectedExtension.id,e);this.selectedRelease.paymentRequest=t.payment_request,this.selectedRelease.payment_hash=t.payment_hash,this.selectedRelease=_.clone(this.selectedRelease),this.rememberPaylinkHash(this.selectedRelease.pay_link,this.selectedRelease.payment_hash),this.subscribeToPaylinkWs(this.selectedRelease.pay_link,t.payment_hash)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async showEnableQRCode(e){try{e.payToEnable.showQRCode=!0,this.selectedExtension=_.clone(e);const t=await this.requestPaymentForEnable(e.id,e.payToEnable.paidAmount);e.payToEnable.paymentRequest=t.payment_request,this.selectedExtension=_.clone(e);const a=new URL(window.location);a.protocol="https:"===a.protocol?"wss":"ws",a.pathname=`/api/v1/ws/${t.payment_hash}`;const s=new WebSocket(a);s.addEventListener("message",async({data:t})=>{!1===JSON.parse(t).pending&&(Quasar.Notify.create({type:"positive",message:"Invoice Paid!"}),this.enableExtension(e),s.close())})}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async requestPaymentForInstall(e,t){const{data:a}=await LNbits.api.request("PUT",`/api/v1/extension/${e}/invoice/install`,null,{ext_id:e,archive:t.archive,source_repo:t.source_repo,cost_sats:t.paidAmount,version:t.version});return a},async requestPaymentForEnable(e,t){const{data:a}=await LNbits.api.request("PUT",`/api/v1/extension/${e}/invoice/enable`,null,{amount:t});return a},clearHangingInvoice(e){this.forgetPaylinkHash(e.pay_link),e.payment_hash=null},rememberPaylinkHash(e,t){this.$q.localStorage.set(`lnbits.extensions.paylink.${e}`,t)},getPaylinkHash(e){return this.$q.localStorage.getItem(`lnbits.extensions.paylink.${e}`)},forgetPaylinkHash(e){this.$q.localStorage.remove(`lnbits.extensions.paylink.${e}`)},subscribeToPaylinkWs(e,t){const a=new URL(`${e}/${t}`);a.protocol="https:"===a.protocol?"wss":"ws",this.paylinkWebsocket=new WebSocket(a),this.paylinkWebsocket.addEventListener("message",async({data:e})=>{JSON.parse(e).paid?(Quasar.Notify.create({type:"positive",message:"Invoice Paid!"}),this.installExtension(this.selectedRelease)):Quasar.Notify.create({type:"warning",message:"Invoice tracking lost!"})})},unsubscribeFromPaylinkWs(){try{this.paylinkWebsocket&&this.paylinkWebsocket.close()}catch(e){console.warn(e)}},hasNewVersion(e){if(e.installedRelease&&e.latestRelease)return e.installedRelease.version!==e.latestRelease.version},isInstalledVersion(e,t){if(e.installedRelease)return e.installedRelease.source_repo===t.source_repo&&e.installedRelease.version===t.version},getReleaseIcon:e=>e.is_version_compatible?e.isInstalled?"download_done":"download":"block",getReleaseIconColor:e=>e.is_version_compatible?e.isInstalled?"text-green":"":"text-red",async getGitHubReleaseDetails(e){if(!e.is_github_release||e.loaded)return;const[t,a]=e.source_repo.split("/");e.inProgress=!0;try{const{data:s}=await LNbits.api.request("GET",`/api/v1/extension/release/${t}/${a}/${e.version}`);e.loaded=!0,e.is_version_compatible=s.is_version_compatible,e.min_lnbits_version=s.min_lnbits_version,e.warning=s.warning}catch(t){console.warn(t),e.error=t,LNbits.utils.notifyApiError(t)}finally{e.inProgress=!1}},async selectAllUpdatableExtensionss(){this.updatableExtensions.forEach(e=>e.selectedForUpdate=!0)},async updateSelectedExtensions(){let e=0;for(const t of this.updatableExtensions)try{if(!t.selectedForUpdate)continue;t.inProgress=!0,await LNbits.api.request("POST","/api/v1/extension",null,{ext_id:t.id,archive:t.latestRelease.archive,source_repo:t.latestRelease.source_repo,payment_hash:t.latestRelease.payment_hash,version:t.latestRelease.version}),e++,t.isAvailable=!0,t.isInstalled=!0,t.isUpgraded=!0,t.inProgress=!1,t.installedRelease=t.latestRelease,t.isActive=!0,this.toggleExtension(t)}catch(e){console.warn(e),Quasar.Notify.create({type:"negative",message:`Failed to update ${t.id}!`})}finally{t.inProgress=!1}Quasar.Notify.create({type:e?"positive":"warning",message:`${e||"No"} extensions updated!`}),this.showUpdateAllDialog=!1},formatAvg(e){const t=Number(e||0);return Math.round(t/2/100*2)/2},async loadReviewStats(){if(this.reviewsUrl)try{const{data:e}=await LNbits.api.request("GET","/api/v1/extension/reviews/tags"),t={};e.forEach(e=>{t[e.tag]=e}),this.extensions.forEach(e=>{e.reviewStats=t[e.id]||null}),this.filterExtensions(this.searchTerm,this.tab)}catch(e){console.warn(e)}else console.info("Extension reviews are not configured")},async openReviews(e){const t=e||(this.selectedExtensionDetails?this.extensions.find(e=>e.id===this.selectedExtensionDetails.id):null);t&&(this.reviewsUrl?(this.reviewsDialog.extension=t,this.selectedExtension=e,this.reviewsDialog.show=!0,await this.getTagReviews()):Quasar.Notify.create({type:"warning",message:this.$t("reviews_url_not_configured")}))},async getTagReviews(e){if(this.reviewsUrl)try{this.reviewsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.reviewsTable,e),{data:a}=await LNbits.api.request("GET",`/api/v1/extension/reviews/${this.selectedExtension.id}?${t}`);this.reviews=a.data,this.reviewsTable.pagination.rowsNumber=a.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.reviewsTable.loading=!1}else Quasar.Notify.create({type:"warning",message:this.$t("reviews_url_not_configured")})},formatReviewDate(e){if(!e)return"";const t=Number(e);return Number.isNaN(t)?this.utils.formatDate(e):this.utils.formatTimestamp(t)},async submitReview(){if(this.reviewsDialog.extension&&this.reviewsUrl){this.reviewsDialog.submitting=!0;try{const e={tag:this.reviewsDialog.extension.id,name:this.reviewsDialog.form.name,rating:100*this.reviewsDialog.form.rating,comment:this.reviewsDialog.form.comment},{data:t}=await LNbits.api.request("PUT","/api/v1/extension/reviews",null,e);t.payment_request?this.openInvoiceDialog(t.payment_request,t.payment_hash):(Quasar.Notify.create({type:"positive",message:"Review submitted"}),this.resetReviewForm(),await this.getTagReviews(),await this.loadReviewStats())}catch(e){LNbits.utils.notifyApiError(e)}finally{this.reviewsDialog.submitting=!1}}},openInvoiceDialog(e,t){this.paymentDialog.invoice=e,this.paymentDialog.hash=t,this.paymentDialog.show=!0,this.listenForPayment(t)},resetReviewForm(){this.reviewsDialog.form={name:"",rating:0,comment:""},this.paymentDialog={show:!1,invoice:"",hash:""}},listenForPayment(e){try{const t=new URL(this.reviewsUrl);t.protocol="https:"===t.protocol?"wss:":"ws:",t.pathname=`/api/v1/ws/${e}`;const a=new WebSocket(t);a.addEventListener("message",async()=>{Quasar.Notify.create({type:"positive",message:this.$t("reviews_invoice_paid")}),this.paymentDialog.show=!1,this.resetReviewForm(),setTimeout(async()=>{await this.getTagReviews()},1e3),await this.loadReviewStats(),a.close()})}catch(e){console.warn(e)}},async fetchAllExtensions(){try{const{data:e}=await LNbits.api.request("GET","/api/v1/extension/all");return e}catch(e){return console.warn(e),LNbits.utils.notifyApiError(e),[]}}},async created(){this.extensions=await this.fetchAllExtensions(),this.extbuilderEnabled=this.g.user.admin||this.g.settings.extBuilder,this.reviewsUrl=this.g.settings.extensionsReviewsUrl,0===this.g.user.extensions.length&&(this.tab="all");const e=window.location.hash.replace("#",""),t=this.extensions.find(t=>t.id===e);t&&(this.searchTerm=t.id,t.isInstalled&&(this.tab="installed")),this.updatableExtensions=this.extensions.filter(e=>this.hasNewVersion(e)),await this.loadReviewStats(),this.filterExtensions(this.searchTerm,this.tab)}},window.PageFirstInstall={template:"#page-first-install",data:()=>({loginData:{isPwd:!0,isPwdRepeat:!0,username:"",password:"",passwordRepeat:"",firstInstallToken:""}}),computed:{checkPasswordsMatch(){return this.loginData.password!==this.loginData.passwordRepeat}},methods:{setPassword(){LNbits.api.request("PUT","/api/v1/auth/first_install",null,{username:this.loginData.username,password:this.loginData.password,password_repeat:this.loginData.passwordRepeat,first_install_token:this.loginData.firstInstallToken}).then(async()=>{const e=await LNbits.api.getAuthUser();this.g.user=LNbits.map.user(e.data),this.g.isPublicPage=!1,this.$router.push("/admin")}).catch(this.utils.notifyApiError)}},created(){const e=new URLSearchParams(window.location.search);this.loginData.firstInstallToken=e.get("token")||""}},window.PagePayments={template:"#page-payments",data:()=>({payments:[],dailyChartData:[],searchDate:{from:null,to:null},searchData:{wallet_id:null,payment_hash:null,memo:null,internal_memo:null},statusFilters:{success:!0,pending:!0,failed:!0,incoming:!0,outgoing:!0},chartData:{showPaymentStatus:!0,showPaymentTags:!0,showBalance:!0,showWalletsSize:!1,showBalanceInOut:!1,showPaymentCountInOut:!1},searchOptions:{status:[]},paymentsTable:{columns:[{name:"status",align:"left",label:"Status",field:"status",sortable:!1},{name:"created_at",align:"left",label:"Created At",field:"created_at",sortable:!0},{name:"amount",align:"right",label:"Amount",field:"amount",sortable:!0},{name:"amountFiat",align:"right",label:"Fiat",field:"amountFiat",sortable:!1},{name:"fee_sats",align:"left",label:"Fee",field:"fee_sats",sortable:!0},{name:"tag",align:"left",label:"Tag",field:"tag",sortable:!1},{name:"memo",align:"left",label:"Memo",field:"memo",sortable:!1,max_length:20},{name:"internal_memo",align:"left",label:"Internal Memo",field:"internal_memo",sortable:!1,max_length:20},{name:"wallet_id",align:"left",label:"Wallet (ID)",field:"wallet_id",sortable:!1},{name:"payment_hash",align:"left",label:"Payment Hash",field:"payment_hash",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:25,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},chartsReady:!1,showDetails:!1,paymentDetails:null,lnbitsBalance:0}),async mounted(){this.chartsReady=!0,await this.$nextTick(),this.initCharts(),await this.fetchPayments()},computed:{},methods:{async fetchPayments(e){const t=Object.entries(this.searchData).reduce((e,[t,a])=>a?(e[t]=a,e):e,{});delete t["time[ge]"],delete t["time[le]"],this.searchDate.from&&(t["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(t["time[le]"]=this.searchDate.to+"T23:59:59"),this.paymentsTable.filter=t;try{const t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e),{data:a}=await LNbits.api.request("GET",`/api/v1/payments/all/paginated?${t}`);this.paymentsTable.pagination.rowsNumber=a.total,this.payments=a.data.map(e=>(e.extra&&e.extra.tag&&(e.tag=e.extra.tag),e.timeFrom=moment.utc(e.created_at).local().fromNow(),e.outgoing=e.amount<0,e.amount=new Intl.NumberFormat(this.g.locale).format(e.amount/1e3)+" sats",e.extra?.wallet_fiat_amount&&(e.amountFiat=this.formatCurrency(e.extra.wallet_fiat_amount,e.extra.wallet_fiat_currency)),e.extra?.internal_memo&&(e.internal_memo=e.extra.internal_memo),e.fee_sats=new Intl.NumberFormat(this.g.locale).format(e.fee/1e3)+" sats",e))}catch(e){console.error(e),LNbits.utils.notifyApiError(e)}finally{this.updateCharts(e)}},async searchPaymentsBy(e,t){e&&(this.searchData[e]=t),await this.fetchPayments()},clearDateSeach(){this.searchDate={from:null,to:null},delete this.paymentsTable.filter["time[ge]"],delete this.paymentsTable.filter["time[le]"],this.fetchPayments()},searchByDate(){"string"==typeof this.searchDate&&(this.searchDate={from:this.searchDate,to:this.searchDate}),this.searchDate.from&&(this.paymentsTable.filter["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(this.paymentsTable.filter["time[le]"]=this.searchDate.to+"T23:59:59"),this.fetchPayments()},handleFilterChanged(){const{success:e,pending:t,failed:a,incoming:s,outgoing:i}=this.statusFilters;delete this.searchData["status[ne]"],delete this.searchData["status[eq]"],e&&t&&a||(e&&t?this.searchData["status[ne]"]="failed":e&&a?this.searchData["status[ne]"]="pending":a&&t?this.searchData["status[ne]"]="success":e?this.searchData["status[eq]"]="success":t?this.searchData["status[eq]"]="pending":a&&(this.searchData["status[eq]"]="failed")),delete this.searchData["amount[ge]"],delete this.searchData["amount[le]"],s&&i||(s?this.searchData["amount[ge]"]="0":i&&(this.searchData["amount[le]"]="0")),this.fetchPayments()},showDetailsToggle(e){return this.paymentDetails=e,this.showDetails=!this.showDetails},formatCurrency(e,t){try{return LNbits.utils.formatCurrency(e,t)}catch(t){return console.error(t),`${e} ???`}},shortify:(e,t=10)=>(valueLength=(e||"").length,valueLength<=t?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`),async updateCharts(e){let t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e);try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/count?${t}&count_by=status`);e.sort((e,t)=>e.field-t.field).reverse(),this.searchOptions.status=e.map(e=>e.field),this.paymentsStatusChart.data.datasets[0].data=e.map(e=>e.total),this.paymentsStatusChart.data.labels=[...this.searchOptions.status],this.paymentsStatusChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/wallets?${t}`),a=e.map(e=>e.balance/e.payments_count),s=Math.min(...a),i=Math.max(...a),n=e=>Math.floor(3+22*(e-s)/(i-s)),l=this.randomColors(20),o=e.map((e,t)=>({data:[{x:e.payments_count,y:e.balance,r:n(Math.max(e.balance/e.payments_count,5))}],label:e.wallet_name,wallet_id:e.wallet_id,backgroundColor:l[t%100],hoverOffset:4}));this.paymentsWalletsChart.data.datasets=o,this.paymentsWalletsChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/count?${t}&count_by=tag`);this.searchOptions.tag=e.map(e=>e.field),this.searchOptions.status.sort(),this.paymentsTagsChart.data.datasets[0].data=e.map(e=>e.total),this.paymentsTagsChart.data.labels=e.map(e=>e.field||"core"),this.paymentsTagsChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const t=Object.entries(this.searchData).reduce((e,[t,a])=>a?(e[t]=a,e):e,{}),a={...this.paymentsTable,filter:t},s=LNbits.utils.prepareFilterQuery(a,e);let{data:i}=await LNbits.api.request("GET",`/api/v1/payments/stats/daily?${s}`);const n=this.searchDate.from+"T00:00:00",l=this.searchDate.to+"T23:59:59";this.lnbitsBalance=i.length?i[i.length-1].balance:0,i=i.filter(e=>this.searchDate.from&&this.searchDate.to?e.date>=n&&e.date<=l:this.searchDate.from?e.date>=n:!this.searchDate.to||e.date<=l),this.paymentsDailyChart.data.datasets=[{label:"Balance",data:i.map(e=>e.balance),pointStyle:!1,borderWidth:2,tension:.7,fill:1},{label:"Fees",data:i.map(e=>e.fee),pointStyle:!1,borderWidth:1,tension:.4,fill:1}],this.paymentsDailyChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsDailyChart.update(),this.paymentsBalanceInOutChart.data.datasets=[{label:"Incoming Payments Balance",data:i.map(e=>e.balance_in)},{label:"Outgoing Payments Balance",data:i.map(e=>e.balance_out)}],this.paymentsBalanceInOutChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsBalanceInOutChart.update(),this.paymentsCountInOutChart.data.datasets=[{label:"Incoming Payments Count",data:i.map(e=>e.count_in)},{label:"Outgoing Payments Count",data:i.map(e=>-e.count_out)}],this.paymentsCountInOutChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsCountInOutChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async initCharts(){const e=this.$q.localStorage.getItem("lnbits.payments.chartData")||{};this.chartData={...this.chartData,...e},this.chartsReady?(this.paymentsStatusChart=new Chart(this.$refs.paymentsStatusChart.getContext("2d"),{type:"doughnut",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchPaymentsBy("status",a.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(0, 205, 86)","rgb(64, 72, 78)","rgb(255, 99, 132)"],hoverOffset:4}]}}),this.paymentsWalletsChart=new Chart(this.$refs.paymentsWalletsChart.getContext("2d"),{type:"bubble",options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},title:{display:!1}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].datasetIndex;this.searchPaymentsBy("wallet_id",a.data.datasets[e].wallet_id)}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(20),hoverOffset:4}]}}),this.paymentsTagsChart=new Chart(this.$refs.paymentsTagsChart.getContext("2d"),{type:"pie",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!1,title:{display:!1,text:"Tags"}}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchPaymentsBy("tag",a.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(10),hoverOffset:4}]}}),this.paymentsDailyChart=new Chart(this.$refs.paymentsDailyChart.getContext("2d"),{type:"line",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:"Tags"}}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(10),hoverOffset:4}]}}),this.paymentsBalanceInOutChart=new Chart(this.$refs.paymentsBalanceInOutChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:"Tags"}}},scales:{x:{stacked:!0},y:{stacked:!0}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(50),hoverOffset:4}]}}),this.paymentsCountInOutChart=new Chart(this.$refs.paymentsCountInOutChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:""}}},scales:{x:{stacked:!0},y:{stacked:!0}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(80),hoverOffset:4}]}})):console.warn("Charts are not ready yet. Initialization delayed.")},saveChartsPreferences(){this.$q.localStorage.set("lnbits.payments.chartData",this.chartData)},randomColors(e=1){const t=[];for(let a=1;a<=10;a++)for(let s=1;s<=10;s++)t.push(`rgb(${s*e*33%200}, ${71*(a+s+e)%255}, ${(a+30*e)%255})`);return t}}},window.PageNode={template:"#page-node",config:{globalProperties:{LNbits:LNbits,msg:"hello"}},data(){return{isSuperUser:!1,wallet:{},tab:"dashboard",payments:1e3,info:{},channel_stats:{},channels:{data:[],filter:""},activeBalance:{},ranks:{},peers:{data:[],filter:""},connectPeerDialog:{show:!1,data:{}},setFeeDialog:{show:!1,data:{fee_ppm:0,fee_base_msat:0}},openChannelDialog:{show:!1,data:{}},closeChannelDialog:{show:!1,data:{}},nodeInfoDialog:{show:!1,data:{}},transactionDetailsDialog:{show:!1,data:{}},states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}],stateFilters:[{label:"Active",value:"active"},{label:"Pending",value:"pending"}],paymentsTable:{data:[],columns:[{name:"pending",label:""},{name:"date",align:"left",label:this.$t("date"),field:"date",sortable:!0},{name:"sat",align:"right",label:this.$t("amount"),field:e=>this.formatMsat(e.amount),sortable:!0},{name:"fee",align:"right",label:this.$t("fee"),field:"fee"},{name:"destination",align:"right",label:"Destination",field:"destination"},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"}],pagination:{rowsPerPage:10,page:1,rowsNumber:10},filter:null},invoiceTable:{data:[],columns:[{name:"pending",label:""},{name:"paid_at",field:"paid_at",align:"left",label:"Paid at",sortable:!0},{name:"expiry",label:this.$t("expiry"),field:"expiry",align:"left",sortable:!0},{name:"amount",label:this.$t("amount"),field:e=>this.formatMsat(e.amount),sortable:!0},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"}],pagination:{rowsPerPage:10,page:1,rowsNumber:10},filter:null}}},created(){this.getInfo(),this.get1MLStats()},watch:{tab(e){"transactions"!==e||this.paymentsTable.data.length?"channels"!==e||this.channels.data.length||(this.getChannels(),this.getPeers()):(this.getPayments(),this.getInvoices())}},computed:{checkChanges(){return!_.isEqual(this.settings,this.formData)},filteredChannels(){return this.stateFilters?this.channels.data.filter(e=>this.stateFilters.find(({value:t})=>t==e.state)):this.channels.data},totalBalance(){return this.filteredChannels.reduce((e,t)=>(e.local_msat+=t.balance.local_msat,e.remote_msat+=t.balance.remote_msat,e.total_msat+=t.balance.total_msat,e),{local_msat:0,remote_msat:0,total_msat:0})}},methods:{formatMsat:e=>LNbits.utils.formatMsat(e),nodeApi(e,t,a){const s=new URLSearchParams(a?.query);return LNbits.api.request(e,`/node/api/v1${t}?${s}`,{},a?.data).catch(e=>{LNbits.utils.notifyApiError(e)})},getChannel(e){return this.nodeApi("GET",`/channels/${e}`).then(e=>{this.setFeeDialog.data.fee_ppm=e.data.fee_ppm,this.setFeeDialog.data.fee_base_msat=e.data.fee_base_msat})},getChannels(){return this.nodeApi("GET","/channels").then(e=>{this.channels.data=e.data})},getInfo(){return this.nodeApi("GET","/info").then(e=>{this.info=e.data,this.channel_stats=e.data.channel_stats}).catch(()=>{this.info={},this.channel_stats={}})},get1MLStats(){return this.nodeApi("GET","/rank").then(e=>{this.ranks=e.data}).catch(()=>{this.ranks={}})},getPayments(e){e&&(this.paymentsTable.pagination=e.pagination);let t=this.paymentsTable.pagination;const a={limit:t.rowsPerPage,offset:(t.page-1)*t.rowsPerPage??0};return this.nodeApi("GET","/payments",{query:a}).then(e=>{this.paymentsTable.data=e.data.data,this.paymentsTable.pagination.rowsNumber=e.data.total})},getInvoices(e){e&&(this.invoiceTable.pagination=e.pagination);let t=this.invoiceTable.pagination;const a={limit:t.rowsPerPage,offset:(t.page-1)*t.rowsPerPage??0};return this.nodeApi("GET","/invoices",{query:a}).then(e=>{this.invoiceTable.data=e.data.data,this.invoiceTable.pagination.rowsNumber=e.data.total})},getPeers(){return this.nodeApi("GET","/peers").then(e=>{this.peers.data=e.data})},connectPeer(){this.nodeApi("POST","/peers",{data:this.connectPeerDialog.data}).then(()=>{this.connectPeerDialog.show=!1,this.getPeers()})},disconnectPeer(e){LNbits.utils.confirmDialog("Do you really wanna disconnect this peer?").onOk(()=>{this.nodeApi("DELETE",`/peers/${e}`).then(e=>{Quasar.Notify.create({message:"Disconnected",icon:null}),this.needsRestart=!0,this.getPeers()})})},setChannelFee(e){this.nodeApi("PUT",`/channels/${e}`,{data:this.setFeeDialog.data}).then(e=>{this.setFeeDialog.show=!1,this.getChannels()}).catch(LNbits.utils.notifyApiError)},openChannel(){this.nodeApi("POST","/channels",{data:this.openChannelDialog.data}).then(e=>{this.openChannelDialog.show=!1,this.getChannels()}).catch(e=>{console.log(e)})},showCloseChannelDialog(e){this.closeChannelDialog.show=!0,this.closeChannelDialog.data={force:!1,short_id:e.short_id,...e.point}},closeChannel(){this.nodeApi("DELETE","/channels",{query:this.closeChannelDialog.data}).then(e=>{this.closeChannelDialog.show=!1,this.getChannels()})},showSetFeeDialog(e){this.setFeeDialog.show=!0,this.setFeeDialog.channel_id=e,this.getChannel(e)},showOpenChannelDialog(e){this.openChannelDialog.show=!0,this.openChannelDialog.data={peer_id:e,funding_amount:0}},showNodeInfoDialog(e){this.nodeInfoDialog.show=!0,this.nodeInfoDialog.data=e},showTransactionDetailsDialog(e){this.transactionDetailsDialog.show=!0,this.transactionDetailsDialog.data=e},shortenNodeId:e=>e?e.substring(0,5)+"..."+e.substring(e.length-5):"..."}},window.PageNodePublic={template:"#page-node-public",data:()=>({enabled:!1,isSuperUser:!1,wallet:{},tab:"dashboard",payments:1e3,info:{},channel_stats:{},channels:[],activeBalance:{},ranks:{},peers:[],connectPeerDialog:{show:!1,data:{}},openChannelDialog:{show:!1,data:{}},closeChannelDialog:{show:!1,data:{}},nodeInfoDialog:{show:!1,data:{}},states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}]}),created(){this.getInfo(),this.get1MLStats()},methods:{formatMsat:e=>LNbits.utils.formatMsat(e),api:(e,t,a)=>LNbits.api.request(e,"/node/public/api/v1"+t,{},a),getInfo(){this.api("GET","/info",{}).then(e=>{this.info=e.data,this.channel_stats=e.data.channel_stats,this.enabled=!0}).catch(()=>{this.info={},this.channel_stats={}})},get1MLStats(){this.api("GET","/rank",{}).then(e=>{this.ranks=e.data}).catch(()=>{this.ranks={}})}}},window.PageAudit={template:"#page-audit",data:()=>({chartsReady:!1,auditEntries:[],searchData:{user_id:"",ip_address:"",request_type:"",component:"",request_method:"",response_code:"",path:""},searchOptions:{component:[],request_method:[],response_code:[]},auditTable:{columns:[{name:"created_at",align:"center",label:"Date",field:"created_at",sortable:!0},{name:"duration",align:"left",label:"Duration (sec)",field:"duration",sortable:!0},{name:"component",align:"left",label:"Component",field:"component",sortable:!1},{name:"request_method",align:"left",label:"Method",field:"request_method",sortable:!1},{name:"response_code",align:"left",label:"Code",field:"response_code",sortable:!1},{name:"user_id",align:"left",label:"User Id",field:"user_id",sortable:!1},{name:"ip_address",align:"left",label:"IP Address",field:"ip_address",sortable:!1},{name:"path",align:"left",label:"Path",field:"path",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},auditDetailsDialog:{data:null,show:!1}}),async created(){},async mounted(){this.chartsReady=!0,await this.$nextTick(),this.initCharts(),await this.fetchAudit()},methods:{async fetchAudit(e){try{const t=LNbits.utils.prepareFilterQuery(this.auditTable,e),{data:a}=await LNbits.api.request("GET",`/audit/api/v1?${t}`);this.auditTable.pagination.rowsNumber=a.total,this.auditEntries=a.data,await this.fetchAuditStats(e)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.auditTable.loading=!1}},async fetchAuditStats(e){try{const t=LNbits.utils.prepareFilterQuery(this.auditTable,e),{data:a}=await LNbits.api.request("GET",`/audit/api/v1/stats?${t}`),s=a.request_method.map(e=>e.field);this.searchOptions.request_method=[...new Set(this.searchOptions.request_method.concat(s))],this.requestMethodChart.data.labels=s,this.requestMethodChart.data.datasets[0].data=a.request_method.map(e=>e.total),this.requestMethodChart.update();const i=a.response_code.map(e=>e.field);this.searchOptions.response_code=[...new Set(this.searchOptions.response_code.concat(i))],this.responseCodeChart.data.labels=i,this.responseCodeChart.data.datasets[0].data=a.response_code.map(e=>e.total),this.responseCodeChart.update();const n=a.component.map(e=>e.field);this.searchOptions.component=[...new Set(this.searchOptions.component.concat(n))],this.componentUseChart.data.labels=n,this.componentUseChart.data.datasets[0].data=a.component.map(e=>e.total),this.componentUseChart.update(),this.longDurationChart.data.labels=a.long_duration.map(e=>e.field),this.longDurationChart.data.datasets[0].data=a.long_duration.map(e=>e.total),this.longDurationChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async searchAuditBy(e,t){e&&(this.searchData[e]=t),this.auditTable.filter=Object.entries(this.searchData).reduce((e,[t,a])=>a?(e[t]=a,e):e,{}),await this.fetchAudit()},showDetailsDialog(e){const t=JSON.parse(e?.request_details||"");try{t.body&&(t.body=JSON.parse(t.body))}catch(e){}this.auditDetailsDialog.data=JSON.stringify(t,null,4),this.auditDetailsDialog.show=!0},shortify:e=>(valueLength=(e||"").length,valueLength<=10?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`),async initCharts(){this.chartsReady?(this.responseCodeChart=new Chart(this.$refs.responseCodeChart.getContext("2d"),{type:"doughnut",options:{responsive:!0,plugins:{legend:{position:"bottom"},title:{display:!1,text:"HTTP Response Codes"}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("response_code",a.data.labels[e])}}},data:{datasets:[{label:"",data:[20,10],backgroundColor:["rgb(100, 99, 200)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)"]}],labels:[]}}),this.requestMethodChart=new Chart(this.$refs.requestMethodChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("request_method",a.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)"],hoverOffset:4}]}}),this.componentUseChart=new Chart(this.$refs.componentUseChart.getContext("2d"),{type:"pie",options:{responsive:!0,plugins:{legend:{position:"xxx"},title:{display:!1,text:"Components"}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("component",a.data.labels[e])}}},data:{datasets:[{data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)","rgb(100, 205, 250)","rgb(120, 205, 250)","rgb(140, 205, 250)","rgb(160, 205, 250)"],hoverOffset:4}]}}),this.longDurationChart=new Chart(this.$refs.longDurationChart.getContext("2d"),{type:"bar",options:{responsive:!0,indexAxis:"y",maintainAspectRatio:!1,plugins:{legend:{title:{display:!1,text:"Long Duration"}}},onClick:(e,t,a)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("path",a.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)","rgb(100, 205, 250)","rgb(120, 205, 250)","rgb(140, 205, 250)","rgb(160, 205, 250)"],hoverOffset:4}]}})):console.warn("Charts are not ready yet. Initialization delayed.")}}},window.PageWallet={template:"#page-wallet",data:()=>({parse:{show:!1,invoice:null,lnurlpay:null,lnurlauth:null,data:{request:"",amount:0,comment:"",internalMemo:null,unit:"sat"},paymentChecker:null,copy:{show:!1},camera:{show:!1,camera:"auto"}},receive:{show:!1,status:"pending",paymentReq:null,paymentHash:null,amountMsat:null,minMax:[0,21e14],lnurl:null,units:[],unit:"sat",fiatProvider:"",data:{amount:null,memo:"",internalMemo:null,payment_hash:null}},update:{name:null,currency:null},hasNfc:!1,nfcReaderAbortController:null,formattedFiatAmount:0,paymentFilter:{"status[ne]":"failed"},chartConfig:Quasar.LocalStorage.getItem("lnbits.wallets.chartConfig")||{showPaymentInOutChart:!0,showBalanceChart:!0,showBalanceInOutChart:!0}}),computed:{canPay(){return!!this.parse.invoice&&(this.parse.invoice.expired?(Quasar.Notify.create({message:"Invoice has expired",color:"negative"}),!1):this.parse.invoice.sat<=this.g.wallet.sat)},formattedAmount(){return"sat"==this.receive.unit&&this.g.isSatsDenomination?LNbits.utils.formatMsat(this.receive.amountMsat)+" sat":LNbits.utils.formatCurrency(Number(this.receive.data.amount).toFixed(2),this.g.isSatsDenomination?this.receive.unit:this.g.denomination)},formattedSatAmount(){return LNbits.utils.formatMsat(this.receive.amountMsat)+" sat"}},methods:{handleSendLnurl(e){this.parse.data.request=e,this.parse.show=!0,this.lnurlScan()},msatoshiFormat:e=>LNbits.utils.formatSat(e/1e3),showReceiveDialog(){this.receive.show=!0,this.receive.status="pending",this.receive.paymentReq=null,this.receive.paymentHash=null,this.receive.data.amount=null,this.receive.data.memo=null,this.receive.data.internalMemo=null,this.receive.data.payment_hash=null,this.receive.units=["sat",...this.g.allowedCurrencies.length>0?this.g.allowedCurrencies:this.g.currencies],this.receive.unit=this.g.isFiatPriority&&this.g.wallet.currency||"sat",this.receive.minMax=[0,21e14],this.receive.lnurl=null},onReceiveDialogHide(){this.hasNfc&&this.nfcReaderAbortController.abort()},showParseDialog(){this.parse.show=!0,this.parse.invoice=null,this.parse.lnurlpay=null,this.parse.lnurlauth=null,this.parse.copy.show=window.isSecureContext&&void 0!==navigator.clipboard?.readText,this.parse.data.request="",this.parse.data.comment="",this.parse.data.internalMemo=null,this.parse.data.paymentChecker=null,this.parse.camera.show=!1},closeParseDialog(){setTimeout(()=>{clearInterval(this.parse.paymentChecker)},1e4)},handleBalanceUpdate(e){this.g.wallet.sat=this.g.wallet.sat+e},createInvoice(){this.receive.status="loading",this.g.isSatsDenomination||(this.receive.data.amount=100*this.receive.data.amount),LNbits.api.createInvoice(this.g.wallet,this.receive.data.amount,this.receive.data.memo,this.receive.unit,this.receive.lnurlWithdraw,this.receive.fiatProvider,this.receive.data.internalMemo,this.receive.data.payment_hash).then(e=>{if(this.g.updatePayments=!this.g.updatePayments,this.receive.status="success",this.receive.paymentReq=e.data.bolt11,this.receive.fiatPaymentReq=e.data.extra?.fiat_payment_request,this.receive.amountMsat=e.data.amount,this.receive.paymentHash=e.data.payment_hash,this.receive.lnurl||this.readNfcTag(),this.receive.lnurl&&null!==e.data.extra?.lnurl_response){!1===e.data.extra.lnurl_response&&(e.data.extra.lnurl_response="Unable to connect");const t=this.receive.lnurl.callback.split("/")[2];if("string"==typeof e.data.extra.lnurl_response)return void Quasar.Notify.create({timeout:5e3,type:"warning",message:`${t} lnurl-withdraw call failed.`,caption:e.data.extra.lnurl_response});!0===e.data.extra.lnurl_response&&Quasar.Notify.create({timeout:3e3,message:`Invoice sent to ${t}!`,spinner:!0})}}).catch(e=>{LNbits.utils.notifyApiError(e),this.receive.status="pending"})},lnurlScan(){LNbits.api.request("POST","/api/v1/lnurlscan",this.g.wallet.adminkey,{lnurl:this.parse.data.request}).then(e=>{const t=e.data;if("ERROR"!==t.status){if("payRequest"===t.tag)this.parse.lnurlpay=Object.freeze(t),this.parse.data.amount=t.minSendable/1e3;else if("login"===t.tag)this.parse.lnurlauth=Object.freeze(t);else if("withdrawRequest"===t.tag){this.parse.show=!1,this.receive.show=!0,this.receive.lnurlWithdraw=Object.freeze(t),this.receive.status="pending",this.receive.paymentReq=null,this.receive.paymentHash=null,this.receive.data.amount=t.maxWithdrawable/1e3,this.receive.data.memo=t.defaultDescription,this.receive.minMax=[t.minWithdrawable/1e3,t.maxWithdrawable/1e3];const e=t.callback.split("/")[2];this.receive.lnurl={domain:e,callback:t.callback,fixed:t.fixed}}}else Quasar.Notify.create({timeout:5e3,type:"warning",message:"lnurl scan failed.",caption:t.reason})}).catch(e=>{LNbits.utils.notifyApiError(e)})},decodeQR(e){this.parse.data.request=e,this.decodeRequest(),this.parse.camera.show=!1},isLnurl:e=>e.toLowerCase().startsWith("lnurl1")||e.startsWith("lnurlp://")||e.startsWith("lnurlw://")||e.startsWith("lnurlauth://")||e.match(/[\w.+-~_]+@[\w.+-~_]/),decodeRequest(){this.parse.show=!0,this.parse.data.request=this.parse.data.request.trim();const e=this.parse.data.request.toLowerCase();if(e.startsWith("lightning:")?this.parse.data.request=this.parse.data.request.slice(10):e.startsWith("lnurl:")?this.parse.data.request=this.parse.data.request.slice(6):e.includes("lightning=lnurl1")&&(this.parse.data.request=this.parse.data.request.split("lightning=")[1].split("&")[0]),this.isLnurl(this.parse.data.request))return void this.lnurlScan();let t;this.parse.data.request.toLowerCase().includes("lightning")&&(this.parse.data.request=this.parse.data.request.split("lightning=")[1],this.parse.data.request.includes("&")&&(this.parse.data.request=this.parse.data.request.split("&")[0]));try{t=decode(this.parse.data.request)}catch(e){return Quasar.Notify.create({timeout:3e3,type:"warning",message:e+".",caption:"400 BAD REQUEST"}),void(this.parse.show=!1)}let a={msat:t.human_readable_part.amount,sat:t.human_readable_part.amount/1e3,fsat:LNbits.utils.formatSat(t.human_readable_part.amount/1e3),bolt11:this.parse.data.request};_.each(t.data.tags,e=>{if(_.isObject(e)&&_.has(e,"description"))if("payment_hash"===e.description)a.hash=e.value;else if("description"===e.description)a.description=e.value;else if("expiry"===e.description){const s=new Date(1e3*(t.data.time_stamp+e.value)),i=new Date(1e3*t.data.time_stamp);a.expireDate=Quasar.date.formatDate(s,"YYYY-MM-DDTHH:mm:ss.SSSZ"),a.createdDate=Quasar.date.formatDate(i,"YYYY-MM-DDTHH:mm:ss.SSSZ"),a.expireDateFrom=moment.utc(s).local().fromNow(),a.createdDateFrom=moment.utc(i).local().fromNow(),a.expired=!1}}),this.g.wallet.currency&&(a.fiatAmount=LNbits.utils.formatCurrency((a.sat/1e8*this.g.exchangeRate).toFixed(2),this.g.wallet.currency)),this.parse.invoice=Object.freeze(a)},payInvoice(){const e=Quasar.Notify.create({timeout:0,message:this.$t("payment_processing")});LNbits.api.payInvoice(this.g.wallet,this.parse.data.request,this.parse.data.internalMemo).then(t=>{e(),this.g.updatePayments=!this.g.updatePayments,this.parse.show=!1,"success"==t.data.status&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")}),"pending"==t.data.status&&Quasar.Notify.create({type:"info",message:this.$t("payment_pending")})}).catch(t=>{e(),LNbits.utils.notifyApiError(t),this.g.updatePayments=!this.g.updatePayments,this.parse.show=!1})},payLnurl(){LNbits.api.request("post","/api/v1/payments/lnurl",this.g.wallet.adminkey,{res:this.parse.lnurlpay,lnurl:this.parse.data.request,unit:this.parse.data.unit,amount:1e3*this.parse.data.amount,comment:this.parse.data.comment,internalMemo:this.parse.data.internalMemo}).then(e=>{if(this.parse.show=!1,e.data.extra.success_action){const t=JSON.parse(e.data.extra.success_action);switch(t.tag){case"url":Quasar.Notify.create({message:`${t.url}`,caption:t.description,html:!0,type:"positive",timeout:0,closeBtn:!0});break;case"message":Quasar.Notify.create({message:t.message,type:"positive",timeout:0,closeBtn:!0});break;case"aes":this.utils.decryptLnurlPayAES(t,e.data.preimage),Quasar.Notify.create({message:value,caption:extra.success_action.description,html:!0,type:"positive",timeout:0,closeBtn:!0})}}}).catch(LNbits.utils.notifyApiError)},authLnurl(){const e=Quasar.Notify.create({timeout:10,message:"Performing authentication..."});LNbits.api.request("post","/api/v1/lnurlauth",wallet.adminkey,this.parse.lnurlauth).then(t=>{e(),Quasar.Notify.create({message:"Authentication successful.",type:"positive",timeout:3500}),this.parse.show=!1}).catch(e=>{e.response.data.reason?Quasar.Notify.create({message:`Authentication failed. ${this.parse.lnurlauth.callback} says:`,caption:e.response.data.reason,type:"warning",timeout:5e3}):LNbits.utils.notifyApiError(e)})},updateWallet(e){LNbits.api.request("PATCH","/api/v1/wallet",this.g.wallet.adminkey,e).then(e=>{this.g.wallet={...this.g.wallet,...e.data};const t=this.g.user.wallets.findIndex(t=>t.id===e.data.id);-1!==t&&(this.g.user.wallets[t]={...this.g.user.wallets[t],...e.data}),Quasar.Notify.create({message:"Wallet updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},pasteToTextArea(){this.$refs.textArea.focus(),navigator.clipboard.readText().then(e=>{this.parse.data.request=e.trim()})},readNfcTag(){try{if("undefined"==typeof NDEFReader)return void console.debug("NFC not supported on this device or browser.");const e=new NDEFReader;this.nfcReaderAbortController=new AbortController,this.nfcReaderAbortController.signal.onabort=e=>{console.debug("All NFC Read operations have been aborted.")},this.hasNfc=!0;const t=Quasar.Notify.create({message:"Tap your NFC tag to pay this invoice with LNURLw."});return e.scan({signal:this.nfcReaderAbortController.signal}).then(()=>{e.onreadingerror=()=>{Quasar.Notify.create({type:"negative",message:"There was an error reading this NFC tag."})},e.onreading=({message:e})=>{const a=new TextDecoder("utf-8"),s=e.records.find(e=>-1!==a.decode(e.data).toUpperCase().indexOf("LNURLW"));if(s){t(),Quasar.Notify.create({type:"positive",message:"NFC tag read successfully."});const e=a.decode(s.data);this.payInvoiceWithNfc(e)}else Quasar.Notify.create({type:"warning",message:"NFC tag does not have LNURLw record."})}})}catch(e){Quasar.Notify.create({type:"negative",message:e?e.toString():"An unexpected error has occurred."})}},payInvoiceWithNfc(e){const t=Quasar.Notify.create({timeout:0,spinner:!0,message:this.$t("processing_payment")});LNbits.api.request("POST",`/api/v1/payments/${this.receive.paymentReq}/pay-with-nfc`,this.g.wallet.adminkey,{lnurl_w:e}).then(e=>{t(),e.data.success?Quasar.Notify.create({type:"positive",message:"Payment successful"}):Quasar.Notify.create({type:"negative",message:e.data.detail||"Payment failed"})}).catch(e=>{t(),LNbits.utils.notifyApiError(e)})}},created(){const e=new URLSearchParams(window.location.search);(e.has("lightning")||e.has("lnurl"))&&(this.parse.data.request=e.get("lightning")||e.get("lnurl"),this.decodeRequest(),this.parse.show=!0);const t=this.g.user.wallets.find(e=>e.id===this.$route.params.id);t?(this.g.wallet=t,this.g.lastActiveWallet=t.id,this.$q.localStorage.setItem("lnbits.lastActiveWallet",t.id),this.$router.replace(`/wallet/${t.id}`)):(this.g.errorCode=404,this.g.errorMessage="Wallet not found.",this.$router.push("/error"))},watch:{"g.updatePaymentsHash"(){this.receive.show=!1},"g.updatePayments"(){this.parse.show=!1,this.g.wallet.currency&&this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency)&&(this.g.exchangeRate=this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency),this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat)},"g.wallet"(){this.g.wallet.currency?(this.g.fiatTracking=!0,this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat):(this.g.fiatBalance=0,this.g.fiatTracking=!1)},"g.isFiatPriority"(){this.receive.unit=this.g.isFiatPriority?this.g.wallet.currency:"sat"},"g.fiatBalance"(){this.formattedFiatAmount=LNbits.utils.formatCurrency(this.g.fiatBalance.toFixed(2),this.g.wallet.currency)},"g.exchangeRate"(){this.g.fiatTracking&&this.g.wallet.currency&&(this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat)}}},window.PageWallets={template:"#page-wallets",data:()=>({user:null,tab:"wallets",wallets:[],addWalletDialog:{show:!1},walletsTable:{columns:[{name:"name",align:"left",label:"Name",field:"name",sortable:!0},{name:"currency",align:"center",label:"Currency",field:"currency",sortable:!0},{name:"updated_at",align:"right",label:"Last Updated",field:"updated_at",sortable:!0}],pagination:{sortBy:"updated_at",rowsPerPage:12,page:1,descending:!0,rowsNumber:10},search:"",hideEmpty:!0,loading:!1}}),watch:{"walletsTable.search":{handler(){const e={};this.walletsTable.search&&(e.search=this.walletsTable.search),this.getUserWallets()}}},methods:{async getUserWallets(e){try{this.walletsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.walletsTable,e),{data:a}=await LNbits.api.request("GET",`/api/v1/wallet/paginated?${t}`,null);this.wallets=a.data,this.walletsTable.pagination.rowsNumber=a.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.walletsTable.loading=!1}},goToWallet(e){this.$router.push({path:"/wallet",query:{wal:e}})},formattedFiatAmount:(e,t)=>LNbits.utils.formatCurrency(Number(e).toFixed(2),t),formattedSatAmount:e=>LNbits.utils.formatMsat(e)+" sat"},async created(){await this.getUserWallets()}},window.PageUsers={template:"#page-users",data(){return{paymentsWallet:{},cancel:{},users:[],wallets:[],searchData:{user:"",username:"",email:"",pubkey:""},paymentPage:{show:!1},activeWallet:{userId:null,show:!1},activeUser:{data:null,showUserId:!1,show:!1},createWalletDialog:{data:{},show:!1},walletTable:{columns:[{name:"name",align:"left",label:"Name",field:"name"},{name:"id",align:"left",label:"Wallet Id",field:"id"},{name:"currency",align:"left",label:"Currency",field:"currency"},{name:"balance_msat",align:"left",label:"Balance",field:"balance_msat"}],pagination:{sortBy:"name",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},usersTable:{columns:[{name:"activated",align:"left",label:this.$t("activated"),field:"activated",sortable:!1},{name:"wallet_id",align:"left",label:"Wallets",field:"wallet_id",sortable:!1},{name:"id",align:"left",label:"User Id",field:"id",sortable:!1},{name:"username",align:"left",label:"Username",field:"username",sortable:!1},{name:"email",align:"left",label:"Email",field:"email",sortable:!1},{name:"pubkey",align:"left",label:"Public Key",field:"pubkey",sortable:!1},{name:"balance_msat",align:"left",label:"Balance",field:"balance_msat",sortable:!1},{name:"transaction_count",align:"left",label:"Payments",field:"transaction_count",sortable:!1},{name:"last_payment",align:"left",label:"Last Payment",field:"last_payment",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},sortFields:[{name:"id",label:"User ID"},{name:"username",label:"Username"},{name:"email",label:"Email"},{name:"pubkey",label:"Public Key"},{name:"created_at",label:"Creation Date"},{name:"updated_at",label:"Last Updated"}],search:null,hideEmpty:!0,loading:!1}}},watch:{"usersTable.hideEmpty":function(e,t){this.usersTable.filter=e?{"transaction_count[gt]":0}:{},this.fetchUsers()}},created(){this.fetchUsers()},methods:{formatSat:e=>LNbits.utils.formatSat(Math.floor(e/1e3)),backToUsersPage(){this.activeUser.show=!1,this.paymentPage.show=!1,this.activeWallet.show=!1,this.fetchUsers()},handleBalanceUpdate(){this.fetchWallets(this.activeWallet.userId)},resetPassword(e){return LNbits.api.request("PUT",`/users/api/v1/user/${e}/reset_password`).then(e=>{LNbits.utils.confirmDialog(this.$t("reset_key_generated")+" "+this.$t("reset_key_copy")).onOk(()=>{const t=window.location.origin+"?reset_key="+e.data;this.utils.copyText(t)})}).catch(LNbits.utils.notifyApiError)},sortByColumn(e){this.usersTable.pagination.sortBy===e?this.usersTable.pagination.descending=!this.usersTable.pagination.descending:(this.usersTable.pagination.sortBy=e,this.usersTable.pagination.descending=!1),this.fetchUsers()},createUser(){LNbits.api.request("POST","/users/api/v1/user",null,this.activeUser.data).then(e=>{Quasar.Notify.create({type:"positive",message:"User created!",icon:null}),this.activeUser.setPassword=!0,this.activeUser.data=e.data,this.fetchUsers()}).catch(LNbits.utils.notifyApiError)},updateUser(){LNbits.api.request("PUT",`/users/api/v1/user/${this.activeUser.data.id}`,null,this.activeUser.data).then(()=>{Quasar.Notify.create({type:"positive",message:"User updated!",icon:null}),this.activeUser.data=null,this.activeUser.show=!1,this.fetchUsers()}).catch(LNbits.utils.notifyApiError)},createWallet(){const e=this.activeWallet.userId;e?LNbits.api.request("POST",`/users/api/v1/user/${e}/wallet`,null,this.createWalletDialog.data).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"Wallet created!"})}).catch(LNbits.utils.notifyApiError):Quasar.Notify.create({type:"warning",message:"No user selected!",icon:null})},deleteUser(e){LNbits.utils.confirmDialog("Are you sure you want to delete this user?").onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}`).then(()=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:"User deleted!",icon:null}),this.activeUser.data=null,this.activeUser.show=!1}).catch(LNbits.utils.notifyApiError)})},undeleteUserWallet(e,t){LNbits.api.request("PUT",`/users/api/v1/user/${e}/wallet/${t}/undelete`).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"Undeleted user wallet!",icon:null})}).catch(LNbits.utils.notifyApiError)},deleteUserWallet(e,t,a){const s=a?"Wallet is already deleted, are you sure you want to permanently delete this user wallet?":"Are you sure you want to delete this user wallet?";LNbits.utils.confirmDialog(s).onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}/wallet/${t}`).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"User wallet deleted!",icon:null})}).catch(LNbits.utils.notifyApiError)})},deleteAllUserWallets(e){LNbits.utils.confirmDialog(this.$t("confirm_delete_all_wallets")).onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}/wallets`).then(t=>{Quasar.Notify.create({type:"positive",message:t.data.message,icon:null}),this.fetchWallets(e)}).catch(LNbits.utils.notifyApiError)})},copyWalletLink(e){const t=`${window.location.origin}/wallet?usr=${this.activeWallet.userId}&wal=${e}`;this.utils.copyText(t)},fetchUsers(e){this.relaxFilterForFields(["username","email"]);const t=LNbits.utils.prepareFilterQuery(this.usersTable,e);LNbits.api.request("GET",`/users/api/v1/user?${t}`).then(e=>{this.usersTable.loading=!1,this.usersTable.pagination.rowsNumber=e.data.total,this.users=e.data.data}).catch(LNbits.utils.notifyApiError)},fetchWallets(e){return LNbits.api.request("GET",`/users/api/v1/user/${e}/wallet`).then(t=>{this.wallets=t.data,this.activeWallet.userId=e,this.activeWallet.show=!0}).catch(LNbits.utils.notifyApiError)},relaxFilterForFields(e=[]){e.forEach(e=>{const t=this.usersTable?.filter?.[e];t&&this.usersTable.filter[e]&&(this.usersTable.filter[`${e}[like]`]=t,delete this.usersTable.filter[e])})},updateWallet(e){LNbits.api.request("PATCH","/api/v1/wallet",e.adminkey,{name:e.name}).then(()=>{e.editable=!1,Quasar.Notify.create({message:"Wallet name updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},toggleAdmin(e){LNbits.api.request("PUT",`/users/api/v1/user/${e}/admin`).then(()=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:"Toggled admin!",icon:null})}).catch(LNbits.utils.notifyApiError)},toggleUserActivated(e){LNbits.api.request("PUT",`/users/api/v1/user/${e}/activate`).then(e=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:e.data.message,icon:null})}).catch(LNbits.utils.notifyApiError)},async showAccountPage(e){if(this.activeUser.showPassword=!1,this.activeUser.showUserId=!1,this.activeUser.setPassword=!1,!e)return this.activeUser.data={extra:{}},void(this.activeUser.show=!0);try{const{data:t}=await LNbits.api.request("GET",`/users/api/v1/user/${e}`);this.activeUser.data=t,this.activeUser.show=!0}catch(e){console.warn(e),Quasar.Notify.create({type:"warning",message:"Failed to get user!"}),this.activeUser.show=!1}},async impersonateUser(e){try{await LNbits.api.impersonateUser(e),LNbits.utils.backupLocalStorage("impersonation",!0),this.$q.localStorage.setItem("lnbits.disclaimerShown",!0),window.location="/wallet"}catch(e){console.warn(e),Quasar.Notify.create({type:"warning",message:"Failed to impersonate user!"})}},async showWalletPayments(e){this.activeUser.show=!1,await this.fetchWallets(this.users[0].id),await this.showPayments(e)},showPayments(e){this.paymentsWallet=this.wallets.find(t=>t.id===e),this.paymentPage.show=!0},searchUserBy(e){const t=this.searchData[e];this.usersTable.filter={},t&&(this.usersTable.filter[e]=t),this.fetchUsers()},shortify:e=>(valueLength=(e||"").length,valueLength<=10?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`)}},window.PageAccount={template:"#page-account",data(){return{untouchedUser:null,hasUsername:!1,showUserId:!1,themeOptions:[{name:"bitcoin",color:"deep-orange"},{name:"mint",color:"green"},{name:"autumn",color:"brown"},{name:"monochrome",color:"grey"},{name:"salvador",color:"blue-10"},{name:"freedom",color:"pink-13"},{name:"cyber",color:"light-green-9"},{name:"flamingo",color:"pink-3"}],defaultSiteCustomisation:{locale:"en"},reactionOptions:["None","confettiBothSides","confettiFireworks","confettiStars","confettiTop"],borderOptions:["retro-border","hard-border","neon-border","no-border"],tab:"user",credentialsData:{show:!1,oldPassword:null,newPassword:null,newPasswordRepeat:null,username:null,pubkey:null},apiAcl:{showNewAclDialog:!1,showPasswordDialog:!1,showNewTokenDialog:!1,data:[],passwordGuardedFunction:null,newAclName:"",newTokenName:"",password:"",apiToken:null,selectedTokenId:null,columns:[{name:"Name",align:"left",label:this.$t("Name"),field:"Name",sortable:!1},{name:"path",align:"left",label:this.$t("path"),field:"path",sortable:!1},{name:"read",align:"left",label:this.$t("read"),field:"read",sortable:!1},{name:"write",align:"left",label:this.$t("write"),field:"write",sortable:!1}],pagination:{rowsPerPage:100,page:1}},selectedApiAcl:{id:null,name:null,endpoints:[],token_id_list:[],allRead:!1,allWrite:!1},assets:[],assetsTable:{loading:!1,columns:[{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"created_at",align:"left",label:this.$t("created_at"),field:"created_at",sortable:!0}],pagination:{rowsPerPage:6,page:1}},assetsUploadToPublic:!1,notifications:{nostr:{identifier:""}},labels:[],labelsDialog:{show:!1,data:{name:"",description:"",color:"#000000"}},labelsTable:{loading:!1,columns:[{name:"actions",align:"left"},{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"description",align:"left",label:this.$t("description"),field:"description"},{name:"color",align:"left",label:this.$t("color"),field:"color"}],pagination:{rowsPerPage:6,page:1}}}},watch:{tab(e){this.$router.push(`/account#${e}`)},$route(e){e.hash.length>1&&(this.tab=e.hash.replace("#",""))},"assetsTable.search":{handler(){const e={};this.assetsTable.search&&(e.search=this.assetsTable.search),this.getUserAssets()}}},computed:{isUserTouched(){return!_.isEqual(this.g.user,this.untouchedUser)}},methods:{changeLanguage(e){window.i18n.global.locale=e,this.$q.localStorage.set("lnbits.lang",e)},async updateAccount(){try{const{data:e}=await LNbits.api.request("PATCH","/api/v1/auth",null,{user_id:this.g.user.id,username:this.g.user.username,email:this.g.user.email,extra:this.g.user.extra});this.untouchedUser=JSON.parse(JSON.stringify(this.g.user)),this.hasUsername=!!e.username,Quasar.Notify.create({type:"positive",message:"Account updated."})}catch(e){LNbits.utils.notifyApiError(e)}},disableUpdatePassword(){return!this.credentialsData.newPassword||!this.credentialsData.newPasswordRepeat||this.credentialsData.newPassword!==this.credentialsData.newPasswordRepeat},async updatePassword(){if(this.credentialsData.username)try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/password",null,{user_id:this.g.user.id,username:this.credentialsData.username,password_old:this.credentialsData.oldPassword,password:this.credentialsData.newPassword,password_repeat:this.credentialsData.newPasswordRepeat});this.untouchedUser=JSON.parse(JSON.stringify(e)),this.hasUsername=!!e.username,this.credentialsData.show=!1,Quasar.Notify.create({type:"positive",message:"Password updated."})}catch(e){LNbits.utils.notifyApiError(e)}else Quasar.Notify.create({type:"warning",message:"Please set a username."})},async updatePubkey(){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/pubkey",null,{user_id:this.g.user.id,pubkey:this.credentialsData.pubkey});this.untouchedUser=JSON.parse(JSON.stringify(e)),this.hasUsername=!!e.username,this.credentialsData.show=!1,this.$q.notify({type:"positive",message:"Public key updated."})}catch(e){LNbits.utils.notifyApiError(e)}},showUpdateCredentials(){this.credentialsData={show:!0,oldPassword:null,username:this.g.user.username,pubkey:this.g.user.pubkey,newPassword:null,newPasswordRepeat:null}},newApiAclDialog(){this.apiAcl.newAclName=null,this.apiAcl.showNewAclDialog=!0},newTokenAclDialog(){this.apiAcl.newTokenName=null,this.apiAcl.newTokenExpiry=null,this.apiAcl.showNewTokenDialog=!0},handleApiACLSelected(e){this.selectedApiAcl={id:null,name:null,endpoints:[],token_id_list:[]},this.apiAcl.selectedTokenId=null,e&&setTimeout(()=>{const t=this.apiAcl.data.find(t=>t.id===e);this.selectedApiAcl&&(this.selectedApiAcl={...t},this.selectedApiAcl.allRead=this.selectedApiAcl.endpoints.every(e=>e.read),this.selectedApiAcl.allWrite=this.selectedApiAcl.endpoints.every(e=>e.write))})},handleAllEndpointsReadAccess(){this.selectedApiAcl.endpoints.forEach(e=>e.read=this.selectedApiAcl.allRead)},handleAllEndpointsWriteAccess(){this.selectedApiAcl.endpoints.forEach(e=>e.write=this.selectedApiAcl.allWrite)},async getApiACLs(){try{const{data:e}=await LNbits.api.request("GET","/api/v1/auth/acl",null);this.apiAcl.data=e.access_control_list}catch(e){LNbits.utils.notifyApiError(e)}},askPasswordAndRunFunction(e){this.apiAcl.passwordGuardedFunction=e,this.apiAcl.showPasswordDialog=!0},runPasswordGuardedFunction(){this.apiAcl.showPasswordDialog=!1;const e=this.apiAcl.passwordGuardedFunction;e&&this[e]()},async addApiACL(){if(this.apiAcl.newAclName){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/acl",null,{id:this.apiAcl.newAclName,name:this.apiAcl.newAclName,password:this.apiAcl.password});this.apiAcl.data=e.access_control_list;const t=this.apiAcl.data.find(e=>e.name===this.apiAcl.newAclName);this.handleApiACLSelected(t.id),this.apiAcl.showNewAclDialog=!1,this.$q.notify({type:"positive",message:"Access Control List created."})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.name="",this.apiAcl.password=""}this.apiAcl.showNewAclDialog=!1}else this.$q.notify({type:"warning",message:"Name is required."})},async updateApiACLs(){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/acl",null,{id:this.g.user.id,password:this.apiAcl.password,...this.selectedApiAcl});this.apiAcl.data=e.access_control_list}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async deleteApiACL(){if(this.selectedApiAcl.id){try{await LNbits.api.request("DELETE","/api/v1/auth/acl",null,{id:this.selectedApiAcl.id,password:this.apiAcl.password}),this.$q.notify({type:"positive",message:"Access Control List deleted."})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}this.apiAcl.data=this.apiAcl.data.filter(e=>e.id!==this.selectedApiAcl.id),this.handleApiACLSelected(this.apiAcl.data[0]?.id)}},async generateApiToken(){if(!this.selectedApiAcl.id)return;const e=new Date(this.apiAcl.newTokenExpiry)-new Date;try{const{data:t}=await LNbits.api.request("POST","/api/v1/auth/acl/token",null,{acl_id:this.selectedApiAcl.id,token_name:this.apiAcl.newTokenName,password:this.apiAcl.password,expiration_time_minutes:Math.trunc(e/6e4)});this.apiAcl.apiToken=t.api_token,this.apiAcl.selectedTokenId=t.id,Quasar.Notify.create({type:"positive",message:"Token Generated."}),await this.getApiACLs(),this.handleApiACLSelected(this.selectedApiAcl.id),this.apiAcl.showNewTokenDialog=!1}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async deleteToken(){if(this.apiAcl.selectedTokenId)try{await LNbits.api.request("DELETE","/api/v1/auth/acl/token",null,{id:this.apiAcl.selectedTokenId,acl_id:this.selectedApiAcl.id,password:this.apiAcl.password}),this.$q.notify({type:"positive",message:"Token deleted."}),this.selectedApiAcl.token_id_list=this.selectedApiAcl.token_id_list.filter(e=>e.id!==this.apiAcl.selectedTokenId),this.apiAcl.selectedTokenId=null}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async getUserAssets(e){try{this.assetsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.assetsTable,e),{data:a}=await LNbits.api.request("GET",`/api/v1/assets/paginated?${t}`,null);this.assets=a.data,this.assetsTable.pagination.rowsNumber=a.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.assetsTable.loading=!1}},onImageInput(e){const t=e.target.files[0];t&&this.uploadAsset(t)},async uploadAsset(e){const t=new FormData;t.append("file",e);try{await LNbits.api.request("POST",`/api/v1/assets?public_asset=${this.assetsUploadToPublic}`,null,t,{headers:{"Content-Type":"multipart/form-data"}}),this.$q.notify({type:"positive",message:"Upload successful!",icon:null}),await this.getUserAssets()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async deleteAsset(e){LNbits.utils.confirmDialog("Are you sure you want to delete this asset?").onOk(async()=>{try{await LNbits.api.request("DELETE",`/api/v1/assets/${e.id}`,null),this.$q.notify({type:"positive",message:"Asset deleted."}),await this.getUserAssets()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}})},async toggleAssetPublicAccess(e){try{await LNbits.api.request("PUT",`/api/v1/assets/${e.id}`,null,{is_public:!e.is_public}),this.$q.notify({type:"positive",message:"Update successful!",icon:null}),await this.getUserAssets()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},copyAssetLinkToClipboard(e){const t=`${window.location.origin}/api/v1/assets/${e.id}/data`;this.utils.copyText(t)},addUserLabel(){if(!this.labelsDialog.data.name)return void this.$q.notify({type:"warning",message:"Name is required."});if(!this.labelsDialog.data.color)return void this.$q.notify({type:"warning",message:"Color is required."});this.g.user.extra.labels=this.g.user.extra.labels||[];if(!this.g.user.extra.labels.find(e=>e.name===this.labelsDialog.data.name))return this.g.user.extra.labels.unshift({...this.labelsDialog.data}),this.labelsDialog.show=!1,!0;this.$q.notify({type:"warning",message:"A label with this name already exists."})},openAddLabelDialog(){this.labelsDialog.data={name:"",description:"",color:"#000000"},this.labelsDialog.show=!0},openEditLabelDialog(e){this.labelsDialog.data={name:e.name,description:e.description,color:e.color},this.labelsDialog.show=!0},updateUserLabel(){const e=this.labelsDialog.data,t=JSON.parse(JSON.stringify(this.g.user.extra.labels));this.g.user.extra.labels=this.g.user.extra.labels.filter(t=>t.name!==e.name);this.addUserLabel()||(this.g.user.extra.labels=t),this.labelsDialog.show=!1},deleteUserLabel(e){LNbits.utils.confirmDialog("Are you sure you want to delete this label?").onOk(()=>{this.g.user.extra.labels=this.g.user.extra.labels.filter(t=>t.name!==e.name)})},async siteCustomisationChanged(e={}){try{Object.entries(e||{}).forEach(([e,t])=>{e in this.g&&(this.g[e]=t)}),await LNbits.api.updateUiCustomization(e),this.$q.notify({type:"positive",message:"UI Customization updated."})}catch(e){LNbits.utils.notifyApiError(e)}},resetThemeDefaults(){const e={themeChoice:this.g.settings.defaultTheme,borderChoice:this.g.settings.defaultBorder,gradientChoice:this.g.settings.defaultGradient,bgimageChoice:this.g.settings.defaultBgimage||"",reactionChoice:this.g.settings.defaultReaction,darkChoice:this.g.settings.defaultDark,cardRoundedChoice:this.g.settings.defaultCardRounded,cardGradientChoice:this.g.settings.defaultCardGradient,cardShadowChoice:this.g.settings.defaultCardShadow};this.siteCustomisationChanged(e)}},async created(){this.untouchedUser=JSON.parse(JSON.stringify(this.g.user)),this.hasUsername=!!this.g.user.username,this.$route.hash.length>1&&(this.tab=this.$route.hash.replace("#","")),await this.getApiACLs(),await this.getUserAssets(),this.themeOptions=this.themeOptions.filter(e=>this.g.settings.themeOptions.includes(e.name))}},window.PageAdmin={template:"#page-admin",data:()=>({tab:"funding",settings:{},formData:{lnbits_exchange_rate_providers:[],lnbits_audit_exclude_paths:[],lnbits_audit_include_paths:[],lnbits_audit_http_response_codes:[]},isSuperUser:!1,needsRestart:!1}),watch:{tab(e){this.$router.push(`/admin#${e}`)},$route(e){e.hash.length>1&&(this.tab=e.hash.replace("#",""))}},async created(){this.$route.hash.length>1&&(this.tab=this.$route.hash.replace("#","")),await this.getSettings()},computed:{checkChanges(){return!_.isEqual(this.settings,this.formData)}},methods:{getDefaultSetting(e){LNbits.api.getDefaultSetting(e).then(t=>{this.formData[e]=t.data.default_value})},restartServer(){LNbits.api.request("GET","/admin/api/v1/restart/").then(e=>{this.$q.notify({type:"positive",message:"Success! Restarted Server",icon:null}),this.needsRestart=!1}).catch(LNbits.utils.notifyApiError)},async getSettings(){await LNbits.api.request("GET","/admin/api/v1/settings",this.g.user.wallets[0].adminkey).then(e=>{this.isSuperUser=e.data.is_super_user||!1,this.settings=e.data,this.formData={...this.settings}}).catch(LNbits.utils.notifyApiError)},updateSettings(){const e=_.omit(this.formData,["is_super_user","lnbits_allowed_funding_sources","touch"]);LNbits.api.request("PUT","/admin/api/v1/settings",this.g.user.wallets[0].adminkey,e).then(e=>{this.needsRestart=this.settings.lnbits_backend_wallet_class!==this.formData.lnbits_backend_wallet_class,this.settings=this.formData,this.formData=_.clone(this.settings),Quasar.Notify.create({type:"positive",message:"Success! Settings changed! "+(this.needsRestart?"Restart required!":""),icon:null})}).catch(LNbits.utils.notifyApiError)},deleteSettings(){LNbits.utils.confirmDialog("Are you sure you want to restore settings to default?").onOk(()=>{LNbits.api.request("DELETE","/admin/api/v1/settings").then(e=>{Quasar.Notify.create({type:"positive",message:"Success! Restored settings to defaults. Restarting...",icon:null}),this.$q.localStorage.clear()}).catch(LNbits.utils.notifyApiError)})},downloadBackup(){window.open("/admin/api/v1/backup","_blank")}}},window.app.component("lnbits-admin-funding",{props:["is-super-user","form-data","settings"],template:"#lnbits-admin-funding",data:()=>({auditData:[]}),created(){this.getAudit()},methods:{getAudit(){LNbits.api.request("GET","/admin/api/v1/audit",this.g.user.wallets[0].adminkey).then(e=>{this.auditData=e.data}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("lnbits-admin-funding-sources",{template:"#lnbits-admin-funding-sources",props:["form-data","allowed-funding-sources"],methods:{getFundingSourceLabel(e){const t=this.rawFundingSources.find(t=>t[0]===e);return t?t[1]:e},showQRValue(e){this.qrValue=e,this.showQRDialog=!0}},computed:{fundingSources(){let e=[];for(const[t,a,s]of this.rawFundingSources){const a={};if(null!==s)for(let[e,t]of Object.entries(s))a[e]="string"==typeof t?{label:t,value:null}:t||{};e.push([t,a])}return new Map(e)},sortedAllowedFundingSources(){return this.allowedFundingSources.sort()}},data:()=>({hideInput:!0,showQRDialog:!1,qrValue:"",rawFundingSources:[["VoidWallet","Void Wallet",null],["FakeWallet","Fake Wallet",{fake_wallet_secret:"Secret",lnbits_denomination:'"sats" or 3 Letter Custom Denomination'}],["CLNRestWallet","Core Lightning Rest (plugin)",{clnrest_url:"Endpoint",clnrest_ca:"ca.pem",clnrest_cert:"server.pem",clnrest_readonly_rune:"Rune used for readonly requests",clnrest_invoice_rune:"Rune used for creating invoices",clnrest_pay_rune:"Rune used for paying invoices using pay",clnrest_renepay_rune:"Rune used for paying invoices using renepay",clnrest_last_pay_index:"Ignores any invoices paid prior to or including this index. 0 is equivalent to not specifying and negative value is invalid.",clnrest_nodeid:"Node id"}],["CoreLightningWallet","Core Lightning",{corelightning_rpc:"Endpoint",corelightning_pay_command:"Custom Pay Command"}],["CoreLightningRestWallet","Core Lightning Rest (legacy)",{corelightning_rest_url:"Endpoint",corelightning_rest_cert:"Certificate",corelightning_rest_macaroon:"Macaroon"}],["LndRestWallet","Lightning Network Daemon (LND Rest)",{lnd_rest_endpoint:"Endpoint",lnd_rest_cert:"Certificate",lnd_rest_macaroon:"Macaroon",lnd_rest_macaroon_encrypted:"Encrypted Macaroon",lnd_rest_route_hints:{advanced:!0,label:"Enable Route Hints"},lnd_rest_allow_self_payment:{advanced:!0,label:"Allow Self Payment"}}],["LndWallet","Lightning Network Daemon (LND)",{lnd_grpc_endpoint:"Endpoint",lnd_grpc_cert:"Certificate",lnd_grpc_port:"Port",lnd_grpc_macaroon:"GRPC Macaroon",lnd_grpc_invoice_macaroon:"GRPC Invoice Macaroon",lnd_grpc_admin_macaroon:"GRPC Admin Macaroon",lnd_grpc_macaroon_encrypted:"Encrypted Macaroon"}],["LnTipsWallet","LN.Tips",{lntips_api_endpoint:"Endpoint",lntips_api_key:"API Key"}],["LNPayWallet","LN Pay",{lnpay_api_endpoint:"Endpoint",lnpay_api_key:"API Key",lnpay_wallet_key:"Wallet Key"}],["EclairWallet","Eclair (ACINQ)",{eclair_url:"URL",eclair_pass:"Password"}],["LNbitsWallet","LNbits",{lnbits_endpoint:"Endpoint",lnbits_key:"Admin Key"}],["BlinkWallet","Blink",{blink_api_endpoint:"Endpoint",blink_ws_endpoint:"WebSocket",blink_token:"Key"}],["AlbyWallet","Alby",{alby_api_endpoint:"Endpoint",alby_access_token:"Key"}],["BoltzWallet","Boltz",{boltz_client_endpoint:{label:"Boltz client endpoint",value:"127.0.0.1:9002"},boltz_client_macaroon:{label:"Admin Macaroon path or hex",value:"/home/ubuntu/.boltz/macaroons/admin.macaroon"},boltz_client_cert:{label:"Certificate path or hex",value:"/home/ubuntu/.boltz/tls.cert"},boltz_mnemonic:{label:"Liquid seed phrase",hint:"Boltz will fetch once connected, but you can change later (can be opened in a liquid wallet) ",copy:!0,qrcode:!0},boltz_client_password:{label:"Wallet Password (optional)",advanced:!0}}],["ZBDWallet","ZBD",{zbd_api_endpoint:"Endpoint",zbd_api_key:"Key"}],["PhoenixdWallet","Phoenixd",{phoenixd_api_endpoint:"Endpoint",phoenixd_api_password:"Key"}],["OpenNodeWallet","OpenNode",{opennode_api_endpoint:"Endpoint",opennode_key:"Key"}],["ClicheWallet","Cliche (NBD)",{cliche_endpoint:"Endpoint"}],["SparkWallet","Spark",{spark_url:"Endpoint",spark_token:"Token"}],["SparkL2Wallet","Spark (L2)",{spark_l2_external_endpoint:{label:"External Sidecar Endpoint",hint:"Make sure to also specify the API key if your sidecar requires authentication.",value:""},spark_l2_mnemonic:{label:"External Sidecar Mnemonic",hint:"Mnemonic for the Spark wallet on the external sidecar. Required if the side car does not have its own mnemonic.",value:""},spark_l2_external_api_key:{label:"External Sidecar API Key",hint:"API key for authenticating with the external sidecar if it requires authentication.",value:""},spark_l2_network:{label:"Network",value:"MAINNET",hint:"The network to use for the Spark wallet.",advanced:!0},spark_l2_pay_wait_ms:{label:"Payment Wait Time (ms)",hint:"The time to wait for a payment to be processed before considering it failed.",advanced:!0},spark_l2_pay_poll_ms:{label:"Payment Poll Time (ms)",hint:"The time to wait between polling for payment status updates.",advanced:!0},spark_l2_stream_keepalive_ms:{label:"Stream Keepalive Time (ms)",hint:"The time to wait between sending keepalive messages to the Spark sidecar to keep the connection open.",advanced:!0}}],["NWCWallet","Nostr Wallet Connect",{nwc_pairing_url:"Pairing URL"}],["BreezSdkWallet","Breez SDK",{breez_api_key:"Breez API Key",breez_greenlight_seed:"Greenlight Seed",breez_greenlight_device_key:"Greenlight Device Key",breez_greenlight_device_cert:"Greenlight Device Cert",breez_greenlight_invite_code:"Greenlight Invite Code"}],["StrikeWallet","Strike (alpha)",{strike_api_endpoint:"API Endpoint",strike_api_key:"API Key"}],["BreezLiquidSdkWallet","Breez Liquid SDK",{breez_liquid_api_key:"Breez API Key (can be empty)",breez_liquid_seed:"Liquid seed phrase",breez_liquid_fee_offset_sat:"Offset amount in sats to increase fee limit"}]]})}),window.app.component("lnbits-admin-fiat-providers",{props:["form-data"],template:"#lnbits-admin-fiat-providers",data:()=>({formAddStripeUser:"",formAddPaypalUser:"",hideInputToggle:!0}),computed:{stripeWebhookUrl(){return this.formData?.stripe_payment_webhook_url||this.calculateWebhookUrl("stripe")},paypalWebhookUrl(){return this.formData?.paypal_payment_webhook_url||this.calculateWebhookUrl("paypal")}},watch:{formData:{handler(){this.syncWebhookUrls()},immediate:!0}},methods:{basePathFromLocation(){if("undefined"==typeof window)return"";const e=window.location.pathname.replace(/\/+$/,""),t=e.lastIndexOf("/admin");return(t>=0?e.slice(0,t):e||"")||""},calculateWebhookUrl(e){if("undefined"==typeof window)return"";const t=`${this.basePathFromLocation()}/api/v1/callback/${e}`.replace(/\/+/g,"/"),a=t.startsWith("/")?t:`/${t}`;return`${window.location.origin}${a}`},syncWebhookUrls(){this.maybeSetWebhookUrl("stripe_payment_webhook_url","stripe"),this.maybeSetWebhookUrl("paypal_payment_webhook_url","paypal")},maybeSetWebhookUrl(e,t){if(!this.formData)return;const a=this.calculateWebhookUrl(t),s=this.formData[e];(!s||s.includes("your-lnbits-domain-here.com"))&&a&&(this.formData[e]=a)},copyWebhookUrl(e){e&&this.copyText(e)},addStripeAllowedUser(){const e=this.formAddStripeUser||"";e.length&&!this.formData.stripe_limits.allowed_users.includes(e)&&(this.formData.stripe_limits.allowed_users=[...this.formData.stripe_limits.allowed_users,e],this.formAddStripeUser="")},removeStripeAllowedUser(e){this.formData.stripe_limits.allowed_users=this.formData.stripe_limits.allowed_users.filter(t=>t!==e)},addPaypalAllowedUser(){const e=this.formAddPaypalUser||"";e.length&&!this.formData.paypal_limits.allowed_users.includes(e)&&(this.formData.paypal_limits.allowed_users=[...this.formData.paypal_limits.allowed_users,e],this.formAddPaypalUser="")},removePaypalAllowedUser(e){this.formData.paypal_limits.allowed_users=this.formData.paypal_limits.allowed_users.filter(t=>t!==e)},checkFiatProvider(e){LNbits.api.request("PUT",`/api/v1/fiat/check/${e}`).then(e=>{const t=e.data;Quasar.Notify.create({type:t.success?"positive":"warning",message:t.message,icon:null})}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("lnbits-admin-exchange-providers",{props:["form-data"],template:"#lnbits-admin-exchange-providers",data:()=>({exchangeData:{selectedProvider:null,showTickerConversion:!1,convertFromTicker:null,convertToTicker:null},exchangesTable:{columns:[{name:"name",align:"left",label:"Exchange Name",field:"name",sortable:!0},{name:"api_url",align:"left",label:"URL",field:"api_url",sortable:!1},{name:"path",align:"left",label:"JSON Path",field:"path",sortable:!1},{name:"exclude_to",align:"left",label:"Exclude Currencies",field:"exclude_to",sortable:!1},{name:"ticker_conversion",align:"left",label:"Ticker Conversion",field:"ticker_conversion",sortable:!1}],pagination:{sortBy:"name",rowsPerPage:100,page:1,rowsNumber:100},search:null,hideEmpty:!0}}),mounted(){this.getExchangeRateHistory()},created(){const e=window.location.hash.replace("#","");"exchange_providers"===e&&this.showExchangeProvidersTab(e)},methods:{getDefaultSetting(e){LNbits.api.getDefaultSetting(e).then(t=>{this.formData[e]=t.data.default_value})},getExchangeRateHistory(){LNbits.api.request("GET","/api/v1/rate/history",this.g.user.wallets[0].inkey).then(e=>{this.initExchangeChart(e.data)}).catch(function(e){LNbits.utils.notifyApiError(e)})},showExchangeProvidersTab(e){"exchange_providers"===e&&this.getExchangeRateHistory()},addExchangeProvider(){this.formData.lnbits_exchange_rate_providers=[{name:"",api_url:"",path:"",exclude_to:[]},...this.formData.lnbits_exchange_rate_providers]},removeExchangeProvider(e){this.formData.lnbits_exchange_rate_providers=this.formData.lnbits_exchange_rate_providers.filter(t=>t!==e)},removeExchangeTickerConversion(e,t){e.ticker_conversion=e.ticker_conversion.filter(e=>e!==t),this.formData.touch=null},addExchangeTickerConversion(){this.exchangeData.selectedProvider&&(this.exchangeData.selectedProvider.ticker_conversion.push(`${this.exchangeData.convertFromTicker}:${this.exchangeData.convertToTicker}`),this.formData.touch=null,this.exchangeData.showTickerConversion=!1)},showTickerConversionDialog(e){this.exchangeData.convertFromTicker=null,this.exchangeData.convertToTicker=null,this.exchangeData.selectedProvider=e,this.exchangeData.showTickerConversion=!0},initExchangeChart(e){const t=e.map(e=>this.utils.formatTimestamp(e.timestamp,"HH:mm")),a=[...this.formData.lnbits_exchange_rate_providers,{name:"LNbits"}].map(t=>({label:t.name,data:e.map(e=>e.rates[t.name]),pointStyle:!0,borderWidth:"LNbits"===t.name?4:1,tension:.4}));this.exchangeRatesChart=new Chart(this.$refs.exchangeRatesChart.getContext("2d"),{type:"line",options:{plugins:{legend:{display:!1}}},data:{labels:t,datasets:a}})}}}),window.app.component("lnbits-admin-security",{props:["form-data"],template:"#lnbits-admin-security",data:()=>({logs:[],formBlockedIPs:"",serverlogEnabled:!1,nostrAcceptedUrl:"",formAllowedIPs:"",formCallbackUrlRule:""}),created(){},methods:{addAllowedIPs(){const e=this.formAllowedIPs.trim(),t=this.formData.lnbits_allowed_ips;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_allowed_ips=[...t,e],this.formAllowedIPs="")},removeAllowedIPs(e){const t=this.formData.lnbits_allowed_ips;this.formData.lnbits_allowed_ips=t.filter(t=>t!==e)},addBlockedIPs(){const e=this.formBlockedIPs.trim(),t=this.formData.lnbits_blocked_ips;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_blocked_ips=[...t,e],this.formBlockedIPs="")},removeBlockedIPs(e){const t=this.formData.lnbits_blocked_ips;this.formData.lnbits_blocked_ips=t.filter(t=>t!==e)},addCallbackUrlRule(){const e=this.formCallbackUrlRule.trim(),t=this.formData.lnbits_callback_url_rules;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_callback_url_rules=[...t,e],this.formCallbackUrlRule="")},removeCallbackUrlRule(e){const t=this.formData.lnbits_callback_url_rules;this.formData.lnbits_callback_url_rules=t.filter(t=>t!==e)},addNostrUrl(){const e=this.nostrAcceptedUrl.trim();this.removeNostrUrl(e),this.formData.nostr_absolute_request_urls.push(e),this.nostrAcceptedUrl=""},removeNostrUrl(e){this.formData.nostr_absolute_request_urls=this.formData.nostr_absolute_request_urls.filter(t=>t!==e)},async toggleServerLog(){if(this.serverlogEnabled=!this.serverlogEnabled,this.serverlogEnabled){const e="http:"!==location.protocol?"wss://":"ws://",t=await LNbits.utils.digestMessage(this.g.user.id),a=e+document.domain+":"+location.port+"/api/v1/ws/"+t;this.ws=new WebSocket(a),this.ws.addEventListener("message",async({data:e})=>{this.logs.push(e.toString());const t=this.$refs.logScroll;if(t){const e=t.getScrollTarget(),a=0;t.setScrollPosition(e.scrollHeight,a)}})}else this.ws.close()}}}),window.app.component("lnbits-admin-users",{props:["form-data"],template:"#lnbits-admin-users",data:()=>({formAddUser:"",formAddAdmin:"",formAddActivationCode:"",showReusableActivationCode:!1}),methods:{addAllowedUser(){let e=this.formAddUser,t=this.formData.lnbits_allowed_users;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_allowed_users=[...t,e],this.formAddUser="")},removeAllowedUser(e){let t=this.formData.lnbits_allowed_users;this.formData.lnbits_allowed_users=t.filter(t=>t!==e)},addAdminUser(){let e=this.formAddAdmin,t=this.formData.lnbits_admin_users;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_admin_users=[...t,e],this.formAddAdmin="")},removeAdminUser(e){let t=this.formData.lnbits_admin_users;this.formData.lnbits_admin_users=t.filter(t=>t!==e)},addOneTimeActivationCode(){const e=this.formAddActivationCode,t=this.formData.lnbits_register_one_time_activation_codes;e?.length&&!t.includes(e)&&(this.formData.lnbits_register_one_time_activation_codes=[...t,e],this.formAddActivationCode="")},removeOneTimeActivationCode(e){const t=this.formData.lnbits_register_one_time_activation_codes;this.formData.lnbits_register_one_time_activation_codes=t.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-server",{props:["form-data"],template:"#lnbits-admin-server"}),window.app.component("lnbits-admin-extensions",{props:["form-data"],template:"#lnbits-admin-extensions",data:()=>({formAddExtensionsManifest:""}),methods:{addExtensionsManifest(){const e=this.formAddExtensionsManifest.trim(),t=this.formData.lnbits_extensions_manifests;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_extensions_manifests=[...t,e],this.formAddExtensionsManifest="")},removeExtensionsManifest(e){const t=this.formData.lnbits_extensions_manifests;this.formData.lnbits_extensions_manifests=t.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-notifications",{props:["form-data"],template:"#lnbits-admin-notifications",data:()=>({nostrNotificationIdentifier:"",emailNotificationAddress:""}),methods:{sendTestEmail(){LNbits.api.request("GET","/admin/api/v1/testemail",this.g.user.wallets[0].adminkey).then(e=>{if("error"===e.data.status)throw new Error(e.data.message);this.$q.notify({message:"Test email sent!",color:"positive"})}).catch(e=>{this.$q.notify({message:e.message,color:"negative"})})},addNostrNotificationIdentifier(){const e=this.nostrNotificationIdentifier.trim(),t=this.formData.lnbits_nostr_notifications_identifiers;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_nostr_notifications_identifiers=[...t,e],this.nostrNotificationIdentifier="")},removeNostrNotificationIdentifier(e){const t=this.formData.lnbits_nostr_notifications_identifiers;this.formData.lnbits_nostr_notifications_identifiers=t.filter(t=>t!==e)},addEmailNotificationAddress(){const e=this.emailNotificationAddress.trim(),t=this.formData.lnbits_email_notifications_to_emails;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_email_notifications_to_emails=[...t,e],this.emailNotificationAddress="")},removeEmailNotificationAddress(e){const t=this.formData.lnbits_email_notifications_to_emails;this.formData.lnbits_email_notifications_to_emails=t.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-site-customisation",{props:["form-data"],template:"#lnbits-admin-site-customisation",data:()=>({lnbits_theme_options:["classic","bitcoin","flamingo","cyber","freedom","mint","autumn","monochrome","salvador"],colors:["primary","secondary","accent","positive","negative","info","warning","red","yellow","orange"],reactionOptions:["none","confettiBothSides","confettiFireworks","confettiStars","confettiTop"],globalBorderOptions:["retro-border","hard-border","neon-border","no-border"]}),methods:{}}),window.app.component("lnbits-admin-assets-config",{props:["form-data"],template:"#lnbits-admin-assets-config",data:()=>({newAllowedAssetMimeType:"",newNoLimitUser:""}),async created(){},methods:{addAllowedAssetMimeType(){this.newAllowedAssetMimeType&&(this.removeAllowedAssetMimeType(this.newAllowedAssetMimeType),this.formData.lnbits_assets_allowed_mime_types.push(this.newAllowedAssetMimeType),this.newAllowedAssetMimeType="",this.formData.touch=null)},removeAllowedAssetMimeType(e){const t=this.formData.lnbits_assets_allowed_mime_types.indexOf(e);-1!==t&&this.formData.lnbits_assets_allowed_mime_types.splice(t,1),this.formData.touch=null},addNewNoLimitUser(){this.newNoLimitUser&&(this.removeNoLimitUser(this.newNoLimitUser),this.formData.lnbits_assets_no_limit_users.push(this.newNoLimitUser),this.newNoLimitUser="",this.formData.touch=null)},removeNoLimitUser(e){e&&(this.formData.lnbits_assets_no_limit_users=this.formData.lnbits_assets_no_limit_users.filter(t=>t!==e),this.formData.touch=null)}}}),window.app.component("lnbits-admin-audit",{props:["form-data"],template:"#lnbits-admin-audit",data:()=>({formAddIncludePath:"",formAddExcludePath:"",formAddIncludeResponseCode:""}),methods:{addIncludePath(){if(""===this.formAddIncludePath)return;const e=this.formData.lnbits_audit_include_paths;e.includes(this.formAddIncludePath)||(this.formData.lnbits_audit_include_paths=[...e,this.formAddIncludePath]),this.formAddIncludePath=""},removeIncludePath(e){this.formData.lnbits_audit_include_paths=this.formData.lnbits_audit_include_paths.filter(t=>t!==e)},addExcludePath(){if(""===this.formAddExcludePath)return;const e=this.formData.lnbits_audit_exclude_paths;e.includes(this.formAddExcludePath)||(this.formData.lnbits_audit_exclude_paths=[...e,this.formAddExcludePath]),this.formAddExcludePath=""},removeExcludePath(e){this.formData.lnbits_audit_exclude_paths=this.formData.lnbits_audit_exclude_paths.filter(t=>t!==e)},addIncludeResponseCode(){if(""===this.formAddIncludeResponseCode)return;const e=this.formData.lnbits_audit_http_response_codes;e.includes(this.formAddIncludeResponseCode)||(this.formData.lnbits_audit_http_response_codes=[...e,this.formAddIncludeResponseCode]),this.formAddIncludeResponseCode=""},removeIncludeResponseCode(e){this.formData.lnbits_audit_http_response_codes=this.formData.lnbits_audit_http_response_codes.filter(t=>t!==e)}}}),window.app.component("lnbits-wallet-charts",{template:"#lnbits-wallet-charts",props:["paymentFilter","chartConfig"],data:()=>({debounceTimeoutValue:1337,debounceTimeout:null,chartData:[],chartDataPointCount:0,walletBalanceChart:null,walletBalanceInOut:null,walletPaymentInOut:null,colorPrimary:Quasar.colors.changeAlpha(Quasar.colors.getPaletteColor("primary"),.3),colorSecondary:Quasar.colors.changeAlpha(Quasar.colors.getPaletteColor("secondary"),.3),barOptions:{responsive:!0,maintainAspectRatio:!1,scales:{x:{stacked:!0},y:{stacked:!0}}}}),watch:{paymentFilter:{deep:!0,handler(){this.changeCharts()}},chartConfig:{deep:!0,handler(e){this.$q.localStorage.setItem("lnbits.wallets.chartConfig",e),this.changeCharts()}}},methods:{changeCharts(){this.debounceTimeout&&clearTimeout(this.debounceTimeout),this.debounceTimeout=setTimeout(async()=>{await this.fetchChartData(),this.drawCharts()},this.debounceTimeoutValue)},filterChartData(){const e=this.paymentFilter["time[ge]"]+"T00:00:00",t=this.paymentFilter["time[le]"]+"T23:59:59";let a=0,s=this.chartData.map(e=>void 0!==this.paymentFilter["amount[ge]"]?(a+=e.balance_in,{...e,balance:a,balance_out:0,count_out:0}):void 0!==this.paymentFilter["amount[le]"]?(a-=e.balance_out,{...e,balance:a,balance_in:0,count_in:0}):{...e});s=s.filter(a=>this.paymentFilter["time[ge]"]&&this.paymentFilter["time[le]"]?a.date>=e&&a.date<=t:this.paymentFilter["time[ge]"]?a.date>=e:!this.paymentFilter["time[le]"]||a.date<=t);const i=s.map(e=>new Date(e.date).toLocaleString("default",{month:"short",day:"numeric"}));return this.chartDataPointCount=s.length,{data:s,labels:i}},drawBalanceInOutChart(e,t){this.walletBalanceInOut&&this.walletBalanceInOut.destroy();const a=this.$refs.walletBalanceInOut;a&&(this.walletBalanceInOut=new Chart(a.getContext("2d"),{type:"bar",options:this.barOptions,data:{labels:t,datasets:[{label:"Balance In",borderRadius:5,data:e.map(e=>e.balance_in),backgroundColor:this.colorPrimary},{label:"Balance Out",borderRadius:5,data:e.map(e=>e.balance_out),backgroundColor:this.colorSecondary}]}}))},drawPaymentInOut(e,t){this.walletPaymentInOut&&this.walletPaymentInOut.destroy();const a=this.$refs.walletPaymentInOut;a&&(this.walletPaymentInOut=new Chart(a.getContext("2d"),{type:"bar",options:this.barOptions,data:{labels:t,datasets:[{label:"Payments In",data:e.map(e=>e.count_in),backgroundColor:this.colorPrimary},{label:"Payments Out",data:e.map(e=>-e.count_out),backgroundColor:this.colorSecondary}]}}))},drawBalanceChart(e,t){this.walletBalanceChart&&this.walletBalanceChart.destroy();const a=this.$refs.walletBalanceChart;a&&(this.walletBalanceChart=new Chart(a.getContext("2d"),{type:"line",options:{responsive:!0,maintainAspectRatio:!1},data:{labels:t,datasets:[{label:"Balance",data:e.map(e=>e.balance),pointStyle:!1,backgroundColor:this.colorPrimary,borderColor:this.colorPrimary,borderWidth:2,fill:!0,tension:.7,fill:1},{label:"Fees",data:e.map(e=>e.fee),pointStyle:!1,backgroundColor:this.colorSecondary,borderColor:this.colorSecondary,borderWidth:1,fill:!0,tension:.7,fill:1}]}}))},drawCharts(){const{data:e,labels:t}=this.filterChartData();this.chartConfig.showBalanceChart&&this.drawBalanceChart(e,t),this.chartConfig.showBalanceInOutChart&&this.drawBalanceInOutChart(e,t),this.chartConfig.showPaymentInOutChart&&this.drawPaymentInOut(e,t)},async fetchChartData(){try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/daily?wallet_id=${this.g.wallet.id}`);this.chartData=e}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}}},async created(){await this.fetchChartData(),this.drawCharts()}}),window.app.component("lnbits-wallet-api-docs",{template:"#lnbits-wallet-api-docs",methods:{resetKeys(){LNbits.utils.confirmDialog("Are you sure you want to reset your API keys?").onOk(()=>{LNbits.api.resetWalletKeys(this.g.wallet).then(e=>{const{id:t,adminkey:a,inkey:s}=e;this.g.wallet={...this.g.wallet,inkey:s,adminkey:a};const i=this.g.user.wallets.findIndex(e=>e.id===t);-1!==i&&(this.g.user.wallets[i]={...this.g.user.wallets[i],inkey:s,adminkey:a}),Quasar.Notify.create({timeout:3500,type:"positive",message:"API keys reset!"})}).catch(e=>{LNbits.utils.notifyApiError(e)})})}},data:()=>({origin:window.location.origin,inkeyHidden:!0,adminkeyHidden:!0,walletIdHidden:!0})}),window.app.component("lnbits-wallet-icon",{template:"#lnbits-wallet-icon",data:()=>({icon:{show:!1,data:{},colorOptions:["primary","purple","orange","green","brown","blue","red","pink"],options:["home","star","bolt","paid","savings","store","videocam","music_note","flight","train","directions_car","school","construction","science","sports_esports","sports_tennis","theaters","water","headset_mic","videogame_asset","person","group","pets","sunny","elderly","verified","snooze","mail","forum","shopping_cart","shopping_bag","attach_money","print_connect","dark_mode","light_mode","android","network_wifi","shield","fitness_center","lunch_dining"]}}),methods:{setSelectedIcon(e){this.icon.data.icon=e},setSelectedColor(e){this.icon.data.color=e},setIcon(){this.$emit("update-wallet",this.icon.data),this.icon.show=!1}}}),window.app.component("lnbits-wallet-new",{template:"#lnbits-wallet-new",data:()=>({walletTypes:[{label:"Lightning Wallet",value:"lightning"}],wallet:{name:"",sharedWalletId:""},showNewWalletDialog:!1}),watch:{"g.newWalletType"(e){null!==e&&(this.showNewWalletDialog=!0)},showNewWalletDialog(e){!0!==e&&this.reset()}},computed:{isLightning(){return"lightning"===this.g.newWalletType},isLightningShared(){return"lightning-shared"===this.g.newWalletType},inviteWalletOptions(){return(this.g.user?.extra?.wallet_invite_requests||[]).map(e=>({label:`${e.to_wallet_name} (from ${e.from_user_name})`,value:e.to_wallet_id}))}},methods:{reset(){this.showNewWalletDialog=!1,this.g.newWalletType=null,this.wallet={name:"",sharedWalletId:""}},async submitRejectWalletInvitation(){try{const e=this.g.user.extra.wallet_invite_requests||[],t=e.find(e=>e.to_wallet_id===this.wallet.sharedWalletId);if(!t)return void Quasar.Notify.create({message:"Cannot find invitation for the selected wallet.",type:"warning"});await LNbits.api.request("DELETE",`/api/v1/wallet/share/invite/${t.request_id}`,this.g.wallet.adminkey),Quasar.Notify.create({message:"Invitation rejected.",type:"positive"}),this.g.user.extra.wallet_invite_requests=e.filter(e=>e.request_id!==t.request_id)}catch(e){LNbits.utils.notifyApiError(e)}},submitAddWallet(){const e=this.wallet;"lightning"!==this.g.newWalletType||e.name?"lightning-shared"!==this.g.newWalletType||e.sharedWalletId?LNbits.api.createWallet(e.name,this.g.newWalletType,{shared_wallet_id:e.sharedWalletId}).then(e=>{this.$q.notify({message:"Wallet created successfully",color:"positive"}),this.reset(),this.g.user.wallets.push(LNbits.map.wallet(e.data)),this.g.lastWalletId=e.data.id,this.$router.push(`/wallet/${e.data.id}`)}).catch(LNbits.utils.notifyApiError):this.$q.notify({message:"Missing a shared wallet ID",color:"warning"}):this.$q.notify({message:"Please enter a name for the wallet",color:"warning"})}},created(){this.g.user?.extra?.wallet_invite_requests?.length&&this.walletTypes.push({label:`Lightning Wallet (Share Invite: ${this.g.user.extra.wallet_invite_requests.length})`,value:"lightning-shared"})}}),window.app.component("lnbits-wallet-share",{template:"#lnbits-wallet-share",computed:{walletApprovedShares(){return this.g.wallet.extra.shared_with.filter(e=>"approved"===e.status)},walletPendingRequests(){return this.g.wallet.extra.shared_with.filter(e=>"request_access"===e.status)},walletPendingInvites(){return this.g.wallet.extra.shared_with.filter(e=>"invite_sent"===e.status)}},data:()=>({permissionOptions:[{label:"View",value:"view-payments"},{label:"Receive",value:"receive-payments"},{label:"Send",value:"send-payments"}],walletShareInvite:{username:"",permissions:[]}}),methods:{async updateSharePermissions(e){try{const{data:t}=await LNbits.api.request("PUT","/api/v1/wallet/share",this.g.wallet.adminkey,e);Object.assign(e,t),Quasar.Notify.create({message:"Wallet permission updated.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async inviteUserToWallet(){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/wallet/share/invite",this.g.wallet.adminkey,{...this.walletShareInvite,status:"invite_sent",wallet_id:this.g.wallet.id});this.g.wallet.extra.shared_with.push(e),this.walletShareInvite={username:"",permissions:[]},Quasar.Notify.create({message:"User invited to wallet.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},deleteSharePermission(e){LNbits.utils.confirmDialog("Are you sure you want to remove this share permission?").onOk(async()=>{try{await LNbits.api.request("DELETE",`/api/v1/wallet/share/${e.request_id}`,this.g.wallet.adminkey),this.g.wallet.extra.shared_with=this.g.wallet.extra.shared_with.filter(t=>t.wallet_id!==e.wallet_id),Quasar.Notify.create({message:"Wallet permission deleted.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})}}}),window.app.component("lnbits-wallet-paylinks",{template:"#lnbits-wallet-paylinks",data:()=>({storedPaylinks:[]}),watch:{"g.wallet"(e){this.storedPaylinks=e.storedPaylinks??[]}},created(){this.storedPaylinks=this.g.wallet.storedPaylinks},methods:{updatePaylinks(){LNbits.api.request("PUT",`/api/v1/wallet/stored_paylinks/${this.g.wallet.id}`,this.g.wallet.adminkey,{links:this.storedPaylinks}).then(()=>{this.$q.notify({message:"Paylinks updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},sendToPaylink(e){this.$emit("send-lnurl",e)},editPaylink(){this.$nextTick(()=>{this.updatePaylinks()})},deletePaylink(e){const t=[];this.storedPaylinks.forEach(a=>{a.lnurl!==e&&t.push(a)}),this.storedPaylinks=t,this.updatePaylinks()}}}),window.app.component("lnbits-wallet-extra",{template:"#lnbits-wallet-extra",props:["chartConfig"],computed:{exportUrl(){return`${window.location.origin}/wallet?usr=${this.g.user.id}&wal=${this.g.wallet.id}`}},methods:{handleSendLnurl(e){this.$emit("send-lnurl",e)},updateWallet(e){this.$emit("update-wallet",e)},handleFiatTracking(){this.g.fiatTracking=!this.g.fiatTracking,this.g.fiatTracking?(this.updateWallet({currency:this.g.wallet.currency}),this.updateFiatBalance()):(this.g.isFiatPriority=!1,this.g.wallet.currency="",this.updateWallet({currency:""}))},deleteWallet(){LNbits.utils.confirmDialog("Are you sure you want to delete this wallet?").onOk(()=>{LNbits.api.deleteWallet(this.g.wallet).then(()=>{this.g.user.wallets=this.g.user.wallets.filter(e=>e.id!==this.g.wallet.id),this.g.lastActiveWallet=this.g.user.wallets[0].id,this.$router.push(`/wallet/${this.g.lastActiveWallet}`),Quasar.Notify.create({timeout:3e3,message:"Wallet deleted!",spinner:!0})}).catch(e=>{LNbits.utils.notifyApiError(e)})})},updateFiatBalance(){this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency)&&(this.g.exchangeRate=this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency),this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat),LNbits.api.request("GET","/api/v1/rate/"+this.g.wallet.currency,null).then(e=>{this.g.fiatBalance=e.data.price/1e8*this.g.wallet.sat,this.g.exchangeRate=e.data.price.toFixed(2),this.g.fiatTracking=!0,this.$q.localStorage.set("lnbits.exchangeRate."+this.g.wallet.currency,this.g.exchangeRate),this.g.exchangeRate<=0&&(this.g.fiatTracking=!1,this.g.isFiatPriority=!1)}).catch(e=>console.error(e))}},created(){""!==this.g.wallet.currency&&this.g.isSatsDenomination?(this.g.fiatTracking=!0,this.updateFiatBalance()):this.g.fiatTracking=!1}}),window.app.component("lnbits-home-logos",{template:"#lnbits-home-logos",data:()=>({logos:[{href:"https://github.com/ElementsProject/lightning",lightSrc:"/static/images/clnl.png",darkSrc:"/static/images/cln.png"},{href:"https://github.com/lightningnetwork/lnd",lightSrc:"/static/images/lnd.png",darkSrc:"/static/images/lnd.png"},{href:"https://opennode.com",lightSrc:"/static/images/opennodel.png",darkSrc:"/static/images/opennode.png"},{href:"https://lnpay.co/",lightSrc:"/static/images/lnpayl.png",darkSrc:"/static/images/lnpay.png"},{href:"https://github.com/rootzoll/raspiblitz",lightSrc:"/static/images/blitzl.png",darkSrc:"/static/images/blitz.png"},{href:"https://start9.com/",lightSrc:"/static/images/start9l.png",darkSrc:"/static/images/start9.png"},{href:"https://getumbrel.com/",lightSrc:"/static/images/umbrell.png",darkSrc:"/static/images/umbrel.png"},{href:"https://mynodebtc.com",lightSrc:"/static/images/mynodel.png",darkSrc:"/static/images/mynode.png"},{href:"https://github.com/shesek/spark-wallet",lightSrc:"/static/images/sparkl.png",darkSrc:"/static/images/spark.png"},{href:"https://voltage.cloud",lightSrc:"/static/images/voltagel.png",darkSrc:"/static/images/voltage.png"},{href:"https://breez.technology/sdk/",lightSrc:"/static/images/breezl.png",darkSrc:"/static/images/breez.png"},{href:"https://blockstream.com/lightning/greenlight/",lightSrc:"/static/images/greenlightl.png",darkSrc:"/static/images/greenlight.png"},{href:"https://getalby.com",lightSrc:"/static/images/albyl.png",darkSrc:"/static/images/alby.png"},{href:"https://zbd.gg",lightSrc:"/static/images/zbdl.png",darkSrc:"/static/images/zbd.png"},{href:"https://phoenix.acinq.co/server",lightSrc:"/static/images/phoenixdl.png",darkSrc:"/static/images/phoenixd.png"},{href:"https://boltz.exchange/",lightSrc:"/static/images/boltzl.svg",darkSrc:"/static/images/boltz.svg"},{href:"https://www.blink.sv/",lightSrc:"/static/images/blink_logol.png",darkSrc:"/static/images/blink_logo.png"}]}),computed:{showLogos(){return this.g.isSatsDenomination&&"LNbits"==this.g.settings.siteTitle&&1==this.g.settings.showHomePageElements}}}),window.app.component("lnbits-error",{template:"#lnbits-error",props:["dynamic","code","message"],computed:{isExtension(){return 403==this.code&&(!!this.message.startsWith("Extension ")||void 0)}},methods:{goBack(){window.history.back()},goHome(){window.location="/"},goToWallet(){this.dynamic?this.$router.push("/wallet"):window.location="/wallet"},goToExtension(){const e=`/extensions#${this.message.match(/'([^']+)'/)[1]}`;this.dynamic?this.$router.push(e):window.location=e},async logOut(){try{await LNbits.api.logout(),window.location="/"}catch(e){LNbits.utils.notifyApiError(e)}}},async created(){if(!this.dynamic&&401==this.code)return console.warn(`Unauthorized: ${this.errorMessage}`),void this.logOut()}}),window.app.component("lnbits-qrcode",{template:"#lnbits-qrcode",components:{QrcodeVue:QrcodeVue.default},props:{value:{type:String,required:!0},nfc:{type:Boolean,default:!1},print:{type:Boolean,default:!1},showButtons:{type:Boolean,default:!0},href:{type:String,default:""},margin:{type:Number,default:3},maxWidth:{type:Number,default:450},logo:{type:String,default:window.g.settings.qrLogo||null}},data:()=>({nfcTagWriting:!1,nfcSupported:"undefined"!=typeof NDEFReader}),methods:{printQrCode(){const e=this.$refs.qrCode.$el.outerHTML,t=window.open("","_blank");t.document.write(`\n \n \n Print QR Code\n \n \n ${e}\n \n `),t.document.close(),t.focus(),t.print(),t.close()},clickQrCode(e){if(""===this.href)return this.utils.copyText(this.value),e.preventDefault(),e.stopPropagation(),!1},async writeNfcTag(){try{if(!this.nfcSupported)throw{toString:function(){return"NFC not supported on this device or browser."}};const e=new NDEFReader;this.nfcTagWriting=!0,this.$q.notify({message:"Tap your NFC tag to write the LNURL-withdraw link to it."}),await e.write({records:[{recordType:"url",data:this.value,lang:"en"}]}),this.nfcTagWriting=!1,this.$q.notify({type:"positive",message:"NFC tag written successfully."})}catch(e){this.nfcTagWriting=!1,this.$q.notify({type:"negative",message:e?e.toString():"An unexpected error has occurred."})}},downloadSVG(){const e=this.$refs.qrCode.$el;if(!e)return void console.error("SVG element not found");let t=(new XMLSerializer).serializeToString(e);t.match(/^]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)||(t=t.replace(/^({tab:"bech32",lnurl:""}),methods:{setLnurl(){if("bech32"==this.tab){const e=(new TextEncoder).encode(this.url),t=NostrTools.nip19.encodeBytes("lnurl",e);this.lnurl=`lightning:${t.toUpperCase()}`}else"lud17"==this.tab&&(this.url.startsWith("http://")?this.lnurl=this.url.replace("http://",this.prefix+"://"):this.lnurl=this.url.replace("https://",this.prefix+"://"));this.$emit("update:lnurl",this.lnurl)}},watch:{url(){this.setLnurl()},tab(){this.setLnurl()}},created(){this.setLnurl()}}),window.app.component("lnbits-disclaimer",{template:"#lnbits-disclaimer",computed:{showDisclaimer:()=>!g.disclaimerShown&&g.isUserAuthorized}}),window.app.component("lnbits-footer",{template:"#lnbits-footer",computed:{title(){return`${this.g.settings.siteTitle}, ${this.g.settings.siteTagline}`},version(){return this.$t("lnbits_version")+": "+this.g.settings.version}}}),window.app.component("lnbits-header",{template:"#lnbits-header",computed:{showAdmin(){return this.g.user&&(this.g.user.super_user||this.g.user.admin)},displayName(){return this.g.user?.extra?.display_name||this.g.user.username||this.g.user?.extra?.first_name||"Anon"},displayRole(){return this.g.user?.super_user?"Super User":this.g.user?.admin?"Admin":"User"}},methods:{async stopImpersonation(){try{await LNbits.api.stopImpersonation(),LNbits.utils.restoreLocalStorage("impersonation"),window.location="/users"}catch(e){console.warn(e)}},async handleLanguageChanged(e){try{await LNbits.api.updateUiCustomization({locale:e.locale}),this.$q.notify({type:"positive",message:"Language Updated",caption:e.locale})}catch(e){LNbits.utils.notifyApiError(e)}}}}),window.app.component("lnbits-header-wallets",{template:"#lnbits-header-wallets"}),window.app.component("lnbits-drawer",{template:"#lnbits-drawer"}),window.app.component("lnbits-theme",{watch:{"g.walletFlip"(e){this.$q.localStorage.setItem("lnbits.walletFlip",e),!0===e&&this.$q.screen.lt.md&&(this.g.visibleDrawer=!1)},"g.disclaimerShown"(e){this.$q.localStorage.setItem("lnbits.disclaimerShown",e)},"g.locale"(e){this.$q.localStorage.setItem("lnbits.lang",e),window.i18n.global.locale=e},"g.isFiatPriority"(e){this.$q.localStorage.setItem("lnbits.isFiatPriority",e)},"g.reactionChoice"(e){this.$q.localStorage.set("lnbits.reactions",e)},"g.themeChoice"(e){document.body.setAttribute("data-theme",e),this.$q.localStorage.set("lnbits.theme",e)},"g.darkChoice"(e){this.$q.dark.set(e),this.$q.localStorage.set("lnbits.darkMode",e),Chart.defaults.color=this.$q.dark.isActive?"#fff":"#000"},"g.borderChoice"(e){document.body.classList.forEach(e=>{e.endsWith("-border")&&document.body.classList.remove(e)}),this.$q.localStorage.setItem("lnbits.border",e),document.body.classList.add(e)},"g.gradientChoice"(e){this.$q.localStorage.set("lnbits.gradientBg",e),!0===e?document.body.classList.add("gradient-bg"):document.body.classList.remove("gradient-bg")},"g.cardRoundedChoice"(e){this.$q.localStorage.set("lnbits.cardRounded",e),!0===e?document.body.classList.add("rounded-ui"):document.body.classList.remove("rounded-ui")},"g.cardGradientChoice"(e){this.$q.localStorage.set("lnbits.cardGradient",e),!0===e?document.body.classList.add("card-gradient"):document.body.classList.remove("card-gradient")},"g.cardShadowChoice"(e){this.$q.localStorage.set("lnbits.cardShadow",e),!0===e?document.body.classList.add("card-shadow"):document.body.classList.remove("card-shadow")},"g.mobileSimple"(e){this.$q.localStorage.set("lnbits.mobileSimple",e),!0===e?document.body.classList.add("mobile-simple"):document.body.classList.remove("mobile-simple")},"g.bgimageChoice"(e){this.$q.localStorage.set("lnbits.backgroundImage",e),""===e?document.body.classList.remove("bg-image"):(document.body.classList.add("bg-image"),document.body.style.setProperty("--background",`url(${e})`))}},methods:{async checkUrlParams(){const e=new URLSearchParams(window.location.search);if(0===e.length)return;if(e.has("theme")){const t=e.get("theme").trim().toLowerCase();this.g.themeChoice=t,e.delete("theme")}if(e.has("border")){const t=e.get("border").trim().toLowerCase();this.g.borderChoice=t,e.delete("border")}if(e.has("gradient")){const t=e.get("gradient").toLowerCase();this.g.gradientChoice="1"===t||"true"===t,e.delete("gradient")}if(e.has("dark")){const t=e.get("dark").trim().toLowerCase();this.g.darkChoice="1"===t||"true"===t,e.delete("dark")}if(e.has("usr")){try{await LNbits.api.loginUsr(e.get("usr")),window.location.href="/wallet"}catch(e){LNbits.utils.notifyApiError(e)}e.delete("usr")}const t=e.size?`?${e.toString()}`:"",a=window.location.pathname+t;window.history.replaceState(null,null,a)}},created(){this.$q.dark.set(this.g.darkChoice),document.body.setAttribute("data-theme",this.g.themeChoice),Chart.defaults.color=this.$q.dark.isActive?"#fff":"#000",document.body.classList.add(this.g.borderChoice),!0===this.g.gradientChoice&&document.body.classList.add("gradient-bg"),!0===this.g.cardRoundedChoice&&document.body.classList.add("rounded-ui"),!0===this.g.cardGradientChoice&&document.body.classList.add("card-gradient"),!0===this.g.cardShadowChoice&&document.body.classList.add("card-shadow"),""!==this.g.bgimageChoice&&(document.body.classList.add("bg-image"),document.body.style.setProperty("--background",`url(${this.g.bgimageChoice})`)),!0===this.g.mobileSimple&&document.body.classList.add("mobile-simple"),Object.entries(this.g.user?.uiCustomization||{}).forEach(([e,t])=>{e in this.g&&(this.g[e]=t)}),this.checkUrlParams()}}),window.app.component("lnbits-qrcode-scanner",{template:"#lnbits-qrcode-scanner",props:["callback"],data:()=>({showScanner:!1}),watch:{callback(e){return null===e?this.reset():"function"!=typeof e?(Quasar.Notify.create({message:"QR code scanner callback is not a function.",type:"negative"}),this.reset()):!1===this.g.hasCamera?(Quasar.Notify.create({message:"No camera found on this device.",type:"negative"}),this.reset()):void(this.showScanner=!0)}},methods:{reset(){this.showScanner=!1,this.g.scanner=null},detect(e){const t=e[0].rawValue;console.log("Detected QR code value:",t),this.callback(t),this.$emit("detect",t),this.reset()},async onInitQR(e){try{await e}catch(e){const t={NotAllowedError:"ERROR: you need to grant camera access permission",NotFoundError:"ERROR: no camera on this device",NotSupportedError:"ERROR: secure context required (HTTPS, localhost)",NotReadableError:"ERROR: is the camera already in use?",OverconstrainedError:"ERROR: installed cameras are not suitable",StreamApiNotSupportedError:"ERROR: Stream API is not supported in this browser",InsecureContextError:"ERROR: Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP."},a=Object.keys(t).filter(t=>e.name===t),s=a?t[a]:`ERROR: Camera error (${e.name})`;Quasar.Notify.create({message:s,type:"negative"}),this.g.hasCamera=!1,this.reset()}}}}),window.app.component("lnbits-manage-extension-list",{template:"#lnbits-manage-extension-list",data:()=>({extensions:[],userExtensions:[],searchTerm:""}),watch:{"g.user.extensions"(){this.loadExtensions()},searchTerm(){this.filterUserExtensionsByTerm()}},methods:{async loadExtensions(){try{res=await LNbits.api.request("GET","/api/v1/extension"),this.extensions=res.data.sort((e,t)=>e.name.localeCompare(t.name)),this.filterUserExtensionsByTerm()}catch(e){LNbits.utils.notifyApiError(e)}},filterUserExtensionsByTerm(){const e=this.g.user.extensions;this.userExtensions=this.extensions.filter(t=>e.includes(t.code)).filter(e=>""===this.searchTerm||`${e.code} ${e.name} ${e.short_description} ${e.url}`.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase()))}},async created(){await this.loadExtensions()}}),window.app.component("lnbits-manage-wallet-list",{template:"#lnbits-manage-wallet-list",data:()=>({activeWalletId:null}),computed:{maxWallets(){return this.g.user?.extra?.visible_wallet_count||10}},watch:{$route(e){e.path.startsWith("/wallet/")?this.activeWalletId=e.params.id:this.activeWalletId=null},"g.user.wallets":{handler(){this.paymentEvents()},deep:!0,immediate:!0}},created(){this.g.user&&0===this.g.walletEventListeners.length&&this.paymentEvents()},methods:{openNewWalletDialog(){this.g.user.walletInvitesCount?this.g.newWalletType="lightning-shared":this.g.newWalletType="lightning"},onWebsocketMessage(e){const t=JSON.parse(e.data);t.payment?(this.g.user.wallets.forEach(e=>{e.id===t.payment.wallet_id&&(e.sat=t.wallet_balance)}),this.g.wallet.id===t.payment.wallet_id&&(this.g.wallet.sat=t.wallet_balance,this.g.updatePayments=!this.g.updatePayments,this.g.updatePaymentsHash=!this.g.updatePaymentsHash),t.payment.amount>0&&eventReaction(1e3*t.wallet_balance)):console.error("ws message no payment",t)},paymentEvents(){if(!this.g.user)return;let e;this.g.user.wallets.slice(0,this.maxWallets).forEach(t=>{if(!this.g.walletEventListeners.includes(t.id)){this.g.walletEventListeners.push(t.id);const a=new WebSocket(`${websocketUrl}/${t.inkey}`);a.onmessage=this.onWebsocketMessage,a.onopen=()=>console.log("ws connected for wallet",t.id),a.onclose=()=>{console.log("ws closed, reconnecting...",t.id),this.g.walletEventListeners=this.g.walletEventListeners.filter(e=>e!==t.id),clearTimeout(e),e=setTimeout(this.paymentEvents,5e3)},a.onerror=()=>{console.warn("ws error, reconnecting...",t.id),this.g.walletEventListeners=this.g.walletEventListeners.filter(e=>e!==t.id),clearTimeout(e),e=setTimeout(this.paymentEvents,5e3)}}})}}}),window.app.component("lnbits-language-dropdown",{template:"#lnbits-language-dropdown",computed:{currentLanguage(){return this.langs.find(e=>e.value===window.i18n.global.locale)||{value:"en",label:"English",display:"🇬🇧 EN"}}},methods:{activeLanguage:e=>window.i18n.global.locale===e,changeLanguage(e){this.g.locale=e,window.i18n.global.locale=e,this.$q.localStorage.set("lnbits.lang",e),this.$emit("language-changed",e)}},data:()=>({langs:[{value:"en",label:"English",display:"🇬🇧 EN"},{value:"de",label:"Deutsch",display:"🇩🇪 DE"},{value:"es",label:"Español",display:"🇪🇸 ES"},{value:"jp",label:"日本語",display:"🇯🇵 JP"},{value:"cn",label:"中文",display:"🇨🇳 CN"},{value:"fr",label:"Français",display:"🇫🇷 FR"},{value:"it",label:"Italiano",display:"🇮🇹 IT"},{value:"pi",label:"Pirate",display:"🏴‍☠️ PI"},{value:"nl",label:"Nederlands",display:"🇳🇱 NL"},{value:"we",label:"Cymraeg",display:"🏴󠁧󠁢󠁷󠁬󠁳󠁿 CY"},{value:"pl",label:"Polski",display:"🇵🇱 PL"},{value:"pt",label:"Português",display:"🇵🇹 PT"},{value:"br",label:"Português do Brasil",display:"🇧🇷 BR"},{value:"cs",label:"Česky",display:"🇨🇿 CS"},{value:"sk",label:"Slovensky",display:"🇸🇰 SK"},{value:"kr",label:"한국어",display:"🇰🇷 KR"},{value:"fi",label:"Suomi",display:"🇫🇮 FI"}]})}),window.app.component("lnbits-payment-list",{template:"#lnbits-payment-list",props:["wallet","paymentFilter"],data(){return{payments:[],paymentsTable:{columns:[{name:"time",align:"left",label:this.$t("memo")+"/"+this.$t("date"),field:"date",sortable:!0},{name:"amount",align:"right",label:this.$t("amount"),field:"sat",sortable:!0}],pagination:{rowsPerPage:10,page:1,sortBy:"time",descending:!0,rowsNumber:10},sortFields:[{name:"amount",label:"Amount"},{name:"fee",label:"Fee"},{name:"memo",label:"Memo"},{name:"time",label:"Creation Date"},{name:"updated_at",label:"Last Updated"}],search:"",loading:!1},searchDate:{from:null,to:null},searchStatus:{success:!0,pending:!0,failed:!1,incoming:!0,outgoing:!0},exportTagName:"",exportPaymentTagList:[],paymentsCSV:{columns:[{name:"status",align:"right",label:this.$t("status"),field:"status"},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"},{name:"time",align:"left",label:this.$t("date"),field:"date",sortable:!0},{name:"amount",align:"right",label:this.$t("amount"),field:"sat",sortable:!0},{name:"fee",align:"right",label:this.$t("fee"),field:"fee"},{name:"tag",align:"right",label:this.$t("tag"),field:"tag"},{name:"payment_hash",align:"right",label:this.$t("payment_hash"),field:"payment_hash"},{name:"payment_proof",align:"right",label:this.$t("payment_proof"),field:"payment_proof"},{name:"webhook",align:"right",label:this.$t("webhook"),field:"webhook"},{name:"fiat_currency",align:"right",label:"Fiat Currency",field:e=>e.extra.wallet_fiat_currency},{name:"fiat_amount",align:"right",label:"Fiat Amount",field:e=>e.extra.wallet_fiat_amount}],preimage:null,loading:!1},hodlInvoice:{show:!1,payment:null,preimage:null},selectedPayment:null,filterLabels:[]}},computed:{filteredPayments(){const e=this.paymentsTable.search;return e&&""!==e?LNbits.utils.search(this.payments,e):this.payments},paymentsOmitter(){return this.$q.screen.lt.md&&this.g.mobileSimple?this.payments.length>0?[this.payments[0]]:[]:this.payments},pendingPaymentsExist(){return-1!==this.payments.findIndex(e=>e.pending)}},methods:{mapPayment(e){const t={checking_id:e.checking_id,status:e.status,amount:e.amount,fee:e.fee,memo:e.memo,time:e.time,bolt11:e.bolt11,preimage:e.preimage,payment_hash:e.payment_hash,expiry:e.expiry,extra:e.extra??{},wallet_id:e.wallet_id,webhook:e.webhook,webhook_status:e.webhook_status,fiat_amount:e.fiat_amount,fiat_currency:e.fiat_currency,labels:e.labels};t.date=this.utils.formatDate(e.created_at),t.dateFrom=this.utils.formatDateFrom(e.created_at),t.expirydate=this.utils.formatDate(e.expiry),t.expirydateFrom=this.utils.formatDateFrom(e.expiry),t.msat=t.amount,t.sat=t.msat/1e3,t.tag=t.extra?.tag,t.fsat=this.utils.formatSat(t.sat),t.isIn=t.amount>0,t.isOut=t.amount<0,t.isPending="pending"===t.status,t.isPaid="success"===t.status,t.isFailed="failed"===t.status,t._q=[t.memo,t.sat].join(" ").toLowerCase();try{t.details=JSON.parse(e.extra?.details||"{}")}catch{t.details={extraDetails:e.extra?.details}}return t},searchByDate(){"string"==typeof this.searchDate&&(this.searchDate={from:this.searchDate,to:this.searchDate}),this.searchDate.from&&(this.paymentFilter["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(this.paymentFilter["time[le]"]=this.searchDate.to+"T23:59:59"),this.fetchPayments()},searchByLabels(e){e&&0!==e.length?(this.filterLabels=e,this.paymentsTable.filter["labels[every]"]=e,this.fetchPayments()):this.clearLabelSeach()},clearDateSeach(){this.searchDate={from:null,to:null},delete this.paymentFilter["time[ge]"],delete this.paymentFilter["time[le]"],this.fetchPayments()},clearLabelSeach(){this.filterLabels=[],delete this.paymentsTable.filter["labels[every]"],this.fetchPayments()},fetchPayments(e){this.paymentsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e,this.paymentFilter);return LNbits.api.getPayments(this.wallet,t).then(e=>{this.paymentsTable.pagination.rowsNumber=e.data.total,this.payments=e.data.data.map(this.mapPayment),this.paymentsTable.loading=!1,this.recheckPendingPayments()}).catch(e=>{this.paymentsTable.loading=!1,g.user.admin?this.fetchPaymentsAsAdmin(this.wallet.id,t):LNbits.utils.notifyApiError(e)})},sortByColumn(e){this.paymentsTable.pagination.sortBy===e?this.paymentsTable.pagination.descending=!this.paymentsTable.pagination.descending:(this.paymentsTable.pagination.sortBy=e,this.paymentsTable.pagination.descending=!1),this.fetchPayments()},fetchPaymentsAsAdmin(e,t){return t=(t||"")+"&wallet_id="+e,LNbits.api.request("GET","/api/v1/payments/all/paginated?"+t).then(e=>{this.paymentsTable.loading=!1,this.paymentsTable.pagination.rowsNumber=e.data.total,this.payments=e.data.data.map(this.mapPayment)}).catch(e=>{this.paymentsTable.loading=!1,LNbits.utils.notifyApiError(e)})},checkPayment(e){LNbits.api.getPayment(this.wallet,e).then(e=>{this.update=!this.update,"success"==e.data.status&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")}),"pending"==e.data.status&&Quasar.Notify.create({type:"info",message:this.$t("payment_pending")})}).catch(LNbits.utils.notifyApiError)},recheckPendingPayments(){const e=this.payments.filter(e=>"pending"===e.status);if(0===e.length)return;const t=["recheck_pending=true","checking_id[in]="+e.map(e=>e.checking_id).join(",")].join("&");LNbits.api.getPayments(this.wallet,t).then(e=>{let t=0;e.data.data.forEach(e=>{if("pending"!==e.status){const a=this.payments.findIndex(t=>t.checking_id===e.checking_id);-1!==a&&(this.payments.splice(a,1,this.mapPayment(e)),t+=1)}}),t>0&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")})}).catch(e=>{console.warn(e)})},showHoldInvoiceDialog(e){this.hodlInvoice.show=!0,this.hodlInvoice.preimage="",this.hodlInvoice.payment=e},cancelHoldInvoice(e){LNbits.api.cancelInvoice(this.wallet,e).then(()=>{this.update=!this.update,Quasar.Notify.create({type:"positive",message:this.$t("invoice_cancelled")})}).catch(LNbits.utils.notifyApiError)},settleHoldInvoice(e){LNbits.api.settleInvoice(this.wallet,e).then(()=>{this.update=!this.update,Quasar.Notify.create({type:"positive",message:this.$t("invoice_settled")})}).catch(LNbits.utils.notifyApiError)},paymentTableRowKey:e=>e.payment_hash+e.amount,exportCSV(e=!1){const t=this.paymentsTable.pagination,a={sortby:t.sortBy??"time",direction:t.descending?"desc":"asc"},s=new URLSearchParams(a);LNbits.api.getPayments(this.wallet,s).then(t=>{let a=t.data.data.map(this.mapPayment),s=this.paymentsCSV.columns;if(e){this.exportPaymentTagList.length&&(a=a.filter(e=>this.exportPaymentTagList.includes(e.tag)));const e=Object.keys(a.reduce((e,t)=>({...e,...t.details}),{})).map(e=>({name:e,align:"right",label:e.charAt(0).toUpperCase()+e.slice(1).replace(/([A-Z])/g," $1"),field:t=>t.details[e],format:e=>"object"==typeof e?JSON.stringify(e):e}));s=this.paymentsCSV.columns.concat(e)}LNbits.utils.exportCSV(s,a,this.wallet.name+"-payments")})},addFilterTag(){if(!this.exportTagName)return;const e=this.exportTagName.trim();this.exportPaymentTagList=this.exportPaymentTagList.filter(t=>t!==e),this.exportPaymentTagList.push(e),this.exportTagName=""},removeExportTag(e){this.exportPaymentTagList=this.exportPaymentTagList.filter(t=>t!==e)},formatCurrency(e,t){try{return LNbits.utils.formatCurrency(e,t)}catch(t){return console.error(t),`${e} ???`}},handleFilterChanged(){const{success:e,pending:t,failed:a,incoming:s,outgoing:i}=this.searchStatus;let n=this.paymentFilter||{};delete n["status[ne]"],delete n["status[eq]"],e&&t&&a||(e&&t?n["status[ne]"]="failed":e&&a?n["status[ne]"]="pending":a&&t?n["status[ne]"]="success":!e||t||a?!t||e||a?!a||e||t||(n["status[eq]"]="failed"):n["status[eq]"]="pending":n["status[eq]"]="success"),delete n["amount[ge]"],delete n["amount[le]"],s&&i||!s&&!i||(s&&!i?n["amount[ge]"]=0:i&&!s&&(n["amount[le]"]=0)),this.paymentFilter=n},async savePaymentLabels(e){if(this.selectedPayment)try{await LNbits.api.request("PUT",`/api/v1/payments/${this.selectedPayment.payment_hash}/labels`,this.wallet.adminkey,{labels:e});const t=this.payments.find(e=>e.checking_id===this.selectedPayment.checking_id);t&&(t.labels=[...e]),Quasar.Notify.create({type:"positive",message:this.$t("payment_labels_updated")})}catch(e){LNbits.utils.notifyApiError(e)}else Quasar.Notify.create({type:"warning",message:"No payment selected"})},isLightColor(e){try{return Quasar.colors.luminosity(e)>.5}catch(e){return console.warning(e),!1}}},watch:{"paymentsTable.search":{handler(){const e={};this.paymentsTable.search&&(e.search=this.paymentsTable.search),this.fetchPayments()}},"g.updatePayments"(){this.fetchPayments()}},created(){this.fetchPayments()}}),window.app.component("lnbits-label-selector",{template:"#lnbits-label-selector",props:["labels"],data:()=>({labelFilter:"",localLabels:[]}),methods:{toggleLabel(e){if(this.localLabels.includes(e.name)){const t=this.localLabels.indexOf(e.name);-1!==t&&this.localLabels.splice(t,1)}else this.localLabels.push(e.name)},saveLabels(){this.$emit("update:labels",this.localLabels)},clearLabels(){this.localLabels=[],this.saveLabels()}},created(){this.localLabels=[...this.labels]}}),window.app.component("lnbits-extension-settings-form",{name:"lnbits-extension-settings-form",template:"#lnbits-extension-settings-form",props:["options","adminkey","endpoint"],methods:{async updateSettings(){if(!this.settings)return Quasar.Notify.create({message:"No settings to update",type:"negative"});try{const{data:e}=await LNbits.api.request("PUT",this.endpoint,this.adminkey,this.settings);this.settings=e}catch(e){LNbits.utils.notifyApiError(e)}},async getSettings(){try{const{data:e}=await LNbits.api.request("GET",this.endpoint,this.adminkey);this.settings=e}catch(e){LNbits.utils.notifyApiError(e)}},async resetSettings(){LNbits.utils.confirmDialog("Are you sure you want to reset the settings?").onOk(async()=>{try{await LNbits.api.request("DELETE",this.endpoint,this.adminkey),await this.getSettings()}catch(e){LNbits.utils.notifyApiError(e)}})}},async created(){await this.getSettings()},data:()=>({settings:void 0})}),window.app.component("lnbits-extension-settings-btn-dialog",{template:"#lnbits-extension-settings-btn-dialog",name:"lnbits-extension-settings-btn-dialog",props:["options","adminkey","endpoint"],data:()=>({show:!1})}),window.app.component("lnbits-data-fields",{name:"lnbits-data-fields",template:"#lnbits-data-fields",props:["fields","hide-advanced"],data:()=>({fieldTypes:[{label:"Text",value:"str"},{label:"Integer",value:"int"},{label:"Float",value:"float"},{label:"Boolean",value:"bool"},{label:"Date Time",value:"datetime"},{label:"JSON",value:"json"},{label:"Wallet Select",value:"wallet"},{label:"Currency Select",value:"currency"}],fieldsTable:{columns:[{name:"name",align:"left",label:"Field Name",field:"name",sortable:!0},{name:"type",align:"left",label:"Type",field:"type",sortable:!1},{name:"label",align:"left",label:"UI Label",field:"label",sortable:!0},{name:"hint",align:"left",label:"UI Hint",field:"hint",sortable:!1},{name:"optional",align:"left",label:"Optional",field:"optional",sortable:!1}],pagination:{sortBy:"name",rowsPerPage:100,page:1,rowsNumber:100},search:null,hideEmpty:!0}}),methods:{addField:function(){this.fields.push({name:"field_name_"+(this.fields.length+1),type:"text",label:"",hint:"",optional:!0,sortable:!0,searchable:!0,editable:!0,fields:[]})},removeField:function(e){const t=this.fields.indexOf(e);t>-1&&this.fields.splice(t,1)}},async created(){this.hideAdvanced||this.fieldsTable.columns.push({name:"editable",align:"left",label:"UI Editable",field:"editable",sortable:!1},{name:"sortable",align:"left",label:"Sortable",field:"sortable",sortable:!1},{name:"searchable",align:"left",label:"Searchable",field:"searchable",sortable:!1})}}),window.app.component(QrcodeVue),window.app.component("lnbits-extension-rating",{template:"#lnbits-extension-rating",name:"lnbits-extension-rating",props:{rating:{type:Number,default:0},count:{type:Number,default:null},clickable:{type:Boolean,default:!1}},computed:{displayRating(){return Math.round(2*(this.rating||0))/2},hasData(){return null!==this.count&&void 0!==this.count}},methods:{handleClick(){this.clickable&&this.$emit("click")}}}),window.app.component("lnbits-manage",{template:"#lnbits-manage",methods:{isActive:e=>window.location.pathname===e},data:()=>({extensions:[]})}),window.app.component("lnbits-payment-details",{template:"#lnbits-payment-details",props:["payment"],computed:{hasPreimage(){return this.payment.preimage&&"0000000000000000000000000000000000000000000000000000000000000000"!==this.payment.preimage},hasExpiry(){return!!this.payment.expiry},hasSuccessAction(){return this.hasPreimage&&this.payment.extra&&this.payment.extra.success_action},webhookStatusColor(){return this.payment.webhook_status>=300||this.payment.webhook_status<0?"red-10":this.payment.webhook_status?"green-10":"cyan-7"},webhookStatusText(){return this.payment.webhook_status?this.payment.webhook_status:"not sent yet"},hasTag(){return this.payment.extra&&!!this.payment.extra.tag},extras(){if(!this.payment.extra)return[];let e=_.omit(this.payment.extra,["tag","success_action"]);return Object.keys(e).map(t=>({key:t,value:e[t]}))}}}),window.app.component("lnbits-lnurlpay-success-action",{template:"#lnbits-lnurlpay-success-action",props:["payment","success_action"],data(){return{decryptedValue:this.success_action.ciphertext}},mounted(){if("aes"!==this.success_action.tag)return null;this.utils.decryptLnurlPayAES(this.success_action,this.payment.preimage).then(e=>{this.decryptedValue=e})}}),window.app.component("lnbits-notifications-btn",{template:"#lnbits-notifications-btn",props:["pubkey"],data:()=>({isSupported:!1,isSubscribed:!1,isPermissionGranted:!1,isPermissionDenied:!1}),methods:{urlB64ToUint8Array(e){const t=(e+"=".repeat((4-e.length%4)%4)).replace(/\-/g,"+").replace(/_/g,"/"),a=atob(t),s=new Uint8Array(a.length);for(let e=0;et!==e),this.$q.localStorage.set("lnbits.webpush.subscribedUsers",JSON.stringify(t))},isUserSubscribed(e){return(JSON.parse(this.$q.localStorage.getItem("lnbits.webpush.subscribedUsers"))||[]).includes(e)},subscribe(){this.isSupported&&!this.isPermissionDenied&&(Notification.requestPermission().then(e=>{this.isPermissionGranted="granted"===e,this.isPermissionDenied="denied"===e}).catch(console.log),navigator.serviceWorker.ready.then(e=>{navigator.serviceWorker.getRegistration().then(e=>{e.pushManager.getSubscription().then(t=>{if(null===t||!this.isUserSubscribed(this.g.user.id)){const t={applicationServerKey:this.urlB64ToUint8Array(this.pubkey),userVisibleOnly:!0};e.pushManager.subscribe(t).then(e=>{LNbits.api.request("POST","/api/v1/webpush",null,{subscription:JSON.stringify(e)}).then(e=>{this.saveUserSubscribed(e.data.user),this.isSubscribed=!0}).catch(LNbits.utils.notifyApiError)})}}).catch(console.log)})}))},unsubscribe(){navigator.serviceWorker.ready.then(e=>{e.pushManager.getSubscription().then(e=>{e&&LNbits.api.request("DELETE","/api/v1/webpush?endpoint="+btoa(e.endpoint),null).then(()=>{this.removeUserSubscribed(this.g.user.id),this.isSubscribed=!1}).catch(LNbits.utils.notifyApiError)})}).catch(console.log)},checkSupported(){let e="https:"===window.location.protocol,t="serviceWorker"in navigator,a="Notification"in window,s="PushManager"in window;return this.isSupported=e&&t&&a&&s,this.isSupported||console.log("Notifications disabled because requirements are not met:",{HTTPS:e,"Service Worker API":t,"Notification API":a,"Push API":s}),this.isSupported},async updateSubscriptionStatus(){await navigator.serviceWorker.ready.then(e=>{e.pushManager.getSubscription().then(e=>{this.isSubscribed=!!e&&this.isUserSubscribed(this.g.user.id)})}).catch(console.log)}},created(){this.isPermissionDenied="denied"===Notification.permission,this.checkSupported()&&this.updateSubscriptionStatus()}}),window.app.component("lnbits-dynamic-fields",{template:"#lnbits-dynamic-fields",props:["options","modelValue"],data:()=>({formData:null,rules:[e=>!!e||"Field is required"]}),methods:{applyRules(e){return e?this.rules:[]},buildData(e,t={}){return e.reduce((e,a)=>(a.options?.length?e[a.name]=this.buildData(a.options,t[a.name]):e[a.name]=t[a.name]??a.default,e),{})},handleValueChanged(){this.$emit("update:model-value",this.formData)}},created(){this.formData=this.buildData(this.options,this.modelValue)}}),window.app.component("lnbits-dynamic-chips",{template:"#lnbits-dynamic-chips",props:["modelValue"],data:()=>({chip:"",chips:[]}),methods:{addChip(){this.chip&&(this.chips.push(this.chip),this.chip="",this.$emit("update:model-value",this.chips.join(",")))},removeChip(e){this.chips.splice(e,1),this.$emit("update:model-value",this.chips.join(","))}},created(){"string"==typeof this.modelValue?this.chips=this.modelValue.split(","):this.chips=[...this.modelValue]}}),window.app.component("lnbits-update-balance",{template:"#lnbits-update-balance",props:["wallet_id","small_btn"],computed:{admin(){return!0===this.g.user?.super_user}},data:()=>({credit:0}),methods:{updateBalance(e){LNbits.api.updateBalance(e.value,this.wallet_id).then(t=>{if(!0!==t.data.success)throw new Error(t.data);credit=parseInt(e.value),Quasar.Notify.create({type:"positive",message:this.$t("credit_ok",{amount:credit}),icon:null}),this.credit=0,e.value=0,e.set()}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("user-id-only",{template:"#user-id-only",props:{allowed_new_users:Boolean,authAction:String,authMethod:String,usr:String,wallet:String},data(){return{user:this.usr,walletName:this.wallet}},methods:{showLogin(e){this.$emit("show-login",e)},showRegister(e){this.$emit("show-register",e)},loginUsr(){this.$emit("update:usr",this.user),this.$emit("login-usr")},createWallet(){this.$emit("update:wallet",this.walletName),this.$emit("create-wallet")}},computed:{showInstantLogin(){return"username-password"!==this.authMethod||"register"!==this.authAction}},created(){}}),window.app.component("username-password",{template:"#username-password",props:{allowed_new_users:Boolean,authMethods:Array,authAction:String,username:String,password_1:String,password_2:String,invitationCode:String,resetKey:String},data(){return{oauth:["nostr-auth-nip98","google-auth","github-auth","keycloak-auth"],username:this.userName,password:this.password_1,passwordRepeat:this.password_2,reset_key:this.resetKey,confirmationMethod:"code",confirmationEmail:"",confirmationCode:this.invitationCode||"",showConfirmationCode:!1}},methods:{login(){this.$emit("update:userName",this.username),this.$emit("update:password_1",this.password),this.$emit("login")},register(){this.$emit("update:userName",this.username),this.$emit("update:password_1",this.password),this.$emit("update:password_2",this.passwordRepeat),this.$emit("update:invitationCode",this.confirmationCode),this.$emit("register")},reset(){this.$emit("update:resetKey",this.reset_key),this.$emit("update:password_1",this.password),this.$emit("update:password_2",this.passwordRepeat),this.$emit("reset")},validateUsername:e=>new RegExp("^(?=[a-zA-Z0-9._]{2,20}$)(?!.*[_.]{2})[^_.].*[^_.]$").test(e),async signInWithNostr(){try{const e=await this.createNostrToken();if(!e)return;resp=await LNbits.api.loginByProvider("nostr",{Authorization:e},{}),window.location.href="/wallet"}catch(e){console.warn(e);const t=e?.response?.data?.detail||`${e}`;Quasar.Notify.create({type:"negative",message:"Failed to sign in with Nostr.",caption:t})}},async createNostrToken(){try{if(!window.nostr?.signEvent)return void Quasar.Notify.create({type:"negative",message:"No Nostr signing app detected.",caption:'Is "window.nostr" present?'});const e=`${window.location}nostr`,t="POST",a=await NostrTools.nip98.getToken(e,t,e=>async function(e){try{const{data:t}=await LNbits.api.getServerHealth();return e.created_at=t.server_time,await window.nostr.signEvent(e)}catch(e){console.error(e),Quasar.Notify.create({type:"negative",message:"Failed to sign nostr event.",caption:`${e}`})}}(e),!0);if(!await NostrTools.nip98.validateToken(a,e,t))throw new Error("Invalid signed token!");return a}catch(e){console.warn(e),Quasar.Notify.create({type:"negative",message:"Failed create Nostr event.",caption:`${e}`})}}},computed:{showOauth(){return this.oauth.some(e=>this.authMethods.includes(e))},disableRegister(){const e=!!this.username,t=!!this.password&&this.password.length>=8,a=this.password===this.passwordRepeat,s=0===this.confirmationMethodsCount||"code"!==this.confirmationMethod||this.confirmationCode.length>0;return!(e&&t&&a&&s)},confirmationMethodsCount(){return[this.g.settings.userActivationByEmail,this.g.settings.userActivationByPayment,this.g.settings.userActivationByInvitationCode].filter(Boolean).length}},created(){}}),window.app.component("separator-text",{template:"#separator-text",props:{text:String,uppercase:{type:Boolean,default:!1},color:{type:String,default:"grey"}}}),window.app.component("lnbits-node-ranks",{props:["ranks"],data:()=>({stats:[{label:"Capacity",key:"capacity"},{label:"Channels",key:"channelcount"},{label:"Age",key:"age"},{label:"Growth",key:"growth"},{label:"Availability",key:"availability"}]}),template:"\n \n
\n
1ml Node Rank
\n
\n
\n
{{ stat.label }}
\n
\n {{ (ranks && ranks[stat.key]) ?? '-' }}\n
\n
\n
\n
\n \n "}),window.app.component("lnbits-channel-stats",{props:["stats"],data:()=>({states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}]}),template:"\n \n
\n
Channels
\n
\n
\n
\n {{ state.label }}\n
\n
\n {{ (stats?.counts && stats.counts[state.value]) ?? \"-\" }}\n
\n
\n
\n
\n
\n "}),window.app.component("lnbits-stat",{props:["title","amount","msat","btc"],computed:{value(){return this.amount??(this.btc?LNbits.utils.formatSat(this.btc):LNbits.utils.formatMsat(this.msat))}},template:"\n \n \n
\n {{ title }}\n
\n
\n {{ value }}\n sats\n BTC\n
\n
\n
\n "}),window.app.component("lnbits-node-qrcode",{props:["info"],template:'\n \n \n
\n
\n \n
\n No addresses available\n
\n
\n
\n
\n \n Public Key Click to copy \n \n \n
\n '}),window.app.component("lnbits-channel-balance",{props:["balance","color"],methods:{formatMsat:e=>LNbits.utils.formatMsat(e)},template:'\n
\n
\n \n Local: {{ formatMsat(balance.local_msat) }}\n sats\n \n \n Remote: {{ formatMsat(balance.remote_msat) }}\n sats\n \n
\n\n \n
\n \n {{ balance.alias }}\n \n
\n \n
\n '}),window.app.component("lnbits-node-info",{props:["info"],data:()=>({showDialog:!1}),methods:{shortenNodeId:e=>e?e.substring(0,5)+"..."+e.substring(e.length-5):"..."},template:"\n
\n
{{ this.info.alias }}
\n
\n
{{ this.info.backend_name }}
\n \n #{{ this.info.color }}\n \n
{{ shortenNodeId(this.info.id) }}
\n \n \n
\n \n \n \n
\n "}),window.app.component("lnbits-stat",{props:["title","amount","msat","btc"],computed:{value(){return this.amount??(this.btc?LNbits.utils.formatSat(this.btc):LNbits.utils.formatMsat(this.msat))}},template:"\n \n \n
\n {{ title }}\n
\n
\n {{ value }}\n sats\n BTC\n
\n
\n
\n "});const quasarConfig={config:{loading:{spinner:Quasar.QSpinnerBars},table:{rowsPerPageOptions:[5,10,20,50,100,200,500,0]}}},DynamicComponent={async created(){const e=this.$route.path.split("/")[1],t=`/${e}/`,a=`/${e}/static/routes.json`;this.$router.getRoutes().some(e=>e.path===t)||this.$route.fullPath.startsWith("/extensions/builder/preview")||fetch(a).then(async e=>{if(!e.ok)throw new Error("No dynamic routes found");(await e.json()).forEach(e=>{console.log("Adding dynamic route:",e.path),window.router.addRoute({path:e.path,name:e.name,component:async()=>(await LNbits.utils.loadTemplate(e.template),await LNbits.utils.loadScript(e.component),window[e.name])}),window.router.push(this.$route.fullPath)})}).catch(()=>{let e=RENDERED_ROUTE;if(2===e.split("/").length&&(e+="/"),e!==this.$route.path)return console.log("Redirecting to non-vue route:",this.$route.fullPath),void(window.location=this.$route.fullPath)})}},routes=[{path:"/node",name:"Node",component:PageNode},{path:"/node/public",name:"NodePublic",component:PageNodePublic},{path:"/payments",name:"Payments",component:PagePayments},{path:"/audit",name:"Audit",component:PageAudit},{path:"/wallet",redirect:e=>{const t=window.g?.lastActiveWallet||window.g?.user?.wallets[0].id;return`/wallet/${e.query.wal||t||"default"}`}},{path:"/wallet/:id",name:"Wallet",component:PageWallet},{path:"/wallets",name:"Wallets",component:PageWallets},{path:"/users",name:"Users",component:PageUsers},{path:"/admin",name:"Admin",component:PageAdmin},{path:"/account",name:"Account",component:PageAccount},{path:"/extensions/builder",name:"ExtensionsBuilder",component:PageExtensionBuilder},{path:"/extensions/builder/preview",name:"ExtensionsBuilderPreview",component:PageExtensionBuilderPreview},{path:"/extensions",name:"Extensions",component:PageExtensions},{path:"/first_install",name:"FirstInstall",component:PageFirstInstall},{path:"/",name:"PageHome",component:PageHome},{path:"/error",name:"PageError",component:PageError},{path:"/:pathMatch(.*)*",name:"DynamicComponent",component:DynamicComponent}];window.router=VueRouter.createRouter({history:VueRouter.createWebHistory(),routes:routes}),window.LOCALE=window.g.locale,window.i18n=new VueI18n.createI18n({locale:window.g.locale,fallbackLocale:"en",messages:window.localisation}),window.app.mixin({data:()=>({api:window._lnbitsApi,utils:window._lnbitsUtils,g:window.g}),methods:{copyText:window._lnbitsUtils.copyText,formatBalance:window._lnbitsUtils.formatBalance}}),window.app.use(VueQrcodeReader),window.app.use(Quasar,quasarConfig),window.app.use(window.i18n),window.app.use(window.router),window.app.mount("#vue"); \ No newline at end of file +window.PageError={template:"#page-error"},window.PageHome={template:"#page-home",data:()=>({lnurl:"",authAction:"login",authMethod:"username-password",usr:"",username:"",reset_key:"",email:"",password:"",passwordRepeat:"",invitationCode:"",walletName:"",signup:!1}),computed:{showClaimLnurl(){return""!==this.lnurl&&this.g.settings.allowRegister&&this.g.settings.authMethods.includes("user-id-only")},formatDescription(){return LNbits.utils.convertMarkdown(this.g.settings.siteDescription)},isAccessTokenExpired(){return this.$q.cookies.get("is_access_token_expired")}},methods:{showLogin(e){this.authAction="login",this.authMethod=e},showRegister(e){this.user="",this.username=null,this.password=null,this.passwordRepeat=null,this.invitationCode=null,this.authAction="register",this.authMethod=e},async register(){try{await LNbits.api.register(this.username,this.email,this.password,this.passwordRepeat,this.invitationCode),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async reset(){try{await LNbits.api.reset(this.reset_key,this.password,this.passwordRepeat),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async login(){try{await LNbits.api.login(this.username,this.password),this.refreshAuthUser()}catch(e){LNbits.utils.notifyApiError(e)}},async loginUsr(){try{await LNbits.api.loginUsr(this.usr),this.refreshAuthUser()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async refreshAuthUser(){try{const e=await LNbits.api.getAuthUser();this.g.user=LNbits.map.user(e.data),this.g.isPublicPage=!1,this.$router.push(`/wallet/${this.g.user.wallets[0].id}`)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},createWallet(){LNbits.api.createAccount(this.walletName).then(e=>{this.$router.push(`/wallet/${e.data.id}`)})},processing(){Quasar.Notify.create({timeout:0,message:"Processing...",icon:null})}},created(){if(this.g.isUserAuthorized)return this.refreshAuthUser();const e=new URLSearchParams(window.location.search);this.reset_key=e.get("reset_key"),this.reset_key&&(this.authAction="reset"),e.has("lightning")&&(this.lnurl=e.get("lightning"))}},window.PageExtensionBuilder={template:"#page-extension-builder",data:()=>({step:1,previewStepNames:{2:"settings",3:"owner_data",4:"client_data",5:"public_page"},extensionDataCleanString:"",extensionData:{id:"",name:"",stub_version:"",short_description:"",description:"",public_page:{has_public_page:!0,owner_data_fields:{name:"",description:""},client_data_fields:{public_inputs:[]},action_fields:{generate_action:!0,generate_payment_logic:!1,wallet_id:"",currency:"",amount:"",paid_flag:""}},preview_action:{is_preview_mode:!1,is_settings_preview:!1,is_owner_data_preview:!1,is_client_data_preview:!1,is_public_page_preview:!1},settings_data:{name:"Settings",enabled:!0,type:"user",fields:[]},owner_data:{name:"OwnerData",fields:[]},client_data:{enabled:!0,name:"ClientData",fields:[]}},sampleField:{name:"name",type:"str",label:"Name",hint:"",optional:!0,editable:!0,searchable:!0,sortable:!0},settingsTypes:[{label:"User Settings",value:"user"},{label:"Admin Settings",value:"admin"}],amountSource:[{label:"Client Data",value:"client_data"},{label:"Owner Data",value:"owner_data"}],extensionStubVersions:[]}),watch:{"extensionData.public_page.action_fields.amount_source":function(e,t){t&&e!==t&&(this.extensionData.public_page.action_fields.amount="")}},computed:{paymentActionAmountFields(){const e=this.extensionData.public_page.action_fields.amount_source;return e?"owner_data"===e?[""].concat(this.extensionData.owner_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):"client_data"===e?[""].concat(this.extensionData.client_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):void 0:[""]}},methods:{saveState(){this.$q.localStorage.set("lnbits.extension.builder.data",JSON.stringify(this.extensionData)),this.$q.localStorage.set("lnbits.extension.builder.step",this.step)},nextStep(){this.saveState(),this.$refs.stepper.next(),this.refreshPreview()},previousStep(){this.saveState(),this.$refs.stepper.previous(),this.refreshPreview()},onStepChange(){this.saveState(),this.refreshPreview()},clearAllData(){LNbits.utils.confirmDialog("Are you sure you want to clear all data? This action cannot be undone.").onOk(()=>{this.extensionData=JSON.parse(this.extensionDataCleanString),this.$q.localStorage.remove("lnbits.extension.builder.data"),this.$refs.stepper.set(1)})},exportJsonData(){!0!==Quasar.exportFile(`${this.extensionData.id||"data-export"}.json`,JSON.stringify(this.extensionData,null,2),"text/json")?Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null}):Quasar.Notify.create({message:"File downloaded!",color:"positive",icon:"file_download"})},onJsonDataInput(e){const t=e.target.files[0],s=new FileReader;s.onload=e=>{this.extensionData={...this.extensionData,...JSON.parse(e.target.result)},this.$refs.extensionDataInput.value=null,Quasar.Notify.create({message:"File loaded!",color:"positive",icon:"file_upload"})},s.readAsText(t)},async buildExtension(){try{const e={responseType:"blob"},t=await LNbits.api.request("POST","/api/v1/extension/builder/zip",null,this.extensionData,e),s=window.URL.createObjectURL(new Blob([t.data])),a=document.createElement("a");a.href=s,a.download=`${this.extensionData.id||"lnbits-extension"}.zip`,document.body.appendChild(a),a.click(),a.remove(),window.URL.revokeObjectURL(s)}catch(e){LNbits.utils.notifyApiError(e)}},async buildExtensionAndDeploy(){try{const{data:e}=await LNbits.api.request("POST","/api/v1/extension/builder/deploy",null,this.extensionData);Quasar.Notify.create({message:e.message||"Extension deployed!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async cleanCacheData(){LNbits.utils.confirmDialog("Are you sure you want to clean the cache data? This action cannot be undone.","Clean Cache Data").onOk(async()=>{try{const{data:e}=await LNbits.api.request("DELETE","/api/v1/extension/builder",null,{});Quasar.Notify.create({message:e.message||"Cache data cleaned!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})},async previewExtension(e){this.saveState();try{await LNbits.api.request("POST","/api/v1/extension/builder/preview",null,{...this.extensionData,preview_action:{is_preview_mode:!!e,is_settings_preview:"settings"===e,is_owner_data_preview:"owner_data"===e,is_client_data_preview:"client_data"===e,is_public_page_preview:"public_page"===e}}),this.refreshIframe(e)}catch(e){LNbits.utils.notifyApiError(e)}},async refreshPreview(){setTimeout(()=>{const e=this.previewStepNames[`${this.step}`]||"";e&&this.previewExtension(e)},100)},async getStubExtensionReleases(){try{const e="extension_builder_stub",{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e}/releases`);this.extensionStubVersions=t;const s=t.filter(e=>e.is_version_compatible);this.extensionData.stub_version=s[0]?s[0].version:""}catch(e){LNbits.utils.notifyApiError(e)}},refreshIframe(e=""){const t=this.$refs[`iframeStep${this.step}`];if(!t)return void console.warn("Extension Builder Preview iframe not loaded yet.");t.onload=()=>{const e=t.contentDocument||t.contentWindow.document;e.body.style.transform="scale(0.8)",e.body.style.transformOrigin="center top"};let s="Page"+this.extensionData.id.toLowerCase().split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("");"public_page"===e&&(s+="Public"),t.src=`/extensions/builder/preview?ext_id=${this.extensionData.id}&page=${e}&component=${s}`},initBasicData(){this.extensionData.owner_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.client_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.settings_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionDataCleanString=JSON.stringify(this.extensionData)}},created(){this.initBasicData();const e=this.$q.localStorage.getItem("lnbits.extension.builder.data");e&&(this.extensionData={...this.extensionData,...JSON.parse(e)});const t=+this.$q.localStorage.getItem("lnbits.extension.builder.step");t&&(this.step=t),this.g.user.admin&&this.getStubExtensionReleases(),setTimeout(()=>{this.refreshIframe()},1e3)}},window.PageExtensionBuilder={template:"#page-extension-builder",data:()=>({step:1,previewStepNames:{2:"settings",3:"owner_data",4:"client_data",5:"public_page"},extensionDataCleanString:"",extensionData:{id:"",name:"",stub_version:"",short_description:"",description:"",public_page:{has_public_page:!0,owner_data_fields:{name:"",description:""},client_data_fields:{public_inputs:[]},action_fields:{generate_action:!0,generate_payment_logic:!1,wallet_id:"",currency:"",amount:"",paid_flag:""}},preview_action:{is_preview_mode:!1,is_settings_preview:!1,is_owner_data_preview:!1,is_client_data_preview:!1,is_public_page_preview:!1},settings_data:{name:"Settings",enabled:!0,type:"user",fields:[]},owner_data:{name:"OwnerData",fields:[]},client_data:{enabled:!0,name:"ClientData",fields:[]}},sampleField:{name:"name",type:"str",label:"Name",hint:"",optional:!0,editable:!0,searchable:!0,sortable:!0},settingsTypes:[{label:"User Settings",value:"user"},{label:"Admin Settings",value:"admin"}],amountSource:[{label:"Client Data",value:"client_data"},{label:"Owner Data",value:"owner_data"}],extensionStubVersions:[]}),watch:{"extensionData.public_page.action_fields.amount_source":function(e,t){t&&e!==t&&(this.extensionData.public_page.action_fields.amount="")}},computed:{paymentActionAmountFields(){const e=this.extensionData.public_page.action_fields.amount_source;return e?"owner_data"===e?[""].concat(this.extensionData.owner_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):"client_data"===e?[""].concat(this.extensionData.client_data.fields.filter(e=>"int"===e.type||"float"===e.type).map(e=>e.name)):void 0:[""]}},methods:{saveState(){this.$q.localStorage.set("lnbits.extension.builder.data",JSON.stringify(this.extensionData)),this.$q.localStorage.set("lnbits.extension.builder.step",this.step)},nextStep(){this.saveState(),this.$refs.stepper.next(),this.refreshPreview()},previousStep(){this.saveState(),this.$refs.stepper.previous(),this.refreshPreview()},onStepChange(){this.saveState(),this.refreshPreview()},clearAllData(){LNbits.utils.confirmDialog("Are you sure you want to clear all data? This action cannot be undone.").onOk(()=>{this.extensionData=JSON.parse(this.extensionDataCleanString),this.$q.localStorage.remove("lnbits.extension.builder.data"),this.$refs.stepper.set(1)})},exportJsonData(){!0!==Quasar.exportFile(`${this.extensionData.id||"data-export"}.json`,JSON.stringify(this.extensionData,null,2),"text/json")?Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null}):Quasar.Notify.create({message:"File downloaded!",color:"positive",icon:"file_download"})},onJsonDataInput(e){const t=e.target.files[0],s=new FileReader;s.onload=e=>{this.extensionData={...this.extensionData,...JSON.parse(e.target.result)},this.$refs.extensionDataInput.value=null,Quasar.Notify.create({message:"File loaded!",color:"positive",icon:"file_upload"})},s.readAsText(t)},async buildExtension(){try{const e={responseType:"blob"},t=await LNbits.api.request("POST","/api/v1/extension/builder/zip",null,this.extensionData,e),s=window.URL.createObjectURL(new Blob([t.data])),a=document.createElement("a");a.href=s,a.download=`${this.extensionData.id||"lnbits-extension"}.zip`,document.body.appendChild(a),a.click(),a.remove(),window.URL.revokeObjectURL(s)}catch(e){LNbits.utils.notifyApiError(e)}},async buildExtensionAndDeploy(){try{const{data:e}=await LNbits.api.request("POST","/api/v1/extension/builder/deploy",null,this.extensionData);Quasar.Notify.create({message:e.message||"Extension deployed!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async cleanCacheData(){LNbits.utils.confirmDialog("Are you sure you want to clean the cache data? This action cannot be undone.","Clean Cache Data").onOk(async()=>{try{const{data:e}=await LNbits.api.request("DELETE","/api/v1/extension/builder",null,{});Quasar.Notify.create({message:e.message||"Cache data cleaned!",color:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})},async previewExtension(e){this.saveState();try{await LNbits.api.request("POST","/api/v1/extension/builder/preview",null,{...this.extensionData,preview_action:{is_preview_mode:!!e,is_settings_preview:"settings"===e,is_owner_data_preview:"owner_data"===e,is_client_data_preview:"client_data"===e,is_public_page_preview:"public_page"===e}}),this.refreshIframe(e)}catch(e){LNbits.utils.notifyApiError(e)}},async refreshPreview(){setTimeout(()=>{const e=this.previewStepNames[`${this.step}`]||"";e&&this.previewExtension(e)},100)},async getStubExtensionReleases(){try{const e="extension_builder_stub",{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e}/releases`);this.extensionStubVersions=t;const s=t.filter(e=>e.is_version_compatible);this.extensionData.stub_version=s[0]?s[0].version:""}catch(e){LNbits.utils.notifyApiError(e)}},refreshIframe(e=""){const t=this.$refs[`iframeStep${this.step}`];if(!t)return void console.warn("Extension Builder Preview iframe not loaded yet.");t.onload=()=>{const e=t.contentDocument||t.contentWindow.document;e.body.style.transform="scale(0.8)",e.body.style.transformOrigin="center top"};let s="Page"+this.extensionData.id.toLowerCase().split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("");"public_page"===e&&(s+="Public"),t.src=`/extensions/builder/preview?ext_id=${this.extensionData.id}&page=${e}&component=${s}`},initBasicData(){this.extensionData.owner_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.client_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionData.settings_data.fields=[JSON.parse(JSON.stringify(this.sampleField))],this.extensionDataCleanString=JSON.stringify(this.extensionData)}},created(){this.initBasicData();const e=this.$q.localStorage.getItem("lnbits.extension.builder.data");e&&(this.extensionData={...this.extensionData,...JSON.parse(e)});const t=+this.$q.localStorage.getItem("lnbits.extension.builder.step");t&&(this.step=t),this.g.user.admin&&this.getStubExtensionReleases(),setTimeout(()=>{this.refreshIframe()},1e3)}},window.PageExtensionBuilderPreview={template:"#page-extension-builder-preview",mixins:[windowMixin],watch:{name:"reload"},data:()=>({extId:"",pageName:"",componentName:null}),methods:{async reload(){await LNbits.utils.loadTemplate(`/extensions/builder/preview/${this.extId}/template?page_name=${this.pageName}`),await LNbits.utils.loadScript(`/extensions/builder/preview/${this.extId}/component?page_name=${this.pageName}`),this._component=window[this.componentName],console.log("LNbits preview reloaded componentName:",this.componentName,!!this._component),this.$forceUpdate()}},async created(){const e=new URLSearchParams(window.location.search);this.extId=e.get("ext_id")||"",this.pageName=e.get("page")||"",this.componentName=e.get("component")||"",await this.reload()},render(){return this._component?Vue.h(this._component):Vue.h("div","Loading...")}};const EXTENSION_PERMISSION_DEFAULT_MAX_ROWS_PER_SOURCE=1e4,EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT=1e6,EXTENSION_PERMISSION_MAX_MESSAGES_PER_SECOND_LIMIT=100;window.PageExtensions={template:"#page-extensions",data(){return{extbuilderEnabled:!1,slide:0,fullscreen:!1,autoplay:!0,searchTerm:"",tab:"installed",manageExtensionTab:"releases",filteredExtensions:[],categories:new Set,updatableExtensions:[],showUninstallDialog:!1,showManageExtensionDialog:!1,showExtensionDetailsDialog:!1,showDropDbDialog:!1,showPayToEnableDialog:!1,showUpdateAllDialog:!1,dropDbExtensionId:"",selectedExtension:null,selectedImage:null,selectedExtensionDetails:null,selectedExtensionDetailsDescription:"",selectedExtensionRepos:null,selectedRelease:null,permissionGrant:{show:!1,permissions:[],resolve:null},extensionPermissionMaxRowsPerSourceLimit:1e6,extensionPermissionMaxMessagesPerSecondLimit:100,managedExtensionPermissions:{loading:!1,extensionPermissions:[],userPermissions:{},savingExtensionPermissions:!1,savingKey:"",deletingKey:""},backgroundPaymentDestinationOptions:[{label:"Only transfers to my wallets",value:"own_wallets_only"},{label:"Allow external payments",value:"external_allowed"}],uninstallAndDropDb:!1,maxStars:5,paylinkWebsocket:null,searchToggle:!1,reviewsUrl:null,reviewsDialog:{show:!1,extension:null,loading:!1,submitting:!1,form:{name:"",rating:0,comment:""},error:null},reviews:[],reviewsTable:{loading:!1,columns:[{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"comment",align:"left",label:this.$t("Comment"),field:"comment"},{name:"created_at",align:"left",label:this.$t("Date"),field:"created_at"},{name:"rating",align:"right",label:"Rating",field:"rating"}],pagination:{rowsPerPage:5,sortBy:"created_at",descending:!0,page:1}},paymentDialog:{show:!1,invoice:"",hash:""}}},watch:{searchTerm(e){this.filterExtensions(e,this.tab)},tab(e){this.filterExtensions(this.searchTerm,e)}},computed:{managedUserPermissionRows(){const e=[],t=this.managedExtensionPermissions.userPermissions||{};return Object.entries(t).forEach(([t,s])=>{Array.isArray(s)&&s.forEach(s=>{if(!s||"object"!=typeof s)return;const a=String(s.id||""),i=String(s.wallet_id||"");a&&i&&e.push({key:a,permissionId:t,label:this.permissionLabelById(t),grantId:a,walletId:i,walletName:this.walletName(i),grant:s})})}),e}},methods:{filterExtensions(e,t){const s=!["installed","all","featured"].includes(t);var a;this.filteredExtensions=this.extensions.filter(e=>"all"!==t||!e.isInstalled).filter(e=>"installed"!==t||e.isInstalled).filter(e=>"installed"!==t||(!!e.isActive||!!this.g.user.admin)).filter(e=>"featured"!==t||e.isFeatured).filter(e=>!s||(e=>e.categories?.includes(t)??!1)(e)).filter((a=e,function(e){return e.name.toLowerCase().includes(a.toLowerCase())||e.shortDescription?.toLowerCase().includes(a.toLowerCase())})).map(e=>({...e,details_link:e.installedRelease?.details_link||e.latestRelease?.details_link}))},async installExtension(e){this.unsubscribeFromPaylinkWs();const t=await this.resolveExtensionPermissionGrant(e);null!==t&&(this.selectedExtension.inProgress=!0,this.showManageExtensionDialog=!1,e.payment_hash=e.payment_hash||this.getPaylinkHash(e.pay_link),LNbits.api.request("POST","/api/v1/extension",this.g.user.wallets[0].adminkey,{ext_id:this.selectedExtension.id,archive:e.archive,source_repo:e.source_repo,payment_hash:e.payment_hash,version:e.version,permissions:t}).then(t=>{this.selectedExtension.inProgress=!1;const s=this.extensions.find(e=>e.id===this.selectedExtension.id);s.isAvailable=!0,s.isInstalled=!0,s.isWasm=!0===t.data.is_wasm||!0===t.data.isWasm||"wasm"===e.extension_type||!0===s.isWasm,s.icon=t.data.icon||s.icon,s.installedRelease=e,this.toggleExtension(s),s.inProgress=!1,this.selectedExtension=s,this.extensions=this.extensions.concat([]),this.tab="installed"}).catch(e=>{console.warn(e),this.selectedExtension.inProgress=!1,LNbits.utils.notifyApiError(e)}))},async uninstallExtension(){this.showManageExtensionDialog=!1,this.showUninstallDialog=!1,this.selectedExtension.inProgress=!0,LNbits.api.request("DELETE",`/api/v1/extension/${this.selectedExtension.id}`,this.g.user.wallets[0].adminkey).then(e=>{const t=this.extensions.find(e=>e.id===this.selectedExtension.id);t.isAvailable=!1,t.isInstalled=!1,t.inProgress=!1,t.installedRelease=null,this.filteredExtensions=this.filteredExtensions.filter(e=>e.id!==t.id),Quasar.Notify.create({type:"positive",message:"Extension uninstalled!"}),this.uninstallAndDropDb&&this.showDropDb()}).catch(e=>{LNbits.utils.notifyApiError(e),extension.inProgress=!1})},async dropExtensionDb(){const e=this.selectedExtension;this.showManageExtensionDialog=!1,this.showDropDbDialog=!1,this.dropDbExtensionId="",e.inProgress=!0,LNbits.api.request("DELETE",`/api/v1/extension/${e.id}/db`,this.g.user.wallets[0].adminkey).then(t=>{e.installedRelease=null,e.inProgress=!1,e.hasDatabaseTables=!1,Quasar.Notify.create({type:"positive",message:"Extension DB deleted!"})}).catch(t=>{LNbits.utils.notifyApiError(t),e.inProgress=!1})},toggleExtension(e){const t=e.isActive?"activate":"deactivate";LNbits.api.request("PUT",`/api/v1/extension/${e.id}/${t}`,this.g.user.wallets[0].adminkey).then(s=>{Quasar.Notify.create({timeout:2e3,type:"positive",message:`Extension '${e.id}' ${t}d!`})}).catch(t=>{LNbits.utils.notifyApiError(t),e.isActive=!1,e.inProgress=!1})},async enableExtensionForUser(e){e.isPaymentRequired?this.showPayToEnable(e):this.enableExtension(e)},async enableExtension(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/enable`,this.g.user.wallets[0].adminkey).then(t=>{this.g.user.extensions=this.g.user.extensions.concat([e.id]),Quasar.Notify.create({type:"positive",message:"Extension enabled!"})}).catch(e=>{console.warn(e),LNbits.utils.notifyApiError(e)})},disableExtension(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/disable`,this.g.user.wallets[0].adminkey).then(t=>{this.g.user.extensions=this.g.user.extensions.filter(t=>t!==e.id),Quasar.Notify.create({type:"positive",message:"Extension disabled!"})}).catch(e=>{console.warn(error),LNbits.utils.notifyApiError(e)})},showPayToEnable(e){this.selectedExtension=e,this.selectedExtension.payToEnable.paidAmount=e.payToEnable.amount,this.selectedExtension.payToEnable.showQRCode=!1,this.showPayToEnableDialog=!0},updatePayToInstallData(e){LNbits.api.request("PUT",`/api/v1/extension/${e.id}/sell`,this.g.user.wallets[0].adminkey,{required:e.payToEnable.required,amount:e.payToEnable.amount,wallet:e.payToEnable.wallet}).then(e=>{Quasar.Notify.create({type:"positive",message:"Payment info updated!"}),this.showManageExtensionDialog=!1}).catch(t=>{LNbits.utils.notifyApiError(t),e.inProgress=!1})},showUninstall(){this.showManageExtensionDialog=!1,this.showUninstallDialog=!0,this.uninstallAndDropDb=!1},showDropDb(){this.showDropDbDialog=!0},async showManageExtension(e){if(this.selectedExtension=e,this.selectedRelease=null,this.selectedExtensionRepos=null,this.resetManagedExtensionPermissions(),this.manageExtensionTab=this.g.user.admin?"releases":"extension-permissions",this.showManageExtensionDialog=!0,this.canManageExtensionPermissions(e)&&this.loadManagedExtensionPermissions(e),this.g.user.admin)try{const{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e.id}/releases`);this.selectedExtensionRepos=t.reduce((e,t)=>(e[t.source_repo]=e[t.source_repo]||{releases:[],isInstalled:!1,repo:t.repo},t.inProgress=!1,t.error=null,t.loaded=!1,t.isInstalled=this.isInstalledVersion(this.selectedExtension,t),t.isInstalled&&(e[t.source_repo].isInstalled=!0),t.pay_link&&(t.requiresPayment=!0,t.paidAmount=t.cost_sats,t.payment_hash=this.getPaylinkHash(t.pay_link)),e[t.source_repo].releases.push(t),e),{})}catch(t){LNbits.utils.notifyApiError(t),e.inProgress=!1}},canShowManageExtensionButton(e){return this.g.user.admin||!0===e?.isWasm&&!0===e?.isInstalled},canManageExtensionPermissions(e=this.selectedExtension){return!0===e?.isWasm&&!0===e?.isInstalled},canShowAdminManageTabs(){return!0===this.g.user.admin},resetManagedExtensionPermissions(){this.managedExtensionPermissions={loading:!1,extensionPermissions:[],userPermissions:{},savingExtensionPermissions:!1,savingKey:"",deletingKey:""}},async loadManagedExtensionPermissions(e=this.selectedExtension){if(this.canManageExtensionPermissions(e)){this.managedExtensionPermissions.loading=!0;try{const{data:t}=await LNbits.api.request("GET",`/api/v1/extension/${e.id}/permissions`);this.managedExtensionPermissions.extensionPermissions=this.cloneEditableExtensionPermissions(t.extension_permissions||[]),this.managedExtensionPermissions.userPermissions=this.cloneUserPermissions(t.user_permissions||{})}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.managedExtensionPermissions.loading=!1}}},cloneEditableExtensionPermissions(e){return(e||[]).filter(e=>e&&"object"==typeof e).map(e=>({...e,policies:Array.isArray(e.policies)?e.policies.map(t=>this.cloneEditablePermissionPolicy(e.id,t)):e.policies}))},cloneEditablePermissionPolicy(e,t){if(!t||"object"!=typeof t||Array.isArray(t))return t;const s=Object.entries(t).reduce((e,[t,s])=>({...e,[t]:Array.isArray(s)?s.slice():s}),{});return"ext.storage.append_public"===e&&(s.max_rows_per_source=this.maxRowsPerSourceValue(s.max_rows_per_source,1e4)),"websocket.publish"===e&&(s.max_messages_per_second=Number(s.max_messages_per_second)),s},maxRowsPerSourceValue(e,t){const s=Number(e);return!Number.isInteger(s)||s<=0?t:Math.min(s,1e6)},extensionPermissionLimitError(e){const t=(e||[]).find(e=>"ext.storage.append_public"===e?.id);if(!t||!Array.isArray(t.policies))return this.websocketPublishLimitError(e);for(const e of t.policies){if(!e||"object"!=typeof e)continue;const t=Number(e.max_rows_per_source);if(!Number.isInteger(t)||t<=0)return"Max rows per source must be a positive integer.";if(t>1e6)return"Max rows per source cannot exceed 1000000."}return this.websocketPublishLimitError(e)},websocketPublishLimitError(e){const t=(e||[]).find(e=>"websocket.publish"===e?.id);if(!t)return"";if(!Array.isArray(t.policies)||1!==t.policies.length)return"Websocket publish requires a max messages per second policy.";const s=t.policies[0];if(!s||"object"!=typeof s)return"Websocket publish requires a max messages per second policy.";const a=Number(s.max_messages_per_second);return!Number.isInteger(a)||a<=0?"Max messages per second must be a positive integer.":a>100?"Max messages per second cannot exceed 100.":""},validateExtensionPermissionLimits(e){const t=this.extensionPermissionLimitError(e);return!t||(Quasar.Notify.create({type:"negative",message:t}),!1)},extensionPermissionsHaveEditableLimits:e=>(e||[]).some(e=>"ext.storage.append_public"===e?.id&&Array.isArray(e.policies)&&e.policies.length>0||"websocket.publish"===e?.id),async saveManagedExtensionPermissions(){const e=this.managedExtensionPermissions.extensionPermissions;if(this.validateExtensionPermissionLimits(e)){this.managedExtensionPermissions.savingExtensionPermissions=!0;try{const{data:t}=await LNbits.api.request("PUT",`/api/v1/extension/${this.selectedExtension.id}/permissions`,this.g.user.wallets[0].adminkey,{permissions:this.cloneEditableExtensionPermissions(e)});this.managedExtensionPermissions.extensionPermissions=this.cloneEditableExtensionPermissions(t.extension_permissions||[]),Quasar.Notify.create({type:"positive",message:"Permission updated."})}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.managedExtensionPermissions.savingExtensionPermissions=!1}}},cloneUserPermissions(e){const t={};return Object.entries(e||{}).forEach(([e,s])=>{Array.isArray(s)&&(t[e]=s.filter(e=>e&&"object"==typeof e).map(e=>({...e,_original:{...e}})))}),t},async showExtensionDetails(e,t){if(t){this.selectedExtension=this.extensions.find(t=>t.id===e)||this.selectedExtension,this.selectedExtensionDetails=null,this.selectedExtensionDetailsDescription="",this.showExtensionDetailsDialog=!0,this.slide=0,this.fullscreen=!1;try{const{data:s}=await LNbits.api.request("GET",`/api/v1/extension/${e}/details?details_link=${t}`);this.selectedExtensionDetails=s,this.selectedExtensionDetailsDescription=this.extensionDescriptionDocument(s.description_md)}catch(e){console.warn(e)}}},extensionDescriptionDocument(e){const t="string"==typeof e?e:"",s=LNbits.utils.convertMarkdown(t),a=(new DOMParser).parseFromString(s,"text/html");a.body.querySelectorAll("applet, base, embed, form, frame, iframe, link, meta, object, portal, script").forEach(e=>e.remove()),a.body.querySelectorAll("*").forEach(e=>{for(const t of[...e.attributes]){const s=t.name.toLowerCase();(s.startsWith("on")||"srcdoc"===s||"xlink:href"===s)&&e.removeAttribute(t.name)}}),a.body.querySelectorAll("a[href], area[href]").forEach(e=>{try{const t=new URL(e.getAttribute("href"),window.location.origin);if(!["http:","https:"].includes(t.protocol)||t.username||t.password)return void e.removeAttribute("href");e.setAttribute("href",t.href),e.setAttribute("target","_blank"),e.setAttribute("rel","noopener noreferrer")}catch(t){e.removeAttribute("href")}});return`\n \n \n \n \n \n \n \n \n \n ${a.body.innerHTML}\n \n `},async payAndInstall(e){try{if(null===await this.resolveExtensionPermissionGrant(e))return;this.selectedExtension.inProgress=!0,this.showManageExtensionDialog=!1;const t=await this.requestPaymentForInstall(this.selectedExtension.id,e);this.rememberPaylinkHash(e.pay_link,t.payment_hash);const s=this.g.user.wallets.find(t=>t.id===e.wallet),{data:a}=await LNbits.api.payInvoice(s,t.payment_request);e.payment_hash=a.payment_hash,await this.installExtension(e)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.selectedExtension.inProgress=!1}},async payAndEnable(e){try{const t=await this.requestPaymentForEnable(e.id,e.payToEnable.paidAmount),s=this.g.user.wallets.find(t=>t.id===e.payToEnable.paymentWallet),{data:a}=await LNbits.api.payInvoice(s,t.payment_request);this.enableExtension(e),this.showPayToEnableDialog=!1}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async showInstallQRCode(e){if(null!==await this.resolveExtensionPermissionGrant(e)){this.selectedRelease=e;try{const t=await this.requestPaymentForInstall(this.selectedExtension.id,e);this.selectedRelease.paymentRequest=t.payment_request,this.selectedRelease.payment_hash=t.payment_hash,this.selectedRelease=_.clone(this.selectedRelease),this.rememberPaylinkHash(this.selectedRelease.pay_link,this.selectedRelease.payment_hash),this.subscribeToPaylinkWs(this.selectedRelease.pay_link,t.payment_hash)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}}},async showEnableQRCode(e){try{e.payToEnable.showQRCode=!0,this.selectedExtension=_.clone(e);const t=await this.requestPaymentForEnable(e.id,e.payToEnable.paidAmount);e.payToEnable.paymentRequest=t.payment_request,this.selectedExtension=_.clone(e);const s=new URL(window.location);s.protocol="https:"===s.protocol?"wss":"ws",s.pathname=`/api/v1/ws/${t.payment_hash}`;const a=new WebSocket(s);a.addEventListener("message",async({data:t})=>{!1===JSON.parse(t).pending&&(Quasar.Notify.create({type:"positive",message:"Invoice Paid!"}),this.enableExtension(e),a.close())})}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async requestPaymentForInstall(e,t){const{data:s}=await LNbits.api.request("PUT",`/api/v1/extension/${e}/invoice/install`,null,{ext_id:e,archive:t.archive,source_repo:t.source_repo,cost_sats:t.paidAmount,version:t.version});return s},async requestPaymentForEnable(e,t){const{data:s}=await LNbits.api.request("PUT",`/api/v1/extension/${e}/invoice/enable`,null,{amount:t});return s},clearHangingInvoice(e){this.forgetPaylinkHash(e.pay_link),e.payment_hash=null},rememberPaylinkHash(e,t){this.$q.localStorage.set(`lnbits.extensions.paylink.${e}`,t)},getPaylinkHash(e){return this.$q.localStorage.getItem(`lnbits.extensions.paylink.${e}`)},forgetPaylinkHash(e){this.$q.localStorage.remove(`lnbits.extensions.paylink.${e}`)},subscribeToPaylinkWs(e,t){const s=new URL(`${e}/${t}`);s.protocol="https:"===s.protocol?"wss":"ws",this.paylinkWebsocket=new WebSocket(s),this.paylinkWebsocket.addEventListener("message",async({data:e})=>{JSON.parse(e).paid?(Quasar.Notify.create({type:"positive",message:"Invoice Paid!"}),this.installExtension(this.selectedRelease)):Quasar.Notify.create({type:"warning",message:"Invoice tracking lost!"})})},unsubscribeFromPaylinkWs(){try{this.paylinkWebsocket&&this.paylinkWebsocket.close()}catch(e){console.warn(e)}},hasNewVersion(e){if(e.installedRelease&&e.latestRelease)return e.installedRelease.version!==e.latestRelease.version},isInstalledVersion(e,t){if(e.installedRelease)return e.installedRelease.source_repo===t.source_repo&&e.installedRelease.version===t.version},getReleaseIcon:e=>e.is_version_compatible?e.isInstalled?"download_done":"download":"block",getReleaseIconColor:e=>e.is_version_compatible?e.isInstalled?"text-green":"":"text-red",extensionOpenUrl:e=>e.isWasm?`/ext/${e.id}`:`/${e.id}`,permissionLabelById(e){const t=`extension_permission_${String(e).replace(/[^A-Za-z0-9]/g,"_")}`,s=this.$t(t);return s===t?e:s},walletName(e){const t=(this.g.user.wallets||[]).find(t=>t.id===e);return t?t.name||t.id:e},userPermissionRowCaption:e=>`${e.walletName} (${e.walletId.slice(0,8)}...)`,isBackgroundPaymentPermission:e=>"wallet.pay_invoice_background"===e.permissionId,userPermissionGrantPayload(e){return{wallet_id:e.walletId,max_amount:this.positiveInteger(e.grant.max_amount,0),destination_policy:this.backgroundPaymentDestinationPolicy(e.grant.destination_policy)}},positiveInteger(e,t){const s=Number(e);return!Number.isFinite(s)||s<=0?t:Math.floor(s)},backgroundPaymentDestinationPolicy:e=>"external_allowed"===e?"external_allowed":"own_wallets_only",backgroundPaymentGrantIncreased(e,t){const s=e.grant._original||{},a=this.positiveInteger(s.max_amount,0),i=this.backgroundPaymentDestinationPolicy(s.destination_policy);return t.max_amount>a||"own_wallets_only"===i&&"external_allowed"===t.destination_policy},confirmUserPermissionIncrease:()=>new Promise(e=>{let t=!1;const s=s=>{t||(t=!0,e(s))};LNbits.utils.confirmDialog("This increases what the extension can do with this wallet. Continue?").onOk(()=>s(!0)).onCancel(()=>s(!1)).onDismiss(()=>s(!1))}),async saveUserPermissionGrant(e){if(!this.isBackgroundPaymentPermission(e))return;const t=this.userPermissionGrantPayload(e);if(t.max_amount){if(!this.backgroundPaymentGrantIncreased(e,t)||await this.confirmUserPermissionIncrease()){this.managedExtensionPermissions.savingKey=e.key;try{await LNbits.api.request("POST",`/api/v1/extension/${this.selectedExtension.id}/permissions/background-payment`,null,t),Quasar.Notify.create({type:"positive",message:"Permission updated."}),await this.loadManagedExtensionPermissions()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.managedExtensionPermissions.savingKey=""}}}else Quasar.Notify.create({type:"negative",message:"Max payment amount must be greater than zero."})},deleteUserPermissionGrant(e){LNbits.utils.confirmDialog("Remove this permission grant?").onOk(async()=>{this.managedExtensionPermissions.deletingKey=e.key;try{const t=encodeURIComponent(e.grantId);await LNbits.api.request("DELETE",`/api/v1/extension/${this.selectedExtension.id}/permissions/user/${t}`),Quasar.Notify.create({type:"positive",message:"Permission removed."}),await this.loadManagedExtensionPermissions()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.managedExtensionPermissions.deletingKey=""}})},async getGitHubReleaseDetails(e){if(!e.is_github_release||e.loaded)return;const[t,s]=e.source_repo.split("/");e.inProgress=!0;try{const{data:a}=await LNbits.api.request("GET",`/api/v1/extension/release/${t}/${s}/${e.version}`);e.loaded=!0,e.is_version_compatible=a.is_version_compatible,e.min_lnbits_version=a.min_lnbits_version,e.warning=a.warning,e.extension_type=a.extension_type,e.permissions=a.permissions||[]}catch(t){console.warn(t),e.error=t,LNbits.utils.notifyApiError(t)}finally{e.inProgress=!1}},async resolveExtensionPermissionGrant(e){const t=this.extensionPermissionsForRelease(e);if(!this.releaseRequiresPermissionGrant(e)||!t.length)return[];if(e.grantedPermissions)return e.grantedPermissions;const s=await this.confirmExtensionPermissions(t);return s?(e.grantedPermissions=s,s):null},extensionPermissionsForRelease(e){return e.permissions||this.selectedExtension?.permissions||[]},releaseRequiresPermissionGrant(e){return"wasm"===e.extension_type||!0===this.selectedExtension?.isWasm},confirmExtensionPermissions(e){return new Promise(t=>{this.selectedRelease=null,this.permissionGrant={show:!0,permissions:this.cloneEditableExtensionPermissions(e),resolve:t},this.showManageExtensionDialog=!0})},grantExtensionPermissions(){this.validateExtensionPermissionLimits(this.permissionGrant.permissions)&&this.resolveExtensionPermissionDialog(this.cloneEditableExtensionPermissions(this.permissionGrant.permissions))},cancelExtensionPermissions(){this.resolveExtensionPermissionDialog(null)},onManageExtensionDialogHide(){this.permissionGrant.show&&this.resolveExtensionPermissionDialog(null)},resolveExtensionPermissionDialog(e){const t=this.permissionGrant.resolve;this.permissionGrant={show:!1,permissions:[],resolve:null},this.showManageExtensionDialog=!1,t&&t(e)},permissionGrantHasHighRisk(){return window.LNbitsExtensionPermissions.hasHighRisk({permissions:this.permissionGrant.permissions,extensions:this.extensions,translate:e=>this.$t(e)})},async selectAllUpdatableExtensionss(){this.updatableExtensions.forEach(e=>e.selectedForUpdate=!0)},async updateSelectedExtensions(){let e=0;for(const t of this.updatableExtensions)try{if(!t.selectedForUpdate)continue;if(t.isWasm){Quasar.Notify.create({type:"warning",message:`Skipping ${t.id}; this extension update requires permission approval.`});continue}t.inProgress=!0,await LNbits.api.request("POST","/api/v1/extension",null,{ext_id:t.id,archive:t.latestRelease.archive,source_repo:t.latestRelease.source_repo,payment_hash:t.latestRelease.payment_hash,version:t.latestRelease.version}),e++,t.isAvailable=!0,t.isInstalled=!0,t.isUpgraded=!0,t.inProgress=!1,t.installedRelease=t.latestRelease,t.isActive=!0,this.toggleExtension(t)}catch(e){console.warn(e),Quasar.Notify.create({type:"negative",message:`Failed to update ${t.id}!`})}finally{t.inProgress=!1}Quasar.Notify.create({type:e?"positive":"warning",message:`${e||"No"} extensions updated!`}),this.showUpdateAllDialog=!1},formatAvg(e){const t=Number(e||0);return Math.round(t/2/100*2)/2},async loadReviewStats(){if(this.reviewsUrl)try{const{data:e}=await LNbits.api.request("GET","/api/v1/extension/reviews/tags"),t={};e.forEach(e=>{t[e.tag]=e}),this.extensions.forEach(e=>{e.reviewStats=t[e.id]||null}),this.filterExtensions(this.searchTerm,this.tab)}catch(e){console.warn(e)}else console.info("Extension reviews are not configured")},async openReviews(e){const t=e||(this.selectedExtensionDetails?this.extensions.find(e=>e.id===this.selectedExtensionDetails.id):null);t&&(this.reviewsUrl?(this.reviewsDialog.extension=t,this.selectedExtension=e,this.reviewsDialog.show=!0,await this.getTagReviews()):Quasar.Notify.create({type:"warning",message:this.$t("reviews_url_not_configured")}))},async getTagReviews(e){if(this.reviewsUrl)try{this.reviewsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.reviewsTable,e),{data:s}=await LNbits.api.request("GET",`/api/v1/extension/reviews/${this.selectedExtension.id}?${t}`);this.reviews=s.data,this.reviewsTable.pagination.rowsNumber=s.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.reviewsTable.loading=!1}else Quasar.Notify.create({type:"warning",message:this.$t("reviews_url_not_configured")})},formatReviewDate(e){if(!e)return"";const t=Number(e);return Number.isNaN(t)?this.utils.formatDate(e):this.utils.formatTimestamp(t)},async submitReview(){if(this.reviewsDialog.extension&&this.reviewsUrl){this.reviewsDialog.submitting=!0;try{const e={tag:this.reviewsDialog.extension.id,name:this.reviewsDialog.form.name,rating:100*this.reviewsDialog.form.rating,comment:this.reviewsDialog.form.comment},{data:t}=await LNbits.api.request("PUT","/api/v1/extension/reviews",null,e);t.payment_request?this.openInvoiceDialog(t.payment_request,t.payment_hash):(Quasar.Notify.create({type:"positive",message:"Review submitted"}),this.resetReviewForm(),await this.getTagReviews(),await this.loadReviewStats())}catch(e){LNbits.utils.notifyApiError(e)}finally{this.reviewsDialog.submitting=!1}}},openInvoiceDialog(e,t){this.paymentDialog.invoice=e,this.paymentDialog.hash=t,this.paymentDialog.show=!0,this.listenForPayment(t)},resetReviewForm(){this.reviewsDialog.form={name:"",rating:0,comment:""},this.paymentDialog={show:!1,invoice:"",hash:""}},listenForPayment(e){try{const t=new URL(this.reviewsUrl);t.protocol="https:"===t.protocol?"wss:":"ws:",t.pathname=`/api/v1/ws/${e}`;const s=new WebSocket(t);s.addEventListener("message",async()=>{Quasar.Notify.create({type:"positive",message:this.$t("reviews_invoice_paid")}),this.paymentDialog.show=!1,this.resetReviewForm(),setTimeout(async()=>{await this.getTagReviews()},1e3),await this.loadReviewStats(),s.close()})}catch(e){console.warn(e)}},async fetchAllExtensions(){try{const{data:e}=await LNbits.api.request("GET","/api/v1/extension/all");return e.forEach(e=>{e.categories?.forEach(e=>this.categories.add(e))}),e}catch(e){return console.warn(e),LNbits.utils.notifyApiError(e),[]}}},async created(){this.extensions=await this.fetchAllExtensions(),this.extbuilderEnabled=this.g.user.admin||this.g.settings.extBuilder,this.reviewsUrl=this.g.settings.extensionsReviewsUrl,0===this.g.user.extensions.length&&(this.tab="all");const e=window.location.hash.replace("#",""),t=this.extensions.find(t=>t.id===e);t&&(this.searchTerm=t.id,t.isInstalled&&(this.tab="installed")),this.updatableExtensions=this.extensions.filter(e=>this.hasNewVersion(e)),await this.loadReviewStats(),this.filterExtensions(this.searchTerm,this.tab)}},window.PageFirstInstall={template:"#page-first-install",data:()=>({loginData:{isPwd:!0,isPwdRepeat:!0,username:"",password:"",passwordRepeat:"",firstInstallToken:""}}),computed:{checkPasswordsMatch(){return this.loginData.password!==this.loginData.passwordRepeat}},methods:{setPassword(){LNbits.api.request("PUT","/api/v1/auth/first_install",null,{username:this.loginData.username,password:this.loginData.password,password_repeat:this.loginData.passwordRepeat,first_install_token:this.loginData.firstInstallToken}).then(async()=>{const e=await LNbits.api.getAuthUser();this.g.user=LNbits.map.user(e.data),this.g.isPublicPage=!1,this.$router.push("/admin")}).catch(this.utils.notifyApiError)}},created(){const e=new URLSearchParams(window.location.search);this.loginData.firstInstallToken=e.get("token")||""}},window.PagePayments={template:"#page-payments",data:()=>({payments:[],dailyChartData:[],searchDate:{from:null,to:null},searchData:{wallet_id:null,payment_hash:null,memo:null,internal_memo:null},statusFilters:{success:!0,pending:!0,failed:!0,incoming:!0,outgoing:!0},chartData:{showPaymentStatus:!0,showPaymentTags:!0,showBalance:!0,showWalletsSize:!1,showBalanceInOut:!1,showPaymentCountInOut:!1},searchOptions:{status:[]},paymentsTable:{columns:[{name:"status",align:"left",label:"Status",field:"status",sortable:!1},{name:"created_at",align:"left",label:"Created At",field:"created_at",sortable:!0},{name:"amount",align:"right",label:"Amount",field:"amount",sortable:!0},{name:"amountFiat",align:"right",label:"Fiat",field:"amountFiat",sortable:!1},{name:"fee_sats",align:"left",label:"Fee",field:"fee_sats",sortable:!0},{name:"tag",align:"left",label:"Tag",field:"tag",sortable:!1},{name:"memo",align:"left",label:"Memo",field:"memo",sortable:!1,max_length:20},{name:"internal_memo",align:"left",label:"Internal Memo",field:"internal_memo",sortable:!1,max_length:20},{name:"wallet_id",align:"left",label:"Wallet (ID)",field:"wallet_id",sortable:!1},{name:"payment_hash",align:"left",label:"Payment Hash",field:"payment_hash",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:25,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},chartsReady:!1,showDetails:!1,paymentDetails:null,lnbitsBalance:0}),async mounted(){this.chartsReady=!0,await this.$nextTick(),this.initCharts(),await this.fetchPayments()},computed:{},methods:{async fetchPayments(e){const t=Object.entries(this.searchData).reduce((e,[t,s])=>s?(e[t]=s,e):e,{});delete t["time[ge]"],delete t["time[le]"],this.searchDate.from&&(t["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(t["time[le]"]=this.searchDate.to+"T23:59:59"),this.paymentsTable.filter=t;try{const t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e),{data:s}=await LNbits.api.request("GET",`/api/v1/payments/all/paginated?${t}`);this.paymentsTable.pagination.rowsNumber=s.total,this.payments=s.data.map(e=>(e.extra&&e.extra.tag&&(e.tag=e.extra.tag),e.timeFrom=moment.utc(e.created_at).local().fromNow(),e.outgoing=e.amount<0,e.amount=new Intl.NumberFormat(this.g.locale).format(e.amount/1e3)+" sats",e.extra?.wallet_fiat_amount&&(e.amountFiat=this.formatCurrency(e.extra.wallet_fiat_amount,e.extra.wallet_fiat_currency)),e.extra?.internal_memo&&(e.internal_memo=e.extra.internal_memo),e.fee_sats=new Intl.NumberFormat(this.g.locale).format(e.fee/1e3)+" sats",e))}catch(e){console.error(e),LNbits.utils.notifyApiError(e)}finally{this.updateCharts(e)}},async searchPaymentsBy(e,t){e&&(this.searchData[e]=t),await this.fetchPayments()},clearDateSeach(){this.searchDate={from:null,to:null},delete this.paymentsTable.filter["time[ge]"],delete this.paymentsTable.filter["time[le]"],this.fetchPayments()},searchByDate(){"string"==typeof this.searchDate&&(this.searchDate={from:this.searchDate,to:this.searchDate}),this.searchDate.from&&(this.paymentsTable.filter["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(this.paymentsTable.filter["time[le]"]=this.searchDate.to+"T23:59:59"),this.fetchPayments()},handleFilterChanged(){const{success:e,pending:t,failed:s,incoming:a,outgoing:i}=this.statusFilters;delete this.searchData["status[ne]"],delete this.searchData["status[eq]"],e&&t&&s||(e&&t?this.searchData["status[ne]"]="failed":e&&s?this.searchData["status[ne]"]="pending":s&&t?this.searchData["status[ne]"]="success":e?this.searchData["status[eq]"]="success":t?this.searchData["status[eq]"]="pending":s&&(this.searchData["status[eq]"]="failed")),delete this.searchData["amount[ge]"],delete this.searchData["amount[le]"],a&&i||(a?this.searchData["amount[ge]"]="0":i&&(this.searchData["amount[le]"]="0")),this.fetchPayments()},showDetailsToggle(e){return this.paymentDetails=e,this.showDetails=!this.showDetails},formatCurrency(e,t){try{return LNbits.utils.formatCurrency(e,t)}catch(t){return console.error(t),`${e} ???`}},shortify:(e,t=10)=>(valueLength=(e||"").length,valueLength<=t?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`),async updateCharts(e){let t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e);try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/count?${t}&count_by=status`);e.sort((e,t)=>e.field-t.field).reverse(),this.searchOptions.status=e.map(e=>e.field),this.paymentsStatusChart.data.datasets[0].data=e.map(e=>e.total),this.paymentsStatusChart.data.labels=[...this.searchOptions.status],this.paymentsStatusChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/wallets?${t}`),s=e.map(e=>e.balance/e.payments_count),a=Math.min(...s),i=Math.max(...s),n=e=>Math.floor(3+22*(e-a)/(i-a)),o=this.randomColors(20),r=e.map((e,t)=>({data:[{x:e.payments_count,y:e.balance,r:n(Math.max(e.balance/e.payments_count,5))}],label:e.wallet_name,wallet_id:e.wallet_id,backgroundColor:o[t%100],hoverOffset:4}));this.paymentsWalletsChart.data.datasets=r,this.paymentsWalletsChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/count?${t}&count_by=tag`);this.searchOptions.tag=e.map(e=>e.field),this.searchOptions.status.sort(),this.paymentsTagsChart.data.datasets[0].data=e.map(e=>e.total),this.paymentsTagsChart.data.labels=e.map(e=>e.field||"core"),this.paymentsTagsChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}try{const t=Object.entries(this.searchData).reduce((e,[t,s])=>s?(e[t]=s,e):e,{}),s={...this.paymentsTable,filter:t},a=LNbits.utils.prepareFilterQuery(s,e);let{data:i}=await LNbits.api.request("GET",`/api/v1/payments/stats/daily?${a}`);const n=this.searchDate.from+"T00:00:00",o=this.searchDate.to+"T23:59:59";this.lnbitsBalance=i.length?i[i.length-1].balance:0,i=i.filter(e=>this.searchDate.from&&this.searchDate.to?e.date>=n&&e.date<=o:this.searchDate.from?e.date>=n:!this.searchDate.to||e.date<=o),this.paymentsDailyChart.data.datasets=[{label:"Balance",data:i.map(e=>e.balance),pointStyle:!1,borderWidth:2,tension:.7,fill:1},{label:"Fees",data:i.map(e=>e.fee),pointStyle:!1,borderWidth:1,tension:.4,fill:1}],this.paymentsDailyChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsDailyChart.update(),this.paymentsBalanceInOutChart.data.datasets=[{label:"Incoming Payments Balance",data:i.map(e=>e.balance_in)},{label:"Outgoing Payments Balance",data:i.map(e=>e.balance_out)}],this.paymentsBalanceInOutChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsBalanceInOutChart.update(),this.paymentsCountInOutChart.data.datasets=[{label:"Incoming Payments Count",data:i.map(e=>e.count_in)},{label:"Outgoing Payments Count",data:i.map(e=>-e.count_out)}],this.paymentsCountInOutChart.data.labels=i.map(e=>e.date.substring(0,10)),this.paymentsCountInOutChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async initCharts(){const e=this.$q.localStorage.getItem("lnbits.payments.chartData")||{};this.chartData={...this.chartData,...e},this.chartsReady?(this.paymentsStatusChart=new Chart(this.$refs.paymentsStatusChart.getContext("2d"),{type:"doughnut",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchPaymentsBy("status",s.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(0, 205, 86)","rgb(64, 72, 78)","rgb(255, 99, 132)"],hoverOffset:4}]}}),this.paymentsWalletsChart=new Chart(this.$refs.paymentsWalletsChart.getContext("2d"),{type:"bubble",options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{display:!1},title:{display:!1}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].datasetIndex;this.searchPaymentsBy("wallet_id",s.data.datasets[e].wallet_id)}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(20),hoverOffset:4}]}}),this.paymentsTagsChart=new Chart(this.$refs.paymentsTagsChart.getContext("2d"),{type:"pie",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!1,title:{display:!1,text:"Tags"}}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchPaymentsBy("tag",s.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(10),hoverOffset:4}]}}),this.paymentsDailyChart=new Chart(this.$refs.paymentsDailyChart.getContext("2d"),{type:"line",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:"Tags"}}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(10),hoverOffset:4}]}}),this.paymentsBalanceInOutChart=new Chart(this.$refs.paymentsBalanceInOutChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:"Tags"}}},scales:{x:{stacked:!0},y:{stacked:!0}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(50),hoverOffset:4}]}}),this.paymentsCountInOutChart=new Chart(this.$refs.paymentsCountInOutChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1},legend:{display:!0,title:{display:!1,text:""}}},scales:{x:{stacked:!0},y:{stacked:!0}}},data:{datasets:[{label:"",data:[],backgroundColor:this.randomColors(80),hoverOffset:4}]}})):console.warn("Charts are not ready yet. Initialization delayed.")},saveChartsPreferences(){this.$q.localStorage.set("lnbits.payments.chartData",this.chartData)},randomColors(e=1){const t=[];for(let s=1;s<=10;s++)for(let a=1;a<=10;a++)t.push(`rgb(${a*e*33%200}, ${71*(s+a+e)%255}, ${(s+30*e)%255})`);return t}}},window.PageNode={template:"#page-node",config:{globalProperties:{LNbits:LNbits,msg:"hello"}},data(){return{isSuperUser:!1,wallet:{},tab:"dashboard",payments:1e3,info:{},channel_stats:{},channels:{data:[],filter:""},activeBalance:{},ranks:{},peers:{data:[],filter:""},connectPeerDialog:{show:!1,data:{}},setFeeDialog:{show:!1,data:{fee_ppm:0,fee_base_msat:0}},openChannelDialog:{show:!1,data:{}},closeChannelDialog:{show:!1,data:{}},nodeInfoDialog:{show:!1,data:{}},transactionDetailsDialog:{show:!1,data:{}},states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}],stateFilters:[{label:"Active",value:"active"},{label:"Pending",value:"pending"}],paymentsTable:{data:[],columns:[{name:"pending",label:""},{name:"date",align:"left",label:this.$t("date"),field:"date",sortable:!0},{name:"sat",align:"right",label:this.$t("amount"),field:e=>this.formatMsat(e.amount),sortable:!0},{name:"fee",align:"right",label:this.$t("fee"),field:"fee"},{name:"destination",align:"right",label:"Destination",field:"destination"},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"}],pagination:{rowsPerPage:10,page:1,rowsNumber:10},filter:null},invoiceTable:{data:[],columns:[{name:"pending",label:""},{name:"paid_at",field:"paid_at",align:"left",label:"Paid at",sortable:!0},{name:"expiry",label:this.$t("expiry"),field:"expiry",align:"left",sortable:!0},{name:"amount",label:this.$t("amount"),field:e=>this.formatMsat(e.amount),sortable:!0},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"}],pagination:{rowsPerPage:10,page:1,rowsNumber:10},filter:null}}},created(){this.getInfo(),this.get1MLStats()},watch:{tab(e){"transactions"!==e||this.paymentsTable.data.length?"channels"!==e||this.channels.data.length||(this.getChannels(),this.getPeers()):(this.getPayments(),this.getInvoices())}},computed:{checkChanges(){return!_.isEqual(this.settings,this.formData)},filteredChannels(){return this.stateFilters?this.channels.data.filter(e=>this.stateFilters.find(({value:t})=>t==e.state)):this.channels.data},totalBalance(){return this.filteredChannels.reduce((e,t)=>(e.local_msat+=t.balance.local_msat,e.remote_msat+=t.balance.remote_msat,e.total_msat+=t.balance.total_msat,e),{local_msat:0,remote_msat:0,total_msat:0})}},methods:{formatMsat:e=>LNbits.utils.formatMsat(e),nodeApi(e,t,s){const a=new URLSearchParams(s?.query);return LNbits.api.request(e,`/node/api/v1${t}?${a}`,{},s?.data).catch(e=>{LNbits.utils.notifyApiError(e)})},getChannel(e){return this.nodeApi("GET",`/channels/${e}`).then(e=>{this.setFeeDialog.data.fee_ppm=e.data.fee_ppm,this.setFeeDialog.data.fee_base_msat=e.data.fee_base_msat})},getChannels(){return this.nodeApi("GET","/channels").then(e=>{this.channels.data=e.data})},getInfo(){return this.nodeApi("GET","/info").then(e=>{this.info=e.data,this.channel_stats=e.data.channel_stats}).catch(()=>{this.info={},this.channel_stats={}})},get1MLStats(){return this.nodeApi("GET","/rank").then(e=>{this.ranks=e.data}).catch(()=>{this.ranks={}})},getPayments(e){e&&(this.paymentsTable.pagination=e.pagination);let t=this.paymentsTable.pagination;const s={limit:t.rowsPerPage,offset:(t.page-1)*t.rowsPerPage??0};return this.nodeApi("GET","/payments",{query:s}).then(e=>{this.paymentsTable.data=e.data.data,this.paymentsTable.pagination.rowsNumber=e.data.total})},getInvoices(e){e&&(this.invoiceTable.pagination=e.pagination);let t=this.invoiceTable.pagination;const s={limit:t.rowsPerPage,offset:(t.page-1)*t.rowsPerPage??0};return this.nodeApi("GET","/invoices",{query:s}).then(e=>{this.invoiceTable.data=e.data.data,this.invoiceTable.pagination.rowsNumber=e.data.total})},getPeers(){return this.nodeApi("GET","/peers").then(e=>{this.peers.data=e.data})},connectPeer(){this.nodeApi("POST","/peers",{data:this.connectPeerDialog.data}).then(()=>{this.connectPeerDialog.show=!1,this.getPeers()})},disconnectPeer(e){LNbits.utils.confirmDialog("Do you really wanna disconnect this peer?").onOk(()=>{this.nodeApi("DELETE",`/peers/${e}`).then(e=>{Quasar.Notify.create({message:"Disconnected",icon:null}),this.needsRestart=!0,this.getPeers()})})},setChannelFee(e){this.nodeApi("PUT",`/channels/${e}`,{data:this.setFeeDialog.data}).then(e=>{this.setFeeDialog.show=!1,this.getChannels()}).catch(LNbits.utils.notifyApiError)},openChannel(){this.nodeApi("POST","/channels",{data:this.openChannelDialog.data}).then(e=>{this.openChannelDialog.show=!1,this.getChannels()}).catch(e=>{console.log(e)})},showCloseChannelDialog(e){this.closeChannelDialog.show=!0,this.closeChannelDialog.data={force:!1,short_id:e.short_id,...e.point}},closeChannel(){this.nodeApi("DELETE","/channels",{query:this.closeChannelDialog.data}).then(e=>{this.closeChannelDialog.show=!1,this.getChannels()})},showSetFeeDialog(e){this.setFeeDialog.show=!0,this.setFeeDialog.channel_id=e,this.getChannel(e)},showOpenChannelDialog(e){this.openChannelDialog.show=!0,this.openChannelDialog.data={peer_id:e,funding_amount:0}},showNodeInfoDialog(e){this.nodeInfoDialog.show=!0,this.nodeInfoDialog.data=e},showTransactionDetailsDialog(e){this.transactionDetailsDialog.show=!0,this.transactionDetailsDialog.data=e},shortenNodeId:e=>e?e.substring(0,5)+"..."+e.substring(e.length-5):"..."}},window.PageNodePublic={template:"#page-node-public",data:()=>({enabled:!1,isSuperUser:!1,wallet:{},tab:"dashboard",payments:1e3,info:{},channel_stats:{},channels:[],activeBalance:{},ranks:{},peers:[],connectPeerDialog:{show:!1,data:{}},openChannelDialog:{show:!1,data:{}},closeChannelDialog:{show:!1,data:{}},nodeInfoDialog:{show:!1,data:{}},states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}]}),created(){this.getInfo(),this.get1MLStats()},methods:{formatMsat:e=>LNbits.utils.formatMsat(e),api:(e,t,s)=>LNbits.api.request(e,"/node/public/api/v1"+t,{},s),getInfo(){this.api("GET","/info",{}).then(e=>{this.info=e.data,this.channel_stats=e.data.channel_stats,this.enabled=!0}).catch(()=>{this.info={},this.channel_stats={}})},get1MLStats(){this.api("GET","/rank",{}).then(e=>{this.ranks=e.data}).catch(()=>{this.ranks={}})}}},window.PageAudit={template:"#page-audit",data:()=>({chartsReady:!1,auditEntries:[],searchData:{user_id:"",ip_address:"",request_type:"",component:"",request_method:"",response_code:"",path:""},searchOptions:{component:[],request_method:[],response_code:[]},auditTable:{columns:[{name:"created_at",align:"center",label:"Date",field:"created_at",sortable:!0},{name:"duration",align:"left",label:"Duration (sec)",field:"duration",sortable:!0},{name:"component",align:"left",label:"Component",field:"component",sortable:!1},{name:"request_method",align:"left",label:"Method",field:"request_method",sortable:!1},{name:"response_code",align:"left",label:"Code",field:"response_code",sortable:!1},{name:"user_id",align:"left",label:"User Id",field:"user_id",sortable:!1},{name:"ip_address",align:"left",label:"IP Address",field:"ip_address",sortable:!1},{name:"path",align:"left",label:"Path",field:"path",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},auditDetailsDialog:{data:null,show:!1}}),async created(){},async mounted(){this.chartsReady=!0,await this.$nextTick(),this.initCharts(),await this.fetchAudit()},methods:{async fetchAudit(e){try{const t=LNbits.utils.prepareFilterQuery(this.auditTable,e),{data:s}=await LNbits.api.request("GET",`/audit/api/v1?${t}`);this.auditTable.pagination.rowsNumber=s.total,this.auditEntries=s.data,await this.fetchAuditStats(e)}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}finally{this.auditTable.loading=!1}},async fetchAuditStats(e){try{const t=LNbits.utils.prepareFilterQuery(this.auditTable,e),{data:s}=await LNbits.api.request("GET",`/audit/api/v1/stats?${t}`),a=s.request_method.map(e=>e.field);this.searchOptions.request_method=[...new Set(this.searchOptions.request_method.concat(a))],this.requestMethodChart.data.labels=a,this.requestMethodChart.data.datasets[0].data=s.request_method.map(e=>e.total),this.requestMethodChart.update();const i=s.response_code.map(e=>e.field);this.searchOptions.response_code=[...new Set(this.searchOptions.response_code.concat(i))],this.responseCodeChart.data.labels=i,this.responseCodeChart.data.datasets[0].data=s.response_code.map(e=>e.total),this.responseCodeChart.update();const n=s.component.map(e=>e.field);this.searchOptions.component=[...new Set(this.searchOptions.component.concat(n))],this.componentUseChart.data.labels=n,this.componentUseChart.data.datasets[0].data=s.component.map(e=>e.total),this.componentUseChart.update(),this.longDurationChart.data.labels=s.long_duration.map(e=>e.field),this.longDurationChart.data.datasets[0].data=s.long_duration.map(e=>e.total),this.longDurationChart.update()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async searchAuditBy(e,t){e&&(this.searchData[e]=t),this.auditTable.filter=Object.entries(this.searchData).reduce((e,[t,s])=>s?(e[t]=s,e):e,{}),await this.fetchAudit()},showDetailsDialog(e){const t=JSON.parse(e?.request_details||"");try{t.body&&(t.body=JSON.parse(t.body))}catch(e){}this.auditDetailsDialog.data=JSON.stringify(t,null,4),this.auditDetailsDialog.show=!0},shortify:e=>(valueLength=(e||"").length,valueLength<=10?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`),async initCharts(){this.chartsReady?(this.responseCodeChart=new Chart(this.$refs.responseCodeChart.getContext("2d"),{type:"doughnut",options:{responsive:!0,plugins:{legend:{position:"bottom"},title:{display:!1,text:"HTTP Response Codes"}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("response_code",s.data.labels[e])}}},data:{datasets:[{label:"",data:[20,10],backgroundColor:["rgb(100, 99, 200)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)"]}],labels:[]}}),this.requestMethodChart=new Chart(this.$refs.requestMethodChart.getContext("2d"),{type:"bar",options:{responsive:!0,maintainAspectRatio:!1,plugins:{title:{display:!1}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("request_method",s.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)"],hoverOffset:4}]}}),this.componentUseChart=new Chart(this.$refs.componentUseChart.getContext("2d"),{type:"pie",options:{responsive:!0,plugins:{legend:{position:"xxx"},title:{display:!1,text:"Components"}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("component",s.data.labels[e])}}},data:{datasets:[{data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)","rgb(100, 205, 250)","rgb(120, 205, 250)","rgb(140, 205, 250)","rgb(160, 205, 250)"],hoverOffset:4}]}}),this.longDurationChart=new Chart(this.$refs.longDurationChart.getContext("2d"),{type:"bar",options:{responsive:!0,indexAxis:"y",maintainAspectRatio:!1,plugins:{legend:{title:{display:!1,text:"Long Duration"}}},onClick:(e,t,s)=>{if(t[0]){const e=t[0].index;this.searchAuditBy("path",s.data.labels[e])}}},data:{datasets:[{label:"",data:[],backgroundColor:["rgb(255, 99, 132)","rgb(54, 162, 235)","rgb(255, 205, 86)","rgb(255, 5, 86)","rgb(25, 205, 86)","rgb(255, 205, 250)","rgb(100, 205, 250)","rgb(120, 205, 250)","rgb(140, 205, 250)","rgb(160, 205, 250)"],hoverOffset:4}]}})):console.warn("Charts are not ready yet. Initialization delayed.")}}},window.PageWallet={template:"#page-wallet",data:()=>({parse:{show:!1,invoice:null,lnurlpay:null,lnurlauth:null,sending:!1,data:{request:"",amount:0,comment:"",internalMemo:null,unit:"sat"},paymentChecker:null,copy:{show:!1},camera:{show:!1,camera:"auto"}},receive:{show:!1,status:"pending",paymentReq:null,paymentHash:null,amountMsat:null,minMax:[0,21e14],lnurl:null,units:[],unit:"sat",fiatProvider:"",data:{amount:null,memo:"",internalMemo:null,payment_hash:null}},update:{name:null,currency:null},hasNfc:!1,nfcReaderAbortController:null,formattedFiatAmount:0,totalBreakdown:{show:!1,loading:!1,rows:[],selectedTypes:["bitcoin","fiat"],selectedTags:[]},paymentFilter:{"status[ne]":"failed"},chartConfig:Quasar.LocalStorage.getItem("lnbits.wallets.chartConfig")||{showPaymentInOutChart:!0,showBalanceChart:!0,showBalanceInOutChart:!0}}),computed:{canPay(){return!!this.parse.invoice&&(this.parse.invoice.expired?(Quasar.Notify.create({message:"Invoice has expired",color:"negative"}),!1):this.parse.invoice.sat<=this.g.wallet.sat)},formattedAmount(){return"sat"==this.receive.unit&&this.g.isSatsDenomination?LNbits.utils.formatMsat(this.receive.amountMsat)+" sat":LNbits.utils.formatCurrency(Number(this.receive.data.amount).toFixed(2),this.g.isSatsDenomination?this.receive.unit:this.g.denomination)},formattedSatAmount(){return LNbits.utils.formatMsat(this.receive.amountMsat)+" sat"},totalBreakdownTags(){const e=this.totalBreakdown.rows.map(e=>e.tag||null);return[...new Set(e)].sort((e,t)=>this.totalBreakdownTagLabel(e).localeCompare(this.totalBreakdownTagLabel(t)))},hasFiatTotalBreakdown(){return this.totalBreakdown.rows.some(e=>e.is_fiat)},selectedTotalBreakdownRows(){return this.totalBreakdown.rows.filter(e=>{const t=e.is_fiat?"fiat":"bitcoin";return this.totalBreakdown.selectedTypes.includes(t)&&this.totalBreakdown.selectedTags.includes(this.totalBreakdownTagKey(e.tag))})},selectedTotalBreakdownMsat(){return this.selectedTotalBreakdownRows.reduce((e,t)=>e+t.total,0)},selectedTotalBreakdownSat(){return Math.round(this.selectedTotalBreakdownMsat/1e3)},selectedTotalBreakdownCount(){return this.selectedTotalBreakdownRows.reduce((e,t)=>e+t.payments_count,0)},formattedTotalBreakdown(){return this.utils.formatBalance(this.selectedTotalBreakdownSat,this.g.denomination)},formattedTotalBreakdownFiat(){if(!this.g.fiatTracking)return null;const e=this.selectedTotalBreakdownSat/1e8*this.g.exchangeRate;return LNbits.utils.formatCurrency(e,this.g.wallet.currency)},primaryTotalBreakdownValue(){return this.g.isFiatPriority&&this.g.fiatTracking&&this.formattedTotalBreakdownFiat||this.formattedTotalBreakdown},secondaryTotalBreakdownValue(){return this.g.fiatTracking?this.g.isFiatPriority?this.formattedTotalBreakdown:this.formattedTotalBreakdownFiat:null}},methods:{showWalletTotalBreakdown(){this.totalBreakdown.show=!0,this.totalBreakdown.rows.length||this.fetchTotalBreakdown()},fetchTotalBreakdown(){this.totalBreakdown.loading=!0,LNbits.api.getPaymentTotalBreakdown(this.g.wallet).then(e=>{this.totalBreakdown.rows=e.data,this.totalBreakdown.selectedTypes=["bitcoin","fiat"],this.totalBreakdown.selectedTags=this.totalBreakdownTags.map(this.totalBreakdownTagKey),this.totalBreakdown.loading=!1}).catch(e=>{this.totalBreakdown.loading=!1,LNbits.utils.notifyApiError(e)})},totalBreakdownTagLabel:e=>e||"No tag",totalBreakdownTagKey:e=>e||"__untagged__",totalBreakdownTagCount(e){return this.totalBreakdown.rows.filter(t=>(t.tag||null)===e).reduce((e,t)=>e+t.payments_count,0)},totalBreakdownTagMsat(e){return this.totalBreakdown.rows.filter(t=>(t.tag||null)===e).reduce((e,t)=>e+t.total,0)},formatTotalBreakdownMsat(e){return this.utils.formatBalance(Math.round(e/1e3),this.g.denomination)},handleSendLnurl(e){this.parse.data.request=e,this.parse.show=!0,this.lnurlScan()},msatoshiFormat:e=>LNbits.utils.formatSat(e/1e3),showReceiveDialog(){this.receive.show=!0,this.receive.status="pending",this.receive.paymentReq=null,this.receive.paymentHash=null,this.receive.data.amount=null,this.receive.data.memo=null,this.receive.data.internalMemo=null,this.receive.data.payment_hash=null,this.receive.units=["sat",...this.g.allowedCurrencies.length>0?this.g.allowedCurrencies:this.g.currencies],this.receive.unit=this.g.isFiatPriority&&this.g.wallet.currency||"sat",this.receive.minMax=[0,21e14],this.receive.lnurl=null},onReceiveDialogHide(){this.hasNfc&&this.nfcReaderAbortController.abort()},showParseDialog(){this.parse.show=!0,this.parse.invoice=null,this.parse.lnurlpay=null,this.parse.lnurlauth=null,this.parse.copy.show=window.isSecureContext&&void 0!==navigator.clipboard?.readText,this.parse.data.request="",this.parse.data.comment="",this.parse.data.internalMemo=null,this.parse.sending=!1,this.parse.data.paymentChecker=null,this.parse.camera.show=!1},closeParseDialog(){setTimeout(()=>{clearInterval(this.parse.paymentChecker)},1e4)},handleBalanceUpdate(e){this.g.wallet.sat=this.g.wallet.sat+e},createInvoice(){this.receive.status="loading",this.g.isSatsDenomination||(this.receive.data.amount=100*this.receive.data.amount),LNbits.api.createInvoice(this.g.wallet,this.receive.data.amount,this.receive.data.memo,this.receive.unit,this.receive.lnurlWithdraw,this.receive.fiatProvider,this.receive.data.internalMemo,this.receive.data.payment_hash).then(e=>{if(this.g.updatePayments=!this.g.updatePayments,this.receive.status="success",this.receive.paymentReq=e.data.bolt11,this.receive.fiatPaymentReq=e.data.extra?.fiat_payment_request,this.receive.amountMsat=e.data.amount,this.receive.paymentHash=e.data.payment_hash,this.receive.lnurl||this.readNfcTag(),this.receive.lnurl&&null!==e.data.extra?.lnurl_response){!1===e.data.extra.lnurl_response&&(e.data.extra.lnurl_response="Unable to connect");const t=this.receive.lnurl.callback.split("/")[2];if("string"==typeof e.data.extra.lnurl_response)return void Quasar.Notify.create({timeout:5e3,type:"warning",message:`${t} lnurl-withdraw call failed.`,caption:e.data.extra.lnurl_response});!0===e.data.extra.lnurl_response&&Quasar.Notify.create({timeout:3e3,message:`Invoice sent to ${t}!`,spinner:!0})}}).catch(e=>{LNbits.utils.notifyApiError(e),this.receive.status="pending"})},lnurlScan(){LNbits.api.request("POST","/api/v1/lnurlscan",this.g.wallet.adminkey,{lnurl:this.parse.data.request}).then(e=>{const t=e.data;if("ERROR"!==t.status){if("payRequest"===t.tag)this.parse.lnurlpay=Object.freeze(t),this.parse.data.amount=t.minSendable/1e3,this.receive.units=["sats",...this.g.allowedCurrencies.length>0?this.g.allowedCurrencies:this.g.currencies];else if("login"===t.tag)this.parse.lnurlauth=Object.freeze(t);else if("withdrawRequest"===t.tag){this.parse.show=!1,this.receive.show=!0,this.receive.lnurlWithdraw=Object.freeze(t),this.receive.status="pending",this.receive.paymentReq=null,this.receive.paymentHash=null,this.receive.data.amount=t.maxWithdrawable/1e3,this.receive.data.memo=t.defaultDescription,this.receive.minMax=[t.minWithdrawable/1e3,t.maxWithdrawable/1e3];const e=t.callback.split("/")[2];this.receive.lnurl={domain:e,callback:t.callback,fixed:t.fixed}}}else Quasar.Notify.create({timeout:5e3,type:"warning",message:"lnurl scan failed.",caption:t.reason})}).catch(e=>{LNbits.utils.notifyApiError(e)})},decodeQR(e){this.parse.data.request=e,this.decodeRequest(),this.parse.camera.show=!1},isLnurl:e=>e.toLowerCase().startsWith("lnurl1")||e.startsWith("lnurlp://")||e.startsWith("lnurlw://")||e.startsWith("lnurlauth://")||e.match(/[\w.+-~_]+@[\w.+-~_]/),decodeRequest(){this.parse.show=!0,this.parse.data.request=this.parse.data.request.trim();const e=this.parse.data.request.toLowerCase();if(e.startsWith("lightning:")?this.parse.data.request=this.parse.data.request.slice(10):e.startsWith("lnurl:")?this.parse.data.request=this.parse.data.request.slice(6):e.includes("lightning=lnurl1")&&(this.parse.data.request=this.parse.data.request.split("lightning=")[1].split("&")[0]),this.isLnurl(this.parse.data.request))return void this.lnurlScan();let t;this.parse.data.request.toLowerCase().includes("lightning")&&(this.parse.data.request=this.parse.data.request.split("lightning=")[1],this.parse.data.request.includes("&")&&(this.parse.data.request=this.parse.data.request.split("&")[0]));try{t=decode(this.parse.data.request)}catch(e){return Quasar.Notify.create({timeout:3e3,type:"warning",message:e+".",caption:"400 BAD REQUEST"}),void(this.parse.show=!1)}let s={msat:t.human_readable_part.amount,sat:t.human_readable_part.amount/1e3,fsat:LNbits.utils.formatSat(t.human_readable_part.amount/1e3),bolt11:this.parse.data.request};_.each(t.data.tags,e=>{if(_.isObject(e)&&_.has(e,"description"))if("payment_hash"===e.description)s.hash=e.value;else if("description"===e.description)s.description=e.value;else if("expiry"===e.description){const a=new Date(1e3*(t.data.time_stamp+e.value)),i=new Date(1e3*t.data.time_stamp);s.expireDate=Quasar.date.formatDate(a,"YYYY-MM-DDTHH:mm:ss.SSSZ"),s.createdDate=Quasar.date.formatDate(i,"YYYY-MM-DDTHH:mm:ss.SSSZ"),s.expireDateFrom=moment.utc(a).local().fromNow(),s.createdDateFrom=moment.utc(i).local().fromNow(),s.expired=!1}}),this.g.wallet.currency&&(s.fiatAmount=LNbits.utils.formatCurrency((s.sat/1e8*this.g.exchangeRate).toFixed(2),this.g.wallet.currency)),this.parse.invoice=Object.freeze(s)},payInvoice(){if(this.parse.sending)return;this.parse.sending=!0;const e=Quasar.Notify.create({timeout:0,message:this.$t("payment_processing")});LNbits.api.payInvoice(this.g.wallet,this.parse.data.request,this.parse.data.internalMemo).then(t=>{this.parse.sending=!1,e(),this.g.updatePayments=!this.g.updatePayments,this.parse.show=!1,"success"==t.data.status&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")}),"pending"==t.data.status&&Quasar.Notify.create({type:"info",message:this.$t("payment_pending")})}).catch(t=>{this.parse.sending=!1,e(),LNbits.utils.notifyApiError(t),this.g.updatePayments=!this.g.updatePayments})},payLnurl(){this.parse.sending||(this.parse.sending=!0,LNbits.api.request("post","/api/v1/payments/lnurl",this.g.wallet.adminkey,{res:this.parse.lnurlpay,lnurl:this.parse.data.request,unit:this.parse.data.unit,amount:1e3*this.parse.data.amount,comment:this.parse.data.comment,internalMemo:this.parse.data.internalMemo}).then(e=>{if(this.parse.sending=!1,this.parse.show=!1,e.data.extra.success_action){const t=JSON.parse(e.data.extra.success_action);switch(t.tag){case"url":Quasar.Notify.create({message:t.url,caption:t.description,html:!1,type:"positive",timeout:0,closeBtn:!0,actions:[{label:"Open link",color:"white",handler:()=>this.utils.openUrlInNewTab(t.url)}]});break;case"message":Quasar.Notify.create({message:t.message,type:"positive",timeout:0,closeBtn:!0});break;case"aes":this.utils.decryptLnurlPayAES(t,e.data.preimage).then(e=>{Quasar.Notify.create({message:e,caption:t.description,html:!1,type:"positive",timeout:0,closeBtn:!0})}).catch(e=>{Quasar.Notify.create({message:t.description||"Payment successful.",caption:"Could not decrypt success action.",html:!1,type:"warning",timeout:0,closeBtn:!0})})}}}).catch(e=>{this.parse.sending=!1,LNbits.utils.notifyApiError(e)}))},authLnurl(){const e=Quasar.Notify.create({timeout:10,message:"Performing authentication..."});LNbits.api.request("post","/api/v1/lnurlauth",wallet.adminkey,this.parse.lnurlauth).then(t=>{e(),Quasar.Notify.create({message:"Authentication successful.",type:"positive",timeout:3500}),this.parse.show=!1}).catch(e=>{e.response.data.reason?Quasar.Notify.create({message:`Authentication failed. ${this.parse.lnurlauth.callback} says:`,caption:e.response.data.reason,type:"warning",timeout:5e3}):LNbits.utils.notifyApiError(e)})},updateWallet(e){LNbits.api.request("PATCH","/api/v1/wallet",this.g.wallet.adminkey,e).then(e=>{const t={...e.data};t.lightning_address&&(t.lightningAddress=t.lightning_address,t.lightningAddressFull=`${t.lightning_address}@${window.location.host}`),this.g.wallet={...this.g.wallet,...t};const s=this.g.user.wallets.findIndex(t=>t.id===e.data.id);-1!==s&&(this.g.user.wallets[s]={...this.g.user.wallets[s],...t}),Quasar.Notify.create({message:"Wallet updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},pasteToTextArea(){this.$refs.textArea.focus(),navigator.clipboard.readText().then(e=>{this.parse.data.request=e.trim()})},readNfcTag(){try{if("undefined"==typeof NDEFReader)return void console.debug("NFC not supported on this device or browser.");const e=new NDEFReader;this.nfcReaderAbortController=new AbortController,this.nfcReaderAbortController.signal.onabort=e=>{console.debug("All NFC Read operations have been aborted.")},this.hasNfc=!0;const t=Quasar.Notify.create({message:"Tap your NFC tag to pay this invoice with LNURLw."});return e.scan({signal:this.nfcReaderAbortController.signal}).then(()=>{e.onreadingerror=()=>{Quasar.Notify.create({type:"negative",message:"There was an error reading this NFC tag."})},e.onreading=({message:e})=>{const s=new TextDecoder("utf-8"),a=e.records.find(e=>-1!==s.decode(e.data).toUpperCase().indexOf("LNURLW"));if(a){t(),Quasar.Notify.create({type:"positive",message:"NFC tag read successfully."});const e=s.decode(a.data);this.payInvoiceWithNfc(e)}else Quasar.Notify.create({type:"warning",message:"NFC tag does not have LNURLw record."})}})}catch(e){Quasar.Notify.create({type:"negative",message:e?e.toString():"An unexpected error has occurred."})}},payInvoiceWithNfc(e){const t=Quasar.Notify.create({timeout:0,spinner:!0,message:this.$t("payment_processing")});LNbits.api.request("POST",`/api/v1/payments/${this.receive.paymentReq}/pay-with-nfc`,this.g.wallet.adminkey,{lnurl_w:e}).then(e=>{t(),e.data.success?Quasar.Notify.create({type:"positive",message:"Payment successful"}):Quasar.Notify.create({type:"negative",message:e.data.detail||"Payment failed"})}).catch(e=>{t(),LNbits.utils.notifyApiError(e)})}},created(){const e=new URLSearchParams(window.location.search);(e.has("lightning")||e.has("lnurl"))&&(this.parse.data.request=e.get("lightning")||e.get("lnurl"),this.decodeRequest(),this.parse.show=!0);const t=this.g.user.wallets.find(e=>e.id===this.$route.params.id);t?(this.g.wallet=t,this.g.lastActiveWallet=t.id,this.$q.localStorage.setItem("lnbits.lastActiveWallet",t.id),this.$router.replace(`/wallet/${t.id}`)):(this.g.errorCode=404,this.g.errorMessage="Wallet not found.",this.$router.push("/error"))},watch:{"g.updatePaymentsHash"(){this.receive.show=!1},"g.updatePayments"(){this.parse.show=!1,this.g.wallet.currency&&this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency)&&(this.g.exchangeRate=this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency),this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat)},"g.wallet"(){this.g.wallet.currency?(this.g.fiatTracking=!0,this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat):(this.g.fiatBalance=0,this.g.fiatTracking=!1)},"g.isFiatPriority"(){this.receive.unit=this.g.isFiatPriority?this.g.wallet.currency:"sat"},"g.fiatBalance"(){this.formattedFiatAmount=LNbits.utils.formatCurrency(this.g.fiatBalance.toFixed(2),this.g.wallet.currency)},"g.exchangeRate"(){this.g.fiatTracking&&this.g.wallet.currency&&(this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat)}}},window.PageWallets={template:"#page-wallets",data:()=>({user:null,tab:"wallets",wallets:[],addWalletDialog:{show:!1},walletsTable:{columns:[{name:"name",align:"left",label:"Name",field:"name",sortable:!0},{name:"currency",align:"center",label:"Currency",field:"currency",sortable:!0},{name:"updated_at",align:"right",label:"Last Updated",field:"updated_at",sortable:!0}],pagination:{sortBy:"updated_at",rowsPerPage:12,page:1,descending:!0,rowsNumber:10},search:"",hideEmpty:!0,loading:!1}}),watch:{"walletsTable.search":{handler(){const e={};this.walletsTable.search&&(e.search=this.walletsTable.search),this.getUserWallets()}}},methods:{async getUserWallets(e){try{this.walletsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.walletsTable,e),{data:s}=await LNbits.api.request("GET",`/api/v1/wallet/paginated?${t}`,null);this.wallets=s.data,this.walletsTable.pagination.rowsNumber=s.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.walletsTable.loading=!1}},goToWallet(e){this.$router.push({path:"/wallet",query:{wal:e}})},formattedFiatAmount:(e,t)=>LNbits.utils.formatCurrency(Number(e).toFixed(2),t),formattedSatAmount:e=>LNbits.utils.formatMsat(e)+" sat"},async created(){await this.getUserWallets()}},window.PageUsers={template:"#page-users",data(){return{paymentsWallet:{},cancel:{},users:[],wallets:[],searchData:{user:"",username:"",email:"",pubkey:""},paymentPage:{show:!1},activeWallet:{userId:null,show:!1},activeUser:{data:null,showUserId:!1,show:!1},createWalletDialog:{data:{},show:!1},lightningAddressDialog:{wallet:null,lightningAddress:"",show:!1},walletTable:{columns:[{name:"name",align:"left",label:"Name",field:"name"},{name:"id",align:"left",label:"Wallet Id",field:"id"},{name:"currency",align:"left",label:"Currency",field:"currency"},{name:"balance_msat",align:"left",label:"Balance",field:"balance_msat"}],pagination:{sortBy:"name",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},search:null,hideEmpty:!0,loading:!1},usersTable:{columns:[{name:"activated",align:"left",label:this.$t("activated"),field:"activated",sortable:!1},{name:"wallet_id",align:"left",label:"Wallets",field:"wallet_id",sortable:!1},{name:"id",align:"left",label:"User Id",field:"id",sortable:!1},{name:"username",align:"left",label:"Username",field:"username",sortable:!1},{name:"email",align:"left",label:"Email",field:"email",sortable:!1},{name:"pubkey",align:"left",label:"Public Key",field:"pubkey",sortable:!1},{name:"balance_msat",align:"left",label:"Balance",field:"balance_msat",sortable:!1},{name:"transaction_count",align:"left",label:"Payments",field:"transaction_count",sortable:!1},{name:"last_payment",align:"left",label:"Last Payment",field:"last_payment",sortable:!1}],pagination:{sortBy:"created_at",rowsPerPage:10,page:1,descending:!0,rowsNumber:10},sortFields:[{name:"id",label:"User ID"},{name:"username",label:"Username"},{name:"email",label:"Email"},{name:"pubkey",label:"Public Key"},{name:"created_at",label:"Creation Date"},{name:"updated_at",label:"Last Updated"}],search:null,hideEmpty:!0,loading:!1}}},watch:{"usersTable.hideEmpty":function(e,t){this.usersTable.filter=e?{"transaction_count[gt]":0}:{},this.fetchUsers()}},created(){this.fetchUsers()},computed:{lightningAddressSuffix:()=>`@${window.location.host}`},methods:{formatSat:e=>LNbits.utils.formatSat(Math.floor(e/1e3)),backToUsersPage(){this.activeUser.show=!1,this.paymentPage.show=!1,this.activeWallet.show=!1,this.fetchUsers()},handleBalanceUpdate(){this.fetchWallets(this.activeWallet.userId)},resetPassword(e){return LNbits.api.request("PUT",`/users/api/v1/user/${e}/reset_password`).then(e=>{LNbits.utils.confirmDialog(this.$t("reset_key_generated")+" "+this.$t("reset_key_copy")).onOk(()=>{const t=window.location.origin+"?reset_key="+e.data;this.utils.copyText(t)})}).catch(LNbits.utils.notifyApiError)},sortByColumn(e){this.usersTable.pagination.sortBy===e?this.usersTable.pagination.descending=!this.usersTable.pagination.descending:(this.usersTable.pagination.sortBy=e,this.usersTable.pagination.descending=!1),this.fetchUsers()},createUser(){LNbits.api.request("POST","/users/api/v1/user",null,this.activeUser.data).then(e=>{Quasar.Notify.create({type:"positive",message:"User created!",icon:null}),this.activeUser.setPassword=!0,this.activeUser.data=e.data,this.fetchUsers()}).catch(LNbits.utils.notifyApiError)},updateUser(){LNbits.api.request("PUT",`/users/api/v1/user/${this.activeUser.data.id}`,null,this.activeUser.data).then(()=>{Quasar.Notify.create({type:"positive",message:"User updated!",icon:null}),this.activeUser.data=null,this.activeUser.show=!1,this.fetchUsers()}).catch(LNbits.utils.notifyApiError)},createWallet(){const e=this.activeWallet.userId;e?LNbits.api.request("POST",`/users/api/v1/user/${e}/wallet`,null,this.createWalletDialog.data).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"Wallet created!"})}).catch(LNbits.utils.notifyApiError):Quasar.Notify.create({type:"warning",message:"No user selected!",icon:null})},deleteUser(e){LNbits.utils.confirmDialog("Are you sure you want to delete this user?").onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}`).then(()=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:"User deleted!",icon:null}),this.activeUser.data=null,this.activeUser.show=!1}).catch(LNbits.utils.notifyApiError)})},undeleteUserWallet(e,t){LNbits.api.request("PUT",`/users/api/v1/user/${e}/wallet/${t}/undelete`).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"Undeleted user wallet!",icon:null})}).catch(LNbits.utils.notifyApiError)},deleteUserWallet(e,t,s){const a=s?"Wallet is already deleted, are you sure you want to permanently delete this user wallet?":"Are you sure you want to delete this user wallet?";LNbits.utils.confirmDialog(a).onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}/wallet/${t}`).then(()=>{this.fetchWallets(e),Quasar.Notify.create({type:"positive",message:"User wallet deleted!",icon:null})}).catch(LNbits.utils.notifyApiError)})},deleteAllUserWallets(e){LNbits.utils.confirmDialog(this.$t("confirm_delete_all_wallets")).onOk(()=>{LNbits.api.request("DELETE",`/users/api/v1/user/${e}/wallets`).then(t=>{Quasar.Notify.create({type:"positive",message:t.data.message,icon:null}),this.fetchWallets(e)}).catch(LNbits.utils.notifyApiError)})},copyWalletLink(e){const t=`${window.location.origin}/wallet?usr=${this.activeWallet.userId}&wal=${e}`;this.utils.copyText(t)},showLightningAddressDialog(e){this.lightningAddressDialog.wallet=e,this.lightningAddressDialog.lightningAddress=e.lightning_address||"",this.lightningAddressDialog.show=!0},saveLightningAddress(){const e=this.lightningAddressDialog.wallet;e&&LNbits.api.request("PUT",`/users/api/v1/user/${e.user}/wallet/${e.id}/lightning-address`,null,{lightning_address:this.lightningAddressDialog.lightningAddress}).then(t=>{Object.assign(e,t.data),this.lightningAddressDialog.show=!1,Quasar.Notify.create({type:"positive",message:this.$t("lightning_address_updated"),icon:null})}).catch(LNbits.utils.notifyApiError)},fetchUsers(e){this.relaxFilterForFields(["username","email"]);const t=LNbits.utils.prepareFilterQuery(this.usersTable,e);LNbits.api.request("GET",`/users/api/v1/user?${t}`).then(e=>{this.usersTable.loading=!1,this.usersTable.pagination.rowsNumber=e.data.total,this.users=e.data.data}).catch(LNbits.utils.notifyApiError)},fetchWallets(e){return LNbits.api.request("GET",`/users/api/v1/user/${e}/wallet`).then(t=>{this.wallets=t.data,this.activeWallet.userId=e,this.activeWallet.show=!0}).catch(LNbits.utils.notifyApiError)},relaxFilterForFields(e=[]){e.forEach(e=>{const t=this.usersTable?.filter?.[e];t&&this.usersTable.filter[e]&&(this.usersTable.filter[`${e}[like]`]=t,delete this.usersTable.filter[e])})},updateWallet(e){LNbits.api.request("PATCH","/api/v1/wallet",e.adminkey,{name:e.name}).then(()=>{e.editable=!1,Quasar.Notify.create({message:"Wallet name updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},toggleAdmin(e){LNbits.api.request("PUT",`/users/api/v1/user/${e}/admin`).then(()=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:"Toggled admin!",icon:null})}).catch(LNbits.utils.notifyApiError)},toggleUserActivated(e){LNbits.api.request("PUT",`/users/api/v1/user/${e}/activate`).then(e=>{this.fetchUsers(),Quasar.Notify.create({type:"positive",message:e.data.message,icon:null})}).catch(LNbits.utils.notifyApiError)},async showAccountPage(e){if(this.activeUser.showPassword=!1,this.activeUser.showUserId=!1,this.activeUser.setPassword=!1,!e)return this.activeUser.data={extra:{}},void(this.activeUser.show=!0);try{const{data:t}=await LNbits.api.request("GET",`/users/api/v1/user/${e}`);this.activeUser.data=t,this.activeUser.show=!0}catch(e){console.warn(e),Quasar.Notify.create({type:"warning",message:"Failed to get user!"}),this.activeUser.show=!1}},async impersonateUser(e){try{await LNbits.api.impersonateUser(e),LNbits.utils.backupLocalStorage("impersonation",!0),this.$q.localStorage.setItem("lnbits.disclaimerShown",!0),window.location="/wallet"}catch(e){console.warn(e),Quasar.Notify.create({type:"warning",message:"Failed to impersonate user!"})}},async showWalletPayments(e){this.activeUser.show=!1,await this.fetchWallets(this.users[0].id),await this.showPayments(e)},showPayments(e){this.paymentsWallet=this.wallets.find(t=>t.id===e),this.paymentPage.show=!0},searchUserBy(e){const t=this.searchData[e];this.usersTable.filter={},t&&(this.usersTable.filter[e]=t),this.fetchUsers()},shortify:e=>(valueLength=(e||"").length,valueLength<=10?e:`${e.substring(0,5)}...${e.substring(valueLength-5,valueLength)}`)}},window.PageAccount={template:"#page-account",data(){return{untouchedUser:null,hasUsername:!1,showUserId:!1,themeOptions:[{name:"bitcoin",color:"deep-orange"},{name:"classic",color:"purple"},{name:"mint",color:"green"},{name:"autumn",color:"brown"},{name:"monochrome",color:"grey"},{name:"salvador",color:"blue-10"},{name:"freedom",color:"pink-13"},{name:"cyber",color:"light-green-9"},{name:"flamingo",color:"pink-3"}],defaultSiteCustomisation:{locale:"en"},reactionOptions:["None","confettiBothSides","confettiFireworks","confettiStars","confettiTop","lightningStrike"],borderOptions:["retro-border","hard-border","neon-border","no-border"],tab:"user",credentialsData:{show:!1,oldPassword:null,newPassword:null,newPasswordRepeat:null,username:null,pubkey:null},apiAcl:{showNewAclDialog:!1,showPasswordDialog:!1,showNewTokenDialog:!1,data:[],passwordGuardedFunction:null,newAclName:"",newTokenName:"",password:"",apiToken:null,selectedTokenId:null,columns:[{name:"Name",align:"left",label:this.$t("Name"),field:"Name",sortable:!1},{name:"path",align:"left",label:this.$t("path"),field:"path",sortable:!1},{name:"read",align:"left",label:this.$t("read"),field:"read",sortable:!1},{name:"write",align:"left",label:this.$t("write"),field:"write",sortable:!1}],pagination:{rowsPerPage:100,page:1}},selectedApiAcl:{id:null,name:null,endpoints:[],token_id_list:[],allRead:!1,allWrite:!1},assets:[],assetsTable:{loading:!1,columns:[{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"created_at",align:"left",label:this.$t("created_at"),field:"created_at",sortable:!0}],pagination:{rowsPerPage:6,page:1}},assetsUploadToPublic:!1,notifications:{nostr:{identifier:""}},labels:[],labelsDialog:{show:!1,data:{name:"",description:"",color:"#000000"}},labelsTable:{loading:!1,columns:[{name:"actions",align:"left"},{name:"name",align:"left",label:this.$t("Name"),field:"name",sortable:!0},{name:"description",align:"left",label:this.$t("description"),field:"description"},{name:"color",align:"left",label:this.$t("color"),field:"color"}],pagination:{rowsPerPage:6,page:1}}}},watch:{tab(e){this.$router.push(`/account#${e}`)},$route(e){e.hash.length>1&&(this.tab=e.hash.replace("#",""))},"assetsTable.search":{handler(){const e={};this.assetsTable.search&&(e.search=this.assetsTable.search),this.getUserAssets()}}},computed:{isUserTouched(){return!_.isEqual(this.g.user,this.untouchedUser)},selectedApiToken(){return this.selectedApiAcl.token_id_list.find(e=>e.id===this.apiAcl.selectedTokenId)},expiryAt(){return this.selectedApiToken.expires_at?`${this.$t("expiry")}: ${LNbits.utils.formatTimestamp(this.selectedApiToken.expires_at)}`:""},tokenStatus(){if(this.selectedApiToken.expires_at){const e=new Date;let t="",s="positive";return new Date(1e3*this.selectedApiToken.expires_at){const t=this.apiAcl.data.find(t=>t.id===e);this.selectedApiAcl&&(this.selectedApiAcl={...t},this.selectedApiAcl.allRead=this.selectedApiAcl.endpoints.every(e=>e.read),this.selectedApiAcl.allWrite=this.selectedApiAcl.endpoints.every(e=>e.write))})},handleAllEndpointsReadAccess(){this.selectedApiAcl.endpoints.forEach(e=>e.read=this.selectedApiAcl.allRead)},handleAllEndpointsWriteAccess(){this.selectedApiAcl.endpoints.forEach(e=>e.write=this.selectedApiAcl.allWrite)},async getApiACLs(){try{const{data:e}=await LNbits.api.request("GET","/api/v1/auth/acl",null);this.apiAcl.data=e.access_control_list}catch(e){LNbits.utils.notifyApiError(e)}},askPasswordAndRunFunction(e){this.apiAcl.passwordGuardedFunction=e,this.apiAcl.showPasswordDialog=!0},runPasswordGuardedFunction(){this.apiAcl.showPasswordDialog=!1;const e=this.apiAcl.passwordGuardedFunction;e&&this[e]()},async addApiACL(){if(this.apiAcl.newAclName){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/acl",null,{id:this.apiAcl.newAclName,name:this.apiAcl.newAclName,password:this.apiAcl.password});this.apiAcl.data=e.access_control_list;const t=this.apiAcl.data.find(e=>e.name===this.apiAcl.newAclName);this.handleApiACLSelected(t.id),this.apiAcl.showNewAclDialog=!1,this.$q.notify({type:"positive",message:"Access Control List created."})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.name="",this.apiAcl.password=""}this.apiAcl.showNewAclDialog=!1}else this.$q.notify({type:"warning",message:"Name is required."})},async updateApiACLs(){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/auth/acl",null,{id:this.g.user.id,password:this.apiAcl.password,...this.selectedApiAcl});this.apiAcl.data=e.access_control_list}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async deleteApiACL(){if(this.selectedApiAcl.id){try{await LNbits.api.request("DELETE","/api/v1/auth/acl",null,{id:this.selectedApiAcl.id,password:this.apiAcl.password}),this.$q.notify({type:"positive",message:"Access Control List deleted."})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}this.apiAcl.data=this.apiAcl.data.filter(e=>e.id!==this.selectedApiAcl.id),this.handleApiACLSelected(this.apiAcl.data[0]?.id)}},async generateApiToken(){if(!this.selectedApiAcl.id)return;const e=new Date(this.apiAcl.newTokenExpiry)-new Date;try{const{data:t}=await LNbits.api.request("POST","/api/v1/auth/acl/token",null,{acl_id:this.selectedApiAcl.id,token_name:this.apiAcl.newTokenName,password:this.apiAcl.password,expiration_time_minutes:Math.trunc(e/6e4)});this.apiAcl.apiToken=t.api_token,this.apiAcl.selectedTokenId=t.id,Quasar.Notify.create({type:"positive",message:"Token Generated."}),await this.getApiACLs(),this.handleApiACLSelected(this.selectedApiAcl.id),this.apiAcl.showNewTokenDialog=!1}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async deleteToken(){if(this.apiAcl.selectedTokenId)try{await LNbits.api.request("DELETE","/api/v1/auth/acl/token",null,{id:this.apiAcl.selectedTokenId,acl_id:this.selectedApiAcl.id,password:this.apiAcl.password}),this.$q.notify({type:"positive",message:"Token deleted."}),this.selectedApiAcl.token_id_list=this.selectedApiAcl.token_id_list.filter(e=>e.id!==this.apiAcl.selectedTokenId),this.apiAcl.selectedTokenId=null}catch(e){LNbits.utils.notifyApiError(e)}finally{this.apiAcl.password=""}},async getUserAssets(e){try{this.assetsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.assetsTable,e),{data:s}=await LNbits.api.request("GET",`/api/v1/assets/paginated?${t}`,null);this.assets=s.data,this.assetsTable.pagination.rowsNumber=s.total}catch(e){LNbits.utils.notifyApiError(e)}finally{this.assetsTable.loading=!1}},onImageInput(e){const t=e.target.files[0];t&&this.uploadAsset(t),e.target.value=null},onBackgroundImageInput(e){const t=e.target.files[0];t&&this.uploadBackgroundImage(t),e.target.value=null},async uploadAsset(e,{isPublic:t=this.assetsUploadToPublic,notifySuccess:s=!0}={}){const a=new FormData;a.append("file",e);try{const{data:e}=await LNbits.api.request("POST",`/api/v1/assets?public_asset=${t}`,null,a,{headers:{"Content-Type":"multipart/form-data"}});return s&&this.$q.notify({type:"positive",message:"Upload successful!",icon:null}),await this.getUserAssets(),e}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},async uploadBackgroundImage(e){const t=await this.uploadAsset(e,{isPublic:!1,notifySuccess:!1});if(!t)return;const s=`${window.location.origin}/api/v1/assets/${t.id}/thumbnail`;await this.siteCustomisationChanged({bgimageChoice:s})},async deleteAsset(e){LNbits.utils.confirmDialog("Are you sure you want to delete this asset?").onOk(async()=>{try{await LNbits.api.request("DELETE",`/api/v1/assets/${e.id}`,null),this.$q.notify({type:"positive",message:"Asset deleted."}),await this.getUserAssets()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}})},async toggleAssetPublicAccess(e){try{await LNbits.api.request("PUT",`/api/v1/assets/${e.id}`,null,{is_public:!e.is_public}),this.$q.notify({type:"positive",message:"Update successful!",icon:null}),await this.getUserAssets()}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}},copyAssetLinkToClipboard(e){const t=`${window.location.origin}/api/v1/assets/${e.id}/data`;this.utils.copyText(t)},addUserLabel(){if(!this.labelsDialog.data.name)return void this.$q.notify({type:"warning",message:"Name is required."});if(!this.labelsDialog.data.color)return void this.$q.notify({type:"warning",message:"Color is required."});this.g.user.extra.labels=this.g.user.extra.labels||[];if(!this.g.user.extra.labels.find(e=>e.name===this.labelsDialog.data.name))return this.g.user.extra.labels.unshift({...this.labelsDialog.data}),this.labelsDialog.show=!1,!0;this.$q.notify({type:"warning",message:"A label with this name already exists."})},openAddLabelDialog(){this.labelsDialog.data={name:"",description:"",color:"#000000"},this.labelsDialog.show=!0},openEditLabelDialog(e){this.labelsDialog.data={name:e.name,description:e.description,color:e.color},this.labelsDialog.show=!0},updateUserLabel(){const e=this.labelsDialog.data,t=JSON.parse(JSON.stringify(this.g.user.extra.labels));this.g.user.extra.labels=this.g.user.extra.labels.filter(t=>t.name!==e.name);this.addUserLabel()||(this.g.user.extra.labels=t),this.labelsDialog.show=!1},deleteUserLabel(e){LNbits.utils.confirmDialog("Are you sure you want to delete this label?").onOk(()=>{this.g.user.extra.labels=this.g.user.extra.labels.filter(t=>t.name!==e.name)})},async siteCustomisationChanged(e={}){try{Object.entries(e||{}).forEach(([e,t])=>{e in this.g&&(this.g[e]=t)}),await LNbits.api.updateUiCustomization(e),this.$q.notify({type:"positive",message:"UI Customization updated."})}catch(e){LNbits.utils.notifyApiError(e)}},resetThemeDefaults(){const e={themeChoice:this.g.settings.defaultTheme,borderChoice:this.g.settings.defaultBorder,gradientChoice:this.g.settings.defaultGradient,bgimageChoice:this.g.settings.defaultBgimage||"",reactionChoice:this.g.settings.defaultReaction,darkChoice:this.g.settings.defaultDark,cardRoundedChoice:this.g.settings.defaultCardRounded,cardGradientChoice:this.g.settings.defaultCardGradient,cardShadowChoice:this.g.settings.defaultCardShadow,burgerMenuChoice:this.g.settings.defaultBurgerMenuBackground};this.siteCustomisationChanged(e)}},async created(){this.untouchedUser=JSON.parse(JSON.stringify(this.g.user)),this.hasUsername=!!this.g.user.username,this.$route.hash.length>1&&(this.tab=this.$route.hash.replace("#","")),await this.getApiACLs(),await this.getUserAssets(),this.themeOptions=this.themeOptions.filter(e=>this.g.settings.themeOptions.includes(e.name))}},window.PageAdmin={template:"#page-admin",data:()=>({tab:"funding",settings:{},formData:{lnbits_exchange_rate_providers:[],lnbits_audit_exclude_paths:[],lnbits_audit_include_paths:[],lnbits_audit_http_response_codes:[]},isSuperUser:!1,needsRestart:!1}),watch:{tab(e){if(["wasm-runtime","wasm-limit-config"].includes(e)&&this.$route.path.startsWith("/admin/extensions/wasm"))return;const t=this.adminRouteForTab(e);this.$route.fullPath!==t&&this.$router.push(t)},$route(e){const t=this.adminTabFromRoute(e);this.tab!==t&&(this.tab=t)}},async created(){this.tab=this.adminTabFromRoute(this.$route),await this.getSettings()},computed:{checkChanges(){return!_.isEqual(this.settings,this.formData)}},methods:{adminTabFromRoute:e=>e.path.startsWith("/admin/extensions/wasm/limits")?"wasm-limit-config":e.path.startsWith("/admin/extensions/wasm")?"wasm-runtime":e.hash.length>1?e.hash.replace("#",""):"funding",adminRouteForTab:e=>"wasm-runtime"===e?"/admin/extensions/wasm":"wasm-limit-config"===e?"/admin/extensions/wasm/limits":`/admin#${e}`,getDefaultSetting(e){LNbits.api.getDefaultSetting(e).then(t=>{this.formData[e]=t.data.default_value})},restartServer(){LNbits.api.request("GET","/admin/api/v1/restart/").then(e=>{this.$q.notify({type:"positive",message:"Success! Restarted Server",icon:null}),this.needsRestart=!1}).catch(LNbits.utils.notifyApiError)},async getSettings(){await LNbits.api.request("GET","/admin/api/v1/settings",this.g.user.wallets[0].adminkey).then(e=>{this.isSuperUser=e.data.is_super_user||!1,this.settings=e.data,this.formData={...this.settings}}).catch(LNbits.utils.notifyApiError)},updateSettings(){const e=_.omit(this.formData,["is_super_user","lnbits_allowed_funding_sources","touch"]);LNbits.api.request("PUT","/admin/api/v1/settings",this.g.user.wallets[0].adminkey,e).then(e=>{this.needsRestart=this.settings.lnbits_backend_wallet_class!==this.formData.lnbits_backend_wallet_class,this.settings=this.formData,this.formData=_.clone(this.settings),Quasar.Notify.create({type:"positive",message:"Success! Settings changed! "+(this.needsRestart?"Restart required!":""),icon:null})}).catch(LNbits.utils.notifyApiError)},deleteSettings(){LNbits.utils.confirmDialog("Are you sure you want to restore settings to default?").onOk(()=>{LNbits.api.request("DELETE","/admin/api/v1/settings").then(e=>{Quasar.Notify.create({type:"positive",message:"Success! Restored settings to defaults. Restarting...",icon:null}),this.$q.localStorage.clear()}).catch(LNbits.utils.notifyApiError)})},downloadBackup(){window.open("/admin/api/v1/backup","_blank")}}},window.app.component("lnbits-admin-funding-seed-backup",{props:["active","is-super-user","form-data","settings"],template:"#lnbits-admin-funding-seed-backup",data:()=>({dialog:{show:!1,step:1,seed:"",visible:!1,challenge:[],answers:{},error:"",confirmField:""}}),watch:{active(e){e&&this.openIfRequired()},"formData.lnbits_backend_wallet_class"(e,t){const s=this.seedBackupSource(e);t&&s&&this.formData[s.seedField]&&(this.formData[s.confirmField]=!1),this.openIfRequired()},"formData.boltz_mnemonic"(){this.formData.boltz_mnemonic_backup_confirmed=this.formData.boltz_mnemonic===this.settings.boltz_mnemonic&&this.settings.boltz_mnemonic_backup_confirmed,this.openIfRequired()},"formData.phoenixd_mnemonic"(){this.formData.phoenixd_mnemonic_backup_confirmed=this.formData.phoenixd_mnemonic===this.settings.phoenixd_mnemonic&&this.settings.phoenixd_mnemonic_backup_confirmed,this.openIfRequired()},"formData.spark_l2_mnemonic"(){this.formData.spark_l2_mnemonic_backup_confirmed=this.formData.spark_l2_mnemonic===this.settings.spark_l2_mnemonic&&this.settings.spark_l2_mnemonic_backup_confirmed,this.openIfRequired()}},computed:{seedWords(){return this.dialog.seed.split(/\s+/).filter(Boolean).map((e,t)=>({index:t,word:e}))}},created(){this.openIfRequired()},methods:{seedBackupSource(e=this.formData.lnbits_backend_wallet_class){return"BoltzWallet"===e?{seedField:"boltz_mnemonic",confirmField:"boltz_mnemonic_backup_confirmed"}:"PhoenixdWallet"===e?{seedField:"phoenixd_mnemonic",confirmField:"phoenixd_mnemonic_backup_confirmed"}:"SparkL2Wallet"===e?{seedField:"spark_l2_mnemonic",confirmField:"spark_l2_mnemonic_backup_confirmed"}:void 0},openIfRequired(){if(!this.active||!this.isSuperUser)return;const e=this.seedBackupSource();if(!e)return;const t=(this.formData[e.seedField]||"").trim(),s=this.formData[e.confirmField];!t||s||this.dialog.show||(this.dialog={show:!0,step:1,seed:t,visible:!1,challenge:[],answers:{},error:"",confirmField:e.confirmField})},prepareChallenge(){const e=this.dialog.seed.split(/\s+/).filter(Boolean),t=Math.min(4,e.length),s=_.shuffle([...Array(e.length).keys()]).slice(0,t);this.dialog.challenge=s.sort((e,t)=>e-t).map(t=>({index:t,word:e[t]})),this.dialog.answers={},this.dialog.error="",this.dialog.step=2},submitChallenge(){if(!this.dialog.challenge.every(({index:e,word:t})=>(this.dialog.answers[e]||"").trim().toLowerCase()===t.toLowerCase()))return void(this.dialog.error="One or more words are incorrect. Check your backup and try again.");const e=this.dialog.confirmField;LNbits.api.request("PATCH","/admin/api/v1/settings",this.g.user.wallets[0].adminkey,{[e]:!0}).then(()=>{this.formData[e]=!0,this.settings[e]=!0,this.dialog.show=!1,Quasar.Notify.create({type:"positive",message:"Seed backup confirmed",icon:"check"})}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("lnbits-admin-funding",{props:["active","is-super-user","form-data","settings"],template:"#lnbits-admin-funding",data:()=>({auditData:[]}),created(){this.getAudit()},methods:{getAudit(){LNbits.api.request("GET","/admin/api/v1/audit",this.g.user.wallets[0].adminkey).then(e=>{this.auditData=e.data}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("lnbits-admin-funding-sources",{template:"#lnbits-admin-funding-sources",props:["form-data","allowed-funding-sources"],methods:{getFundingSourceLabel(e){const t=this.rawFundingSources.find(t=>t[0]===e);return t?t[1]:e},showQRValue(e){this.qrValue=e,this.showQRDialog=!0}},computed:{fundingSources(){let e=[];for(const[t,s,a]of this.rawFundingSources){const s={};if(null!==a)for(let[e,t]of Object.entries(a))s[e]="string"==typeof t?{label:t,value:null}:t||{};e.push([t,s])}return new Map(e)},sortedAllowedFundingSources(){return this.allowedFundingSources.sort()}},data:()=>({hideInput:!0,showQRDialog:!1,qrValue:"",rawFundingSources:[["VoidWallet","Void Wallet",null],["FakeWallet","Fake Wallet",{fake_wallet_secret:"Secret",lnbits_denomination:'"sats" or 3 Letter Custom Denomination'}],["CLNRestWallet","Core Lightning Rest (plugin)",{clnrest_url:"Endpoint",clnrest_ca:"ca.pem",clnrest_cert:"server.pem",clnrest_readonly_rune:"Rune used for readonly requests",clnrest_invoice_rune:"Rune used for creating invoices",clnrest_pay_rune:"Rune used for paying invoices using pay",clnrest_renepay_rune:"Rune used for paying invoices using renepay",clnrest_last_pay_index:"Ignores any invoices paid prior to or including this index. 0 is equivalent to not specifying and negative value is invalid.",clnrest_nodeid:"Node id"}],["CoreLightningWallet","Core Lightning",{corelightning_rpc:"Endpoint",corelightning_pay_command:"Custom Pay Command"}],["CoreLightningRestWallet","Core Lightning Rest (legacy)",{corelightning_rest_url:"Endpoint",corelightning_rest_cert:"Certificate",corelightning_rest_macaroon:"Macaroon"}],["LndRestWallet","Lightning Network Daemon (LND Rest)",{lnd_rest_endpoint:"Endpoint",lnd_rest_cert:"Certificate",lnd_rest_macaroon:"Macaroon",lnd_rest_macaroon_encrypted:"Encrypted Macaroon",lnd_rest_route_hints:{advanced:!0,label:"Enable Route Hints"},lnd_rest_allow_self_payment:{advanced:!0,label:"Allow Self Payment"}}],["LndWallet","Lightning Network Daemon (LND)",{lnd_grpc_endpoint:"Endpoint",lnd_grpc_cert:"Certificate",lnd_grpc_port:"Port",lnd_grpc_macaroon:"GRPC Macaroon",lnd_grpc_invoice_macaroon:"GRPC Invoice Macaroon",lnd_grpc_admin_macaroon:"GRPC Admin Macaroon",lnd_grpc_macaroon_encrypted:"Encrypted Macaroon",lnd_grpc_allow_self_payment:{advanced:!0,label:"Allow Self Payment"}}],["LnTipsWallet","LN.Tips",{lntips_api_endpoint:"Endpoint",lntips_api_key:"API Key"}],["LNPayWallet","LN Pay",{lnpay_api_endpoint:"Endpoint",lnpay_api_key:"API Key",lnpay_wallet_key:"Wallet Key"}],["EclairWallet","Eclair (ACINQ)",{eclair_url:"URL",eclair_pass:"Password"}],["LNbitsWallet","LNbits",{lnbits_endpoint:"Endpoint",lnbits_key:"Admin Key"}],["BlinkWallet","Blink",{blink_api_endpoint:"Endpoint",blink_ws_endpoint:"WebSocket",blink_token:"Key",blink_send_without_probe:{advanced:!0,label:"Send payment if fee probe fails",hint:"If enabled (default), payments to destinations that cannot be probed (e.g. fedimints) are still sent. If disabled, such payments fail."}}],["AlbyWallet","Alby",{alby_api_endpoint:"Endpoint",alby_access_token:"Key"}],["BarkWallet","Bark",{bark_api_endpoint:{label:"Endpoint",value:"http://localhost:3000"},bark_api_token:"auth_token"}],["BoltzWallet","Boltz",{boltz_client_endpoint:{label:"Boltz client endpoint",value:"127.0.0.1:9002"},boltz_client_macaroon:{label:"Admin Macaroon path or hex",value:"/home/ubuntu/.boltz/macaroons/admin.macaroon"},boltz_client_cert:{label:"Certificate path or hex",value:"/home/ubuntu/.boltz/tls.cert"},boltz_mnemonic:{label:"Liquid seed phrase",hint:"Boltz will fetch once connected, but you can change later (can be opened in a liquid wallet) ",copy:!0,qrcode:!0},boltz_client_password:{label:"Wallet Password (optional)",advanced:!0}}],["ZBDWallet","ZBD",{zbd_api_endpoint:"Endpoint",zbd_api_key:"Key"}],["PhoenixdWallet","Phoenixd",{phoenixd_api_endpoint:"Endpoint",phoenixd_api_password:"Key",phoenixd_data_dir:{label:"Data Directory",hint:"Directory where phoenixd stores its data, including the seed phrase."},phoenixd_mnemonic:{label:"Phoenixd Seed Phrase",hint:"Only available if phoenixd data-dir is specified",readonly:!0,copy:!0,qrcode:!0}}],["OpenNodeWallet","OpenNode",{opennode_api_endpoint:"Endpoint",opennode_key:"Key"}],["ClicheWallet","Cliche (NBD)",{cliche_endpoint:"Endpoint"}],["SparkWallet","Spark",{spark_url:"Endpoint",spark_token:"Token"}],["SparkL2Wallet","Spark (L2)",{spark_l2_external_endpoint:{label:"External Sidecar Endpoint",hint:"Make sure to also specify the API key if your sidecar requires authentication.",value:""},spark_l2_mnemonic:{label:"External Sidecar Mnemonic",hint:"Mnemonic for the Spark wallet on the external sidecar. Required if the side car does not have its own mnemonic.",value:""},spark_l2_external_api_key:{label:"External Sidecar API Key",hint:"API key for authenticating with the external sidecar if it requires authentication.",value:""},spark_l2_network:{label:"Network",value:"MAINNET",hint:"The network to use for the Spark wallet.",advanced:!0},spark_l2_pay_wait_ms:{label:"Payment Wait Time (ms)",hint:"The time to wait for a payment to be processed before considering it failed.",advanced:!0},spark_l2_pay_poll_ms:{label:"Payment Poll Time (ms)",hint:"The time to wait between polling for payment status updates.",advanced:!0},spark_l2_stream_keepalive_ms:{label:"Stream Keepalive Time (ms)",hint:"The time to wait between sending keepalive messages to the Spark sidecar to keep the connection open.",advanced:!0}}],["NWCWallet","Nostr Wallet Connect",{nwc_pairing_url:"Pairing URL"}],["BreezSdkWallet","Breez SDK",{breez_api_key:"Breez API Key",breez_greenlight_seed:"Greenlight Seed",breez_greenlight_device_key:"Greenlight Device Key",breez_greenlight_device_cert:"Greenlight Device Cert",breez_greenlight_invite_code:"Greenlight Invite Code"}],["StrikeWallet","Strike (alpha)",{strike_api_endpoint:"API Endpoint",strike_api_key:"API Key"}],["BreezLiquidSdkWallet","Breez Liquid SDK",{breez_liquid_api_key:"Breez API Key (can be empty)",breez_liquid_seed:"Liquid seed phrase",breez_liquid_fee_offset_sat:"Offset amount in sats to increase fee limit"}]]})}),window.app.component("lnbits-admin-fiat-providers",{props:["form-data"],template:"#lnbits-admin-fiat-providers",data:()=>({formAddStripeUser:"",formAddPaypalUser:"",formAddSquareUser:"",formAddRevolutUser:"",creatingRevolutWebhook:!1,hideInputToggle:!0}),computed:{stripeWebhookUrl(){return this.formData?.stripe_payment_webhook_url||this.calculateWebhookUrl("stripe")},paypalWebhookUrl(){return this.formData?.paypal_payment_webhook_url||this.calculateWebhookUrl("paypal")},revolutWebhookUrl(){return this.formData?.revolut_payment_webhook_url||this.calculateWebhookUrl("revolut")}},watch:{formData:{handler(){this.syncWebhookUrls()},immediate:!0}},methods:{basePathFromLocation(){if("undefined"==typeof window)return"";const e=window.location.pathname.replace(/\/+$/,""),t=e.lastIndexOf("/admin");return(t>=0?e.slice(0,t):e||"")||""},calculateWebhookUrl(e){if("undefined"==typeof window)return"";const t=`${this.basePathFromLocation()}/api/v1/callback/${e}`.replace(/\/+/g,"/"),s=t.startsWith("/")?t:`/${t}`;return`${window.location.origin}${s}`},syncWebhookUrls(){this.maybeSetWebhookUrl("stripe_payment_webhook_url","stripe"),this.maybeSetWebhookUrl("paypal_payment_webhook_url","paypal"),this.maybeSetWebhookUrl("square_payment_webhook_url","square"),this.maybeSetWebhookUrl("revolut_payment_webhook_url","revolut")},maybeSetWebhookUrl(e,t){if(!this.formData)return;const s=this.calculateWebhookUrl(t),a=this.formData[e];(!a||a.includes("your-lnbits-domain-here.com"))&&s&&(this.formData[e]=s)},copyWebhookUrl(e){e&&this.copyText(e)},isClearnetWebhookUrl(e){let t;try{t=new URL(e)}catch(e){return!1}const s=t.hostname.toLowerCase();return!!["http:","https:"].includes(t.protocol)&&(!("localhost"===s||s.endsWith(".localhost")||s.endsWith(".local")||s.endsWith(".onion"))&&!(/^127\./.test(s)||/^10\./.test(s)||/^192\.168\./.test(s)||/^169\.254\./.test(s)||/^172\.(1[6-9]|2\d|3[0-1])\./.test(s)||"0.0.0.0"===s||"::1"===s))},notifyRevolutWebhookWarning(e){Quasar.Notify.create({type:"warning",message:e,icon:null,closeBtn:!0})},addStripeAllowedUser(){const e=this.formAddStripeUser||"";e.length&&!this.formData.stripe_limits.allowed_users.includes(e)&&(this.formData.stripe_limits.allowed_users=[...this.formData.stripe_limits.allowed_users,e],this.formAddStripeUser="")},removeStripeAllowedUser(e){this.formData.stripe_limits.allowed_users=this.formData.stripe_limits.allowed_users.filter(t=>t!==e)},addPaypalAllowedUser(){const e=this.formAddPaypalUser||"";e.length&&!this.formData.paypal_limits.allowed_users.includes(e)&&(this.formData.paypal_limits.allowed_users=[...this.formData.paypal_limits.allowed_users,e],this.formAddPaypalUser="")},removePaypalAllowedUser(e){this.formData.paypal_limits.allowed_users=this.formData.paypal_limits.allowed_users.filter(t=>t!==e)},addSquareAllowedUser(){const e=this.formAddSquareUser||"";e.length&&!this.formData.square_limits.allowed_users.includes(e)&&(this.formData.square_limits.allowed_users=[...this.formData.square_limits.allowed_users,e],this.formAddSquareUser="")},removeSquareAllowedUser(e){this.formData.square_limits.allowed_users=this.formData.square_limits.allowed_users.filter(t=>t!==e)},addRevolutAllowedUser(){const e=this.formAddRevolutUser||"";e.length&&!this.formData.revolut_limits.allowed_users.includes(e)&&(this.formData.revolut_limits.allowed_users=[...this.formData.revolut_limits.allowed_users,e],this.formAddRevolutUser="")},removeRevolutAllowedUser(e){this.formData.revolut_limits.allowed_users=this.formData.revolut_limits.allowed_users.filter(t=>t!==e)},checkFiatProvider(e){LNbits.api.request("PUT",`/api/v1/fiat/check/${e}`).then(e=>{const t=e.data;Quasar.Notify.create({type:t.success?"positive":"warning",message:t.message,icon:null})}).catch(LNbits.utils.notifyApiError)},createRevolutWebhook(){const e=this.calculateWebhookUrl("revolut");this.formData.revolut_payment_webhook_url=e,this.formData.revolut_api_secret_key?this.isClearnetWebhookUrl(e)?(this.creatingRevolutWebhook=!0,LNbits.api.request("POST","/api/v1/fiat/revolut/webhook",null,{url:e,endpoint:this.formData.revolut_api_endpoint,api_secret_key:this.formData.revolut_api_secret_key,api_version:this.formData.revolut_api_version}).then(e=>{const t=e.data;this.formData.revolut_payment_webhook_url=t.url,this.formData.revolut_webhook_signing_secret=t.signing_secret,Quasar.Notify.create({type:"positive",message:`Revolut webhook ${t.already_exists?"already exists":"created"}${t.id?`: ${t.id}`:""}.`,icon:null})}).catch(LNbits.utils.notifyApiError).finally(()=>{this.creatingRevolutWebhook=!1})):this.notifyRevolutWebhookWarning("Revolut webhook URL must be a clearnet URL."):this.notifyRevolutWebhookWarning("Add your Revolut API secret key before creating a webhook.")}}}),window.app.component("lnbits-admin-exchange-providers",{props:["form-data"],template:"#lnbits-admin-exchange-providers",data:()=>({exchangeData:{selectedProvider:null,showTickerConversion:!1,convertFromTicker:null,convertToTicker:null},exchangesTable:{columns:[{name:"name",align:"left",label:"Exchange Name",field:"name",sortable:!0},{name:"api_url",align:"left",label:"URL",field:"api_url",sortable:!1},{name:"path",align:"left",label:"JSON Path",field:"path",sortable:!1},{name:"exclude_to",align:"left",label:"Exclude Currencies",field:"exclude_to",sortable:!1},{name:"ticker_conversion",align:"left",label:"Ticker Conversion",field:"ticker_conversion",sortable:!1}],pagination:{sortBy:"name",rowsPerPage:100,page:1,rowsNumber:100},search:null,hideEmpty:!0}}),mounted(){this.getExchangeRateHistory()},methods:{getDefaultSetting(e){LNbits.api.getDefaultSetting(e).then(t=>{this.formData[e]=t.data.default_value})},getExchangeRateHistory(){LNbits.api.request("GET","/api/v1/rate/history",this.g.user.wallets[0].inkey).then(e=>{this.initExchangeChart(e.data)}).catch(function(e){LNbits.utils.notifyApiError(e)})},showExchangeProvidersTab(e){"exchange_providers"===e&&this.getExchangeRateHistory()},addExchangeProvider(){this.formData.lnbits_exchange_rate_providers=[{name:"",api_url:"",path:"",exclude_to:[]},...this.formData.lnbits_exchange_rate_providers]},removeExchangeProvider(e){this.formData.lnbits_exchange_rate_providers=this.formData.lnbits_exchange_rate_providers.filter(t=>t!==e)},removeExchangeTickerConversion(e,t){e.ticker_conversion=e.ticker_conversion.filter(e=>e!==t),this.formData.touch=null},addExchangeTickerConversion(){this.exchangeData.selectedProvider&&(this.exchangeData.selectedProvider.ticker_conversion.push(`${this.exchangeData.convertFromTicker}:${this.exchangeData.convertToTicker}`),this.formData.touch=null,this.exchangeData.showTickerConversion=!1)},showTickerConversionDialog(e){this.exchangeData.convertFromTicker=null,this.exchangeData.convertToTicker=null,this.exchangeData.selectedProvider=e,this.exchangeData.showTickerConversion=!0},initExchangeChart(e){this.exchangeRatesChart&&(this.exchangeRatesChart.destroy(),this.exchangeRatesChart=null);const t=e.map(e=>this.utils.formatTimestamp(e.timestamp,"HH:mm")),s=(this.formData.lnbits_price_aggregator_enabled?[{name:"Aggregator"}]:[...this.formData.lnbits_exchange_rate_providers,{name:"LNbits"}]).map(t=>({label:t.name,data:e.map(e=>e.rates[t.name]),pointStyle:!0,borderWidth:"LNbits"===t.name?4:2,tension:.4}));this.exchangeRatesChart=new Chart(this.$refs.exchangeRatesChart.getContext("2d"),{type:"line",options:{plugins:{legend:{display:!0},title:{display:!0,text:"Bitcoin Price History"}}},data:{labels:t,datasets:s}})}}}),window.app.component("lnbits-admin-security",{props:["form-data"],template:"#lnbits-admin-security",data:()=>({logs:[],formBlockedIPs:"",serverlogEnabled:!1,nostrAcceptedUrl:"",formAllowedIPs:"",formCallbackUrlRule:""}),created(){},methods:{addAllowedIPs(){const e=this.formAllowedIPs.trim(),t=this.formData.lnbits_allowed_ips;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_allowed_ips=[...t,e],this.formAllowedIPs="")},removeAllowedIPs(e){const t=this.formData.lnbits_allowed_ips;this.formData.lnbits_allowed_ips=t.filter(t=>t!==e)},addBlockedIPs(){const e=this.formBlockedIPs.trim(),t=this.formData.lnbits_blocked_ips;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_blocked_ips=[...t,e],this.formBlockedIPs="")},removeBlockedIPs(e){const t=this.formData.lnbits_blocked_ips;this.formData.lnbits_blocked_ips=t.filter(t=>t!==e)},addCallbackUrlRule(){const e=this.formCallbackUrlRule.trim(),t=this.formData.lnbits_callback_url_rules;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_callback_url_rules=[...t,e],this.formCallbackUrlRule="")},removeCallbackUrlRule(e){const t=this.formData.lnbits_callback_url_rules;this.formData.lnbits_callback_url_rules=t.filter(t=>t!==e)},addNostrUrl(){const e=this.nostrAcceptedUrl.trim();this.removeNostrUrl(e),this.formData.nostr_absolute_request_urls.push(e),this.nostrAcceptedUrl=""},removeNostrUrl(e){this.formData.nostr_absolute_request_urls=this.formData.nostr_absolute_request_urls.filter(t=>t!==e)},async toggleServerLog(){if(this.serverlogEnabled=!this.serverlogEnabled,this.serverlogEnabled){const e="http:"!==location.protocol?"wss://":"ws://",t=await LNbits.utils.digestMessage(this.g.user.id),s=e+document.domain+":"+location.port+"/api/v1/ws/"+t;this.ws=new WebSocket(s),this.ws.addEventListener("message",async({data:e})=>{this.logs.push(e.toString());const t=this.$refs.logScroll;if(t){const e=t.getScrollTarget(),s=0;t.setScrollPosition(e.scrollHeight,s)}})}else this.ws.close()}}}),window.app.component("lnbits-admin-users",{props:["form-data"],template:"#lnbits-admin-users",data:()=>({formAddUser:"",formAddAdmin:"",formAddActivationCode:"",showReusableActivationCode:!1}),methods:{addAllowedUser(){let e=this.formAddUser,t=this.formData.lnbits_allowed_users;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_allowed_users=[...t,e],this.formAddUser="")},removeAllowedUser(e){let t=this.formData.lnbits_allowed_users;this.formData.lnbits_allowed_users=t.filter(t=>t!==e)},addAdminUser(){let e=this.formAddAdmin,t=this.formData.lnbits_admin_users;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_admin_users=[...t,e],this.formAddAdmin="")},removeAdminUser(e){let t=this.formData.lnbits_admin_users;this.formData.lnbits_admin_users=t.filter(t=>t!==e)},addOneTimeActivationCode(){const e=this.formAddActivationCode,t=this.formData.lnbits_register_one_time_activation_codes;e?.length&&!t.includes(e)&&(this.formData.lnbits_register_one_time_activation_codes=[...t,e],this.formAddActivationCode="")},removeOneTimeActivationCode(e){const t=this.formData.lnbits_register_one_time_activation_codes;this.formData.lnbits_register_one_time_activation_codes=t.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-server",{props:["form-data"],template:"#lnbits-admin-server",computed:{lightningAddressBlacklistText:{get(){const e=this.formData.lnbits_wallet_lightning_address_blacklist;return Array.isArray(e)?e.join("\n"):e||""},set(e){this.formData.lnbits_wallet_lightning_address_blacklist=e.split(/[\n,]/).map(e=>e.trim().toLowerCase()).filter(e=>e.length)}}}}),window.app.component("lnbits-admin-extensions",{props:["form-data"],template:"#lnbits-admin-extensions",data:()=>({formAddExtensionsManifest:"",formAddWasmManifest:""}),methods:{addExtensionsManifest(){this.addManifest("lnbits_extensions_manifests","formAddExtensionsManifest")},addWasmManifest(){this.addManifest("lnbits_wasm_extensions_manifests","formAddWasmManifest")},addManifest(e,t){const s=this[t].trim(),a=this.formData[e]||[];s&&s.length&&!a.includes(s)&&(this.formData[e]=[...a,s],this[t]="")},removeExtensionsManifest(e){this.removeManifest("lnbits_extensions_manifests",e)},removeWasmManifest(e){this.removeManifest("lnbits_wasm_extensions_manifests",e)},removeManifest(e,t){const s=this.formData[e]||[];this.formData[e]=s.filter(e=>e!==t)}}}),window.app.component("lnbits-admin-wasm-runtime",{props:["form-data"],template:"#lnbits-admin-wasm-runtime",data(){return{wasmRuntimeLoading:!1,wasmHistoryLoading:!1,wasmRuntimeTimer:null,wasmStats:{},wasmCurrentInvocations:[],wasmInvocationHistory:[],wasmStatItems:[{key:"total",label:"Total",icon:"data_usage",color:"primary"},{key:"running",label:"Running",icon:"play_circle",color:"green"},{key:"completed",label:"Completed",icon:"task_alt",color:"teal"},{key:"failed",label:"Failed",icon:"error",color:"red"},{key:"stopped",label:"Stopped",icon:"stop_circle",color:"orange"},{key:"timeout",label:"Timeouts",icon:"timer_off",color:"purple"}],wasmCurrentColumns:[{name:"extension_id",label:"Extension",field:"extension_id",align:"left",sortable:!0},{name:"export_name",label:"Export",field:"export_name",align:"left",sortable:!0},{name:"trigger_type",label:"Trigger",field:"trigger_type",align:"left",sortable:!0},{name:"status",label:"Status",field:"status",align:"left",sortable:!0},{name:"user_id",label:"User",field:"user_id",align:"left",sortable:!0},{name:"started_at",label:"Started",field:"started_at",align:"left",sortable:!0},{name:"duration_ms",label:"Duration",field:e=>e.duration_ms||0,align:"right",sortable:!0},{name:"context",label:"Context",field:e=>this.wasmContextValue(e),align:"left",sortable:!0},{name:"actions",label:"",field:"actions",align:"right"}],wasmHistoryColumns:[{name:"extension_id",label:"Extension",field:"extension_id",align:"left",sortable:!0},{name:"export_name",label:"Export",field:"export_name",align:"left",sortable:!0},{name:"trigger_type",label:"Trigger",field:"trigger_type",align:"left",sortable:!0},{name:"status",label:"Status",field:"status",align:"left",sortable:!0},{name:"user_id",label:"User",field:"user_id",align:"left",sortable:!0},{name:"started_at",label:"Started",field:"started_at",align:"left",sortable:!0},{name:"duration_ms",label:"Duration",field:e=>e.duration_ms||0,align:"right",sortable:!0},{name:"calls",label:"Calls",field:e=>this.wasmCallCount(e),align:"left",sortable:!0},{name:"context",label:"Context",field:e=>this.wasmContextValue(e),align:"left",sortable:!0},{name:"error_message",label:"Error/Stop Reason",field:e=>e.error_message||e.stop_reason||"",align:"left",sortable:!0}]}},computed:{adminKey(){return this.g.user.wallets[0].adminkey},wasmExtensionId(){return this.$route.params.extId||null},wasmExtensionQuery(){return this.wasmExtensionId?`extension_id=${encodeURIComponent(this.wasmExtensionId)}`:""}},watch:{wasmExtensionId(){this.fetchWasmRuntime()}},methods:{async fetchWasmRuntime(){await Promise.all([this.fetchWasmCurrentInvocations(),this.fetchWasmInvocationHistory(),this.fetchWasmInvocationStats()])},async fetchWasmCurrentInvocations(){this.wasmRuntimeLoading=!0;try{const e=this.wasmExtensionQuery?`?${this.wasmExtensionQuery}`:"",{data:t}=await LNbits.api.request("GET",`/api/v1/extension/wasm/invocations/current${e}`,this.adminKey);this.wasmCurrentInvocations=t||[]}catch(e){LNbits.utils.notifyApiError(e)}finally{this.wasmRuntimeLoading=!1}},async fetchWasmInvocationHistory(){this.wasmHistoryLoading=!0;try{const e=["limit=50"];this.wasmExtensionQuery&&e.push(this.wasmExtensionQuery);const{data:t}=await LNbits.api.request("GET",`/api/v1/extension/wasm/invocations?${e.join("&")}`,this.adminKey);this.wasmInvocationHistory=t||[]}catch(e){LNbits.utils.notifyApiError(e)}finally{this.wasmHistoryLoading=!1}},async fetchWasmInvocationStats(){try{const e=["hours=24"];this.wasmExtensionQuery&&e.push(this.wasmExtensionQuery);const{data:t}=await LNbits.api.request("GET",`/api/v1/extension/wasm/invocations/stats?${e.join("&")}`,this.adminKey);this.wasmStats=t||{}}catch(e){LNbits.utils.notifyApiError(e)}},async stopWasmInvocation(e){try{await LNbits.api.request("POST",`/api/v1/extension/wasm/invocations/${encodeURIComponent(e)}/stop`,this.adminKey),Quasar.Notify.create({type:"positive",message:"WASM invocation stop requested."}),await this.fetchWasmRuntime()}catch(e){LNbits.utils.notifyApiError(e)}},deactivateWasmExtension(e){LNbits.utils.confirmDialog(`Deactivate extension '${e}'?`,"Deactivate Extension").onOk(async()=>{try{await LNbits.api.request("PUT",`/api/v1/extension/${encodeURIComponent(e)}/deactivate`,this.adminKey),Quasar.Notify.create({type:"positive",message:`Extension '${e}' deactivated.`}),await this.fetchWasmRuntime()}catch(e){LNbits.utils.notifyApiError(e)}})},formatWasmStat(e){const t=this.wasmStats[e];return null==t?"0":String(t)},formatWasmDate(e){return e?this.utils.formatDate(e):""},wasmStatusColor:e=>({running:"green",stopping:"orange",completed:"teal",failed:"red",stopped:"orange",timeout:"purple",abandoned:"grey"}[e]||"grey"),wasmTriggerColor:e=>({http:"primary",event:"purple"}[e]||"grey"),formatWasmDuration(e){let t=e.duration_ms;return"running"!==e.status&&"stopping"!==e.status||!e.started_at||(t=Date.now()-new Date(e.started_at).getTime()),null==t?"":t>=1e3?`${(t/1e3).toFixed(1)}s`:`${t}ms`},formatWasmCalls:e=>[`host ${e.host_call_count||0}`,`http ${e.http_call_count||0}`,`storage ${e.storage_call_count||0}`,`wallet ${e.wallet_call_count||0}`].join(" / "),wasmCallCount:e=>(e.host_call_count||0)+(e.http_call_count||0)+(e.storage_call_count||0)+(e.wallet_call_count||0),wasmContextValue:e=>[e.method,e.path,e.event_type,e.wallet_id,e.payment_hash].filter(Boolean).join(" "),formatWasmContext:e=>[e.method,e.path,e.event_type,e.wallet_id?`wallet ${e.wallet_id}`:"",e.payment_hash?`payment ${e.payment_hash.slice(0,12)}...`:""].filter(Boolean).join(" | "),formatWasmUserId(e){if(!e)return"-";const t=String(e);return t.length<=12?t:`${t.slice(0,3)}...${t.slice(-3)}`}},created(){this.fetchWasmRuntime(),this.wasmRuntimeTimer=setInterval(()=>{this.fetchWasmCurrentInvocations()},5e3)},unmounted(){this.wasmRuntimeTimer&&clearInterval(this.wasmRuntimeTimer)}}),window.app.component("lnbits-admin-wasm-limit-config",{props:["form-data"],template:"#lnbits-admin-wasm-limit-config",data:()=>({selectedWasmExtensionId:null,wasmExtensionLimitDraft:{},wasmExtensionLimitsSaving:!1,wasmRuntimeLimitExtensions:[],wasmRuntimeLimitExtensionsLoading:!1,wasmLimitInfoDialog:{show:!1,title:"",details:""},wasmRuntimeLimitGroups:[{title:"Execution",fields:[{name:"wasm_runtime_max_execution_ms",label:"Max execution time (ms)",description:"Maximum wall-clock time allowed for one WASM invocation.",details:"This is the elapsed time from starting the invocation until the export returns. When the limit is reached LNbits requests an interrupt and records the invocation as timed out if it cannot finish quickly. Use this to stop long sleeps, slow host calls, and CPU loops that run for too long."},{name:"wasm_runtime_max_fuel",label:"Max fuel",description:"Maximum Wasmtime instruction budget for one invocation.",details:"Fuel is Wasmtime instruction budgeting. It is more deterministic than wall-clock time for CPU-heavy loops because each executed instruction consumes budget. Set this low enough to stop busy loops, but high enough for legitimate extension startup and JSON processing."},{name:"wasm_runtime_max_wasm_stack_bytes",label:"Max WASM stack (bytes)",description:"Maximum stack space for WASM calls and recursion.",details:"This limits stack used by WebAssembly function calls. It protects the server from deep recursion or very large call chains in extension code. If legitimate extensions fail with stack overflow traps, raise this carefully."}]},{title:"Memory and Data Size",fields:[{name:"wasm_runtime_max_memory_bytes",label:"Max memory (bytes)",description:"Maximum WASM linear memory per invocation.",details:"This caps the linear memory visible to the WASM module. It limits memory.grow and can make instantiation fail if the module asks for too much memory up front. This does not include every byte used by the Python process or Wasmtime engine internals."},{name:"wasm_runtime_max_request_bytes",label:"Max request size (bytes)",description:"Maximum serialized input payload accepted before execution.",details:"This caps the serialized payload passed into a WASM export before execution starts. It protects against huge HTTP bodies, oversized event data, and expensive JSON parsing. Requests above this limit should be rejected before invoking the extension."},{name:"wasm_runtime_max_response_bytes",label:"Max response size (bytes)",description:"Maximum serialized response returned by a WASM export.",details:"This caps the JSON or string response returned by the WASM export. It prevents extensions from returning huge responses that consume memory, slow down API calls, or overload the browser. Responses above this limit are treated as invalid."}]},{title:"Wasmtime Objects",fields:[{name:"wasm_runtime_max_table_elements",label:"Max table elements",description:"Maximum total elements allowed in WASM tables.",details:"Tables store references used by WebAssembly, commonly function references. Limiting table elements prevents a module from allocating very large reference tables. Each table element also has host memory overhead."},{name:"wasm_runtime_max_instances",label:"Max instances",description:"Maximum WebAssembly instances allowed inside one store.",details:"This limits how many WebAssembly instances can be created inside one Wasmtime store. LNbits normally needs one instance per invocation, so a low value is expected. Raising it should only be needed if the runtime starts supporting modules that instantiate other modules."},{name:"wasm_runtime_max_tables",label:"Max tables",description:"Maximum WebAssembly tables allowed inside one store.",details:"This limits the number of WebAssembly tables in the store. It is separate from table elements: one setting limits the number of tables, the other limits their total size. Keep this small unless a component model module legitimately needs more tables."},{name:"wasm_runtime_max_memories",label:"Max memories",description:"Maximum WebAssembly linear memories allowed inside one store.",details:"This limits how many separate linear memories a module can create. Most extensions should need only one memory. Keep this small to reduce memory accounting complexity and prevent multi-memory abuse."}]},{title:"Concurrency",fields:[{name:"wasm_runtime_max_concurrent_invocations",label:"Max concurrent invocations",description:"Maximum running WASM invocations across the server.",details:"This is the global cap for running WASM invocations across all extensions and users. It protects the LNbits process from thread exhaustion, CPU pressure, and too many simultaneous stores. New invocations should be rejected or queued once this is reached."},{name:"wasm_runtime_max_concurrent_invocations_per_extension",label:"Max concurrent per extension",description:"Maximum running WASM invocations for one extension.",details:"This caps how many invocations a single extension can run at once. It prevents one malicious or buggy extension from consuming the whole global concurrency budget. Set it lower than the global limit."},{name:"wasm_runtime_max_concurrent_invocations_per_user",label:"Max concurrent per user",description:"Maximum running WASM invocations for one user.",details:"This caps concurrent invocations attributed to one user. It helps protect against a user repeatedly clicking, refreshing, or scripting extension calls. Invocations without a user can still be governed by the global and per-extension limits."}]},{title:"Host Calls",fields:[{name:"wasm_runtime_max_host_calls",label:"Max host calls",description:"Maximum total calls from WASM into LNbits host APIs.",details:"This is the total budget for calls from the WASM module into LNbits host APIs during one invocation. It should count all categories together. It limits chatty extensions and prevents tight loops that repeatedly call back into Python."},{name:"wasm_runtime_max_http_calls",label:"Max HTTP calls",description:"Maximum outbound HTTP host calls per invocation.",details:"This caps outbound HTTP requests made through the host API during one invocation. It reduces SSRF blast radius, protects network resources, and limits slow external dependencies. It should be enforced together with HTTP timeout and response-size limits."},{name:"wasm_runtime_max_storage_calls",label:"Max storage calls",description:"Maximum storage host calls per invocation.",details:"This caps extension storage operations during one invocation. It protects the database from excessive reads and writes triggered by malicious loops. Use it with storage payload-size limits if those are added later."},{name:"wasm_runtime_max_wallet_calls",label:"Max wallet calls",description:"Maximum wallet/payment host calls per invocation.",details:"This caps wallet and payment-related host calls during one invocation. These calls are security-sensitive and may touch balances, invoices, or payments. Keep this conservative and rely on explicit permissions for what the extension is allowed to do."}]},{title:"HTTP",fields:[{name:"wasm_runtime_http_timeout_ms",label:"HTTP timeout (ms)",description:"Maximum time allowed for one WASM HTTP request.",details:"This is the per-request timeout for HTTP calls made through the WASM host API. It prevents a slow remote server from holding an invocation open indefinitely. The total invocation timeout still applies across all work."},{name:"wasm_runtime_max_http_response_bytes",label:"Max HTTP response size (bytes)",description:"Maximum response body size accepted from one WASM HTTP request.",details:"This caps the response body accepted from each HTTP call made by an extension. It protects memory and parsing time when a remote server returns a very large body. Responses above the limit should fail the host call."}]}]}),computed:{adminKey(){return this.g.user.wallets[0].adminkey},isExtensionLimitRoute(){return this.$route.path.startsWith("/admin/extensions/wasm/limits/")},routeWasmExtensionId(){return this.isExtensionLimitRoute?this.$route.params.extId:null},backRoute(){return this.isExtensionLimitRoute?"/admin/extensions/wasm/limits":"/admin#extensions"},backTooltip(){return this.isExtensionLimitRoute?"Wasm Limit Config":"Extensions Settings"},pageDescription(){return this.isExtensionLimitRoute?"Customize limits for one installed WASM extension.":"These values are global defaults. Use 0 to disable a global limit."},wasmRuntimeLimitExtensionOptions(){return this.wasmRuntimeLimitExtensions.map(e=>({label:`${e.name||e.id} (${e.id})`,value:e.id}))},selectedWasmRuntimeLimitExtension(){return this.wasmRuntimeLimitExtensions.find(e=>e.id===this.selectedWasmExtensionId)||null},customWasmLimitCount(){const e=this.selectedWasmRuntimeLimitExtension;return e&&e.wasm_runtime_limits?Object.keys(e.wasm_runtime_limits).length:0}},watch:{selectedWasmExtensionId(){this.loadSelectedWasmRuntimeLimitExtension()},routeWasmExtensionId(){this.syncWasmExtensionLimitRoute()}},created(){this.fetchWasmRuntimeLimitExtensions()},methods:{async fetchWasmRuntimeLimitExtensions(){this.wasmRuntimeLimitExtensionsLoading=!0;try{const{data:e}=await LNbits.api.request("GET","/api/v1/extension/wasm/runtime-limits/extensions",this.adminKey);this.wasmRuntimeLimitExtensions=e||[],this.selectedWasmExtensionId&&!this.wasmRuntimeLimitExtensions.some(e=>e.id===this.selectedWasmExtensionId)&&(this.selectedWasmExtensionId=null),this.syncWasmExtensionLimitRoute()}catch(e){LNbits.utils.notifyApiError(e)}finally{this.wasmRuntimeLimitExtensionsLoading=!1}},syncWasmExtensionLimitRoute(){this.selectedWasmExtensionId=this.routeWasmExtensionId,this.loadSelectedWasmRuntimeLimitExtension()},openWasmExtensionLimit(e){this.$router.push(`/admin/extensions/wasm/limits/${encodeURIComponent(e)}`)},loadSelectedWasmRuntimeLimitExtension(){const e=this.selectedWasmRuntimeLimitExtension;this.wasmExtensionLimitDraft=e?{...e.wasm_runtime_limits||{}}:{}},wasmExtensionLimitHint(e){return`Inherited global value: ${this.formData[e.name]}. ${e.description}`},wasmExtensionLimitPlaceholder(e){const t=this.formData[e.name];return null==t?"":String(t)},normalizedWasmExtensionLimitDraft(){const e={};return this.wasmRuntimeLimitGroups.forEach(t=>{t.fields.forEach(t=>{const s=this.wasmExtensionLimitDraft[t.name],a="string"==typeof s?s.trim():s;if(""===a||null==a)return;const i=Number(a);if(!Number.isFinite(i)||!Number.isInteger(i)||i<0)throw new Error(`${t.label} must be a non-negative integer.`);e[t.name]=i})}),e},async clearWasmExtensionLimits(){this.wasmExtensionLimitDraft={},await this.saveWasmExtensionLimits()},async saveWasmExtensionLimits(){if(this.selectedWasmExtensionId){this.wasmExtensionLimitsSaving=!0;try{const{data:e}=await LNbits.api.request("PUT",`/api/v1/extension/wasm/runtime-limits/${encodeURIComponent(this.selectedWasmExtensionId)}`,this.adminKey,{limits:this.normalizedWasmExtensionLimitDraft()}),t=this.wasmRuntimeLimitExtensions.findIndex(t=>t.id===e.id);t>=0&&this.wasmRuntimeLimitExtensions.splice(t,1,e),this.loadSelectedWasmRuntimeLimitExtension(),Quasar.Notify.create({type:"positive",message:"WASM extension limits saved."})}catch(e){e instanceof Error&&!e.response?Quasar.Notify.create({type:"negative",message:e.message}):LNbits.utils.notifyApiError(e)}finally{this.wasmExtensionLimitsSaving=!1}}},showWasmLimitInfo(e){this.wasmLimitInfoDialog={show:!0,title:e.label,details:e.details}}}}),window.app.component("lnbits-admin-notifications",{props:["form-data"],template:"#lnbits-admin-notifications",data:()=>({nostrNotificationIdentifier:"",emailNotificationAddress:""}),methods:{sendTestEmail(){LNbits.api.request("GET","/admin/api/v1/testemail",this.g.user.wallets[0].adminkey).then(e=>{if("error"===e.data.status)throw new Error(e.data.message);this.$q.notify({message:"Test email sent!",color:"positive"})}).catch(e=>{this.$q.notify({message:e.message,color:"negative"})})},addNostrNotificationIdentifier(){const e=this.nostrNotificationIdentifier.trim(),t=this.formData.lnbits_nostr_notifications_identifiers;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_nostr_notifications_identifiers=[...t,e],this.nostrNotificationIdentifier="")},removeNostrNotificationIdentifier(e){const t=this.formData.lnbits_nostr_notifications_identifiers;this.formData.lnbits_nostr_notifications_identifiers=t.filter(t=>t!==e)},addEmailNotificationAddress(){const e=this.emailNotificationAddress.trim(),t=this.formData.lnbits_email_notifications_to_emails;e&&e.length&&!t.includes(e)&&(this.formData.lnbits_email_notifications_to_emails=[...t,e],this.emailNotificationAddress="")},removeEmailNotificationAddress(e){const t=this.formData.lnbits_email_notifications_to_emails;this.formData.lnbits_email_notifications_to_emails=t.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-site-customisation",{props:["form-data"],template:"#lnbits-admin-site-customisation",data:()=>({lnbits_theme_options:["classic","bitcoin","flamingo","cyber","freedom","mint","autumn","monochrome","salvador"],colors:["primary","secondary","accent","positive","negative","info","warning","red","yellow","orange"],reactionOptions:["none","confettiBothSides","confettiFireworks","confettiStars","confettiTop","lightningStrike"],globalBorderOptions:["retro-border","hard-border","neon-border","no-border"]}),methods:{onBackgroundImageInput(e){const t=e.target.files[0];t&&this.uploadBackgroundImage(t),e.target.value=null},async uploadBackgroundImage(e){const t=new FormData;t.append("file",e);try{const{data:e}=await LNbits.api.request("POST","/api/v1/assets?public_asset=true",null,t,{headers:{"Content-Type":"multipart/form-data"}}),s=`${window.location.origin}/api/v1/assets/${e.id}/thumbnail`;this.formData.lnbits_default_bgimage=s,Quasar.Notify.create({type:"positive",message:"Background image uploaded.",icon:null})}catch(e){LNbits.utils.notifyApiError(e)}}}}),window.app.component("lnbits-admin-assets-config",{props:["form-data"],template:"#lnbits-admin-assets-config",data:()=>({newAllowedAssetMimeType:"",newNoLimitUser:""}),async created(){},methods:{addAllowedAssetMimeType(){this.newAllowedAssetMimeType&&(this.removeAllowedAssetMimeType(this.newAllowedAssetMimeType),this.formData.lnbits_assets_allowed_mime_types.push(this.newAllowedAssetMimeType),this.newAllowedAssetMimeType="",this.formData.touch=null)},removeAllowedAssetMimeType(e){const t=this.formData.lnbits_assets_allowed_mime_types.indexOf(e);-1!==t&&this.formData.lnbits_assets_allowed_mime_types.splice(t,1),this.formData.touch=null},addNewNoLimitUser(){this.newNoLimitUser&&(this.removeNoLimitUser(this.newNoLimitUser),this.formData.lnbits_assets_no_limit_users.push(this.newNoLimitUser),this.newNoLimitUser="",this.formData.touch=null)},removeNoLimitUser(e){e&&(this.formData.lnbits_assets_no_limit_users=this.formData.lnbits_assets_no_limit_users.filter(t=>t!==e),this.formData.touch=null)}}}),window.app.component("lnbits-admin-audit",{props:["form-data"],template:"#lnbits-admin-audit",data:()=>({formAddIncludePath:"",formAddExcludePath:"",formAddIncludeResponseCode:""}),methods:{addIncludePath(){if(""===this.formAddIncludePath)return;const e=this.formData.lnbits_audit_include_paths;e.includes(this.formAddIncludePath)||(this.formData.lnbits_audit_include_paths=[...e,this.formAddIncludePath]),this.formAddIncludePath=""},removeIncludePath(e){this.formData.lnbits_audit_include_paths=this.formData.lnbits_audit_include_paths.filter(t=>t!==e)},addExcludePath(){if(""===this.formAddExcludePath)return;const e=this.formData.lnbits_audit_exclude_paths;e.includes(this.formAddExcludePath)||(this.formData.lnbits_audit_exclude_paths=[...e,this.formAddExcludePath]),this.formAddExcludePath=""},removeExcludePath(e){this.formData.lnbits_audit_exclude_paths=this.formData.lnbits_audit_exclude_paths.filter(t=>t!==e)},addIncludeResponseCode(){if(""===this.formAddIncludeResponseCode)return;const e=this.formData.lnbits_audit_http_response_codes;e.includes(this.formAddIncludeResponseCode)||(this.formData.lnbits_audit_http_response_codes=[...e,this.formAddIncludeResponseCode]),this.formAddIncludeResponseCode=""},removeIncludeResponseCode(e){this.formData.lnbits_audit_http_response_codes=this.formData.lnbits_audit_http_response_codes.filter(t=>t!==e)}}}),window.app.component("lnbits-admin-blockexplorer",{props:["form-data"],template:"#lnbits-admin-blockexplorer",data:()=>({electrumServers:["ssl://fulcrum.lnbits.com:50002","ssl://mainnet.nunchuk.io:52002","ssl://fulcrum.grey.pw:50002","ssl://electrum2.bluewallet.io:443","ssl://electrum.acinq.co:50002","ssl://electrum.blockstream.info:50002","ssl://bitcoin.mullvad.net:5010"]}),computed:{electrumServerOptions(){return[...this.electrumServers,"Custom"]},electrumServerPreset:{get(){return this.electrumServers.includes(this.formData.lnbits_blockexplorer_electrum_url)?this.formData.lnbits_blockexplorer_electrum_url:"Custom"},set(e){"Custom"!==e?this.formData.lnbits_blockexplorer_electrum_url=e:"Custom"!==this.electrumServerPreset&&(this.formData.lnbits_blockexplorer_electrum_url="")}}}}),window.PageBlockExplorer={template:"#page-blockexplorer",data:()=>({query:"",loading:!1,tip:null,fees:null,blocks:[],selectedBlock:null,blockDialog:!1,txResult:null,txStatus:null,addressResult:null,currentAddress:""}),computed:{feeList(){return this.fees&&this.fees.estimates?Object.entries(this.fees.estimates).map(([e,t])=>({label:this.$t("n_block_fee",{n:e}),rate:(1e5*t).toFixed(1)+" sat/vB"})):[]},formattedBlocks(){const e=Math.floor(Date.now()/1e3);return this.blocks.map(t=>({...t,shortHash:t.hash.slice(0,8)+"..."+t.hash.slice(-4),timeAgo:this._timeAgo(e-t.timestamp),utcTime:new Date(1e3*t.timestamp).toUTCString(),difficulty:this._difficulty(t.bits)}))}},async created(){await Promise.all([this.loadTip(),this.loadFees(),this.loadBlocks()]),this._blockWsActive=!0,this._connectBlocksWs(),this._loadFromRoute()},beforeUnmount(){this._blockWsActive=!1,this._blockWs&&this._blockWs.close(),this._searchWs&&this._searchWs.close()},watch:{$route(e){this._loadFromRoute(e)},blockDialog(e){e||"block"!==this.$route.params.type||this.$router.push("/blockexplorer")}},methods:{_loadFromRoute(e){e=e||this.$route;const{type:t,id:s}=e.params;"tx"===t?(this.query=s,this._fetchTx(s)):"address"===t?(this.query=s,this._fetchAddress(s)):"block"===t?this._openBlockByHeight(s):(this._resetResults(),this.blockDialog=!1)},_openBlockByHeight(e){const t=parseInt(e,10),s=this.formattedBlocks.find(e=>e.height===t)||this.blocks.find(e=>e.height===t);s?(this.selectedBlock=s,this.blockDialog=!0):(this.selectedBlock=null,this.blockDialog=!1)},_resetResults(){this.txResult=null,this.txStatus=null,this.addressResult=null,this._searchWs&&(this._searchWs.close(),this._searchWs=null)},_wsUrl:e=>`${"https:"===window.location.protocol?"wss:":"ws:"}//${window.location.host}/blockexplorer/api/v1${e}`,_connectBlocksWs(){const e=new WebSocket(this._wsUrl("/ws/blocks"));e.onmessage=e=>{const t=JSON.parse(e.data),s=this.blocks.filter(e=>e.height!==t.height);this.blocks=[t,...s].slice(0,5)},e.onerror=()=>e.close(),e.onclose=()=>{this._blockWsActive&&setTimeout(()=>this._connectBlocksWs(),5e3)},this._blockWs=e},_connectSearchWs(e,t){this._searchWs&&(this._searchWs.close(),this._searchWs=null);const s=new WebSocket(this._wsUrl(e));s.onmessage=e=>{try{t(JSON.parse(e.data))}catch(e){}},s.onerror=()=>s.close(),this._searchWs=s},_timeAgo:e=>e<60?e+"s ago":e<3600?Math.floor(e/60)+"m ago":Math.floor(e/3600)+"h ago",_difficulty(e){const t=parseInt(e.slice(0,2),16),s=parseInt(e.slice(2),16),a=65535*Math.pow(2,208)/(s*Math.pow(2,8*(t-3)));return a>=1e12?(a/1e12).toFixed(2)+"T":a>=1e9?(a/1e9).toFixed(2)+"G":a>=1e6?(a/1e6).toFixed(2)+"M":a.toFixed(0)},openBlock(e){this.$router.push(`/blockexplorer/block/${e.height}`)},async loadBlocks(){try{const e=await LNbits.api.request("GET","/blockexplorer/api/v1/blocks");this.blocks=e.data}catch(e){}},async loadTip(){try{const e=await LNbits.api.request("GET","/blockexplorer/api/v1/tip");this.tip=e.data}catch(e){LNbits.utils.notifyApiError(e)}},async loadFees(){try{const e=await LNbits.api.request("GET","/blockexplorer/api/v1/fees");this.fees=e.data}catch(e){}},clearResult(){this.query="","/blockexplorer"!==this.$route.path?this.$router.push("/blockexplorer"):this._resetResults()},search(){const e=this.query.trim();e&&(/^[0-9a-fA-F]{64}$/.test(e)?this.loadTx(e):this.loadAddress(e))},loadTx(e){this.$router.push(`/blockexplorer/tx/${e}`)},loadAddress(e){this.$router.push(`/blockexplorer/address/${e}`)},async _fetchTx(e){this.loading=!0;try{const t=await LNbits.api.request("GET","/blockexplorer/api/v1/tx/"+e);this.txResult=t.data,this.txStatus=null,this.addressResult=null,this._connectSearchWs(`/ws/tx/${e}`,e=>{e.error||(this.txStatus=e)})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.loading=!1}},async _fetchAddress(e){this.loading=!0;try{const t=await LNbits.api.request("GET","/blockexplorer/api/v1/address/"+e);this.addressResult=t.data,this.txResult=null,this.txStatus=null,this.currentAddress=e,this._connectSearchWs(`/ws/address/${e}`,e=>{e.error||(this.addressResult=e)})}catch(e){LNbits.utils.notifyApiError(e)}finally{this.loading=!1}}}},window.app.component("lnbits-wallet-charts",{template:"#lnbits-wallet-charts",props:["paymentFilter","chartConfig"],data:()=>({debounceTimeoutValue:1337,debounceTimeout:null,chartData:[],chartDataPointCount:0,walletBalanceChart:null,walletBalanceInOut:null,walletPaymentInOut:null,colorPrimary:Quasar.colors.changeAlpha(Quasar.colors.getPaletteColor("primary"),.3),colorSecondary:Quasar.colors.changeAlpha(Quasar.colors.getPaletteColor("secondary"),.3),barOptions:{responsive:!0,maintainAspectRatio:!1,scales:{x:{stacked:!0},y:{stacked:!0}}}}),watch:{paymentFilter:{deep:!0,handler(){this.changeCharts()}},chartConfig:{deep:!0,handler(e){this.$q.localStorage.setItem("lnbits.wallets.chartConfig",e),this.changeCharts()}}},methods:{changeCharts(){this.debounceTimeout&&clearTimeout(this.debounceTimeout),this.debounceTimeout=setTimeout(async()=>{await this.fetchChartData(),this.drawCharts()},this.debounceTimeoutValue)},filterChartData(){const e=this.paymentFilter["time[ge]"]+"T00:00:00",t=this.paymentFilter["time[le]"]+"T23:59:59";let s=0,a=this.chartData.map(e=>void 0!==this.paymentFilter["amount[ge]"]?(s+=e.balance_in,{...e,balance:s,balance_out:0,count_out:0}):void 0!==this.paymentFilter["amount[le]"]?(s-=e.balance_out,{...e,balance:s,balance_in:0,count_in:0}):{...e});a=a.filter(s=>this.paymentFilter["time[ge]"]&&this.paymentFilter["time[le]"]?s.date>=e&&s.date<=t:this.paymentFilter["time[ge]"]?s.date>=e:!this.paymentFilter["time[le]"]||s.date<=t);const i=a.map(e=>new Date(e.date).toLocaleString("default",{month:"short",day:"numeric"}));return this.chartDataPointCount=a.length,{data:a,labels:i}},drawBalanceInOutChart(e,t){this.walletBalanceInOut&&this.walletBalanceInOut.destroy();const s=this.$refs.walletBalanceInOut;s&&(this.walletBalanceInOut=new Chart(s.getContext("2d"),{type:"bar",options:this.barOptions,data:{labels:t,datasets:[{label:"Balance In",borderRadius:5,data:e.map(e=>e.balance_in),backgroundColor:this.colorPrimary},{label:"Balance Out",borderRadius:5,data:e.map(e=>e.balance_out),backgroundColor:this.colorSecondary}]}}))},drawPaymentInOut(e,t){this.walletPaymentInOut&&this.walletPaymentInOut.destroy();const s=this.$refs.walletPaymentInOut;s&&(this.walletPaymentInOut=new Chart(s.getContext("2d"),{type:"bar",options:this.barOptions,data:{labels:t,datasets:[{label:"Payments In",data:e.map(e=>e.count_in),backgroundColor:this.colorPrimary},{label:"Payments Out",data:e.map(e=>-e.count_out),backgroundColor:this.colorSecondary}]}}))},drawBalanceChart(e,t){this.walletBalanceChart&&this.walletBalanceChart.destroy();const s=this.$refs.walletBalanceChart;s&&(this.walletBalanceChart=new Chart(s.getContext("2d"),{type:"line",options:{responsive:!0,maintainAspectRatio:!1},data:{labels:t,datasets:[{label:"Balance",data:e.map(e=>e.balance),pointStyle:!1,backgroundColor:this.colorPrimary,borderColor:this.colorPrimary,borderWidth:2,fill:!0,tension:.7,fill:1},{label:"Fees",data:e.map(e=>e.fee),pointStyle:!1,backgroundColor:this.colorSecondary,borderColor:this.colorSecondary,borderWidth:1,fill:!0,tension:.7,fill:1}]}}))},drawCharts(){const{data:e,labels:t}=this.filterChartData();this.chartConfig.showBalanceChart&&this.drawBalanceChart(e,t),this.chartConfig.showBalanceInOutChart&&this.drawBalanceInOutChart(e,t),this.chartConfig.showPaymentInOutChart&&this.drawPaymentInOut(e,t)},async fetchChartData(){try{const{data:e}=await LNbits.api.request("GET",`/api/v1/payments/stats/daily?wallet_id=${this.g.wallet.id}`);this.chartData=e}catch(e){console.warn(e),LNbits.utils.notifyApiError(e)}}},async created(){await this.fetchChartData(),this.drawCharts()}}),window.app.component("lnbits-wallet-api-docs",{template:"#lnbits-wallet-api-docs",methods:{copyAdminKey(){LNbits.utils.confirmDialog(this.$t("admin_key_warning")).onOk(()=>LNbits.utils.copyText(this.g.wallet.adminkey))},resetKeys(){LNbits.utils.confirmDialog("Are you sure you want to reset your API keys?").onOk(()=>{LNbits.api.resetWalletKeys(this.g.wallet).then(e=>{const{id:t,adminkey:s,inkey:a}=e;this.g.wallet={...this.g.wallet,inkey:a,adminkey:s};const i=this.g.user.wallets.findIndex(e=>e.id===t);-1!==i&&(this.g.user.wallets[i]={...this.g.user.wallets[i],inkey:a,adminkey:s}),Quasar.Notify.create({timeout:3500,type:"positive",message:"API keys reset!"})}).catch(e=>{LNbits.utils.notifyApiError(e)})})}},data:()=>({origin:window.location.origin,inkeyHidden:!0,adminkeyHidden:!0,walletIdHidden:!0})}),window.app.component("lnbits-wallet-icon",{template:"#lnbits-wallet-icon",data:()=>({icon:{show:!1,data:{},colorOptions:["primary","purple","orange","green","brown","blue","red","pink"],options:["home","star","bolt","paid","savings","store","videocam","music_note","flight","train","directions_car","school","construction","science","sports_esports","sports_tennis","theaters","water","headset_mic","videogame_asset","person","group","pets","sunny","elderly","verified","snooze","mail","forum","shopping_cart","shopping_bag","attach_money","print_connect","dark_mode","light_mode","android","network_wifi","shield","fitness_center","lunch_dining"]}}),methods:{setSelectedIcon(e){this.icon.data.icon=e},setSelectedColor(e){this.icon.data.color=e},setIcon(){this.$emit("update-wallet",this.icon.data),this.icon.show=!1}}}),window.app.component("lnbits-wallet-new",{template:"#lnbits-wallet-new",data:()=>({walletTypes:[{label:"Lightning Wallet",value:"lightning"}],wallet:{name:"",sharedWalletId:""},showNewWalletDialog:!1}),watch:{"g.newWalletType"(e){null!==e&&(this.showNewWalletDialog=!0)},showNewWalletDialog(e){!0!==e&&this.reset()}},computed:{isLightning(){return"lightning"===this.g.newWalletType},isLightningShared(){return"lightning-shared"===this.g.newWalletType},inviteWalletOptions(){return(this.g.user?.extra?.wallet_invite_requests||[]).map(e=>({label:`${e.to_wallet_name} (from ${e.from_user_name})`,value:e.to_wallet_id}))}},methods:{reset(){this.showNewWalletDialog=!1,this.g.newWalletType=null,this.wallet={name:"",sharedWalletId:""}},async submitRejectWalletInvitation(){try{const e=this.g.user.extra.wallet_invite_requests||[],t=e.find(e=>e.to_wallet_id===this.wallet.sharedWalletId);if(!t)return void Quasar.Notify.create({message:"Cannot find invitation for the selected wallet.",type:"warning"});await LNbits.api.request("DELETE",`/api/v1/wallet/share/invite/${t.request_id}`,this.g.wallet.adminkey),Quasar.Notify.create({message:"Invitation rejected.",type:"positive"}),this.g.user.extra.wallet_invite_requests=e.filter(e=>e.request_id!==t.request_id)}catch(e){LNbits.utils.notifyApiError(e)}},submitAddWallet(){const e=this.wallet;"lightning"!==this.g.newWalletType||e.name?"lightning-shared"!==this.g.newWalletType||e.sharedWalletId?LNbits.api.createWallet(e.name,this.g.newWalletType,{shared_wallet_id:e.sharedWalletId}).then(e=>{this.$q.notify({message:"Wallet created successfully",color:"positive"}),this.reset(),this.g.user.wallets.push(LNbits.map.wallet(e.data)),this.g.lastWalletId=e.data.id,this.$router.push(`/wallet/${e.data.id}`)}).catch(LNbits.utils.notifyApiError):this.$q.notify({message:"Missing a shared wallet ID",color:"warning"}):this.$q.notify({message:"Please enter a name for the wallet",color:"warning"})}},created(){this.g.user?.extra?.wallet_invite_requests?.length&&this.walletTypes.push({label:`Lightning Wallet (Share Invite: ${this.g.user.extra.wallet_invite_requests.length})`,value:"lightning-shared"})}}),window.app.component("lnbits-wallet-share",{template:"#lnbits-wallet-share",computed:{walletApprovedShares(){return this.g.wallet.extra.shared_with.filter(e=>"approved"===e.status)},walletPendingRequests(){return this.g.wallet.extra.shared_with.filter(e=>"request_access"===e.status)},walletPendingInvites(){return this.g.wallet.extra.shared_with.filter(e=>"invite_sent"===e.status)}},data:()=>({permissionOptions:[{label:"View",value:"view-payments"},{label:"Receive",value:"receive-payments"},{label:"Send",value:"send-payments"}],walletShareInvite:{username:"",permissions:[]}}),methods:{async updateSharePermissions(e){try{const{data:t}=await LNbits.api.request("PUT","/api/v1/wallet/share",this.g.wallet.adminkey,e);Object.assign(e,t),Quasar.Notify.create({message:"Wallet permission updated.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},async inviteUserToWallet(){try{const{data:e}=await LNbits.api.request("PUT","/api/v1/wallet/share/invite",this.g.wallet.adminkey,{...this.walletShareInvite,status:"invite_sent",wallet_id:this.g.wallet.id});this.g.wallet.extra.shared_with.push(e),this.walletShareInvite={username:"",permissions:[]},Quasar.Notify.create({message:"User invited to wallet.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}},deleteSharePermission(e){LNbits.utils.confirmDialog("Are you sure you want to remove this share permission?").onOk(async()=>{try{await LNbits.api.request("DELETE",`/api/v1/wallet/share/${e.request_id}`,this.g.wallet.adminkey),this.g.wallet.extra.shared_with=this.g.wallet.extra.shared_with.filter(t=>t.wallet_id!==e.wallet_id),Quasar.Notify.create({message:"Wallet permission deleted.",type:"positive"})}catch(e){LNbits.utils.notifyApiError(e)}})}}}),window.app.component("lnbits-wallet-paylinks",{template:"#lnbits-wallet-paylinks",data:()=>({storedPaylinks:[]}),watch:{"g.wallet"(e){this.storedPaylinks=e.storedPaylinks??[]}},created(){this.storedPaylinks=this.g.wallet.storedPaylinks},methods:{updatePaylinks(){LNbits.api.request("PUT",`/api/v1/wallet/stored_paylinks/${this.g.wallet.id}`,this.g.wallet.adminkey,{links:this.storedPaylinks}).then(()=>{this.$q.notify({message:"Paylinks updated.",type:"positive",timeout:3500})}).catch(e=>{LNbits.utils.notifyApiError(e)})},sendToPaylink(e){this.$emit("send-lnurl",e)},editPaylink(){this.$nextTick(()=>{this.updatePaylinks()})},deletePaylink(e){const t=[];this.storedPaylinks.forEach(s=>{s.lnurl!==e&&t.push(s)}),this.storedPaylinks=t,this.updatePaylinks()}}}),window.app.component("lnbits-wallet-extra",{template:"#lnbits-wallet-extra",props:["chartConfig"],data:()=>({lightningAddressInput:""}),computed:{exportUrl(){return`${window.location.origin}/wallet?usr=${this.g.user.id}&wal=${this.g.wallet.id}`},canEditLightningAddress(){return this.g.settings.enableWalletLightningAddresses&&this.g.settings.allowCustomWalletLightningAddresses&&"lightning"===this.g.wallet.walletType},lightningAddressSuffix:()=>`@${window.location.host}`,lightningAddressChanged(){return this.lightningAddressInput!==(this.g.wallet.lightningAddress||"")},lightningAddressFeeHint(){return this.g.settings.chargeWalletLightningAddresses?`Fee: ${this.g.settings.walletLightningAddressPriceSats} sats`:""}},watch:{"g.wallet.id":"resetLightningAddressInput","g.wallet.lightningAddress":"resetLightningAddressInput"},methods:{resetLightningAddressInput(){this.lightningAddressInput=this.g.wallet.lightningAddress||""},saveLightningAddress(){this.updateWallet({lightning_address:this.lightningAddressInput})},handleSendLnurl(e){this.$emit("send-lnurl",e)},updateWallet(e){this.$emit("update-wallet",e)},handleFiatTracking(){this.g.fiatTracking=!this.g.fiatTracking,this.g.fiatTracking?(this.updateWallet({currency:this.g.wallet.currency}),this.updateFiatBalance()):(this.g.isFiatPriority=!1,this.g.wallet.currency="",this.updateWallet({currency:""}))},deleteWallet(){LNbits.utils.confirmDialog("Are you sure you want to delete this wallet?").onOk(()=>{LNbits.api.deleteWallet(this.g.wallet).then(()=>{this.g.user.wallets=this.g.user.wallets.filter(e=>e.id!==this.g.wallet.id),this.g.lastActiveWallet=this.g.user.wallets[0].id,this.$router.push(`/wallet/${this.g.lastActiveWallet}`),Quasar.Notify.create({timeout:3e3,message:"Wallet deleted!",spinner:!0})}).catch(e=>{LNbits.utils.notifyApiError(e)})})},updateFiatBalance(){this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency)&&(this.g.exchangeRate=this.$q.localStorage.getItem("lnbits.exchangeRate."+this.g.wallet.currency),this.g.fiatBalance=this.g.exchangeRate/1e8*this.g.wallet.sat),LNbits.api.request("GET","/api/v1/rate/"+this.g.wallet.currency,null).then(e=>{this.g.fiatBalance=e.data.price/1e8*this.g.wallet.sat,this.g.exchangeRate=e.data.price.toFixed(2),this.g.fiatTracking=!0,this.$q.localStorage.set("lnbits.exchangeRate."+this.g.wallet.currency,this.g.exchangeRate),this.g.exchangeRate<=0&&(this.g.fiatTracking=!1,this.g.isFiatPriority=!1)}).catch(e=>console.error(e))}},created(){this.resetLightningAddressInput(),""!==this.g.wallet.currency&&this.g.isSatsDenomination?(this.g.fiatTracking=!0,this.updateFiatBalance()):this.g.fiatTracking=!1}}),window.app.component("lnbits-home-logos",{template:"#lnbits-home-logos",data:()=>({logos:[{href:"https://github.com/ElementsProject/lightning",lightSrc:"/static/images/clnl.png",darkSrc:"/static/images/cln.png"},{href:"https://github.com/lightningnetwork/lnd",lightSrc:"/static/images/lnd.png",darkSrc:"/static/images/lnd.png"},{href:"https://opennode.com",lightSrc:"/static/images/opennodel.png",darkSrc:"/static/images/opennode.png"},{href:"https://lnpay.co/",lightSrc:"/static/images/lnpayl.png",darkSrc:"/static/images/lnpay.png"},{href:"https://github.com/rootzoll/raspiblitz",lightSrc:"/static/images/blitzl.png",darkSrc:"/static/images/blitz.png"},{href:"https://start9.com/",lightSrc:"/static/images/start9l.png",darkSrc:"/static/images/start9.png"},{href:"https://getumbrel.com/",lightSrc:"/static/images/umbrell.png",darkSrc:"/static/images/umbrel.png"},{href:"https://mynodebtc.com",lightSrc:"/static/images/mynodel.png",darkSrc:"/static/images/mynode.png"},{href:"https://github.com/shesek/spark-wallet",lightSrc:"/static/images/sparkl.png",darkSrc:"/static/images/spark.png"},{href:"https://voltage.cloud",lightSrc:"/static/images/voltagel.png",darkSrc:"/static/images/voltage.png"},{href:"https://breez.technology/sdk/",lightSrc:"/static/images/breezl.png",darkSrc:"/static/images/breez.png"},{href:"https://blockstream.com/lightning/greenlight/",lightSrc:"/static/images/greenlightl.png",darkSrc:"/static/images/greenlight.png"},{href:"https://getalby.com",lightSrc:"/static/images/albyl.png",darkSrc:"/static/images/alby.png"},{href:"https://zbd.gg",lightSrc:"/static/images/zbdl.png",darkSrc:"/static/images/zbd.png"},{href:"https://phoenix.acinq.co/server",lightSrc:"/static/images/phoenixdl.png",darkSrc:"/static/images/phoenixd.png"},{href:"https://boltz.exchange/",lightSrc:"/static/images/boltzl.svg",darkSrc:"/static/images/boltz.svg"},{href:"https://www.blink.sv/",lightSrc:"/static/images/blink_logol.png",darkSrc:"/static/images/blink_logo.png"}]}),computed:{showLogos(){return this.g.isSatsDenomination&&"LNbits"==this.g.settings.siteTitle&&1==this.g.settings.showHomePageElements}}}),window.app.component("lnbits-error",{template:"#lnbits-error",props:["dynamic","code","message"],computed:{isExtension(){return 403==this.code&&(!!this.message.startsWith("Extension ")||void 0)}},methods:{goBack(){window.history.back()},goHome(){window.location="/"},goToWallet(){this.dynamic?this.$router.push("/wallet"):window.location="/wallet"},goToExtension(){const e=`/extensions#${this.message.match(/'([^']+)'/)[1]}`;this.dynamic?this.$router.push(e):window.location=e},async logOut(){try{await LNbits.api.logout(),window.location="/"}catch(e){LNbits.utils.notifyApiError(e)}}},async created(){if(!this.dynamic&&401==this.code)return console.warn(`Unauthorized: ${this.errorMessage}`),void this.logOut()}}),window.app.component("lnbits-qrcode",{template:"#lnbits-qrcode",components:{QrcodeVue:QrcodeVue.default},props:{value:{type:String,required:!0},nfc:{type:Boolean,default:!1},print:{type:Boolean,default:!1},showButtons:{type:Boolean,default:!0},href:{type:String,default:""},margin:{type:Number,default:3},maxWidth:{type:Number,default:450},logo:{type:String,default:window.g.settings.qrLogo||null}},data:()=>({nfcTagWriting:!1,nfcSupported:"undefined"!=typeof NDEFReader}),methods:{printQrCode(){const e=this.$refs.qrCode.$el.outerHTML,t=window.open("","_blank");t.document.write(`\n \n \n Print QR Code\n \n \n ${e}\n \n `),t.document.close(),t.focus(),t.print(),t.close()},clickQrCode(e){if(""===this.href)return this.utils.copyText(this.value),e.preventDefault(),e.stopPropagation(),!1;this.href&&this.href.startsWith("http")&&(window.open(this.href,"_blank"),e.preventDefault())},async writeNfcTag(){try{if(!this.nfcSupported)throw{toString:function(){return"NFC not supported on this device or browser."}};const e=new NDEFReader;this.nfcTagWriting=!0,this.$q.notify({message:"Tap your NFC tag to write the LNURL-withdraw link to it."}),await e.write({records:[{recordType:"url",data:this.value,lang:"en"}]}),this.nfcTagWriting=!1,this.$q.notify({type:"positive",message:"NFC tag written successfully."})}catch(e){this.nfcTagWriting=!1,this.$q.notify({type:"negative",message:e?e.toString():"An unexpected error has occurred."})}},downloadSVG(){const e=this.$refs.qrCode.$el;if(!e)return void console.error("SVG element not found");let t=(new XMLSerializer).serializeToString(e);t.match(/^]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)||(t=t.replace(/^({tab:"bech32",lnurl:""}),methods:{setLnurl(){if("bech32"==this.tab){const e=(new TextEncoder).encode(this.url),t=NostrTools.nip19.encodeBytes("lnurl",e);this.lnurl=this.href&&""!==this.href.trim()?`${this.href}?lightning=${t.toUpperCase()}`:`lightning:${t.toUpperCase()}`}else"lud17"==this.tab&&(this.url.startsWith("http://")?this.lnurl=this.url.replace("http://",this.prefix+"://"):this.lnurl=this.url.replace("https://",this.prefix+"://"));this.$emit("update:lnurl",this.lnurl)}},watch:{url(){this.setLnurl()},tab(){this.setLnurl()}},created(){this.setLnurl()}}),window.app.component("lnbits-disclaimer",{template:"#lnbits-disclaimer",computed:{showDisclaimer:()=>!g.disclaimerShown&&g.isUserAuthorized}}),window.app.component("lnbits-footer",{template:"#lnbits-footer",computed:{title(){return`${this.g.settings.siteTitle}, ${this.g.settings.siteTagline}`},version(){return this.$t("lnbits_version")+": "+this.g.settings.version}}}),window.app.component("lnbits-header",{template:"#lnbits-header",computed:{showAdmin(){return this.g.user&&(this.g.user.super_user||this.g.user.admin)},displayName(){return this.g.user?.extra?.display_name||this.g.user.username||this.g.user?.extra?.first_name||"Anon"},displayRole(){return this.g.user?.super_user?"Super User":this.g.user?.admin?"Admin":"User"}},methods:{async stopImpersonation(){try{await LNbits.api.stopImpersonation(),LNbits.utils.restoreLocalStorage("impersonation"),window.location="/users"}catch(e){console.warn(e)}},async handleLanguageChanged(e){try{await LNbits.api.updateUiCustomization({locale:e.locale}),this.$q.notify({type:"positive",message:"Language Updated",caption:e.locale})}catch(e){LNbits.utils.notifyApiError(e)}}}}),window.app.component("lnbits-header-wallets",{template:"#lnbits-header-wallets"}),window.app.component("lnbits-drawer",{template:"#lnbits-drawer"}),window.app.component("lnbits-theme",{watch:{"g.walletFlip"(e){this.$q.localStorage.setItem("lnbits.walletFlip",e),!0===e&&this.$q.screen.lt.md&&(this.g.visibleDrawer=!1)},"g.disclaimerShown"(e){this.$q.localStorage.setItem("lnbits.disclaimerShown",e)},"g.locale"(e){this.$q.localStorage.setItem("lnbits.lang",e),window.i18n.global.locale=e},"g.isFiatPriority"(e){this.$q.localStorage.setItem("lnbits.isFiatPriority",e)},"g.reactionChoice"(e){this.$q.localStorage.set("lnbits.reactions",e)},"g.themeChoice"(e){document.body.setAttribute("data-theme",e),this.$q.localStorage.set("lnbits.theme",e)},"g.darkChoice"(e){this.$q.dark.set(e),this.$q.localStorage.set("lnbits.darkMode",e),Chart.defaults.color=this.$q.dark.isActive?"#fff":"#000"},"g.borderChoice"(e){document.body.classList.forEach(e=>{e.endsWith("-border")&&document.body.classList.remove(e)}),this.$q.localStorage.setItem("lnbits.border",e),document.body.classList.add(e)},"g.gradientChoice"(e){this.$q.localStorage.set("lnbits.gradientBg",e),!0===e?document.body.classList.add("gradient-bg"):document.body.classList.remove("gradient-bg")},"g.cardRoundedChoice"(e){this.$q.localStorage.set("lnbits.cardRounded",e),!0===e?document.body.classList.add("rounded-ui"):document.body.classList.remove("rounded-ui")},"g.cardGradientChoice"(e){this.$q.localStorage.set("lnbits.cardGradient",e),!0===e?document.body.classList.add("card-gradient"):document.body.classList.remove("card-gradient")},"g.cardShadowChoice"(e){this.$q.localStorage.set("lnbits.cardShadow",e),!0===e?document.body.classList.add("card-shadow"):document.body.classList.remove("card-shadow")},"g.burgerMenuChoice"(e){this.$q.localStorage.set("lnbits.burgerMenu",e),!0===e?document.body.classList.remove("no-burger-background"):document.body.classList.add("no-burger-background")},"g.mobileSimple"(e){this.$q.localStorage.set("lnbits.mobileSimple",e),!0===e?document.body.classList.add("mobile-simple"):document.body.classList.remove("mobile-simple")},"g.bgimageChoice"(e){this.$q.localStorage.set("lnbits.backgroundImage",e),""===e?document.body.classList.remove("bg-image"):(document.body.classList.add("bg-image"),document.body.style.setProperty("--background",`url(${e})`))}},methods:{async checkUrlParams(){const e=new URLSearchParams(window.location.search);if(0===e.length)return;if(e.has("theme")){const t=e.get("theme").trim().toLowerCase();this.g.themeChoice=t,e.delete("theme")}if(e.has("border")){const t=e.get("border").trim().toLowerCase();this.g.borderChoice=t,e.delete("border")}if(e.has("gradient")){const t=e.get("gradient").toLowerCase();this.g.gradientChoice="1"===t||"true"===t,e.delete("gradient")}if(e.has("dark")){const t=e.get("dark").trim().toLowerCase();this.g.darkChoice="1"===t||"true"===t,e.delete("dark")}if(e.has("usr")){try{await LNbits.api.loginUsr(e.get("usr")),window.location.href="/wallet"}catch(e){LNbits.utils.notifyApiError(e)}e.delete("usr")}const t=e.size?`?${e.toString()}`:"",s=window.location.pathname+t;window.history.replaceState(null,null,s)}},created(){this.$q.dark.set(this.g.darkChoice),document.body.setAttribute("data-theme",this.g.themeChoice),Chart.defaults.color=this.$q.dark.isActive?"#fff":"#000",document.body.classList.add(this.g.borderChoice),!0===this.g.gradientChoice&&document.body.classList.add("gradient-bg"),!0===this.g.cardRoundedChoice&&document.body.classList.add("rounded-ui"),!0===this.g.cardGradientChoice&&document.body.classList.add("card-gradient"),!0===this.g.cardShadowChoice&&document.body.classList.add("card-shadow"),!0!==this.g.burgerMenuChoice&&document.body.classList.add("no-burger-background"),""!==this.g.bgimageChoice&&(document.body.classList.add("bg-image"),document.body.style.setProperty("--background",`url(${this.g.bgimageChoice})`)),!0===this.g.mobileSimple&&document.body.classList.add("mobile-simple"),Object.entries(this.g.user?.uiCustomization||{}).forEach(([e,t])=>{e in this.g&&(this.g[e]=t)}),this.checkUrlParams()}}),window.app.component("lnbits-qrcode-scanner",{template:"#lnbits-qrcode-scanner",props:["callback"],data:()=>({showScanner:!1}),watch:{callback(e){return null===e?this.reset():"function"!=typeof e?(Quasar.Notify.create({message:"QR code scanner callback is not a function.",type:"negative"}),this.reset()):!1===this.g.hasCamera?(Quasar.Notify.create({message:"No camera found on this device.",type:"negative"}),this.reset()):void(this.showScanner=!0)}},methods:{reset(){this.showScanner=!1,this.g.scanner=null},detect(e){const t=e[0].rawValue;console.log("Detected QR code value:",t),this.callback(t),this.$emit("detect",t),this.reset()},async onInitQR(e){try{await e}catch(e){const t={NotAllowedError:"ERROR: you need to grant camera access permission",NotFoundError:"ERROR: no camera on this device",NotSupportedError:"ERROR: secure context required (HTTPS, localhost)",NotReadableError:"ERROR: is the camera already in use?",OverconstrainedError:"ERROR: installed cameras are not suitable",StreamApiNotSupportedError:"ERROR: Stream API is not supported in this browser",InsecureContextError:"ERROR: Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP."},s=Object.keys(t).filter(t=>e.name===t),a=s?t[s]:`ERROR: Camera error (${e.name})`;Quasar.Notify.create({message:a,type:"negative"}),this.g.hasCamera=!1,this.reset()}}}}),window.app.component("lnbits-manage-extension-list",{template:"#lnbits-manage-extension-list",data:()=>({extensions:[],userExtensions:[],searchTerm:""}),watch:{"g.user.extensions"(){this.loadExtensions()},searchTerm(){this.filterUserExtensionsByTerm()}},methods:{async loadExtensions(){try{res=await LNbits.api.request("GET","/api/v1/extension"),this.extensions=res.data.sort((e,t)=>e.name.localeCompare(t.name)),this.filterUserExtensionsByTerm()}catch(e){LNbits.utils.notifyApiError(e)}},filterUserExtensionsByTerm(){const e=this.g.user.extensions;this.userExtensions=this.extensions.filter(t=>e.includes(t.code)).filter(e=>""===this.searchTerm||`${e.code} ${e.name} ${e.short_description} ${e.url}`.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase()))},extensionUrl:e=>e.is_wasm?`/ext/${e.code}`:`/${e.code}/`,extensionActive(e){const t=e.is_wasm?`/ext/${e.code}`:`/${e.code}`;return this.$route.path.startsWith(t)}},async created(){await this.loadExtensions()}}),function(){function e(e,t){return e?e(t):t}function t(t,s){const a=function(e){return`extension_permission_${e.id.replace(/[^A-Za-z0-9]/g,"_")}`}(t),i=e(s,a);return i===a?t.id:i}function s(t){return{level:"low",color:"grey-6",label:e(t,"extension_permission_risk_low"),warning:""}}function a(t,s){return{level:"medium",color:"warning",label:e(t,"extension_permission_risk_medium"),warning:s?e(t,s):""}}function i(t,s){return{level:"high",color:"negative",label:e(t,"extension_permission_risk_high"),warning:e(t,s)}}function n(e,t){const s=(e||[]).find(e=>e.id===t);return s?.name||t}function o(e,t){const s=e.policies;return Array.isArray(s)?s.map(e=>{const s="string"==typeof e?e:e?.id;if(!s)return null;const a="string"==typeof e?["read"]:Array.isArray(e.access)&&e.access.length?e.access:["read"];return{id:s,name:n(t,s),access:a}}).filter(Boolean):[]}function r(e,t,n){const r=e.map(e=>function(e,t,n){if(["wallet.pay_invoice","wallet.pay_invoice_background"].includes(e.id))return i(n,"wallet.pay_invoice_background"===e.id?"extension_permission_warning_wallet_pay_invoice_background":"extension_permission_warning_wallet_pay_invoice");if("extension.api.request"===e.id)return o(e,t).some(e=>e.access.includes("write"))?i(n,"extension_permission_warning_extension_api_request_write"):a(n);return"http.request"===e.id?a(n):"wallet.payments.watch"===e.id?a(n,"extension_permission_warning_wallet_payments_watch"):["websocket.publish","websocket.subscribe"].includes(e.id)||["wallet.list","wallet.balance.read","wallet.create_invoice_public","ext.storage.append_public","ext.storage.read_public"].includes(e.id)?a(n):s(n)}(e,t,n)),l=r.find(e=>"high"===e.level);return l||(r.find(e=>"medium"===e.level)||s(n))}function l(e){const t=["wallet.pay_invoice","wallet.pay_invoice_background","wallet.payments.watch","wallet.list","wallet.balance.read","extension.api.request","http.request","ui.camera.scan_qr","websocket","websocket.publish","websocket.subscribe","ext.storage.read","ext.storage.write","ext.storage.read_public","ext.storage.append_public","wallet.create_invoice_public","wallet.create_invoice","utils.basic"],s=t.indexOf(e);return-1===s?t.length:s}function c(s,a,i){const n=s[0],l=2===s.length&&s.some(e=>"ext.storage.read"===e.id)&&s.some(e=>"ext.storage.write"===e.id),c=s.every(e=>["websocket.publish","websocket.subscribe"].includes(e.id))&&s.some(e=>"websocket.publish"===e.id)&&s.some(e=>"websocket.subscribe"===e.id),d=s.map(e=>function(e){return"string"==typeof e.description?e.description:""}(e)).filter(Boolean),h={id:l?"ext.storage.read_write":c?"websocket":n.id,label:l?e(i,"extension_permission_ext_storage_read_write"):c?e(i,"extension_permission_websocket"):t(n,i),risk:r(s,a,i),badges:[],descriptions:d,fieldGroups:[],appendPolicies:[],websocketPublishPolicies:[],invoicePolicies:[],extensionAccess:[],httpHosts:[]};"ext.storage.read_public"===n.id&&(h.fieldGroups=function(e){const t=e.policies;return Array.isArray(t)?t.map(e=>{const t="string"==typeof e?e:e?.table_name||"",s="string"!=typeof e&&Array.isArray(e?.public_fields)?e.public_fields.filter(e=>"string"==typeof e&&e):[],a="string"==typeof e||"string"!=typeof e?.source_id_field?"":e.source_id_field;return t?{table:t,fields:s,sourceIdField:a}:null}).filter(Boolean):[]}(n),h.badges=h.fieldGroups.map(e=>({key:e.table,label:e.table}))),"extension.api.request"===n.id&&(h.extensionAccess=o(n,a),h.badges=h.extensionAccess.map(e=>({key:e.id,label:e.name}))),"http.request"===n.id&&(h.httpHosts=function(e){const t=e.policies;return Array.isArray(t)?t.map(e=>"string"==typeof e?e:e?.host||"").filter(e=>"string"==typeof e&&e):[]}(n)),"wallet.create_invoice_public"===n.id&&(h.invoicePolicies=function(e){const t=e.policies;return Array.isArray(t)?t.map(e=>{if(!e||"object"!=typeof e)return null;const t=e.table,s=e.wallet_field;return"string"==typeof t&&t&&"string"==typeof s&&s?{table:t,walletField:s}:null}).filter(Boolean):[]}(n)),"ext.storage.append_public"===n.id&&(h.appendPolicies=function(e){const t=e.policies;return Array.isArray(t)?t.map(e=>{if(!e||"object"!=typeof e)return null;const t=e.table,s=e.source_table,a=e.source_id_field,i=Array.isArray(e.allowed_fields)?e.allowed_fields.filter(e=>"string"==typeof e&&e):[],n=Number.isInteger(e.max_rows_per_source)?e.max_rows_per_source:1e4;return"string"==typeof t&&t&&"string"==typeof s&&s&&"string"==typeof a&&a?{table:t,sourceTable:s,sourceIdField:a,allowedFields:i,maxRowsPerSource:n,rawPolicy:e}:null}).filter(Boolean):[]}(n),h.badges=h.appendPolicies.map(e=>({key:e.table+":"+e.sourceTable+":"+e.sourceIdField,label:e.table})));const m=s.find(e=>"websocket.publish"===e.id);return m&&(h.websocketPublishPolicies=function(e){const t=e.policies;return Array.isArray(t)?t.map(e=>e&&"object"==typeof e?{maxMessagesPerSecond:Number.isInteger(e.max_messages_per_second)?e.max_messages_per_second:0,rawPolicy:e}:null).filter(Boolean):[]}(m)),h}function d({permissions:e,extensions:t,translate:s}){const a=e||[],i=new Map(a.map(e=>[e.id,e])),n=i.has("ext.storage.read")&&i.has("ext.storage.write"),o=i.has("websocket.publish")&&i.has("websocket.subscribe");let r=!1,d=!1;return a.map((e,t)=>n&&["ext.storage.read","ext.storage.write"].includes(e.id)?r?null:(r=!0,{index:t,orderId:"ext.storage.read",permissions:[i.get("ext.storage.read"),i.get("ext.storage.write")]}):o&&["websocket.publish","websocket.subscribe"].includes(e.id)?d?null:(d=!0,{index:t,orderId:"websocket",permissions:[i.get("websocket.publish"),i.get("websocket.subscribe")]}):{index:t,orderId:e.id,permissions:[e]}).filter(Boolean).sort((e,t)=>{const s=l(e.orderId),a=l(t.orderId);return s===a?e.index-t.index:s-a}).map(e=>c(e.permissions,t||[],s))}window.LNbitsExtensionPermissions={displayItems:d,hasHighRisk:({permissions:e,extensions:t,translate:s})=>d({permissions:e,extensions:t,translate:s}).some(e=>"high"===e.risk.level)},window.app.component("lnbits-extension-permissions",{template:"#lnbits-extension-permissions",props:{permissions:{type:Array,default:()=>[]},extensions:{type:Array,default:()=>[]},editableAppendPublicLimits:{type:Boolean,default:!1},maxRowsPerSourceLimit:{type:Number,default:1e6},editableWebsocketPublishLimits:{type:Boolean,default:!1},maxMessagesPerSecondLimit:{type:Number,default:100}},computed:{displayItems(){return window.LNbitsExtensionPermissions.displayItems({permissions:this.permissions,extensions:this.extensions,translate:e=>this.$t(e)})}},methods:{publicInvoicePolicySentence:e=>`Invoices will be created using ${e.walletField} from ${e.table}.`,publicAppendPolicySentence:e=>`${e.table} rows can be appended for ${e.sourceTable} using ${e.sourceIdField}. Limit: ${e.maxRowsPerSource} rows per source.`,websocketPublishPolicySentence:e=>`Limit: ${e.maxMessagesPerSecond} messages per second.`,permissionAccessLabel(e){const t=`extension_permission_access_${e}`,s=this.$t(t);return s===t?e:s}}})}(),window.app.component("lnbits-manage-wallet-list",{template:"#lnbits-manage-wallet-list",data:()=>({activeWalletId:null}),computed:{maxWallets(){return this.g.user?.extra?.visible_wallet_count||10}},watch:{$route(e){e.path.startsWith("/wallet/")?this.activeWalletId=e.params.id:this.activeWalletId=null},"g.user.wallets":{handler(){this.paymentEvents()},deep:!0,immediate:!0}},created(){this.g.user&&0===this.g.walletEventListeners.length&&this.paymentEvents()},methods:{openNewWalletDialog(){this.g.user.walletInvitesCount?this.g.newWalletType="lightning-shared":this.g.newWalletType="lightning"},onWebsocketMessage(e){const t=JSON.parse(e.data);t.payment?(this.g.user.wallets.forEach(e=>{e.id===t.payment.wallet_id&&(e.sat=t.wallet_balance)}),this.g.wallet.id===t.payment.wallet_id&&(this.g.wallet.sat=t.wallet_balance,this.g.updatePayments=!this.g.updatePayments,this.g.updatePaymentsHash=!this.g.updatePaymentsHash),t.payment.amount>0&&eventReaction(1e3*t.wallet_balance)):console.error("ws message no payment",t)},paymentEvents(){if(!this.g.user)return;let e;this.g.user.wallets.slice(0,this.maxWallets).forEach(t=>{if(!this.g.walletEventListeners.includes(t.id)){this.g.walletEventListeners.push(t.id);const s=new WebSocket(`${websocketUrl}/${t.inkey}`);s.onmessage=this.onWebsocketMessage,s.onopen=()=>console.log("ws connected for wallet",t.id),s.onclose=()=>{console.log("ws closed, reconnecting...",t.id),this.g.walletEventListeners=this.g.walletEventListeners.filter(e=>e!==t.id),clearTimeout(e),e=setTimeout(this.paymentEvents,5e3)},s.onerror=()=>{console.warn("ws error, reconnecting...",t.id),this.g.walletEventListeners=this.g.walletEventListeners.filter(e=>e!==t.id),clearTimeout(e),e=setTimeout(this.paymentEvents,5e3)}}})}}}),window.app.component("lnbits-language-dropdown",{template:"#lnbits-language-dropdown",computed:{currentLanguage(){return this.langs.find(e=>e.value===window.i18n.global.locale)||{value:"en",label:"English",display:"🇬🇧 EN"}}},methods:{activeLanguage:e=>window.i18n.global.locale===e,changeLanguage(e){this.g.locale=e,window.i18n.global.locale=e,this.$q.localStorage.set("lnbits.lang",e),this.$emit("language-changed",e)}},data:()=>({langs:[{value:"en",label:"English",display:"🇬🇧 EN"},{value:"de",label:"Deutsch",display:"🇩🇪 DE"},{value:"es",label:"Español",display:"🇪🇸 ES"},{value:"jp",label:"日本語",display:"🇯🇵 JP"},{value:"cn",label:"中文",display:"🇨🇳 CN"},{value:"fr",label:"Français",display:"🇫🇷 FR"},{value:"it",label:"Italiano",display:"🇮🇹 IT"},{value:"pi",label:"Pirate",display:"🏴‍☠️ PI"},{value:"nl",label:"Nederlands",display:"🇳🇱 NL"},{value:"we",label:"Cymraeg",display:"🏴󠁧󠁢󠁷󠁬󠁳󠁿 CY"},{value:"pl",label:"Polski",display:"🇵🇱 PL"},{value:"pt",label:"Português",display:"🇵🇹 PT"},{value:"br",label:"Português do Brasil",display:"🇧🇷 BR"},{value:"cs",label:"Česky",display:"🇨🇿 CS"},{value:"sk",label:"Slovensky",display:"🇸🇰 SK"},{value:"kr",label:"한국어",display:"🇰🇷 KR"},{value:"fi",label:"Suomi",display:"🇫🇮 FI"},{value:"fo",label:"Føroyskt",display:"🇫🇴 FO"}]})}),window.app.component("lnbits-payment-list",{template:"#lnbits-payment-list",props:["wallet","paymentFilter"],data(){return{payments:[],paymentsTable:{columns:[{name:"time",align:"left",label:this.$t("memo")+"/"+this.$t("date"),field:"date",sortable:!0},{name:"amount",align:"right",label:this.$t("amount"),field:"sat",sortable:!0}],pagination:{rowsPerPage:10,page:1,sortBy:"time",descending:!0,rowsNumber:10},sortFields:[{name:"amount",label:"Amount"},{name:"fee",label:"Fee"},{name:"memo",label:"Memo"},{name:"time",label:"Creation Date"},{name:"updated_at",label:"Last Updated"}],search:"",loading:!1},searchDate:{from:null,to:null},searchStatus:{success:!0,pending:!0,failed:!1,incoming:!0,outgoing:!0},exportTagName:"",exportPaymentTagList:[],paymentsCSV:{columns:[{name:"status",align:"right",label:this.$t("status"),field:"status"},{name:"memo",align:"left",label:this.$t("memo"),field:"memo"},{name:"time",align:"left",label:this.$t("date"),field:"date",sortable:!0},{name:"amount",align:"right",label:this.$t("amount"),field:"sat",sortable:!0},{name:"fee",align:"right",label:this.$t("fee"),field:"fee"},{name:"tag",align:"right",label:this.$t("tag"),field:"tag"},{name:"payment_hash",align:"right",label:this.$t("payment_hash"),field:"payment_hash"},{name:"payment_proof",align:"right",label:this.$t("payment_proof"),field:"payment_proof"},{name:"webhook",align:"right",label:this.$t("webhook"),field:"webhook"},{name:"fiat_currency",align:"right",label:"Fiat Currency",field:e=>e.extra.wallet_fiat_currency},{name:"fiat_amount",align:"right",label:"Fiat Amount",field:e=>e.extra.wallet_fiat_amount}],preimage:null,loading:!1},hodlInvoice:{show:!1,payment:null,preimage:null},selectedPayment:null,filterLabels:[]}},computed:{filteredPayments(){const e=this.paymentsTable.search;return e&&""!==e?LNbits.utils.search(this.payments,e):this.payments},paymentsOmitter(){return this.$q.screen.lt.md&&this.g.mobileSimple?this.payments.length>0?[this.payments[0]]:[]:this.payments},pendingPaymentsExist(){return-1!==this.payments.findIndex(e=>e.pending)}},methods:{mapPayment(e){const t={checking_id:e.checking_id,status:e.status,amount:e.amount,fee:e.fee,memo:e.memo,time:e.time,bolt11:e.bolt11,preimage:e.preimage,payment_hash:e.payment_hash,expiry:e.expiry,extra:e.extra??{},wallet_id:e.wallet_id,webhook:e.webhook,webhook_status:e.webhook_status,fiat_amount:e.fiat_amount,fiat_currency:e.fiat_currency,labels:e.labels};t.date=this.utils.formatDate(e.created_at),t.dateFrom=this.utils.formatDateFrom(e.created_at),t.expirydate=this.utils.formatDate(e.expiry),t.expirydateFrom=this.utils.formatDateFrom(e.expiry),t.msat=t.amount,t.sat=t.msat/1e3,t.tag=t.extra?.tag,t.fsat=this.utils.formatSat(t.sat),t.isIn=t.amount>0,t.isOut=t.amount<0,t.isPending="pending"===t.status,t.isPaid="success"===t.status,t.isFailed="failed"===t.status,t._q=[t.memo,t.sat].join(" ").toLowerCase();try{t.details=JSON.parse(e.extra?.details||"{}")}catch{t.details={extraDetails:e.extra?.details}}return t},searchByDate(){"string"==typeof this.searchDate&&(this.searchDate={from:this.searchDate,to:this.searchDate}),this.searchDate.from&&(this.paymentFilter["time[ge]"]=this.searchDate.from+"T00:00:00"),this.searchDate.to&&(this.paymentFilter["time[le]"]=this.searchDate.to+"T23:59:59"),this.fetchPayments()},searchByLabels(e){e&&0!==e.length?(this.filterLabels=e,this.paymentsTable.filter["labels[every]"]=e,this.fetchPayments()):this.clearLabelSeach()},clearDateSeach(){this.searchDate={from:null,to:null},delete this.paymentFilter["time[ge]"],delete this.paymentFilter["time[le]"],this.fetchPayments()},clearLabelSeach(){this.filterLabels=[],delete this.paymentsTable.filter["labels[every]"],this.fetchPayments()},fetchPayments(e){this.paymentsTable.loading=!0;const t=LNbits.utils.prepareFilterQuery(this.paymentsTable,e,this.paymentFilter);return LNbits.api.getPayments(this.wallet,t).then(e=>{this.paymentsTable.pagination.rowsNumber=e.data.total,this.payments=e.data.data.map(this.mapPayment),this.paymentsTable.loading=!1,this.recheckPendingPayments()}).catch(e=>{this.paymentsTable.loading=!1,g.user.admin?this.fetchPaymentsAsAdmin(this.wallet.id,t):LNbits.utils.notifyApiError(e)})},sortByColumn(e){this.paymentsTable.pagination.sortBy===e?this.paymentsTable.pagination.descending=!this.paymentsTable.pagination.descending:(this.paymentsTable.pagination.sortBy=e,this.paymentsTable.pagination.descending=!1),this.fetchPayments()},fetchPaymentsAsAdmin(e,t){return t=(t||"")+"&wallet_id="+e,LNbits.api.request("GET","/api/v1/payments/all/paginated?"+t).then(e=>{this.paymentsTable.loading=!1,this.paymentsTable.pagination.rowsNumber=e.data.total,this.payments=e.data.data.map(this.mapPayment)}).catch(e=>{this.paymentsTable.loading=!1,LNbits.utils.notifyApiError(e)})},checkPayment(e){LNbits.api.getPayment(this.wallet,e).then(e=>{this.update=!this.update,"success"==e.data.status&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")}),"pending"==e.data.status&&Quasar.Notify.create({type:"info",message:this.$t("payment_pending")})}).catch(LNbits.utils.notifyApiError)},recheckPendingPayments(){const e=this.payments.filter(e=>"pending"===e.status);if(0===e.length)return;const t=["recheck_pending=true","checking_id[in]="+e.map(e=>e.checking_id).join(",")].join("&");LNbits.api.getPayments(this.wallet,t).then(e=>{let t=0;e.data.data.forEach(e=>{if("pending"!==e.status){const s=this.payments.findIndex(t=>t.checking_id===e.checking_id);-1!==s&&(this.payments.splice(s,1,this.mapPayment(e)),t+=1)}}),t>0&&Quasar.Notify.create({type:"positive",message:this.$t("payment_successful")})}).catch(e=>{console.warn(e)})},showHoldInvoiceDialog(e){this.hodlInvoice.show=!0,this.hodlInvoice.preimage="",this.hodlInvoice.payment=e},cancelHoldInvoice(e){LNbits.api.cancelInvoice(this.wallet,e).then(()=>{this.update=!this.update,Quasar.Notify.create({type:"positive",message:this.$t("invoice_cancelled")})}).catch(LNbits.utils.notifyApiError)},settleHoldInvoice(e){LNbits.api.settleInvoice(this.wallet,e).then(()=>{this.update=!this.update,Quasar.Notify.create({type:"positive",message:this.$t("invoice_settled")})}).catch(LNbits.utils.notifyApiError)},paymentTableRowKey:e=>e.payment_hash+e.amount,async exportCSV(e=!1){const t=this.paymentsTable.pagination,s=1e3;let a=[];this.paymentsCSV.loading=!0;try{for(let e=0;e<100;e++){const i={sortby:t.sortBy??"time",direction:t.descending?"desc":"asc",limit:s,offset:e*s},n=new URLSearchParams(i),o=await LNbits.api.getPayments(this.wallet,n),r=o.data.data||[];if(a=a.concat(r.map(this.mapPayment)),r.length=o.data.total)break}let i=this.paymentsCSV.columns;if(e){this.exportPaymentTagList.length&&(a=a.filter(e=>this.exportPaymentTagList.includes(e.tag)));const e=Object.keys(a.reduce((e,t)=>({...e,...t.details}),{})).map(e=>({name:e,align:"right",label:e.charAt(0).toUpperCase()+e.slice(1).replace(/([A-Z])/g," $1"),field:t=>t.details[e],format:e=>"object"==typeof e?JSON.stringify(e):e}));i=this.paymentsCSV.columns.concat(e)}LNbits.utils.exportCSV(i,a,this.wallet.name+"-payments")}catch(e){LNbits.utils.notifyApiError(e)}finally{this.paymentsCSV.loading=!1}},addFilterTag(){if(!this.exportTagName)return;const e=this.exportTagName.trim();this.exportPaymentTagList=this.exportPaymentTagList.filter(t=>t!==e),this.exportPaymentTagList.push(e),this.exportTagName=""},removeExportTag(e){this.exportPaymentTagList=this.exportPaymentTagList.filter(t=>t!==e)},formatCurrency(e,t){try{return LNbits.utils.formatCurrency(e,t)}catch(t){return console.error(t),`${e} ???`}},handleFilterChanged(){const{success:e,pending:t,failed:s,incoming:a,outgoing:i}=this.searchStatus;let n=this.paymentFilter||{};delete n["status[ne]"],delete n["status[eq]"],e&&t&&s||(e&&t?n["status[ne]"]="failed":e&&s?n["status[ne]"]="pending":s&&t?n["status[ne]"]="success":!e||t||s?!t||e||s?!s||e||t||(n["status[eq]"]="failed"):n["status[eq]"]="pending":n["status[eq]"]="success"),delete n["amount[ge]"],delete n["amount[le]"],a&&i||!a&&!i||(a&&!i?n["amount[ge]"]=0:i&&!a&&(n["amount[le]"]=0)),this.paymentFilter=n},async savePaymentLabels(e){if(this.selectedPayment)try{await LNbits.api.request("PUT",`/api/v1/payments/${this.selectedPayment.payment_hash}/labels`,this.wallet.adminkey,{labels:e});const t=this.payments.find(e=>e.checking_id===this.selectedPayment.checking_id);t&&(t.labels=[...e]),Quasar.Notify.create({type:"positive",message:this.$t("payment_labels_updated")})}catch(e){LNbits.utils.notifyApiError(e)}else Quasar.Notify.create({type:"warning",message:"No payment selected"})},isLightColor(e){try{return Quasar.colors.luminosity(e)>.5}catch(e){return console.warning(e),!1}}},watch:{"paymentsTable.search":{handler(){const e={};this.paymentsTable.search&&(e.search=this.paymentsTable.search),this.fetchPayments()}},"g.updatePayments"(){this.fetchPayments()}},created(){this.fetchPayments()}}),window.app.component("lnbits-label-selector",{template:"#lnbits-label-selector",props:["labels"],data:()=>({labelFilter:"",localLabels:[]}),methods:{toggleLabel(e){if(this.localLabels.includes(e.name)){const t=this.localLabels.indexOf(e.name);-1!==t&&this.localLabels.splice(t,1)}else this.localLabels.push(e.name)},saveLabels(){this.$emit("update:labels",this.localLabels)},clearLabels(){this.localLabels=[],this.saveLabels()}},created(){this.localLabels=[...this.labels]}}),window.app.component("lnbits-extension-settings-form",{name:"lnbits-extension-settings-form",template:"#lnbits-extension-settings-form",props:["options","adminkey","endpoint"],methods:{async updateSettings(){if(!this.settings)return Quasar.Notify.create({message:"No settings to update",type:"negative"});try{const{data:e}=await LNbits.api.request("PUT",this.endpoint,this.adminkey,this.settings);this.settings=e}catch(e){LNbits.utils.notifyApiError(e)}},async getSettings(){try{const{data:e}=await LNbits.api.request("GET",this.endpoint,this.adminkey);this.settings=e}catch(e){LNbits.utils.notifyApiError(e)}},async resetSettings(){LNbits.utils.confirmDialog("Are you sure you want to reset the settings?").onOk(async()=>{try{await LNbits.api.request("DELETE",this.endpoint,this.adminkey),await this.getSettings()}catch(e){LNbits.utils.notifyApiError(e)}})}},async created(){await this.getSettings()},data:()=>({settings:void 0})}),window.app.component("lnbits-extension-settings-btn-dialog",{template:"#lnbits-extension-settings-btn-dialog",name:"lnbits-extension-settings-btn-dialog",props:["options","adminkey","endpoint"],data:()=>({show:!1})}),window.app.component("lnbits-data-fields",{name:"lnbits-data-fields",template:"#lnbits-data-fields",props:["fields","hide-advanced"],data:()=>({fieldTypes:[{label:"Text",value:"str"},{label:"Integer",value:"int"},{label:"Float",value:"float"},{label:"Boolean",value:"bool"},{label:"Date Time",value:"datetime"},{label:"JSON",value:"json"},{label:"Wallet Select",value:"wallet"},{label:"Currency Select",value:"currency"}],fieldsTable:{columns:[{name:"name",align:"left",label:"Field Name",field:"name",sortable:!0},{name:"type",align:"left",label:"Type",field:"type",sortable:!1},{name:"label",align:"left",label:"UI Label",field:"label",sortable:!0},{name:"hint",align:"left",label:"UI Hint",field:"hint",sortable:!1},{name:"optional",align:"left",label:"Optional",field:"optional",sortable:!1}],pagination:{sortBy:"name",rowsPerPage:100,page:1,rowsNumber:100},search:null,hideEmpty:!0}}),methods:{addField:function(){this.fields.push({name:"field_name_"+(this.fields.length+1),type:"text",label:"",hint:"",optional:!0,sortable:!0,searchable:!0,editable:!0,fields:[]})},removeField:function(e){const t=this.fields.indexOf(e);t>-1&&this.fields.splice(t,1)}},async created(){this.hideAdvanced||this.fieldsTable.columns.push({name:"editable",align:"left",label:"UI Editable",field:"editable",sortable:!1},{name:"sortable",align:"left",label:"Sortable",field:"sortable",sortable:!1},{name:"searchable",align:"left",label:"Searchable",field:"searchable",sortable:!1})}}),window.app.component(QrcodeVue),window.app.component("lnbits-extension-rating",{template:"#lnbits-extension-rating",name:"lnbits-extension-rating",props:{rating:{type:Number,default:0},count:{type:Number,default:null},clickable:{type:Boolean,default:!1}},computed:{displayRating(){return Math.round(2*(this.rating||0))/2},hasData(){return null!==this.count&&void 0!==this.count}},methods:{handleClick(){this.clickable&&this.$emit("click")}}}),window.app.component("lnbits-manage",{template:"#lnbits-manage",methods:{isActive:e=>window.location.pathname===e},data:()=>({extensions:[]})}),window.app.component("lnbits-payment-details",{template:"#lnbits-payment-details",props:["payment"],computed:{hasPreimage(){return this.payment.preimage&&"0000000000000000000000000000000000000000000000000000000000000000"!==this.payment.preimage},hasExpiry(){return!!this.payment.expiry},hasSuccessAction(){return this.hasPreimage&&this.payment.extra&&this.payment.extra.success_action},webhookStatusColor(){return this.payment.webhook_status>=300||this.payment.webhook_status<0?"red-10":this.payment.webhook_status?"green-10":"cyan-7"},webhookStatusText(){return this.payment.webhook_status?this.payment.webhook_status:"not sent yet"},hasTag(){return this.payment.extra&&!!this.payment.extra.tag},extras(){if(!this.payment.extra)return[];let e=_.omit(this.payment.extra,["tag","success_action"]);return Object.keys(e).map(t=>({key:t,value:e[t]}))}}}),window.app.component("lnbits-lnurlpay-success-action",{template:"#lnbits-lnurlpay-success-action",props:["payment","success_action"],data(){return{decryptedValue:this.success_action.ciphertext}},mounted(){if("aes"!==this.success_action.tag)return null;this.utils.decryptLnurlPayAES(this.success_action,this.payment.preimage).then(e=>{this.decryptedValue=e})}}),window.app.component("lnbits-notifications-btn",{template:"#lnbits-notifications-btn",props:["pubkey"],data:()=>({isSupported:!1,isSubscribed:!1,isPermissionGranted:!1,isPermissionDenied:!1}),methods:{urlB64ToUint8Array(e){const t=(e+"=".repeat((4-e.length%4)%4)).replace(/\-/g,"+").replace(/_/g,"/"),s=atob(t),a=new Uint8Array(s.length);for(let e=0;et!==e),this.$q.localStorage.set("lnbits.webpush.subscribedUsers",JSON.stringify(t))},isUserSubscribed(e){return(JSON.parse(this.$q.localStorage.getItem("lnbits.webpush.subscribedUsers"))||[]).includes(e)},subscribe(){this.isSupported&&!this.isPermissionDenied&&(Notification.requestPermission().then(e=>{this.isPermissionGranted="granted"===e,this.isPermissionDenied="denied"===e}).catch(console.log),navigator.serviceWorker.ready.then(e=>{navigator.serviceWorker.getRegistration().then(e=>{e.pushManager.getSubscription().then(t=>{if(null===t||!this.isUserSubscribed(this.g.user.id)){const t={applicationServerKey:this.urlB64ToUint8Array(this.pubkey),userVisibleOnly:!0};e.pushManager.subscribe(t).then(e=>{LNbits.api.request("POST","/api/v1/webpush",null,{subscription:JSON.stringify(e)}).then(e=>{this.saveUserSubscribed(e.data.user),this.isSubscribed=!0}).catch(LNbits.utils.notifyApiError)})}}).catch(console.log)})}))},unsubscribe(){navigator.serviceWorker.ready.then(e=>{e.pushManager.getSubscription().then(e=>{e&&LNbits.api.request("DELETE","/api/v1/webpush?endpoint="+btoa(e.endpoint),null).then(()=>{this.removeUserSubscribed(this.g.user.id),this.isSubscribed=!1}).catch(LNbits.utils.notifyApiError)})}).catch(console.log)},checkSupported(){let e="https:"===window.location.protocol,t="serviceWorker"in navigator,s="Notification"in window,a="PushManager"in window;return this.isSupported=e&&t&&s&&a,this.isSupported||console.log("Notifications disabled because requirements are not met:",{HTTPS:e,"Service Worker API":t,"Notification API":s,"Push API":a}),this.isSupported},async updateSubscriptionStatus(){await navigator.serviceWorker.ready.then(e=>{e.pushManager.getSubscription().then(e=>{this.isSubscribed=!!e&&this.isUserSubscribed(this.g.user.id)})}).catch(console.log)}},created(){this.isPermissionDenied="denied"===Notification.permission,this.checkSupported()&&this.updateSubscriptionStatus()}}),window.app.component("lnbits-dynamic-fields",{template:"#lnbits-dynamic-fields",props:["options","modelValue"],data:()=>({formData:null,rules:[e=>!!e||"Field is required"]}),methods:{applyRules(e){return e?this.rules:[]},buildData(e,t={}){return e.reduce((e,s)=>(s.options?.length?e[s.name]=this.buildData(s.options,t[s.name]):e[s.name]=t[s.name]??s.default,e),{})},handleValueChanged(){this.$emit("update:model-value",this.formData)}},created(){this.formData=this.buildData(this.options,this.modelValue)}}),window.app.component("lnbits-dynamic-chips",{template:"#lnbits-dynamic-chips",props:["modelValue"],data:()=>({chip:"",chips:[]}),methods:{addChip(){this.chip&&(this.chips.push(this.chip),this.chip="",this.$emit("update:model-value",this.chips.join(",")))},removeChip(e){this.chips.splice(e,1),this.$emit("update:model-value",this.chips.join(","))}},created(){"string"==typeof this.modelValue?this.chips=this.modelValue.split(","):this.chips=[...this.modelValue]}}),window.app.component("lnbits-update-balance",{template:"#lnbits-update-balance",props:["wallet_id","small_btn"],computed:{admin(){return!0===this.g.user?.super_user}},data:()=>({credit:0}),methods:{updateBalance(e){LNbits.api.updateBalance(e.value,this.wallet_id).then(t=>{if(!0!==t.data.success)throw new Error(t.data);credit=parseInt(e.value),Quasar.Notify.create({type:"positive",message:this.$t("credit_ok",{amount:credit}),icon:null}),this.credit=0,e.value=0,e.set()}).catch(LNbits.utils.notifyApiError)}}}),window.app.component("user-id-only",{template:"#user-id-only",props:{allowed_new_users:Boolean,authAction:String,authMethod:String,usr:String,wallet:String},data(){return{user:this.usr,walletName:this.wallet}},methods:{showLogin(e){this.$emit("show-login",e)},showRegister(e){this.$emit("show-register",e)},loginUsr(){this.$emit("update:usr",this.user),this.$emit("login-usr")},createWallet(){this.$emit("update:wallet",this.walletName),this.$emit("create-wallet")}},computed:{showInstantLogin(){return"username-password"!==this.authMethod||"register"!==this.authAction}},created(){}}),window.app.component("username-password",{template:"#username-password",props:{allowed_new_users:Boolean,authMethods:Array,authAction:String,username:String,password_1:String,password_2:String,invitationCode:String,resetKey:String},data(){return{oauth:["nostr-auth-nip98","google-auth","github-auth","keycloak-auth","oidc-auth"],username:this.userName,password:this.password_1,passwordRepeat:this.password_2,reset_key:this.resetKey,confirmationMethod:"code",confirmationEmail:"",confirmationCode:this.invitationCode||"",showConfirmationCode:!1,showPwd:!1,showPwdRepeat:!1}},methods:{login(){this.$emit("update:userName",this.username),this.$emit("update:password_1",this.password),this.$emit("login")},register(){this.$emit("update:userName",this.username),this.$emit("update:password_1",this.password),this.$emit("update:password_2",this.passwordRepeat),this.$emit("update:invitationCode",this.confirmationCode),this.$emit("register")},reset(){this.$emit("update:resetKey",this.reset_key),this.$emit("update:password_1",this.password),this.$emit("update:password_2",this.passwordRepeat),this.$emit("reset")},validateUsername:e=>new RegExp("^(?=[a-zA-Z0-9._]{2,20}$)(?!.*[_.]{2})[^_.].*[^_.]$").test(e),async signInWithNostr(){try{const e=await this.createNostrToken();if(!e)return;resp=await LNbits.api.loginByProvider("nostr",{Authorization:e},{}),window.location.href="/wallet"}catch(e){console.warn(e);const t=e?.response?.data?.detail||`${e}`;Quasar.Notify.create({type:"negative",message:"Failed to sign in with Nostr.",caption:t})}},async createNostrToken(){try{if(!window.nostr?.signEvent)return void Quasar.Notify.create({type:"negative",message:"No Nostr signing app detected.",caption:'Is "window.nostr" present?'});const e=`${window.location}nostr`,t="POST",s=await NostrTools.nip98.getToken(e,t,e=>async function(e){try{const{data:t}=await LNbits.api.getServerHealth();return e.created_at=t.server_time,await window.nostr.signEvent(e)}catch(e){console.error(e),Quasar.Notify.create({type:"negative",message:"Failed to sign nostr event.",caption:`${e}`})}}(e),!0);if(!await NostrTools.nip98.validateToken(s,e,t))throw new Error("Invalid signed token!");return s}catch(e){console.warn(e),Quasar.Notify.create({type:"negative",message:"Failed create Nostr event.",caption:`${e}`})}}},computed:{showOauth(){return this.oauth.some(e=>this.authMethods.includes(e))},disableRegister(){const e=!!this.username,t=!!this.password&&this.password.length>=8,s=this.password===this.passwordRepeat,a=0===this.confirmationMethodsCount||"code"!==this.confirmationMethod||this.confirmationCode.length>0;return!(e&&t&&s&&a)},confirmationMethodsCount(){return[this.g.settings.userActivationByEmail,this.g.settings.userActivationByPayment,this.g.settings.userActivationByInvitationCode].filter(Boolean).length}},created(){}}),window.app.component("separator-text",{template:"#separator-text",props:{text:String,uppercase:{type:Boolean,default:!1},color:{type:String,default:"grey"}}}),window.app.component("lnbits-node-ranks",{props:["ranks"],data:()=>({stats:[{label:"Capacity",key:"capacity"},{label:"Channels",key:"channelcount"},{label:"Age",key:"age"},{label:"Growth",key:"growth"},{label:"Availability",key:"availability"}]}),template:"\n \n
\n
1ml Node Rank
\n
\n
\n
{{ stat.label }}
\n
\n {{ (ranks && ranks[stat.key]) ?? '-' }}\n
\n
\n
\n
\n \n "}),window.app.component("lnbits-channel-stats",{props:["stats"],data:()=>({states:[{label:"Active",value:"active",color:"green"},{label:"Pending",value:"pending",color:"orange"},{label:"Inactive",value:"inactive",color:"grey"},{label:"Closed",value:"closed",color:"red"}]}),template:"\n \n
\n
Channels
\n
\n
\n
\n {{ state.label }}\n
\n
\n {{ (stats?.counts && stats.counts[state.value]) ?? \"-\" }}\n
\n
\n
\n
\n
\n "}),window.app.component("lnbits-stat",{props:["title","amount","msat","btc"],computed:{value(){return this.amount??(this.btc?LNbits.utils.formatSat(this.btc):LNbits.utils.formatMsat(this.msat))}},template:"\n \n \n
\n {{ title }}\n
\n
\n {{ value }}\n sats\n BTC\n
\n
\n
\n "}),window.app.component("lnbits-node-qrcode",{props:["info"],template:'\n \n \n
\n
\n \n
\n No addresses available\n
\n
\n
\n
\n \n Public Key Click to copy \n \n \n
\n '}),window.app.component("lnbits-channel-balance",{props:["balance","color"],methods:{formatMsat:e=>LNbits.utils.formatMsat(e)},template:'\n
\n
\n \n Local: {{ formatMsat(balance.local_msat) }}\n sats\n \n \n Remote: {{ formatMsat(balance.remote_msat) }}\n sats\n \n
\n\n \n
\n \n {{ balance.alias }}\n \n
\n \n
\n '}),window.app.component("lnbits-node-info",{props:["info"],data:()=>({showDialog:!1}),methods:{shortenNodeId:e=>e?e.substring(0,5)+"..."+e.substring(e.length-5):"..."},template:"\n
\n
{{ this.info.alias }}
\n
\n
{{ this.info.backend_name }}
\n \n #{{ this.info.color }}\n \n
{{ shortenNodeId(this.info.id) }}
\n \n \n
\n \n \n \n
\n "}),window.app.component("lnbits-stat",{props:["title","amount","msat","btc"],computed:{value(){return this.amount??(this.btc?LNbits.utils.formatSat(this.btc):LNbits.utils.formatMsat(this.msat))}},template:"\n \n \n
\n {{ title }}\n
\n
\n {{ value }}\n sats\n BTC\n
\n
\n
\n "}),window.WasmExtensionComponent={template:'\n
\n \n \n \n \n {{ error }}\n \n \n \n \n \n
Camera access
\n
\n \n {{ cameraPrompt.extensionName }} wants to access the camera to scan a QR code.\n \n \n \n \n \n \n
\n
\n \n \n \n
Background payments
\n
\n \n
\n {{ backgroundPaymentPrompt.extensionName }} wants permission to make\n background payments from\n {{ backgroundPaymentPrompt.walletName }}.\n
\n \n This permission can move funds later without an active click.\n \n \n \n
\n \n \n \n \n
\n
\n \n \n \n
Watch wallet payments
\n
\n \n
\n {{ walletPaymentWatchPrompt.extensionName }} wants permission to receive\n payment notifications for\n {{ walletPaymentWatchPrompt.walletName }}.\n
\n \n This permission exposes payment metadata for this wallet to the extension.\n \n
\n \n \n \n \n
\n
\n \n \n \n
Open link
\n
\n \n
\n {{ newTabPrompt.extensionName }} wants to open this link in a new\n tab.\n
\n \n {{ newTabPrompt.url }}\n
\n \n This link is not on the same domain as this LNbits page.\n \n \n \n \n \n \n \n \n \n \n ',data:()=>({allowedPaymentHashes:new Set,bridge:{apiRoutes:[],extensionId:"",permissions:[],public:!1,query:{},routeParams:{}},bridgePort:null,cameraPrompt:{extensionName:"",reject:null,resolve:null,show:!1},backgroundPaymentDestinationOptions:[{label:"Only transfers to my wallets",value:"own_wallets_only"},{label:"Allow external payments",value:"external_allowed"}],backgroundPaymentPrompt:{extensionName:"",form:{destinationPolicy:"own_wallets_only",maxAmount:0},reject:null,resolve:null,show:!1,walletId:"",walletName:""},walletPaymentWatchPrompt:{extensionName:"",reject:null,resolve:null,show:!1,walletId:"",walletName:""},newTabPrompt:{extensionName:"",external:!1,reject:null,resolve:null,show:!1,url:""},error:"",extensionName:"",frameUrl:"",handleWindowMessage:null,loading:!1,loadId:0,paymentSubscriptions:new Map,websocketSubscriptions:new Map}),created(){this.handleWindowMessage=e=>this.onWindowMessage(e),window.addEventListener("message",this.handleWindowMessage)},unmounted(){window.removeEventListener("message",this.handleWindowMessage),this.rejectCameraPrompt("Camera scan cancelled."),this.rejectBackgroundPaymentPrompt("Background payment permission cancelled."),this.rejectWalletPaymentWatchPrompt("Wallet payment watch permission cancelled."),this.rejectNewTabPrompt("Open link cancelled."),this.closeBridgePort()},watch:{"$route.fullPath":{immediate:!0,handler(){this.loadFrameConfig()}}},methods:{emptyBridge:()=>({apiRoutes:[],extensionId:"",permissions:[],public:!1,query:{},routeParams:{}}),plainBridgeContext(){return{extensionId:String(this.bridge.extensionId||""),public:Boolean(this.bridge.public),routeParams:this.plainValue(this.bridge.routeParams||{}),query:this.plainValue(this.bridge.query||{})}},hasBridgePermission(e){return(this.bridge.permissions||[]).includes(e)},cameraPromptStorageKey(){return`lnbits.ext.permissions.${this.bridge.extensionId}.ui.camera.scan_qr`},emptyBackgroundPaymentPrompt:()=>({extensionName:"",form:{destinationPolicy:"own_wallets_only",maxAmount:0},reject:null,resolve:null,show:!1,walletId:"",walletName:""}),emptyCameraPrompt:()=>({extensionName:"",reject:null,resolve:null,show:!1}),emptyWalletPaymentWatchPrompt:()=>({extensionName:"",reject:null,resolve:null,show:!1,walletId:"",walletName:""}),emptyNewTabPrompt:()=>({extensionName:"",external:!1,reject:null,resolve:null,show:!1,url:""}),plainValue(e){try{return JSON.parse(JSON.stringify(e))}catch(e){return{}}},async loadFrameConfig(){const e=String(this.$route.params.extId||""),t=++this.loadId;this.loading=!0,this.error="",this.frameUrl="",this.bridge=this.emptyBridge(),this.allowedPaymentHashes.clear(),this.rejectCameraPrompt("Camera scan cancelled."),this.rejectBackgroundPaymentPrompt("Background payment permission cancelled."),this.rejectWalletPaymentWatchPrompt("Wallet payment watch permission cancelled."),this.rejectNewTabPrompt("Open link cancelled."),this.closeBridgePort();try{const s=await fetch(`/api/v1/ext/${encodeURIComponent(e)}/_ui/frame`,{method:"POST",headers:{"content-type":"application/json"},credentials:"same-origin",body:JSON.stringify({path:this.$route.path,query:this.$route.query||{}})}),a=await s.text();let i={};if(a)try{i=JSON.parse(a)}catch(e){i={detail:a}}if(!s.ok)throw new Error(i?.detail||"Failed to load extension page.");if(t!==this.loadId)return;this.bridge=i.bridge||this.emptyBridge(),this.extensionName=i.extension?.name||e,this.frameUrl=i.frameUrl}catch(e){if(t!==this.loadId)return;console.error("[lnbits wasm extension] Failed to load frame.",e),this.error=e instanceof Error?e.message:String(e)}finally{t===this.loadId&&(this.loading=!1)}},extensionFrameWindow(){return this.$refs.frame?.contentWindow},sendResponse(e,t,s){e({type:"lnbits-extension:response",id:t,...s})},allowedApiRoute(e,t){let s;try{s=new URL(t,window.location.origin)}catch(e){return!1}return s.origin===window.location.origin&&(e=String(e||"GET").toUpperCase(),(this.bridge.apiRoutes||[]).some(t=>t.method===e&&new RegExp(t.pattern).test(s.pathname)))},extensionRoute(e){let t;try{t=new URL(String(e||""),window.location.origin)}catch(e){throw new Error("Invalid extension route.")}if(t.origin!==window.location.origin)throw new Error("Extension route must stay on this server.");const s=`/ext/${encodeURIComponent(this.bridge.extensionId)}`;if(t.pathname!==s&&!t.pathname.startsWith(`${s}/`))throw new Error("Extension route must stay inside this extension.");return`${t.pathname}${t.search}${t.hash}`},replaceExtensionRoute(e){return this.$router.replace(this.extensionRoute(e.path))},newTabUrl(e){const t=String(e||"").trim();if(!t)throw new Error("Open link needs a URL.");let s;try{s=new URL(t,window.location.href)}catch(e){throw new Error("Invalid open link URL.")}if(!["http:","https:"].includes(s.protocol))throw new Error("Only HTTP and HTTPS links can be opened.");if(s.username||s.password)throw new Error("Links with embedded credentials cannot be opened.");return{external:s.origin!==window.location.origin,url:s.href}},openNewTab(e){return this.promptNewTabOpen(this.newTabUrl(e.url||e.href))},promptNewTabOpen(e){if(this.newTabPrompt.show)throw new Error("Open link prompt is already open.");return new Promise((t,s)=>{this.newTabPrompt={extensionName:this.extensionName||this.bridge.extensionId||"This extension",external:e.external,reject:s,resolve:t,show:!0,url:e.url}})},resolveNewTabPrompt(e){const t=this.newTabPrompt;if(t.show)if(this.newTabPrompt=this.emptyNewTabPrompt(),e)try{window.open(t.url,"_blank","noopener,noreferrer"),t.resolve?.({external:t.external,opened:!0,url:t.url})}catch(e){t.reject?.(e)}else t.reject?.(new Error("Open link denied by user."))},rejectNewTabPrompt(e){const t=this.newTabPrompt.reject;this.newTabPrompt=this.emptyNewTabPrompt(),t?.(new Error(e))},async copyNewTabLink(){const e=this.newTabPrompt;if(e.show&&e.url)try{await navigator.clipboard.writeText(e.url),this.notify({level:"positive",message:"Link copied."})}catch(e){this.notify({level:"negative",message:"Could not copy link."})}},bridgeSessionStorageKey(e){const t=String(e||"").trim();if(!t||t.length>128||!/^[A-Za-z0-9._:-]+$/.test(t))throw new Error("Invalid extension session key.");return`lnbits.ext.session.${this.bridge.extensionId}.${t}`},getBridgeSessionValue(e){const t=this.bridgeSessionStorageKey(e.key);return{value:window.sessionStorage.getItem(t)||""}},setBridgeSessionValue(e){const t=this.bridgeSessionStorageKey(e.key),s=String(e.value||"");if(s.length>4096)throw new Error("Extension session value is too large.");return window.sessionStorage.setItem(t,s),{ok:!0}},async callApi(e){const t=String(e.method||"GET").toUpperCase(),s=String(e.path||"");if(!this.allowedApiRoute(t,s))throw new Error("Extension API route is not allowed.");const a={method:t,headers:{},credentials:"same-origin"};void 0!==e.body&&null!==e.body&&(a.headers["content-type"]="application/json",a.body=JSON.stringify(e.body));const i=await fetch(s,a),n=await i.text();let o=n;if(n)try{o=JSON.parse(n)}catch(e){o=n}if(!i.ok)throw new Error("object"==typeof o&&o.detail?o.detail:n);return this.rememberPaymentHashes(o),o},notify(e){const t=["positive","negative","warning","info"].includes(e.level)?e.level:"info";window.Quasar?.Notify&&window.Quasar.Notify.create({color:t,message:String(e.message||"")})},async scanQrCode(){if(!this.hasBridgePermission("ui.camera.scan_qr"))throw new Error("Extension is missing scanner permission.");if(!this.g)throw new Error("LNbits scanner is not available.");if(this.g.scanner)throw new Error("A scanner is already active.");if(await this.requireCameraScanApproval(),this.g.scanner)throw new Error("A scanner is already active.");return new Promise((e,t)=>{let s=!1;const a=()=>{window.clearTimeout(o),window.clearInterval(r),this.g.scanner===n&&(this.g.scanner=null)},i=e=>t=>{s||(s=!0,a(),e(t))},n=t=>{i(e)({value:String(t||"")})},o=window.setTimeout(()=>{i(t)(new Error("QR scan timed out."))},12e4),r=window.setInterval(()=>{s||this.g.scanner===n||i(t)(new Error("QR scan cancelled."))},250);this.g.scanner=n})},async requestBackgroundPaymentPermission(e){const t=await this.requestExtensionPermissions({forcePrompt:!0===e?.forcePrompt,permissions:[{id:"wallet.pay_invoice_background",grant:e?.grant||{}}]});return t.permissions?.[0]||t},async requestWalletPaymentWatchPermission(e){const t=await this.requestExtensionPermissions({permissions:[{id:"wallet.payments.watch",grant:e?.grant||{}}]});return t.permissions?.[0]||t},async requestExtensionPermissions(e){if(this.bridge.public)throw new Error("Public pages cannot request permissions.");const t=Array.isArray(e.permissions)?e.permissions:[];if(!t.length)throw new Error("No permissions requested.");const s=!0===e.forcePrompt,a=t.map(e=>this.normalizePermissionRequest(e)),i=await this.checkExtensionPermissions(a.map(e=>({id:e.id,grant:e.grant}))),n=Array.isArray(i?.permissions)?i.permissions:[],o=[],r=[];for(const[e,t]of a.entries()){const a=n[e]||{};if(a.id&&a.id!==t.id)throw new Error("Permission check response did not match request.");if(a.approved&&!s){o.push(t.label),r.push({id:t.id,approved:!0,grant:a.grant||t.grant});continue}const i=a.grant?{...t,grant:a.grant}:t,l=await this.promptExtensionPermission(i);r.push({id:t.id,approved:!0,grant:l?.grant||t.grant})}return this.notifyApprovedPermissionUse(o),{permissions:r}},normalizePermissionRequest(e){const t=String(e?.id||""),s=e?.grant||{};if("wallet.pay_invoice_background"===t)return this.normalizeBackgroundPaymentPermission(s);if("wallet.payments.watch"===t)return this.normalizeWalletPaymentWatchPermission(s);throw new Error(`Unsupported permission request: ${t}.`)},normalizeBackgroundPaymentPermission(e){if(!this.hasBridgePermission("wallet.pay_invoice_background"))throw new Error("Extension is missing background payment permission.");const t=String(e.walletId||e.wallet_id||""),s=this.walletById(t);if(!s)throw new Error("Selected wallet is not available.");if("lightning-shared"===s.walletType)throw new Error("Background payments are not allowed from shared wallets.");const a={wallet_id:t,max_amount:this.positiveInteger(e.maxAmount||e.max_amount,1e3),destination_policy:this.backgroundPaymentDestinationPolicy(e.destinationPolicy||e.destination_policy)};if(!a.max_amount)throw new Error("Max payment amount must be greater than zero.");return{id:"wallet.pay_invoice_background",grant:a,label:`Background payments from ${s.name||t}`,wallet:s}},normalizeWalletPaymentWatchPermission(e){if(!this.hasBridgePermission("wallet.payments.watch"))throw new Error("Extension is missing wallet payment watch permission.");const t=String(e.walletId||e.wallet_id||""),s=this.walletById(t);if(!s)throw new Error("Selected wallet is not available.");return{id:"wallet.payments.watch",grant:{wallet_id:t},label:`Watch wallet payments for ${s.name||t}`,wallet:s}},walletById(e){return(this.g?.user?.wallets||[]).find(t=>t.id===e)||null},async checkExtensionPermissions(e){return await this.postExtensionPermission("check",{permissions:e},"Could not check extension permissions.")},promptExtensionPermission(e){if("wallet.pay_invoice_background"===e.id)return this.promptBackgroundPaymentPermission(e);if("wallet.payments.watch"===e.id)return this.promptWalletPaymentWatchPermission(e);throw new Error(`Unsupported permission request: ${e.id}.`)},promptBackgroundPaymentPermission(e){if(this.backgroundPaymentPrompt.show)throw new Error("Background payment prompt is already open.");return new Promise((t,s)=>{this.backgroundPaymentPrompt={extensionName:this.extensionName||this.bridge.extensionId||"This extension",form:{destinationPolicy:e.grant.destination_policy,maxAmount:e.grant.max_amount},reject:s,resolve:t,show:!0,walletId:e.grant.wallet_id,walletName:e.wallet.name||e.grant.wallet_id}})},async resolveBackgroundPaymentPrompt(e){const t=this.backgroundPaymentPrompt;if(t.show){if(!e)return this.backgroundPaymentPrompt=this.emptyBackgroundPaymentPrompt(),void t.reject?.(new Error("Background payment permission denied."));try{const e={wallet_id:t.walletId,max_amount:this.positiveInteger(t.form.maxAmount,0),destination_policy:this.backgroundPaymentDestinationPolicy(t.form.destinationPolicy)};if(!e.max_amount)throw new Error("Max payment amount must be greater than zero.");const s=await this.postExtensionPermission("background-payment",e,"Could not save permission.");this.backgroundPaymentPrompt=this.emptyBackgroundPaymentPrompt(),t.resolve?.(s)}catch(e){t.reject?.(e),this.backgroundPaymentPrompt=this.emptyBackgroundPaymentPrompt()}}},rejectBackgroundPaymentPrompt(e){const t=this.backgroundPaymentPrompt.reject;this.backgroundPaymentPrompt=this.emptyBackgroundPaymentPrompt(),t?.(new Error(e))},promptWalletPaymentWatchPermission(e){if(this.walletPaymentWatchPrompt.show)throw new Error("Wallet payment watch prompt is already open.");return new Promise((t,s)=>{this.walletPaymentWatchPrompt={extensionName:this.extensionName||this.bridge.extensionId||"This extension",reject:s,resolve:t,show:!0,walletId:e.grant.wallet_id,walletName:e.wallet.name||e.grant.wallet_id}})},async resolveWalletPaymentWatchPrompt(e){const t=this.walletPaymentWatchPrompt;if(t.show){if(!e)return this.walletPaymentWatchPrompt=this.emptyWalletPaymentWatchPrompt(),void t.reject?.(new Error("Wallet payment watch permission denied."));try{const e=await this.postExtensionPermission("wallet-payments-watch",{wallet_id:t.walletId},"Could not save permission.");this.walletPaymentWatchPrompt=this.emptyWalletPaymentWatchPrompt(),t.resolve?.(e)}catch(e){t.reject?.(e),this.walletPaymentWatchPrompt=this.emptyWalletPaymentWatchPrompt()}}},rejectWalletPaymentWatchPrompt(e){const t=this.walletPaymentWatchPrompt.reject;this.walletPaymentWatchPrompt=this.emptyWalletPaymentWatchPrompt(),t?.(new Error(e))},positiveInteger(e,t){const s=Number(e);return!Number.isFinite(s)||s<=0?t:Math.floor(s)},backgroundPaymentDestinationPolicy:e=>"external_allowed"===e?"external_allowed":"own_wallets_only",async postExtensionPermission(e,t,s){const a=await fetch(`/api/v1/extension/${encodeURIComponent(this.bridge.extensionId)}/permissions/${e}`,{method:"POST",headers:{"content-type":"application/json"},credentials:"same-origin",body:JSON.stringify(t)}),i=await a.text();let n={};if(i)try{n=JSON.parse(i)}catch(e){n={detail:i}}if(!a.ok)throw new Error(n?.detail||s);return n},notifyApprovedPermissionUse(e){const t=e.filter(Boolean).join(", ");t&&this.notify({level:"info",message:`Using approved permissions: ${t}.`})},requireCameraScanApproval(){return this.isCameraScanRemembered()?Promise.resolve():this.cameraPrompt.show?Promise.reject(new Error("Camera access prompt is already open.")):new Promise((e,t)=>{this.cameraPrompt={extensionName:this.extensionName||this.bridge.extensionId||"This extension",reject:t,resolve:e,show:!0}})},isCameraScanRemembered(){try{return"allow"===this.$q.localStorage.getItem(this.cameraPromptStorageKey())}catch(e){return!1}},rememberCameraScanApproval(){try{this.$q.localStorage.set(this.cameraPromptStorageKey(),"allow")}catch(e){}},resolveCameraPrompt(e){const t=this.cameraPrompt.resolve,s=this.cameraPrompt.reject;if(this.cameraPrompt=this.emptyCameraPrompt(),"allow_remember"===e)return this.rememberCameraScanApproval(),void t?.();"allow"!==e?s?.(new Error("Camera scan denied by user.")):t?.()},rejectCameraPrompt(e){const t=this.cameraPrompt.reject;this.cameraPrompt=this.emptyCameraPrompt(),t?.(new Error(e))},rememberPaymentHashes(e){if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(e=>this.rememberPaymentHashes(e));else for(const[t,s]of Object.entries(e))["paymentHash","payment_hash"].includes(t)&&this.isPaymentHash(s)&&this.allowedPaymentHashes.add(s),this.rememberPaymentHashes(s)},isPaymentHash:e=>"string"==typeof e&&/^[a-f0-9]{64}$/i.test(e),isWebsocketItemId:e=>"string"==typeof e&&/^[A-Za-z0-9][A-Za-z0-9:_-]{0,127}$/.test(e),websocketUrl(e){const t=new URL(window.location.href);return t.protocol="https:"===t.protocol?"wss:":"ws:",t.pathname=e,t.search="",t.hash="",t.toString()},sendBridgeEvent(e){this.bridgePort&&this.bridgePort.postMessage({type:"lnbits-extension:event",...e})},closePaymentSubscription(e){const t=this.paymentSubscriptions.get(e);if(t){this.paymentSubscriptions.delete(e);try{t.socket.close()}catch(e){}}},closePaymentSubscriptions(){for(const e of Array.from(this.paymentSubscriptions.keys()))this.closePaymentSubscription(e)},closeWebsocketSubscription(e){const t=this.websocketSubscriptions.get(e);if(t){this.websocketSubscriptions.delete(e);try{t.socket.close()}catch(e){}}},closeWebsocketSubscriptions(){for(const e of Array.from(this.websocketSubscriptions.keys()))this.closeWebsocketSubscription(e)},closeBridgePort(){this.closePaymentSubscriptions(),this.closeWebsocketSubscriptions(),this.bridgePort?.close(),this.bridgePort=null},subscribePayment(e){const t=String(e.subscriptionId||""),s=String(e.paymentHash||"");if(!t||!this.isPaymentHash(s))throw new Error("Invalid payment subscription.");if(!this.allowedPaymentHashes.has(s))throw new Error("Payment subscription is not allowed.");this.closePaymentSubscription(t);const a=new WebSocket(this.websocketUrl(`/api/v1/ws/${encodeURIComponent(s)}`));this.paymentSubscriptions.set(t,{paymentHash:s,socket:a}),a.addEventListener("message",e=>{let a=e.data;try{a=JSON.parse(e.data)}catch(e){}this.sendBridgeEvent({event:"payment.update",subscriptionId:t,paymentHash:s,data:a}),a&&"object"==typeof a&&(!1===a.pending||["success","settled","paid"].includes(String(a.status||"")))&&(this.sendBridgeEvent({event:"payment.settled",subscriptionId:t,paymentHash:s,data:a}),this.closePaymentSubscription(t))}),a.addEventListener("error",()=>{this.sendBridgeEvent({event:"payment.error",subscriptionId:t,paymentHash:s}),this.closePaymentSubscription(t)}),a.addEventListener("close",()=>{this.paymentSubscriptions.delete(t)})},subscribeWebsocket(e){if(!this.hasBridgePermission("websocket.subscribe"))throw new Error("Extension is missing websocket subscribe permission.");const t=String(e.subscriptionId||""),s=String(e.itemId||"");if(!t||t.length>128||!this.isWebsocketItemId(s))throw new Error("Invalid websocket subscription.");this.closeWebsocketSubscription(t);const a=new WebSocket(this.websocketUrl(`/api/v1/ext/ws/${encodeURIComponent(this.bridge.extensionId)}/${encodeURIComponent(s)}`));this.websocketSubscriptions.set(t,{itemId:s,socket:a}),a.addEventListener("message",e=>{let a=e.data;try{a=JSON.parse(e.data)}catch(e){}this.sendBridgeEvent({event:"websocket.message",subscriptionId:t,itemId:s,data:a})}),a.addEventListener("error",()=>{this.sendBridgeEvent({event:"websocket.error",subscriptionId:t,itemId:s}),this.closeWebsocketSubscription(t)}),a.addEventListener("close",()=>{this.websocketSubscriptions.delete(t)})},sendWebsocket(e){if(!this.hasBridgePermission("websocket.subscribe"))throw new Error("Extension is missing websocket subscribe permission.");const t=String(e.subscriptionId||"");if(!t)throw new Error("Invalid websocket subscription.");const s=this.websocketSubscriptions.get(t);if(!s)return;if(s.socket.readyState!==WebSocket.OPEN)return void(s.socket.readyState!==WebSocket.CLOSING&&s.socket.readyState!==WebSocket.CLOSED||this.closeWebsocketSubscription(t));const a="string"==typeof e.data?e.data:JSON.stringify(e.data??{});s.socket.send(a)},async handleBridgeRequest(e,t){if(e&&"lnbits-extension:request"===e.type)try{if("context"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:this.plainBridgeContext()});if("api"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.callApi(e)});if("ui.notify"===e.action)return this.notify(e),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("navigation.replace"===e.action)return await this.replaceExtensionRoute(e),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("navigation.open_new_tab"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.openNewTab(e)});if("storage.session.get"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:this.getBridgeSessionValue(e)});if("storage.session.set"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:this.setBridgeSessionValue(e)});if("ui.scan_qr"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.scanQrCode()});if("permissions.request"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.requestExtensionPermissions(e)});if("permissions.request_background_payment"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.requestBackgroundPaymentPermission(e)});if("permissions.request_wallet_payment_watch"===e.action)return void this.sendResponse(t,e.id,{ok:!0,data:await this.requestWalletPaymentWatchPermission(e)});if("payment.subscribe"===e.action)return this.subscribePayment(e),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("payment.unsubscribe"===e.action)return this.closePaymentSubscription(String(e.subscriptionId||"")),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("websocket.subscribe"===e.action)return this.subscribeWebsocket(e),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("websocket.unsubscribe"===e.action)return this.closeWebsocketSubscription(String(e.subscriptionId||"")),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});if("websocket.send"===e.action)return this.sendWebsocket(e),void this.sendResponse(t,e.id,{ok:!0,data:{ok:!0}});throw new Error("Unknown extension bridge action.")}catch(s){this.sendResponse(t,e.id,{ok:!1,error:s instanceof Error?s.message:String(s)})}},onWindowMessage(e){if(e.source!==this.extensionFrameWindow())return;const t=e.data;if(!t||"lnbits-extension:connect"!==t.type)return;const s=e.ports?.[0];s&&(this.closeBridgePort(),this.bridgePort=s,this.bridgePort.addEventListener("message",e=>{this.handleBridgeRequest(e.data,e=>{s.postMessage(e)})}),this.bridgePort.start(),this.bridgePort.postMessage({type:"lnbits-extension:connected",id:t.id}))}}};const quasarConfig={config:{loading:{spinner:Quasar.QSpinnerBars},table:{rowsPerPageOptions:[5,10,20,50,100,200,500,0]}}},DynamicComponent={async created(){const e=this.$route.path.split("/")[1],t=`/${e}/`,s=`/${e}/static/routes.json`;this.$router.getRoutes().some(e=>e.path===t)||this.$route.fullPath.startsWith("/extensions/builder/preview")||fetch(s).then(async e=>{if(!e.ok)throw new Error("No dynamic routes found");(await e.json()).forEach(e=>{console.log("Adding dynamic route:",e.path),window.router.addRoute({path:e.path,name:e.name,component:async()=>{if(await LNbits.utils.loadTemplate(e.template),e.i18n){const t=window.i18n?.global?.locale?.value??window.i18n?.global?.locale??window.g.locale??"en";await LNbits.utils.loadExtI18n(e.i18n,t)}return await LNbits.utils.loadScript(e.component),window[e.name]}}),window.router.push(this.$route.fullPath)})}).catch(()=>{let e=RENDERED_ROUTE;if(2===e.split("/").length&&(e+="/"),e!==this.$route.path)return console.log("Redirecting to non-vue route:",this.$route.fullPath),void(window.location=this.$route.fullPath)})}},routes=[{path:"/node",name:"Node",component:PageNode},{path:"/node/public",name:"NodePublic",component:PageNodePublic},{path:"/blockexplorer/:type(tx|address|block)?/:id?",name:"BlockExplorer",component:PageBlockExplorer,meta:{stableKey:!0}},{path:"/payments",name:"Payments",component:PagePayments},{path:"/audit",name:"Audit",component:PageAudit},{path:"/wallet",redirect:e=>{const t=window.g?.lastActiveWallet||window.g?.user?.wallets[0].id;return`/wallet/${e.query.wal||t||"default"}`}},{path:"/wallet/:id",name:"Wallet",component:PageWallet},{path:"/wallets",name:"Wallets",component:PageWallets},{path:"/users",name:"Users",component:PageUsers},{path:"/admin/extensions/wasm",name:"AdminWasmRuntime",component:PageAdmin},{path:"/admin/extensions/wasm/limits",name:"AdminWasmLimitConfig",component:PageAdmin},{path:"/admin/extensions/wasm/limits/:extId",name:"AdminWasmLimitConfigDetail",component:PageAdmin},{path:"/admin/extensions/wasm/:extId",name:"AdminWasmRuntimeDetail",component:PageAdmin},{path:"/admin",name:"Admin",component:PageAdmin},{path:"/account",name:"Account",component:PageAccount},{path:"/extensions/builder",name:"ExtensionsBuilder",component:PageExtensionBuilder},{path:"/extensions/builder/preview",name:"ExtensionsBuilderPreview",component:PageExtensionBuilderPreview},{path:"/extensions",name:"Extensions",component:PageExtensions},{path:"/first_install",name:"FirstInstall",component:PageFirstInstall},{path:"/",name:"PageHome",component:PageHome},{path:"/error",name:"PageError",component:PageError},{path:"/ext/:extId",name:"WasmExtensionRoot",component:window.WasmExtensionComponent},{path:"/ext/:extId/:pathMatch(.*)*",name:"WasmExtension",component:window.WasmExtensionComponent},{path:"/:pathMatch(.*)*",name:"DynamicComponent",component:DynamicComponent}];window.router=VueRouter.createRouter({history:VueRouter.createWebHistory(),routes:routes}),window.LOCALE=window.g.locale,window.i18n=new VueI18n.createI18n({locale:window.g.locale,fallbackLocale:"en",messages:window.localisation}),function(){let e=!1,t=null;Vue.watch(()=>window.i18n.global.locale,async(s,a)=>{!e&&LNbits.utils._extI18nDirs.size&&(t=s,e=!0,window.i18n.global.locale=a,e=!1,await Promise.all([...LNbits.utils._extI18nDirs].map(e=>LNbits.utils.loadExtI18n(e,s))),t===s&&(e=!0,window.i18n.global.locale=s,e=!1))},{flush:"sync"})}(),window.app.mixin({data:()=>({api:window._lnbitsApi,utils:window._lnbitsUtils,g:window.g}),methods:{copyText:window._lnbitsUtils.copyText,formatBalance:window._lnbitsUtils.formatBalance}}),window.app.use(VueQrcodeReader),window.app.use(Quasar,quasarConfig),window.app.use(window.i18n),window.app.use(window.router),window.app.mount("#vue"); \ No newline at end of file diff --git a/lnbits/static/bundle.min.css b/lnbits/static/bundle.min.css index 4bcf0a299..01ca75c78 100644 --- a/lnbits/static/bundle.min.css +++ b/lnbits/static/bundle.min.css @@ -1 +1 @@ -*,:after,:before{box-sizing:inherit;-webkit-tap-highlight-color:transparent;-moz-tap-highlight-color:transparent}#q-app,body,html{width:100%;direction:ltr}body.platform-ios.within-iframe,body.platform-ios.within-iframe #q-app{width:100px;min-width:100%}body,html{margin:0;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}img{border-style:none}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;font-family:inherit;margin:0}optgroup{font-weight:700}button,input,select{overflow:visible;text-transform:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button:-moz-focusring,input:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.q-icon{line-height:1;width:1em;height:1em;flex-shrink:0;letter-spacing:normal;text-transform:none;white-space:nowrap;word-wrap:normal;direction:ltr;text-align:center;position:relative;box-sizing:content-box;fill:currentColor}.q-icon:after,.q-icon:before{width:100%;height:100%;display:flex!important;align-items:center;justify-content:center}.q-icon>img,.q-icon>svg{width:100%;height:100%}.q-icon>div{box-sizing:border-box}.material-icons,.material-icons-outlined,.material-icons-round,.material-icons-sharp,.material-symbols-outlined,.material-symbols-rounded,.material-symbols-sharp,.q-icon{-webkit-user-select:none;user-select:none;cursor:inherit;font-size:inherit;display:inline-flex;align-items:center;justify-content:center;vertical-align:middle}.q-panel{height:100%;width:100%}.q-panel>div{height:100%;width:100%}.q-panel-parent{overflow:hidden;position:relative}.q-loading-bar{position:fixed;z-index:9998;transition:transform .5s cubic-bezier(0, 0, .2, 1),opacity .5s;background:#f44336}.q-loading-bar--top{left:0;right:0;top:0;width:100%}.q-loading-bar--bottom{left:0;right:0;bottom:0;width:100%}.q-loading-bar--right{top:0;bottom:0;right:0;height:100%}.q-loading-bar--left{top:0;bottom:0;left:0;height:100%}.q-avatar{position:relative;vertical-align:middle;display:inline-block;border-radius:50%;font-size:48px;height:1em;width:1em}.q-avatar__content{font-size:.5em;line-height:.5em}.q-avatar img:not(.q-icon):not(.q-img__image),.q-avatar__content{border-radius:inherit;height:inherit;width:inherit}.q-avatar--square{border-radius:0}.q-badge{background-color:var(--q-primary);color:#fff;padding:2px 6px;border-radius:4px;font-size:12px;line-height:1;min-height:12px;font-weight:400;vertical-align:baseline}.q-badge--single-line{white-space:nowrap}.q-badge--multi-line{word-break:break-all;word-wrap:break-word}.q-badge--floating{position:absolute;top:-4px;right:-3px;cursor:inherit}.q-badge--transparent{opacity:.8}.q-badge--outline{background-color:transparent;border:1px solid currentColor}.q-badge--rounded{border-radius:1em}.q-banner{min-height:54px;padding:8px 16px;background:#fff}.q-banner--top-padding{padding-top:14px}.q-banner__avatar{min-width:1px!important}.q-banner__avatar>.q-avatar{font-size:46px}.q-banner__avatar>.q-icon{font-size:40px}.q-banner__avatar:not(:empty)+.q-banner__content{padding-left:16px}.q-banner__actions.col-auto{padding-left:16px}.q-banner__actions.col-all .q-btn-item{margin:4px 0 0 4px}.q-banner--dense{min-height:32px;padding:8px}.q-banner--dense.q-banner--top-padding{padding-top:12px}.q-banner--dense .q-banner__avatar>.q-avatar,.q-banner--dense .q-banner__avatar>.q-icon{font-size:28px}.q-banner--dense .q-banner__avatar:not(:empty)+.q-banner__content{padding-left:8px}.q-banner--dense .q-banner__actions.col-auto{padding-left:8px}.q-bar{background:rgba(0,0,0,.2)}.q-bar>.q-icon{margin-left:2px}.q-bar>div,.q-bar>div+.q-icon{margin-left:8px}.q-bar>.q-btn{margin-left:2px}.q-bar>.q-btn:first-child,.q-bar>.q-icon:first-child,.q-bar>div:first-child{margin-left:0}.q-bar--standard{padding:0 12px;height:32px;font-size:18px}.q-bar--standard>div{font-size:16px}.q-bar--standard .q-btn{font-size:11px}.q-bar--dense{padding:0 8px;height:24px;font-size:14px}.q-bar--dense .q-btn{font-size:8px}.q-bar--dark{background:rgba(255,255,255,.15)}.q-breadcrumbs__el{color:inherit}.q-breadcrumbs__el-icon{font-size:125%}.q-breadcrumbs__el-icon--with-label{margin-right:8px}[dir=rtl] .q-breadcrumbs__separator .q-icon{transform:scaleX(-1)}.q-btn{display:inline-flex;flex-direction:column;align-items:stretch;position:relative;outline:0;border:0;vertical-align:middle;font-size:14px;line-height:1.715em;text-decoration:none;color:inherit;background:0 0;font-weight:500;text-transform:uppercase;text-align:center;width:auto;height:auto;cursor:default;padding:4px 16px;min-height:2.572em}.q-btn .q-icon,.q-btn .q-spinner{font-size:1.715em}.q-btn.disabled{opacity:.7!important}.q-btn:before{content:"";display:block;position:absolute;left:0;right:0;top:0;bottom:0;border-radius:inherit;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-btn--actionable{cursor:pointer}.q-btn--actionable.q-btn--standard:before{transition:box-shadow .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--actionable.q-btn--standard.q-btn--active:before,.q-btn--actionable.q-btn--standard:active:before{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px rgba(0,0,0,.14),0 1px 14px rgba(0,0,0,.12)}.q-btn--no-uppercase{text-transform:none}.q-btn--rectangle{border-radius:3px}.q-btn--outline{background:0 0!important}.q-btn--outline:before{border:1px solid currentColor}.q-btn--push{border-radius:7px}.q-btn--push:before{border-bottom:3px solid rgba(0,0,0,.15)}.q-btn--push.q-btn--actionable{transition:transform .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--push.q-btn--actionable:before{transition:border-width .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--push.q-btn--actionable.q-btn--active,.q-btn--push.q-btn--actionable:active{transform:translateY(2px)}.q-btn--push.q-btn--actionable.q-btn--active:before,.q-btn--push.q-btn--actionable:active:before{border-bottom-width:0}.q-btn--rounded{border-radius:28px}.q-btn--round{border-radius:50%;padding:0;min-width:3em;min-height:3em}.q-btn--square{border-radius:0}.q-btn--flat:before,.q-btn--outline:before,.q-btn--unelevated:before{box-shadow:none}.q-btn--dense{padding:.285em;min-height:2em}.q-btn--dense.q-btn--round{padding:0;min-height:2.4em;min-width:2.4em}.q-btn--dense .on-left{margin-right:6px}.q-btn--dense .on-right{margin-left:6px}.q-btn--fab .q-icon,.q-btn--fab-mini .q-icon{font-size:24px}.q-btn--fab{padding:16px;min-height:56px;min-width:56px}.q-btn--fab .q-icon{margin:auto}.q-btn--fab-mini{padding:8px;min-height:40px;min-width:40px}.q-btn__content{transition:opacity .3s;z-index:0}.q-btn__content--hidden{opacity:0;pointer-events:none}.q-btn__progress{border-radius:inherit;z-index:0}.q-btn__progress-indicator{z-index:-1;transform:translateX(-100%);background:rgba(255,255,255,.25)}.q-btn__progress--dark .q-btn__progress-indicator{background:rgba(0,0,0,.2)}.q-btn--flat .q-btn__progress-indicator,.q-btn--outline .q-btn__progress-indicator{opacity:.2;background:currentColor}.q-btn-dropdown--split .q-btn-dropdown__arrow-container{padding:0 4px}.q-btn-dropdown--split .q-btn-dropdown__arrow-container.q-btn--outline{border-left:1px solid currentColor}.q-btn-dropdown--split .q-btn-dropdown__arrow-container:not(.q-btn--outline){border-left:1px solid rgba(255,255,255,.3)}.q-btn-dropdown--simple *+.q-btn-dropdown__arrow{margin-left:8px}.q-btn-dropdown__arrow{transition:transform .28s}.q-btn-dropdown--current{flex-grow:1}.q-btn-group{border-radius:3px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);vertical-align:middle}.q-btn-group>.q-btn-item{border-radius:inherit;align-self:stretch}.q-btn-group>.q-btn-item:before{box-shadow:none}.q-btn-group>.q-btn-item .q-badge--floating{right:0}.q-btn-group>.q-btn-group{box-shadow:none}.q-btn-group>.q-btn-group:first-child>.q-btn:first-child{border-top-left-radius:inherit;border-bottom-left-radius:inherit}.q-btn-group>.q-btn-group:last-child>.q-btn:last-child{border-top-right-radius:inherit;border-bottom-right-radius:inherit}.q-btn-group>.q-btn-group:not(:first-child)>.q-btn:first-child:before{border-left:0}.q-btn-group>.q-btn-group:not(:last-child)>.q-btn:last-child:before{border-right:0}.q-btn-group>.q-btn-item:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.q-btn-group>.q-btn-item:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.q-btn-group>.q-btn-item.q-btn--standard:before{z-index:-1}.q-btn-group--push{border-radius:7px}.q-btn-group--push>.q-btn--push.q-btn--actionable{transform:none}.q-btn-group--push>.q-btn--push.q-btn--actionable .q-btn__content{transition:margin-top .3s cubic-bezier(.25, .8, .5, 1),margin-bottom .3s cubic-bezier(.25, .8, .5, 1)}.q-btn-group--push>.q-btn--push.q-btn--actionable.q-btn--active .q-btn__content,.q-btn-group--push>.q-btn--push.q-btn--actionable:active .q-btn__content{margin-top:2px;margin-bottom:-2px}.q-btn-group--rounded{border-radius:28px}.q-btn-group--square{border-radius:0}.q-btn-group--flat,.q-btn-group--outline,.q-btn-group--unelevated{box-shadow:none}.q-btn-group--outline>.q-separator{display:none}.q-btn-group--outline>.q-btn-item+.q-btn-item:before{border-left:0}.q-btn-group--outline>.q-btn-item:not(:last-child):before{border-right:0}.q-btn-group--stretch{align-self:stretch;border-radius:0}.q-btn-group--glossy>.q-btn-item{background-image:linear-gradient(to bottom,rgba(255,255,255,.3),rgba(255,255,255,0) 50%,rgba(0,0,0,.12) 51%,rgba(0,0,0,.04))!important}.q-btn-group--spread>.q-btn-group{display:flex!important}.q-btn-group--spread>.q-btn-group>.q-btn-item:not(.q-btn-dropdown__arrow-container),.q-btn-group--spread>.q-btn-item{width:auto;min-width:0;max-width:100%;flex:10000 1 0%}.q-btn-toggle{position:relative}.q-card{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;vertical-align:top;background:#fff;position:relative}.q-card>div:not(.q--avoid-card-border),.q-card>img:not(.q--avoid-card-border){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.q-card>div:nth-child(1of:not(.q--avoid-card-border)),.q-card>img:nth-child(1of:not(.q--avoid-card-border)){border-top:0;border-top-left-radius:inherit;border-top-right-radius:inherit}.q-card>div:nth-last-child(1of:not(.q--avoid-card-border)),.q-card>img:nth-last-child(1of:not(.q--avoid-card-border)){border-bottom:0;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.q-card>div:not(.q--avoid-card-border){border-left:0;border-right:0;box-shadow:none}.q-card--bordered{border:1px solid rgba(0,0,0,.12)}.q-card--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-card__section{position:relative}.q-card__section--vert{padding:16px}.q-card__section--horiz>div:not(.q--avoid-card-border),.q-card__section--horiz>img:not(.q--avoid-card-border){border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0}.q-card__section--horiz>div:nth-child(1of:not(.q--avoid-card-border)),.q-card__section--horiz>img:nth-child(1of:not(.q--avoid-card-border)){border-top-left-radius:inherit;border-bottom-left-radius:inherit}.q-card__section--horiz>div:nth-last-child(1of:not(.q--avoid-card-border)),.q-card__section--horiz>img:nth-last-child(1of:not(.q--avoid-card-border)){border-top-right-radius:inherit;border-bottom-right-radius:inherit}.q-card__section--horiz>div:not(.q--avoid-card-border){border-top:0;border-bottom:0;box-shadow:none}.q-card__actions{padding:8px;align-items:center}.q-card__actions .q-btn--rectangle{padding:0 8px}.q-card__actions--horiz>.q-btn-group+.q-btn-item,.q-card__actions--horiz>.q-btn-item+.q-btn-group,.q-card__actions--horiz>.q-btn-item+.q-btn-item{margin-left:8px}.q-card__actions--vert>.q-btn-item.q-btn--round{align-self:center}.q-card__actions--vert>.q-btn-group+.q-btn-item,.q-card__actions--vert>.q-btn-item+.q-btn-group,.q-card__actions--vert>.q-btn-item+.q-btn-item{margin-top:4px}.q-card__actions--vert>.q-btn-group>.q-btn-item{flex-grow:1}.q-card>img{display:block;width:100%;max-width:100%;border:0}.q-carousel{background-color:#fff;height:400px}.q-carousel__slide{min-height:100%;background-size:cover;background-position:50%}.q-carousel .q-carousel--padding,.q-carousel__slide{padding:16px}.q-carousel__slides-container{height:100%}.q-carousel__control{color:#fff}.q-carousel__arrow{pointer-events:none}.q-carousel__arrow .q-icon{font-size:28px}.q-carousel__arrow .q-btn{pointer-events:all}.q-carousel__next-arrow--horizontal,.q-carousel__prev-arrow--horizontal{top:16px;bottom:16px}.q-carousel__prev-arrow--horizontal{left:16px}.q-carousel__next-arrow--horizontal{right:16px}.q-carousel__next-arrow--vertical,.q-carousel__prev-arrow--vertical{left:16px;right:16px}.q-carousel__prev-arrow--vertical{top:16px}.q-carousel__next-arrow--vertical{bottom:16px}.q-carousel__navigation--bottom,.q-carousel__navigation--top{left:16px;right:16px;overflow-x:auto;overflow-y:hidden}.q-carousel__navigation--top{top:16px}.q-carousel__navigation--bottom{bottom:16px}.q-carousel__navigation--left,.q-carousel__navigation--right{top:16px;bottom:16px;overflow-x:hidden;overflow-y:auto}.q-carousel__navigation--left>.q-carousel__navigation-inner,.q-carousel__navigation--right>.q-carousel__navigation-inner{flex-direction:column}.q-carousel__navigation--left{left:16px}.q-carousel__navigation--right{right:16px}.q-carousel__navigation-inner{flex:1 1 auto}.q-carousel__navigation .q-btn{margin:6px 4px;padding:5px}.q-carousel__navigation-icon--inactive{opacity:.7}.q-carousel .q-carousel__thumbnail{margin:2px;height:50px;width:auto;display:inline-block;cursor:pointer;border:1px solid transparent;border-radius:4px;vertical-align:middle;opacity:.7;transition:opacity .3s}.q-carousel .q-carousel__thumbnail--active,.q-carousel .q-carousel__thumbnail:hover{opacity:1}.q-carousel .q-carousel__thumbnail--active{border-color:currentColor;cursor:default}.q-carousel--arrows-vertical .q-carousel--padding,.q-carousel--arrows-vertical.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-top .q-carousel--padding,.q-carousel--navigation-top.q-carousel--with-padding .q-carousel__slide{padding-top:60px}.q-carousel--arrows-vertical .q-carousel--padding,.q-carousel--arrows-vertical.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-bottom .q-carousel--padding,.q-carousel--navigation-bottom.q-carousel--with-padding .q-carousel__slide{padding-bottom:60px}.q-carousel--arrows-horizontal .q-carousel--padding,.q-carousel--arrows-horizontal.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-left .q-carousel--padding,.q-carousel--navigation-left.q-carousel--with-padding .q-carousel__slide{padding-left:60px}.q-carousel--arrows-horizontal .q-carousel--padding,.q-carousel--arrows-horizontal.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-right .q-carousel--padding,.q-carousel--navigation-right.q-carousel--with-padding .q-carousel__slide{padding-right:60px}.q-carousel.fullscreen{height:100%}.q-message-name{font-size:small}.q-message-label{margin:24px 0;text-align:center;font-size:small}.q-message-stamp{color:inherit;margin-top:4px;opacity:.6;display:none;font-size:small}.q-message-avatar{border-radius:50%;width:48px;height:48px;min-width:48px}.q-message{margin-bottom:8px}.q-message:first-child .q-message-label{margin-top:0}.q-message-avatar--received{margin-right:8px}.q-message-text--received{color:#81c784;border-radius:4px 4px 4px 0}.q-message-text--received:last-child:before{right:100%;border-right:0 solid transparent;border-left:8px solid transparent;border-bottom:8px solid currentColor}.q-message-text-content--received{color:#000}.q-message-name--sent{text-align:right}.q-message-avatar--sent{margin-left:8px}.q-message-container--sent{flex-direction:row-reverse}.q-message-text--sent{color:#e0e0e0;border-radius:4px 4px 0 4px}.q-message-text--sent:last-child:before{left:100%;border-left:0 solid transparent;border-right:8px solid transparent;border-bottom:8px solid currentColor}.q-message-text-content--sent{color:#000}.q-message-text{background:currentColor;padding:8px;line-height:1.2;word-break:break-word;position:relative}.q-message-text+.q-message-text{margin-top:3px}.q-message-text:last-child{min-height:48px}.q-message-text:last-child .q-message-stamp{display:block}.q-message-text:last-child:before{content:"";position:absolute;bottom:0;width:0;height:0}.q-checkbox{vertical-align:middle}.q-checkbox__native{width:1px;height:1px}.q-checkbox__bg,.q-checkbox__icon-container{-webkit-user-select:none;user-select:none}.q-checkbox__bg{top:25%;left:25%;width:50%;height:50%;border:2px solid currentColor;border-radius:2px;transition:background .22s cubic-bezier(0, 0, .2, 1) 0s;-webkit-print-color-adjust:exact}.q-checkbox__icon{color:currentColor;font-size:.5em}.q-checkbox__svg{color:#fff}.q-checkbox__truthy{stroke:currentColor;stroke-width:3.12px;stroke-dashoffset:29.78334;stroke-dasharray:29.78334}.q-checkbox__indet{fill:currentColor;transform-origin:50% 50%;transform:rotate(-280deg) scale(0)}.q-checkbox__inner{font-size:40px;width:1em;min-width:1em;height:1em;outline:0;border-radius:50%;color:rgba(0,0,0,.54)}.q-checkbox__inner--indet,.q-checkbox__inner--truthy{color:var(--q-primary)}.q-checkbox__inner--indet .q-checkbox__bg,.q-checkbox__inner--truthy .q-checkbox__bg{background:currentColor}.q-checkbox__inner--truthy path{stroke-dashoffset:0;transition:stroke-dashoffset .18s cubic-bezier(.4, 0, .6, 1) 0s}.q-checkbox__inner--indet .q-checkbox__indet{transform:rotate(0) scale(1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}.q-checkbox.disabled{opacity:.75!important}.q-checkbox--dark .q-checkbox__inner{color:rgba(255,255,255,.7)}.q-checkbox--dark .q-checkbox__inner:before{opacity:.32!important}.q-checkbox--dark .q-checkbox__inner--indet,.q-checkbox--dark .q-checkbox__inner--truthy{color:var(--q-primary)}.q-checkbox--dense .q-checkbox__inner{width:.5em;min-width:.5em;height:.5em}.q-checkbox--dense .q-checkbox__bg{left:5%;top:5%;width:90%;height:90%}.q-checkbox--dense .q-checkbox__label{padding-left:.5em}.q-checkbox--dense.reverse .q-checkbox__label{padding-left:0;padding-right:.5em}body.desktop .q-checkbox:not(.disabled) .q-checkbox__inner:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1)}body.desktop .q-checkbox:not(.disabled):focus .q-checkbox__inner:before,body.desktop .q-checkbox:not(.disabled):hover .q-checkbox__inner:before{transform:scale3d(1,1,1)}body.desktop .q-checkbox--dense:not(.disabled):focus .q-checkbox__inner:before,body.desktop .q-checkbox--dense:not(.disabled):hover .q-checkbox__inner:before{transform:scale3d(1.4,1.4,1)}.q-chip{vertical-align:middle;border-radius:16px;outline:0;position:relative;height:2em;max-width:100%;margin:4px;background:#e0e0e0;color:rgba(0,0,0,.87);font-size:14px;padding:.5em .9em}.q-chip--colored .q-chip__icon,.q-chip--dark .q-chip__icon{color:inherit}.q-chip .q-avatar{font-size:2em;margin-left:-.45em;margin-right:.2em;border-radius:16px}.q-chip--outline{background:0 0!important;border:1px solid currentColor}.q-chip--outline .q-avatar{margin-left:calc(-.45em - 1px)}.q-chip--selected .q-avatar{display:none}.q-chip__icon{color:rgba(0,0,0,.54);font-size:1.5em;margin:-.2em}.q-chip__icon--left{margin-right:.2em}.q-chip__icon--right{margin-left:.2em}.q-chip__icon--remove{margin-left:.1em;margin-right:-.5em;opacity:.6;outline:0}.q-chip__icon--remove:focus,.q-chip__icon--remove:hover{opacity:1}.q-chip__content{white-space:nowrap}.q-chip--dense{border-radius:12px;padding:0 .4em;height:1.5em}.q-chip--dense .q-avatar{font-size:1.5em;margin-left:-.27em;margin-right:.1em;border-radius:12px}.q-chip--dense .q-chip__icon{font-size:1.25em}.q-chip--dense .q-chip__icon--left{margin-right:.195em}.q-chip--dense .q-chip__icon--remove{margin-right:-.25em}.q-chip--square{border-radius:4px}.q-chip--square .q-avatar{border-radius:3px 0 0 3px}body.desktop .q-chip--clickable:focus{box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}body.desktop.body--dark .q-chip--clickable:focus{box-shadow:0 1px 3px rgba(255,255,255,.2),0 1px 1px rgba(255,255,255,.14),0 2px 1px -1px rgba(255,255,255,.12)}.q-circular-progress{display:inline-block;position:relative;vertical-align:middle;width:1em;height:1em;line-height:1}.q-circular-progress.q-focusable{border-radius:50%}.q-circular-progress__svg{width:100%;height:100%}.q-circular-progress__text{font-size:.25em}.q-circular-progress--indeterminate .q-circular-progress__svg{transform-origin:50% 50%;animation:q-spin 2s linear infinite}.q-circular-progress--indeterminate .q-circular-progress__circle{stroke-dasharray:1 400;stroke-dashoffset:0;animation:q-circular-progress-circle 1.5s ease-in-out infinite}@keyframes q-circular-progress-circle{0%{stroke-dasharray:1,400;stroke-dashoffset:0}50%{stroke-dasharray:400,400;stroke-dashoffset:-100}100%{stroke-dasharray:400,400;stroke-dashoffset:-300}}.q-color-picker{overflow:hidden;background:#fff;max-width:350px;vertical-align:top;min-width:180px;border-radius:4px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-color-picker .q-tab{padding:0!important}.q-color-picker--bordered{border:1px solid rgba(0,0,0,.12)}.q-color-picker__header-tabs{height:32px}.q-color-picker__header-banner{height:36px}.q-color-picker__header input{line-height:24px;border:0}.q-color-picker__header .q-tab{min-height:32px!important;height:32px!important}.q-color-picker__header .q-tab--inactive{background:linear-gradient(to top,rgba(0,0,0,.3) 0,rgba(0,0,0,.15) 25%,rgba(0,0,0,.1))}.q-color-picker__error-icon{bottom:2px;right:2px;font-size:24px;opacity:0;transition:opacity .3s ease-in}.q-color-picker__header-content{position:relative;background:#fff}.q-color-picker__header-content--light{color:#000}.q-color-picker__header-content--dark{color:#fff}.q-color-picker__header-content--dark .q-tab--inactive:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(255,255,255,.2)}.q-color-picker__header-banner{height:36px}.q-color-picker__header-bg{background:#fff;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAH0lEQVQoU2NkYGAwZkAFZ5G5jPRRgOYEVDeB3EBjBQBOZwTVugIGyAAAAABJRU5ErkJggg==")!important}.q-color-picker__footer{height:36px}.q-color-picker__footer .q-tab{min-height:36px!important;height:36px!important}.q-color-picker__footer .q-tab--inactive{background:linear-gradient(to bottom,rgba(0,0,0,.3) 0,rgba(0,0,0,.15) 25%,rgba(0,0,0,.1))}.q-color-picker__spectrum{width:100%;height:100%}.q-color-picker__spectrum-tab{padding:0!important}.q-color-picker__spectrum-white{background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.q-color-picker__spectrum-black{background:linear-gradient(to top,#000,rgba(0,0,0,0))}.q-color-picker__spectrum-circle{width:10px;height:10px;box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;transform:translate(-5px,-5px)}.q-color-picker__hue .q-slider__track{background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)!important;opacity:1}.q-color-picker__alpha .q-slider__track-container{padding-top:0}.q-color-picker__alpha .q-slider__track:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:linear-gradient(90deg,rgba(255,255,255,0),#757575)}.q-color-picker__sliders{padding:0 16px}.q-color-picker__sliders .q-slider__thumb{color:#424242}.q-color-picker__sliders .q-slider__thumb path{stroke-width:2px;fill:transparent}.q-color-picker__sliders .q-slider--active path{stroke-width:3px}.q-color-picker__tune-tab .q-slider{margin-left:18px;margin-right:18px}.q-color-picker__tune-tab input{font-size:11px;border:1px solid #e0e0e0;border-radius:4px;width:3.5em}.q-color-picker__palette-tab{padding:0!important}.q-color-picker__palette-rows--editable .q-color-picker__cube{cursor:pointer}.q-color-picker__cube{padding-bottom:10%;width:10%!important}.q-color-picker input{color:inherit;background:0 0;outline:0;text-align:center}.q-color-picker .q-tabs{overflow:hidden}.q-color-picker .q-tab--active{box-shadow:0 0 14px 3px rgba(0,0,0,.2)}.q-color-picker .q-tab--active .q-focus-helper{display:none}.q-color-picker .q-tab__indicator{display:none}.q-color-picker .q-tab-panels{background:inherit}.q-color-picker--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-color-picker--dark .q-color-picker__tune-tab input{border:1px solid rgba(255,255,255,.3)}.q-color-picker--dark .q-slider__thumb{color:#fafafa}.q-date{display:inline-flex;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff;width:290px;min-width:290px;max-width:100%}.q-date--bordered{border:1px solid rgba(0,0,0,.12)}.q-date__header{border-top-left-radius:inherit;color:#fff;background-color:var(--q-primary);padding:16px}.q-date__actions{padding:0 16px 16px}.q-date__content,.q-date__main{outline:0}.q-date__content .q-btn{font-weight:400}.q-date__header-link{opacity:.64;outline:0;transition:opacity .3s ease-out}.q-date__header-link--active,.q-date__header-link:focus,.q-date__header-link:hover{opacity:1}.q-date__header-subtitle{font-size:14px;line-height:1.75;letter-spacing:.00938em}.q-date__header-title-label{font-size:24px;line-height:1.2;letter-spacing:.00735em}.q-date__view{height:100%;width:100%;min-height:290px;padding:16px}.q-date__navigation{height:12.5%}.q-date__navigation>div:first-child{width:8%;min-width:24px;justify-content:flex-end}.q-date__navigation>div:last-child{width:8%;min-width:24px;justify-content:flex-start}.q-date__calendar-weekdays{height:12.5%}.q-date__calendar-weekdays>div{opacity:.38;font-size:12px}.q-date__calendar-item{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;width:14.285%!important;height:12.5%!important;position:relative;padding:1px}.q-date__calendar-item:after{content:"";position:absolute;pointer-events:none;top:1px;right:0;bottom:1px;left:0;border-style:dashed;border-color:transparent;border-width:1px}.q-date__calendar-item button,.q-date__calendar-item>div{width:30px;height:30px;border-radius:50%}.q-date__calendar-item>div{line-height:30px;text-align:center}.q-date__calendar-item>button{line-height:22px}.q-date__calendar-item--out{opacity:.18}.q-date__calendar-item--fill{visibility:hidden}.q-date__range-from:before,.q-date__range-to:before,.q-date__range:before{content:"";background-color:currentColor;position:absolute;top:1px;bottom:1px;left:0;right:0;opacity:.3}.q-date__range-from:nth-child(7n-6):before,.q-date__range-to:nth-child(7n-6):before,.q-date__range:nth-child(7n-6):before{border-top-left-radius:0;border-bottom-left-radius:0}.q-date__range-from:nth-child(7n):before,.q-date__range-to:nth-child(7n):before,.q-date__range:nth-child(7n):before{border-top-right-radius:0;border-bottom-right-radius:0}.q-date__range-from:before{left:50%}.q-date__range-to:before{right:50%}.q-date__edit-range:after{border-color:currentColor transparent}.q-date__edit-range:nth-child(7n-6):after{border-top-left-radius:0;border-bottom-left-radius:0}.q-date__edit-range:nth-child(7n):after{border-top-right-radius:0;border-bottom-right-radius:0}.q-date__edit-range-from-to:after,.q-date__edit-range-from:after{left:4px;border-left-color:currentColor;border-top-color:currentColor;border-bottom-color:currentColor;border-top-left-radius:28px;border-bottom-left-radius:28px}.q-date__edit-range-from-to:after,.q-date__edit-range-to:after{right:4px;border-right-color:currentColor;border-top-color:currentColor;border-bottom-color:currentColor;border-top-right-radius:28px;border-bottom-right-radius:28px}.q-date__calendar-days-container{height:75%;min-height:192px}.q-date__calendar-days>div{height:16.66%!important}.q-date__event{position:absolute;bottom:2px;left:50%;height:5px;width:8px;border-radius:5px;background-color:var(--q-secondary);transform:translate3d(-50%,0,0)}.q-date__today{box-shadow:0 0 1px 0 currentColor}.q-date__years-content{padding:0 8px}.q-date__months-item,.q-date__years-item{flex:0 0 33.3333%}.q-date--readonly .q-date__content,.q-date--readonly .q-date__header,.q-date.disabled .q-date__content,.q-date.disabled .q-date__header{pointer-events:none}.q-date--readonly .q-date__navigation{display:none}.q-date--portrait{flex-direction:column}.q-date--portrait-standard .q-date__content{height:calc(100% - 86px)}.q-date--portrait-standard .q-date__header{border-top-right-radius:inherit;height:86px}.q-date--portrait-standard .q-date__header-title{align-items:center;height:30px}.q-date--portrait-minimal .q-date__content{height:100%}.q-date--landscape{flex-direction:row;align-items:stretch;min-width:420px}.q-date--landscape>div{display:flex;flex-direction:column}.q-date--landscape .q-date__content{height:100%}.q-date--landscape-standard{min-width:420px}.q-date--landscape-standard .q-date__header{border-bottom-left-radius:inherit;min-width:110px;width:110px}.q-date--landscape-standard .q-date__header-title{flex-direction:column}.q-date--landscape-standard .q-date__header-today{margin-top:12px;margin-left:-8px}.q-date--landscape-minimal{width:310px}.q-date--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12);border-color:rgba(255,255,255,.28)}.q-dialog__title{font-size:1.25rem;font-weight:500;line-height:1.6;letter-spacing:.0125em}.q-dialog__progress{font-size:4rem}.q-dialog__inner{outline:0}.q-dialog__inner>div{pointer-events:all;overflow:auto;-webkit-overflow-scrolling:touch;will-change:scroll-position;border-radius:4px}.q-dialog__inner--square>div{border-radius:0!important}.q-dialog__inner>.q-card>.q-card__actions .q-btn--rectangle{min-width:64px}.q-dialog__inner--minimized{padding:24px}.q-dialog__inner--minimized>div{max-height:calc(100vh - 48px)}.q-dialog__inner--maximized>div{height:100%;width:100%;max-height:100vh;max-width:100vw;border-radius:0!important;top:0!important;left:0!important}.q-dialog__inner--bottom,.q-dialog__inner--top{padding-top:0!important;padding-bottom:0!important}.q-dialog__inner--left,.q-dialog__inner--right{padding-right:0!important;padding-left:0!important}.q-dialog__inner--left:not(.q-dialog__inner--animating)>div,.q-dialog__inner--top:not(.q-dialog__inner--animating)>div{border-top-left-radius:0}.q-dialog__inner--right:not(.q-dialog__inner--animating)>div,.q-dialog__inner--top:not(.q-dialog__inner--animating)>div{border-top-right-radius:0}.q-dialog__inner--bottom:not(.q-dialog__inner--animating)>div,.q-dialog__inner--left:not(.q-dialog__inner--animating)>div{border-bottom-left-radius:0}.q-dialog__inner--bottom:not(.q-dialog__inner--animating)>div,.q-dialog__inner--right:not(.q-dialog__inner--animating)>div{border-bottom-right-radius:0}.q-dialog__inner--fullwidth>div{width:100%!important;max-width:100%!important}.q-dialog__inner--fullheight>div{height:100%!important;max-height:100%!important}.q-dialog__backdrop{z-index:-1;pointer-events:all;outline:0;background:rgba(0,0,0,.4)}body.platform-android:not(.native-mobile) .q-dialog__inner--minimized>div,body.platform-ios .q-dialog__inner--minimized>div{max-height:calc(100vh - 108px)}body.q-ios-padding .q-dialog__inner{padding-top:20px!important;padding-top:env(safe-area-inset-top)!important;padding-bottom:env(safe-area-inset-bottom)!important}body.q-ios-padding .q-dialog__inner>div{max-height:calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom))!important}@media (max-width:599.98px){.q-dialog__inner--bottom,.q-dialog__inner--top{padding-left:0;padding-right:0}.q-dialog__inner--bottom>div,.q-dialog__inner--top>div{width:100%!important}}@media (min-width:600px){.q-dialog__inner--minimized>div{max-width:560px}}.q-body--dialog{overflow:hidden}.q-editor{border:1px solid rgba(0,0,0,.12);border-radius:4px;background-color:#fff}.q-editor.disabled{border-style:dashed}.q-editor>div:first-child,.q-editor__toolbars-container,.q-editor__toolbars-container>div:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-editor__content{outline:0;padding:10px;min-height:10em;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;overflow:auto;max-width:100%}.q-editor__content pre{white-space:pre-wrap}.q-editor__content hr{border:0;outline:0;margin:1px;height:1px;background:rgba(0,0,0,.12)}.q-editor__content:empty:not(:focus):before{content:attr(placeholder);opacity:.7}.q-editor__toolbar{border-bottom:1px solid rgba(0,0,0,.12);min-height:32px}.q-editor__toolbars-container{max-width:100%}.q-editor .q-btn{margin:4px}.q-editor__toolbar-group{position:relative;margin:0 4px}.q-editor__toolbar-group+.q-editor__toolbar-group:before{content:"";position:absolute;left:-4px;top:4px;bottom:4px;width:1px;background:rgba(0,0,0,.12)}.q-editor__link-input{color:inherit;text-decoration:none;text-transform:none;border:none;border-radius:0;background:0 0;outline:0}.q-editor--flat,.q-editor--flat .q-editor__toolbar{border:0}.q-editor--dense .q-editor__toolbar-group{display:flex;align-items:center;flex-wrap:nowrap}.q-editor--dark{border-color:rgba(255,255,255,.28)}.q-editor--dark .q-editor__content hr{background:rgba(255,255,255,.28)}.q-editor--dark .q-editor__toolbar{border-color:rgba(255,255,255,.28)}.q-editor--dark .q-editor__toolbar-group+.q-editor__toolbar-group:before{background:rgba(255,255,255,.28)}.q-expansion-item__border{opacity:0}.q-expansion-item__toggle-icon{position:relative;transition:transform .3s}.q-expansion-item__toggle-icon--rotated{transform:rotate(180deg)}.q-expansion-item__toggle-focus{width:1em!important;height:1em!important;position:relative!important}.q-expansion-item__toggle-focus+.q-expansion-item__toggle-icon{margin-top:-1em}.q-expansion-item--standard.q-expansion-item--expanded>div>.q-expansion-item__border{opacity:1}.q-expansion-item--popup{transition:padding .5s}.q-expansion-item--popup>.q-expansion-item__container{border:1px solid rgba(0,0,0,.12)}.q-expansion-item--popup>.q-expansion-item__container>.q-separator{display:none}.q-expansion-item--popup.q-expansion-item--collapsed{padding:0 15px}.q-expansion-item--popup.q-expansion-item--expanded{padding:15px 0}.q-expansion-item--popup.q-expansion-item--expanded+.q-expansion-item--popup.q-expansion-item--expanded{padding-top:0}.q-expansion-item--popup.q-expansion-item--collapsed:not(:first-child)>.q-expansion-item__container{border-top-width:0}.q-expansion-item--popup.q-expansion-item--expanded+.q-expansion-item--popup.q-expansion-item--collapsed>.q-expansion-item__container{border-top-width:1px}.q-expansion-item__content>.q-card{box-shadow:none;border-radius:0}.q-expansion-item:first-child>div>.q-expansion-item__border--top{opacity:0}.q-expansion-item:last-child>div>.q-expansion-item__border--bottom{opacity:0}.q-expansion-item--expanded+.q-expansion-item--expanded>div>.q-expansion-item__border--top{opacity:0}.q-expansion-item--expanded .q-textarea--autogrow textarea{animation:q-expansion-done 0s}@keyframes q-expansion-done{0%{--q-exp-done:1}}.z-fab{z-index:990}.q-fab{position:relative;vertical-align:middle}.q-fab>.q-btn{width:100%}.q-fab--form-rounded{border-radius:28px}.q-fab--form-square{border-radius:4px}.q-fab__active-icon,.q-fab__icon{transition:opacity .4s,transform .4s}.q-fab__icon{opacity:1;transform:rotate(0)}.q-fab__active-icon{opacity:0;transform:rotate(-180deg)}.q-fab__label--external{position:absolute;padding:0 8px;transition:opacity .18s cubic-bezier(.65, .815, .735, .395)}.q-fab__label--external-hidden{opacity:0;pointer-events:none}.q-fab__label--external-left{top:50%;left:-12px;transform:translate(-100%,-50%)}.q-fab__label--external-right{top:50%;right:-12px;transform:translate(100%,-50%)}.q-fab__label--external-bottom{bottom:-12px;left:50%;transform:translate(-50%,100%)}.q-fab__label--external-top{top:-12px;left:50%;transform:translate(-50%,-100%)}.q-fab__label--internal{padding:0;transition:font-size .12s cubic-bezier(.65, .815, .735, .395),max-height .12s cubic-bezier(.65, .815, .735, .395),opacity 70ms cubic-bezier(.65, .815, .735, .395);max-height:30px}.q-fab__label--internal-hidden{font-size:0;opacity:0}.q-fab__label--internal-top{padding-bottom:.12em}.q-fab__label--internal-bottom{padding-top:.12em}.q-fab__label--internal-bottom.q-fab__label--internal-hidden,.q-fab__label--internal-top.q-fab__label--internal-hidden{max-height:0}.q-fab__label--internal-left{padding-left:.285em;padding-right:.571em}.q-fab__label--internal-right{padding-right:.285em;padding-left:.571em}.q-fab__icon-holder{min-width:24px;min-height:24px;position:relative}.q-fab__icon-holder--opened .q-fab__icon{transform:rotate(180deg);opacity:0}.q-fab__icon-holder--opened .q-fab__active-icon{transform:rotate(0);opacity:1}.q-fab__actions{position:absolute;opacity:0;transition:transform .18s ease-in,opacity .18s ease-in;pointer-events:none;align-items:center;justify-content:center;align-self:center;padding:3px}.q-fab__actions .q-btn{margin:5px}.q-fab__actions--right{transform-origin:0 50%;transform:scale(.4) translateX(-62px);height:56px;left:100%;margin-left:9px}.q-fab__actions--left{transform-origin:100% 50%;transform:scale(.4) translateX(62px);height:56px;right:100%;margin-right:9px;flex-direction:row-reverse}.q-fab__actions--up{transform-origin:50% 100%;transform:scale(.4) translateY(62px);width:56px;bottom:100%;margin-bottom:9px;flex-direction:column-reverse}.q-fab__actions--down{transform-origin:50% 0;transform:scale(.4) translateY(-62px);width:56px;top:100%;margin-top:9px;flex-direction:column}.q-fab__actions--down,.q-fab__actions--up{left:50%;margin-left:-28px}.q-fab__actions--opened{opacity:1;transform:scale(1) translate(.1px,0);pointer-events:all}.q-fab--align-left>.q-fab__actions--down,.q-fab--align-left>.q-fab__actions--up{align-items:flex-start;left:28px}.q-fab--align-right>.q-fab__actions--down,.q-fab--align-right>.q-fab__actions--up{align-items:flex-end;left:auto;right:0}.q-field{font-size:14px}.q-field ::-ms-clear,.q-field ::-ms-reveal{display:none}.q-field--with-bottom{padding-bottom:20px}.q-field__marginal{height:56px;color:rgba(0,0,0,.54);font-size:24px}.q-field__marginal>*+*{margin-left:2px}.q-field__marginal .q-avatar{font-size:32px}.q-field__before,.q-field__prepend{padding-right:12px}.q-field__after,.q-field__append{padding-left:12px}.q-field__after:empty,.q-field__append:empty{display:none}.q-field__append+.q-field__append{padding-left:2px}.q-field__inner{text-align:left}.q-field__bottom{font-size:12px;min-height:20px;line-height:1;color:rgba(0,0,0,.54);padding:8px 12px 0;backface-visibility:hidden}.q-field__bottom--animated{transform:translateY(100%);position:absolute;left:0;right:0;bottom:0}.q-field__messages{line-height:1}.q-field__messages>div{word-break:break-word;word-wrap:break-word;overflow-wrap:break-word}.q-field__messages>div+div{margin-top:4px}.q-field__counter{padding-left:8px;line-height:1}.q-field--item-aligned{padding:8px 16px}.q-field--item-aligned .q-field__before{min-width:56px}.q-field__control-container{height:inherit}.q-field__control{color:var(--q-primary);height:56px;max-width:100%;outline:0}.q-field__control:after,.q-field__control:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.q-field__control:before{border-radius:inherit}.q-field__shadow{top:8px;opacity:0;overflow:hidden;white-space:pre-wrap;transition:opacity .36s cubic-bezier(.4, 0, .2, 1)}.q-field__shadow+.q-field__native::placeholder{transition:opacity .36s cubic-bezier(.4, 0, .2, 1)}.q-field__shadow+.q-field__native:focus::placeholder{opacity:0}.q-field__input,.q-field__native,.q-field__prefix,.q-field__suffix{font-weight:400;line-height:28px;letter-spacing:.00937em;text-decoration:inherit;text-transform:inherit;border:none;border-radius:0;background:0 0;color:rgba(0,0,0,.87);outline:0;padding:6px 0}.q-field__input,.q-field__native{width:100%;min-width:0;outline:0!important;-webkit-user-select:auto;user-select:auto}.q-field__input:-webkit-autofill,.q-field__native:-webkit-autofill{-webkit-animation-name:q-autofill;-webkit-animation-fill-mode:both}.q-field__input:invalid,.q-field__native:invalid{box-shadow:none}.q-field__native[type=file]{line-height:1em}.q-field__input{padding:0;height:0;min-height:24px;line-height:24px}.q-field__prefix,.q-field__suffix{transition:opacity .36s cubic-bezier(.4, 0, .2, 1);white-space:nowrap}.q-field__prefix{padding-right:4px}.q-field__suffix{padding-left:4px}.q-field--disabled .q-placeholder,.q-field--readonly .q-placeholder{opacity:1!important}.q-field--readonly.q-field--labeled .q-field__input,.q-field--readonly.q-field--labeled .q-field__native{cursor:default}.q-field--readonly.q-field--float .q-field__input,.q-field--readonly.q-field--float .q-field__native{cursor:text}.q-field--disabled .q-field__inner{cursor:not-allowed}.q-field--disabled .q-field__control{pointer-events:none}.q-field--disabled .q-field__control>div{opacity:.6!important}.q-field--disabled .q-field__control>div,.q-field--disabled .q-field__control>div *{outline:0!important}.q-field__label{left:0;top:18px;max-width:100%;color:rgba(0,0,0,.6);font-size:16px;line-height:1.25;font-weight:400;letter-spacing:.00937em;text-decoration:inherit;text-transform:inherit;transform-origin:left top;transition:transform .36s cubic-bezier(.4, 0, .2, 1),max-width 324ms cubic-bezier(.4, 0, .2, 1);backface-visibility:hidden}.q-field__label:has(+ :is(.q-field__native,.q-field__input):is(:-webkit-autofill,[type=color],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])){transform:translateY(-40%) scale(.75)}.q-field--float .q-field__label{max-width:133%;transform:translateY(-40%) scale(.75);transition:transform .36s cubic-bezier(.4, 0, .2, 1),max-width 396ms cubic-bezier(.4, 0, .2, 1)}.q-field--highlighted .q-field__label{color:currentColor}.q-field--highlighted .q-field__shadow{opacity:.5}.q-field--filled .q-field__control{padding:0 12px;background:rgba(0,0,0,.05);border-radius:4px 4px 0 0}.q-field--filled .q-field__control:before{background:rgba(0,0,0,.05);border-bottom:1px solid rgba(0,0,0,.42);opacity:0;transition:opacity .36s cubic-bezier(.4, 0, .2, 1),background .36s cubic-bezier(.4, 0, .2, 1)}.q-field--filled .q-field__control:hover:before{opacity:1}.q-field--filled .q-field__control:after{height:2px;top:auto;transform-origin:center bottom;transform:scale3d(0,1,1);background:currentColor;transition:transform .36s cubic-bezier(.4, 0, .2, 1)}.q-field--filled.q-field--rounded .q-field__control{border-radius:28px 28px 0 0}.q-field--filled.q-field--highlighted .q-field__control:before{opacity:1;background:rgba(0,0,0,.12)}.q-field--filled.q-field--highlighted .q-field__control:after{transform:scale3d(1,1,1)}.q-field--filled.q-field--dark .q-field__control,.q-field--filled.q-field--dark .q-field__control:before{background:rgba(255,255,255,.07)}.q-field--filled.q-field--dark.q-field--highlighted .q-field__control:before{background:rgba(255,255,255,.1)}.q-field--filled.q-field--readonly .q-field__control:before{opacity:1;background:0 0;border-bottom-style:dashed}.q-field--outlined .q-field__control{border-radius:4px;padding:0 12px}.q-field--outlined .q-field__control:before{border:1px solid rgba(0,0,0,.24);transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--outlined .q-field__control:hover:before{border-color:#000}.q-field--outlined .q-field__control:after{height:inherit;border-radius:inherit;border:2px solid transparent;transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--outlined .q-field__input:-webkit-autofill,.q-field--outlined .q-field__native:-webkit-autofill{margin-top:1px;margin-bottom:1px}.q-field--outlined.q-field--rounded .q-field__control{border-radius:28px}.q-field--outlined.q-field--highlighted .q-field__control:hover:before{border-color:transparent}.q-field--outlined.q-field--highlighted .q-field__control:after{border-color:currentColor;border-width:2px;transform:scale3d(1,1,1)}.q-field--outlined.q-field--readonly .q-field__control:before{border-style:dashed}.q-field--standard .q-field__control:before{border-bottom:1px solid rgba(0,0,0,.24);transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standard .q-field__control:hover:before{border-color:#000}.q-field--standard .q-field__control:after{height:2px;top:auto;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;transform-origin:center bottom;transform:scale3d(0,1,1);background:currentColor;transition:transform .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standard.q-field--highlighted .q-field__control:after{transform:scale3d(1,1,1)}.q-field--standard.q-field--readonly .q-field__control:before{border-bottom-style:dashed}.q-field--dark .q-field__control:before{border-color:rgba(255,255,255,.6)}.q-field--dark .q-field__control:hover:before{border-color:#fff}.q-field--dark .q-field__input,.q-field--dark .q-field__native,.q-field--dark .q-field__prefix,.q-field--dark .q-field__suffix{color:#fff}.q-field--dark .q-field__bottom,.q-field--dark .q-field__marginal,.q-field--dark:not(.q-field--highlighted) .q-field__label{color:rgba(255,255,255,.7)}.q-field--standout .q-field__control{padding:0 12px;background:rgba(0,0,0,.05);border-radius:4px;transition:box-shadow .36s cubic-bezier(.4, 0, .2, 1),background-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standout .q-field__control:before{background:rgba(0,0,0,.07);opacity:0;transition:opacity .36s cubic-bezier(.4, 0, .2, 1),background .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standout .q-field__control:hover:before{opacity:1}.q-field--standout.q-field--rounded .q-field__control{border-radius:28px}.q-field--standout.q-field--highlighted .q-field__control{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);background:#000}.q-field--standout.q-field--highlighted .q-field__append,.q-field--standout.q-field--highlighted .q-field__input,.q-field--standout.q-field--highlighted .q-field__native,.q-field--standout.q-field--highlighted .q-field__prefix,.q-field--standout.q-field--highlighted .q-field__prepend,.q-field--standout.q-field--highlighted .q-field__suffix{color:#fff}.q-field--standout.q-field--readonly .q-field__control:before{opacity:1;background:0 0;border:1px dashed rgba(0,0,0,.24)}.q-field--standout.q-field--dark .q-field__control{background:rgba(255,255,255,.07)}.q-field--standout.q-field--dark .q-field__control:before{background:rgba(255,255,255,.07)}.q-field--standout.q-field--dark.q-field--highlighted .q-field__control{background:#fff}.q-field--standout.q-field--dark.q-field--highlighted .q-field__append,.q-field--standout.q-field--dark.q-field--highlighted .q-field__input,.q-field--standout.q-field--dark.q-field--highlighted .q-field__native,.q-field--standout.q-field--dark.q-field--highlighted .q-field__prefix,.q-field--standout.q-field--dark.q-field--highlighted .q-field__prepend,.q-field--standout.q-field--dark.q-field--highlighted .q-field__suffix{color:#000}.q-field--standout.q-field--dark.q-field--readonly .q-field__control:before{border-color:rgba(255,255,255,.24)}.q-field--labeled .q-field__native,.q-field--labeled .q-field__prefix,.q-field--labeled .q-field__suffix{line-height:24px;padding-top:24px;padding-bottom:8px}.q-field--labeled .q-field__shadow{top:0}.q-field--labeled:not(.q-field--float) .q-field__prefix,.q-field--labeled:not(.q-field--float) .q-field__suffix{opacity:0}.q-field--labeled:not(.q-field--float) .q-field__input::placeholder,.q-field--labeled:not(.q-field--float) .q-field__native::placeholder{color:transparent}.q-field--labeled.q-field--dense .q-field__native,.q-field--labeled.q-field--dense .q-field__prefix,.q-field--labeled.q-field--dense .q-field__suffix{padding-top:14px;padding-bottom:2px}.q-field--dense .q-field--with-bottom{padding-bottom:19px}.q-field--dense .q-field__shadow{top:0}.q-field--dense .q-field__control,.q-field--dense .q-field__marginal{height:40px}.q-field--dense .q-field__bottom{font-size:11px}.q-field--dense .q-field__label{font-size:14px;top:10px}.q-field--dense .q-field__before,.q-field--dense .q-field__prepend{padding-right:6px}.q-field--dense .q-field__after,.q-field--dense .q-field__append{padding-left:6px}.q-field--dense .q-field__append+.q-field__append{padding-left:2px}.q-field--dense .q-field__marginal .q-avatar{font-size:24px}.q-field--dense.q-field--float .q-field__label{transform:translateY(-30%) scale(.75)}.q-field--dense .q-field__label:has(+ :is(.q-field__native,.q-field__input):is(:-webkit-autofill,[type=color],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])){transform:translateY(-30%) scale(.75)}.q-field--borderless .q-field__bottom,.q-field--borderless.q-field--dense .q-field__control,.q-field--standard .q-field__bottom,.q-field--standard.q-field--dense .q-field__control{padding-left:0;padding-right:0}.q-field--error .q-field__label{animation:q-field-label .36s}.q-field--error .q-field__bottom{color:var(--q-negative)}.q-field__focusable-action{opacity:.6;cursor:pointer;outline:0!important;border:0;color:inherit;background:0 0;padding:0}.q-field__focusable-action:focus,.q-field__focusable-action:hover{opacity:1}.q-field--auto-height .q-field__control{height:auto}.q-field--auto-height .q-field__control,.q-field--auto-height .q-field__native{min-height:56px}.q-field--auto-height .q-field__native{align-items:center}.q-field--auto-height .q-field__control-container{padding-top:0}.q-field--auto-height .q-field__native,.q-field--auto-height .q-field__prefix,.q-field--auto-height .q-field__suffix{line-height:18px}.q-field--auto-height.q-field--labeled .q-field__control-container{padding-top:24px}.q-field--auto-height.q-field--labeled .q-field__shadow{top:24px}.q-field--auto-height.q-field--labeled .q-field__native,.q-field--auto-height.q-field--labeled .q-field__prefix,.q-field--auto-height.q-field--labeled .q-field__suffix{padding-top:0}.q-field--auto-height.q-field--labeled .q-field__native{min-height:24px}.q-field--auto-height.q-field--dense .q-field__control,.q-field--auto-height.q-field--dense .q-field__native{min-height:40px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__control-container{padding-top:14px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__shadow{top:14px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__native{min-height:24px}.q-field--square .q-field__control{border-radius:0!important}.q-transition--field-message-enter-active,.q-transition--field-message-leave-active{transition:transform .6s cubic-bezier(.86, 0, .07, 1),opacity .6s cubic-bezier(.86, 0, .07, 1)}.q-transition--field-message-enter-from,.q-transition--field-message-leave-to{opacity:0;transform:translateY(-10px)}.q-transition--field-message-leave-active,.q-transition--field-message-leave-from{position:absolute}@keyframes q-field-label{40%{margin-left:2px}60%,80%{margin-left:-2px}70%,90%{margin-left:2px}}@keyframes q-autofill{to{background:0 0;color:inherit}}.q-file .q-field__native{word-break:break-all;overflow:hidden}.q-file .q-field__input{opacity:0!important}.q-file .q-field__input::-webkit-file-upload-button{cursor:pointer}.q-file__filler{visibility:hidden;width:100%;border:none;padding:0}.q-file__dnd{outline:1px dashed currentColor;outline-offset:-4px}.q-form{position:relative}.q-img{position:relative;width:100%;display:inline-block;vertical-align:middle;overflow:hidden}.q-img__loading .q-spinner{font-size:50px}.q-img__container{border-radius:inherit;font-size:0}.q-img__image{border-radius:inherit;width:100%;height:100%;opacity:0}.q-img__image--with-transition{transition:opacity .28s ease-in}.q-img__image--loaded{opacity:1}.q-img__content{border-radius:inherit;pointer-events:none}.q-img__content>div{pointer-events:all;position:absolute;padding:16px;color:#fff;background:rgba(0,0,0,.47)}.q-img--no-menu .q-img__image,.q-img--no-menu .q-img__placeholder{pointer-events:none}.q-inner-loading{background:rgba(255,255,255,.6);border-radius:inherit}.q-inner-loading--dark{background:rgba(0,0,0,.4)}.q-inner-loading__label{margin-top:8px}.q-textarea .q-field__control{min-height:56px;height:auto}.q-textarea .q-field__control-container{padding-top:2px;padding-bottom:2px}.q-textarea .q-field__shadow{top:2px;bottom:2px}.q-textarea .q-field__native,.q-textarea .q-field__prefix,.q-textarea .q-field__suffix{line-height:18px}.q-textarea .q-field__native{resize:vertical;padding-top:17px;min-height:52px}.q-textarea.q-field--labeled .q-field__control-container{padding-top:26px}.q-textarea.q-field--labeled .q-field__shadow{top:26px}.q-textarea.q-field--labeled .q-field__native,.q-textarea.q-field--labeled .q-field__prefix,.q-textarea.q-field--labeled .q-field__suffix{padding-top:0}.q-textarea.q-field--labeled .q-field__native{min-height:26px;padding-top:1px}.q-textarea--autogrow .q-field__native{resize:none}.q-textarea.q-field--dense .q-field__control,.q-textarea.q-field--dense .q-field__native{min-height:36px}.q-textarea.q-field--dense .q-field__native{padding-top:9px}.q-textarea.q-field--dense.q-field--labeled .q-field__control-container{padding-top:14px}.q-textarea.q-field--dense.q-field--labeled .q-field__shadow{top:14px}.q-textarea.q-field--dense.q-field--labeled .q-field__native{min-height:24px;padding-top:3px}.q-textarea.q-field--dense.q-field--labeled .q-field__prefix,.q-textarea.q-field--dense.q-field--labeled .q-field__suffix{padding-top:2px}.q-textarea.disabled .q-field__native,body.mobile .q-textarea .q-field__native{resize:none}.q-intersection{position:relative}.q-item{min-height:48px;padding:8px 16px;color:inherit;transition:color .3s,background-color .3s}.q-item__section--side{color:#757575;align-items:flex-start;padding-right:16px;width:auto;min-width:0;max-width:100%}.q-item__section--side>.q-icon{font-size:24px}.q-item__section--side>.q-avatar{font-size:40px}.q-item__section--avatar{color:inherit;min-width:56px}.q-item__section--thumbnail img{width:100px;height:56px}.q-item__section--nowrap{white-space:nowrap}.q-item>.q-focus-helper+.q-item__section--thumbnail,.q-item>.q-item__section--thumbnail:first-child{margin-left:-16px}.q-item>.q-item__section--thumbnail:last-of-type{margin-right:-16px}.q-item__label{line-height:1.2em!important;max-width:100%}.q-item__label--overline{color:rgba(0,0,0,.7)}.q-item__label--caption{color:rgba(0,0,0,.54)}.q-item__label--header{color:#757575;padding:16px;font-size:.875rem;line-height:1.25rem;letter-spacing:.01786em}.q-list--padding .q-item__label--header,.q-separator--spaced+.q-item__label--header{padding-top:8px}.q-item__label+.q-item__label{margin-top:4px}.q-item__section--main{width:auto;min-width:0;max-width:100%;flex:10000 1 0%}.q-item__section--main+.q-item__section--main{margin-left:8px}.q-item__section--main~.q-item__section--side{align-items:flex-end;padding-right:0;padding-left:16px}.q-item__section--main.q-item__section--thumbnail{margin-left:0;margin-right:-16px}.q-list--bordered{border:1px solid rgba(0,0,0,.12)}.q-list--separator>.q-item-type+.q-item-type,.q-list--separator>.q-virtual-scroll__content>.q-item-type+.q-item-type{border-top:1px solid rgba(0,0,0,.12)}.q-list--padding{padding:8px 0}.q-item--dense,.q-list--dense>.q-item{min-height:32px;padding:2px 16px}.q-list--dark.q-list--separator>.q-item-type+.q-item-type,.q-list--dark.q-list--separator>.q-virtual-scroll__content>.q-item-type+.q-item-type{border-top-color:rgba(255,255,255,.28)}.q-item--dark,.q-list--dark{color:#fff;border-color:rgba(255,255,255,.28)}.q-item--dark .q-item__section--side:not(.q-item__section--avatar),.q-list--dark .q-item__section--side:not(.q-item__section--avatar){color:rgba(255,255,255,.7)}.q-item--dark .q-item__label--header,.q-list--dark .q-item__label--header{color:rgba(255,255,255,.64)}.q-item--dark .q-item__label--caption,.q-item--dark .q-item__label--overline,.q-list--dark .q-item__label--caption,.q-list--dark .q-item__label--overline{color:rgba(255,255,255,.8)}.q-item{position:relative}.q-item--active,.q-item.q-router-link--active{color:var(--q-primary)}.q-knob{font-size:48px}.q-knob--editable{cursor:pointer;outline:0}.q-knob--editable:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;box-shadow:none;transition:box-shadow .24s ease-in-out}.q-knob--editable:focus:before{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}body.body--dark .q-knob--editable:focus:before{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-layout{width:100%;outline:0}.q-layout-container{position:relative;width:100%;height:100%}.q-layout-container .q-layout{min-height:100%}.q-layout-container>div{transform:translate3d(0,0,0)}.q-layout-container>div>div{min-height:0;max-height:100%}.q-layout__shadow{width:100%}.q-layout__shadow:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;box-shadow:0 0 10px 2px rgba(0,0,0,.2),0 0 10px rgba(0,0,0,.24)}.q-layout__section--marginal{background-color:var(--q-primary);color:#fff}.q-header--hidden{transform:translateY(-110%)}.q-header--bordered{border-bottom:1px solid rgba(0,0,0,.12)}.q-header .q-layout__shadow{bottom:-10px}.q-header .q-layout__shadow:after{bottom:10px}.q-footer--hidden{transform:translateY(110%)}.q-footer--bordered{border-top:1px solid rgba(0,0,0,.12)}.q-footer .q-layout__shadow{top:-10px}.q-footer .q-layout__shadow:after{top:10px}.q-footer,.q-header{z-index:2000}.q-drawer{position:absolute;top:0;bottom:0;background:#fff;z-index:1000}.q-drawer--on-top{z-index:3000}.q-drawer--left{left:0;transform:translateX(-100%)}.q-drawer--left.q-drawer--bordered{border-right:1px solid rgba(0,0,0,.12)}.q-drawer--left .q-layout__shadow{left:10px;right:-10px}.q-drawer--left .q-layout__shadow:after{right:10px}.q-drawer--right{right:0;transform:translateX(100%)}.q-drawer--right.q-drawer--bordered{border-left:1px solid rgba(0,0,0,.12)}.q-drawer--right .q-layout__shadow{left:-10px}.q-drawer--right .q-layout__shadow:after{left:10px}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini{padding:0!important}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section{text-align:center;justify-content:center;padding-left:0;padding-right:0;min-width:0}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__label,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section--main,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section--side~.q-item__section--side{display:none}.q-drawer--mini .q-expansion-item__content,.q-drawer--mini .q-mini-drawer-hide{display:none}.q-drawer--mini-animate .q-drawer__content{overflow-x:hidden!important;white-space:nowrap}.q-drawer--standard .q-mini-drawer-only{display:none}.q-drawer--mobile .q-mini-drawer-hide,.q-drawer--mobile .q-mini-drawer-only{display:none}.q-drawer__backdrop{z-index:2999!important;will-change:background-color}.q-drawer__opener{z-index:2001;height:100%;width:15px;-webkit-user-select:none;user-select:none}.q-footer,.q-header,.q-layout,.q-page{position:relative}.q-page-sticky--shrink{pointer-events:none}.q-page-sticky--shrink>div{display:inline-block;pointer-events:auto}body.q-ios-padding .q-layout--standard .q-drawer--top-padding .q-drawer__content,body.q-ios-padding .q-layout--standard .q-header>.q-tabs:first-child .q-tabs__content,body.q-ios-padding .q-layout--standard .q-header>.q-toolbar:first-child{padding-top:20px;min-height:70px;padding-top:env(safe-area-inset-top);min-height:calc(env(safe-area-inset-top) + 50px)}body.q-ios-padding .q-layout--standard .q-drawer--top-padding .q-drawer__content,body.q-ios-padding .q-layout--standard .q-footer>.q-tabs:nth-last-child(1of:not(.q-layout__shadow)) .q-tabs__content,body.q-ios-padding .q-layout--standard .q-footer>.q-toolbar:last-child{padding-bottom:env(safe-area-inset-bottom);min-height:calc(env(safe-area-inset-bottom) + 50px)}.q-body--layout-animate .q-drawer__backdrop{transition:background-color .12s!important}.q-body--layout-animate .q-drawer{transition:transform .12s,width .12s,top .12s,bottom .12s!important}.q-body--layout-animate .q-layout__section--marginal{transition:transform .12s,left .12s,right .12s!important}.q-body--layout-animate .q-page-container{transition:padding-top .12s,padding-right .12s,padding-bottom .12s,padding-left .12s!important}.q-body--layout-animate .q-page-sticky{transition:transform .12s,left .12s,right .12s,top .12s,bottom .12s!important}body:not(.q-body--layout-animate) .q-layout--prevent-focus{visibility:hidden}.q-body--drawer-toggle{overflow-x:hidden!important}@media (max-width:599.98px){.q-layout-padding{padding:8px}}@media (min-width:600px) and (max-width:1439.98px){.q-layout-padding{padding:16px}}@media (min-width:1440px){.q-layout-padding{padding:24px}}body.body--dark .q-drawer,body.body--dark .q-footer,body.body--dark .q-header{border-color:rgba(255,255,255,.28)}body.body--dark .q-layout__shadow:after{box-shadow:0 0 10px 2px rgba(255,255,255,.2),0 0 10px rgba(255,255,255,.24)}body.platform-ios .q-layout--containerized{position:unset!important}.q-linear-progress{--q-linear-progress-speed:.3s;position:relative;width:100%;overflow:hidden;font-size:4px;height:1em;color:var(--q-primary);transform:scale3d(1,1,1)}.q-linear-progress__model,.q-linear-progress__track{transform-origin:0 0}.q-linear-progress__model--with-transition,.q-linear-progress__track--with-transition{transition:transform var(--q-linear-progress-speed)}.q-linear-progress--reverse .q-linear-progress__model,.q-linear-progress--reverse .q-linear-progress__track{transform-origin:0 100%}.q-linear-progress__model--determinate{background:currentColor}.q-linear-progress__model--indeterminate,.q-linear-progress__model--query{transition:none}.q-linear-progress__model--indeterminate:after,.q-linear-progress__model--indeterminate:before,.q-linear-progress__model--query:after,.q-linear-progress__model--query:before{background:currentColor;content:"";position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:0 0}.q-linear-progress__model--indeterminate:before,.q-linear-progress__model--query:before{animation:q-linear-progress--indeterminate 2.1s cubic-bezier(.65,.815,.735,.395) infinite}.q-linear-progress__model--indeterminate:after,.q-linear-progress__model--query:after{transform:translate3d(-101%,0,0) scale3d(1,1,1);animation:q-linear-progress--indeterminate-short 2.1s cubic-bezier(.165,.84,.44,1) infinite;animation-delay:1.15s}.q-linear-progress__track{opacity:.4}.q-linear-progress__track--light{background:rgba(0,0,0,.26)}.q-linear-progress__track--dark{background:rgba(255,255,255,.6)}.q-linear-progress__stripe{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,rgba(255,255,255,0) 25%,rgba(255,255,255,0) 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,rgba(255,255,255,0) 75%,rgba(255,255,255,0))!important;background-size:40px 40px!important}.q-linear-progress__stripe--with-transition{transition:width var(--q-linear-progress-speed)}@keyframes q-linear-progress--indeterminate{0%{transform:translate3d(-35%,0,0) scale3d(.35,1,1)}60%{transform:translate3d(100%,0,0) scale3d(.9,1,1)}100%{transform:translate3d(100%,0,0) scale3d(.9,1,1)}}@keyframes q-linear-progress--indeterminate-short{0%{transform:translate3d(-101%,0,0) scale3d(1,1,1)}60%{transform:translate3d(107%,0,0) scale3d(.01,1,1)}100%{transform:translate3d(107%,0,0) scale3d(.01,1,1)}}.q-menu{position:fixed!important;display:inline-block;max-width:95vw;max-height:65vh;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);background:#fff;border-radius:4px;overflow-y:auto;overflow-x:hidden;outline:0;z-index:6000}.q-menu--square{border-radius:0}.q-menu--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-option-group--inline>div{display:inline-block}.q-pagination input{text-align:center;-moz-appearance:textfield}.q-pagination input::-webkit-inner-spin-button,.q-pagination input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.q-pagination__content{--q-pagination-gutter-parent:-2px;--q-pagination-gutter-child:2px;margin-top:var(--q-pagination-gutter-parent);margin-left:var(--q-pagination-gutter-parent)}.q-pagination__content>.q-btn,.q-pagination__content>.q-input,.q-pagination__middle>.q-btn{margin-top:var(--q-pagination-gutter-child);margin-left:var(--q-pagination-gutter-child)}.q-parallax{position:relative;width:100%;overflow:hidden;border-radius:inherit}.q-parallax__media>img,.q-parallax__media>video{position:absolute;left:50%;bottom:0;min-width:100%;min-height:100%;will-change:transform;display:none}.q-popup-edit{padding:8px 16px}.q-popup-edit__buttons{margin-top:8px}.q-popup-edit__buttons .q-btn+.q-btn{margin-left:8px}.q-pull-to-refresh{position:relative}.q-pull-to-refresh__puller{border-radius:50%;width:40px;height:40px;color:var(--q-primary);background:#fff;box-shadow:0 0 4px 0 rgba(0,0,0,.3)}.q-pull-to-refresh__puller--animating{transition:transform .3s,opacity .3s}.q-radio{vertical-align:middle}.q-radio__native{width:1px;height:1px}.q-radio__bg,.q-radio__icon-container{-webkit-user-select:none;user-select:none}.q-radio__bg{top:25%;left:25%;width:50%;height:50%;-webkit-print-color-adjust:exact}.q-radio__bg path{fill:currentColor}.q-radio__icon{color:currentColor;font-size:.5em}.q-radio__check{transform-origin:50% 50%;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}.q-radio__inner{font-size:40px;width:1em;min-width:1em;height:1em;outline:0;border-radius:50%;color:rgba(0,0,0,.54)}.q-radio__inner--truthy{color:var(--q-primary)}.q-radio__inner--truthy .q-radio__check{transform:scale3d(1,1,1)}.q-radio.disabled{opacity:.75!important}.q-radio--dark .q-radio__inner{color:rgba(255,255,255,.7)}.q-radio--dark .q-radio__inner:before{opacity:.32!important}.q-radio--dark .q-radio__inner--truthy{color:var(--q-primary)}.q-radio--dense .q-radio__inner{width:.5em;min-width:.5em;height:.5em}.q-radio--dense .q-radio__bg{left:0;top:0;width:100%;height:100%}.q-radio--dense .q-radio__label{padding-left:.5em}.q-radio--dense.reverse .q-radio__label{padding-left:0;padding-right:.5em}body.desktop .q-radio:not(.disabled) .q-radio__inner:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}body.desktop .q-radio:not(.disabled):focus .q-radio__inner:before,body.desktop .q-radio:not(.disabled):hover .q-radio__inner:before{transform:scale3d(1,1,1)}body.desktop .q-radio--dense:not(.disabled):focus .q-radio__inner:before,body.desktop .q-radio--dense:not(.disabled):hover .q-radio__inner:before{transform:scale3d(1.5,1.5,1)}.q-rating{color:#ffeb3b;vertical-align:middle}.q-rating__icon-container{height:1em;outline:0}.q-rating__icon-container+.q-rating__icon-container{margin-left:2px}.q-rating__icon{color:currentColor;text-shadow:0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);position:relative;opacity:.4;transition:transform .2s ease-in,opacity .2s ease-in,color .2s ease-in}.q-rating__icon--hovered{transform:scale(1.3)}.q-rating__icon--active{opacity:1}.q-rating__icon--exselected{opacity:.7}.q-rating--no-dimming .q-rating__icon{opacity:1}.q-rating--editable .q-rating__icon-container{cursor:pointer}.q-responsive{position:relative;max-width:100%;max-height:100%}.q-responsive__filler{width:inherit;max-width:inherit;height:inherit;max-height:inherit}.q-responsive__content{border-radius:inherit}.q-responsive__content>*{width:100%!important;height:100%!important;max-height:100%!important;max-width:100%!important}.q-scrollarea{position:relative;contain:strict}.q-scrollarea__bar,.q-scrollarea__thumb{opacity:.2;transition:opacity .3s;will-change:opacity;cursor:grab}.q-scrollarea__bar--v,.q-scrollarea__thumb--v{right:0;width:10px}.q-scrollarea__bar--h,.q-scrollarea__thumb--h{bottom:0;height:10px}.q-scrollarea__bar--invisible,.q-scrollarea__thumb--invisible{opacity:0!important;pointer-events:none}.q-scrollarea__thumb{background:#000;border-radius:3px}.q-scrollarea__thumb:hover{opacity:.3}.q-scrollarea__thumb:active{opacity:.5}.q-scrollarea__content{min-height:100%;min-width:100%}.q-scrollarea--dark .q-scrollarea__thumb{background:#fff}.q-select--without-input .q-field__control{cursor:pointer}.q-select--with-input .q-field__control{cursor:text}.q-select .q-field__input{min-width:50px!important;cursor:text}.q-select .q-field__input--padding{padding-left:4px}.q-select__autocomplete-input,.q-select__focus-target{position:absolute;outline:0!important;width:1px;height:1px;padding:0;border:0;opacity:0}.q-select__dropdown-icon{cursor:pointer;transition:transform .28s}.q-select.q-field--readonly .q-field__control,.q-select.q-field--readonly .q-select__dropdown-icon{cursor:default}.q-select__dialog{width:90vw!important;max-width:90vw!important;max-height:calc(100vh - 70px)!important;background:#fff;display:flex;flex-direction:column}.q-select__dialog>.scroll{position:relative;background:inherit}body.mobile:not(.native-mobile) .q-select__dialog{max-height:calc(100vh - 108px)!important}body.platform-android.native-mobile .q-dialog__inner--top .q-select__dialog{max-height:calc(100vh - 24px)!important}body.platform-android:not(.native-mobile) .q-dialog__inner--top .q-select__dialog{max-height:calc(100vh - 80px)!important}body.platform-ios.native-mobile .q-dialog__inner--top>div{border-radius:4px}body.platform-ios.native-mobile .q-dialog__inner--top .q-select__dialog--focused{max-height:47vh!important}body.platform-ios:not(.native-mobile) .q-dialog__inner--top .q-select__dialog--focused{max-height:50vh!important}.q-separator{border:0;background:rgba(0,0,0,.12);margin:0;transition:background .3s,opacity .3s;flex-shrink:0}.q-separator--dark{background:rgba(255,255,255,.28)}.q-separator--horizontal{display:block;height:1px}.q-separator--horizontal-inset{margin-left:16px;margin-right:16px}.q-separator--horizontal-item-inset{margin-left:72px;margin-right:0}.q-separator--horizontal-item-thumbnail-inset{margin-left:116px;margin-right:0}.q-separator--vertical{width:1px;height:auto;align-self:stretch}.q-separator--vertical-inset{margin-top:8px;margin-bottom:8px}.q-skeleton{--q-skeleton-speed:1500ms;background:rgba(0,0,0,.12);border-radius:4px;box-sizing:border-box}.q-skeleton--anim{cursor:wait}.q-skeleton:before{content:" "}.q-skeleton--type-text{transform:scale(1,.5)}.q-skeleton--type-QAvatar,.q-skeleton--type-circle{height:48px;width:48px;border-radius:50%}.q-skeleton--type-QBtn{width:90px;height:36px}.q-skeleton--type-QBadge{width:70px;height:16px}.q-skeleton--type-QChip{width:90px;height:28px;border-radius:16px}.q-skeleton--type-QToolbar{height:50px}.q-skeleton--type-QCheckbox,.q-skeleton--type-QRadio{width:40px;height:40px;border-radius:50%}.q-skeleton--type-QToggle{width:56px;height:40px;border-radius:7px}.q-skeleton--type-QRange,.q-skeleton--type-QSlider{height:40px}.q-skeleton--type-QInput{height:56px}.q-skeleton--bordered{border:1px solid rgba(0,0,0,.05)}.q-skeleton--square{border-radius:0}.q-skeleton--anim-fade{animation:q-skeleton--fade var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--anim-pulse{animation:q-skeleton--pulse var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-pulse-x{animation:q-skeleton--pulse-x var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-pulse-y{animation:q-skeleton--pulse-y var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-blink,.q-skeleton--anim-pop,.q-skeleton--anim-wave{position:relative;overflow:hidden;z-index:1}.q-skeleton--anim-blink:after,.q-skeleton--anim-pop:after,.q-skeleton--anim-wave:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.q-skeleton--anim-blink:after{background:rgba(255,255,255,.7);animation:q-skeleton--fade var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--anim-wave:after{background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.5),rgba(255,255,255,0));animation:q-skeleton--wave var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--dark{background:rgba(255,255,255,.05)}.q-skeleton--dark.q-skeleton--bordered{border:1px solid rgba(255,255,255,.25)}.q-skeleton--dark.q-skeleton--anim-wave:after{background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.1),rgba(255,255,255,0))}.q-skeleton--dark.q-skeleton--anim-blink:after{background:rgba(255,255,255,.2)}@keyframes q-skeleton--fade{0%{opacity:1}50%{opacity:.4}100%{opacity:1}}@keyframes q-skeleton--pulse{0%{transform:scale(1)}50%{transform:scale(.85)}100%{transform:scale(1)}}@keyframes q-skeleton--pulse-x{0%{transform:scaleX(1)}50%{transform:scaleX(.75)}100%{transform:scaleX(1)}}@keyframes q-skeleton--pulse-y{0%{transform:scaleY(1)}50%{transform:scaleY(.75)}100%{transform:scaleY(1)}}@keyframes q-skeleton--wave{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.q-slide-item{position:relative;background:#fff}.q-slide-item__bottom,.q-slide-item__left,.q-slide-item__right,.q-slide-item__top{visibility:hidden;font-size:14px;color:#fff}.q-slide-item__bottom .q-icon,.q-slide-item__left .q-icon,.q-slide-item__right .q-icon,.q-slide-item__top .q-icon{font-size:1.714em}.q-slide-item__left{background:#4caf50;padding:8px 16px}.q-slide-item__left>div{transform-origin:left center}.q-slide-item__right{background:#ff9800;padding:8px 16px}.q-slide-item__right>div{transform-origin:right center}.q-slide-item__top{background:#2196f3;padding:16px 8px}.q-slide-item__top>div{transform-origin:top center}.q-slide-item__bottom{background:#9c27b0;padding:16px 8px}.q-slide-item__bottom>div{transform-origin:bottom center}.q-slide-item__content{background:inherit;transition:transform .2s ease-in;-webkit-user-select:none;user-select:none;cursor:pointer}.q-slider{position:relative}.q-slider--h{width:100%}.q-slider--v{height:200px}.q-slider--editable .q-slider__track-container{cursor:grab}.q-slider__track-container{outline:0}.q-slider__track-container--h{width:100%;padding:12px 0}.q-slider__track-container--h .q-slider__selection{will-change:width,left}.q-slider__track-container--v{height:100%;padding:0 12px}.q-slider__track-container--v .q-slider__selection{will-change:height,top}.q-slider__track{color:var(--q-primary);background:rgba(0,0,0,.1);border-radius:4px;width:inherit;height:inherit}.q-slider__inner{background:rgba(0,0,0,.1);border-radius:inherit;width:100%;height:100%}.q-slider__selection{background:currentColor;border-radius:inherit;width:100%;height:100%}.q-slider__markers{color:rgba(0,0,0,.3);border-radius:inherit;width:100%;height:100%}.q-slider__markers:after{content:"";position:absolute;background:currentColor}.q-slider__markers--h{background-image:repeating-linear-gradient(to right,currentColor,currentColor 2px,rgba(255,255,255,0) 0,rgba(255,255,255,0))}.q-slider__markers--h:after{height:100%;width:2px;top:0;right:0}.q-slider__markers--v{background-image:repeating-linear-gradient(to bottom,currentColor,currentColor 2px,rgba(255,255,255,0) 0,rgba(255,255,255,0))}.q-slider__markers--v:after{width:100%;height:2px;left:0;bottom:0}.q-slider__marker-labels-container{position:relative;width:100%;height:100%;min-height:24px;min-width:24px}.q-slider__marker-labels{position:absolute}.q-slider__marker-labels--h-standard{top:0}.q-slider__marker-labels--h-switched{bottom:0}.q-slider__marker-labels--h-ltr{transform:translateX(-50%)}.q-slider__marker-labels--h-rtl{transform:translateX(50%)}.q-slider__marker-labels--v-standard{left:4px}.q-slider__marker-labels--v-switched{right:4px}.q-slider__marker-labels--v-ltr{transform:translateY(-50%)}.q-slider__marker-labels--v-rtl{transform:translateY(50%)}.q-slider__thumb{z-index:1;outline:0;color:var(--q-primary);transition:transform .18s ease-out,fill .18s ease-out,stroke .18s ease-out}.q-slider__thumb.q-slider--focus{opacity:1!important}.q-slider__thumb--h{top:50%;will-change:left}.q-slider__thumb--h-ltr{transform:scale(1) translate(-50%,-50%)}.q-slider__thumb--h-rtl{transform:scale(1) translate(50%,-50%)}.q-slider__thumb--v{left:50%;will-change:top}.q-slider__thumb--v-ltr{transform:scale(1) translate(-50%,-50%)}.q-slider__thumb--v-rtl{transform:scale(1) translate(-50%,50%)}.q-slider__thumb-shape{top:0;left:0;stroke-width:3.5;stroke:currentColor;transition:transform .28s}.q-slider__thumb-shape path{stroke:currentColor;fill:currentColor}.q-slider__focus-ring{border-radius:50%;opacity:0;transition:transform .266s ease-out,opacity .266s ease-out,background-color .266s ease-out;transition-delay:0.14s}.q-slider__pin{opacity:0;white-space:nowrap;transition:opacity .28s ease-out;transition-delay:0.14s}.q-slider__pin:before{content:"";width:0;height:0;position:absolute}.q-slider__pin--h:before{border-left:6px solid transparent;border-right:6px solid transparent;left:50%;transform:translateX(-50%)}.q-slider__pin--h-standard{bottom:100%}.q-slider__pin--h-standard:before{bottom:2px;border-top:6px solid currentColor}.q-slider__pin--h-switched{top:100%}.q-slider__pin--h-switched:before{top:2px;border-bottom:6px solid currentColor}.q-slider__pin--v{top:0}.q-slider__pin--v:before{top:50%;transform:translateY(-50%);border-top:6px solid transparent;border-bottom:6px solid transparent}.q-slider__pin--v-standard{left:100%}.q-slider__pin--v-standard:before{left:2px;border-right:6px solid currentColor}.q-slider__pin--v-switched{right:100%}.q-slider__pin--v-switched:before{right:2px;border-left:6px solid currentColor}.q-slider__label{z-index:1;white-space:nowrap;position:absolute}.q-slider__label--h{left:50%;transform:translateX(-50%)}.q-slider__label--h-standard{bottom:7px}.q-slider__label--h-switched{top:7px}.q-slider__label--v{top:50%;transform:translateY(-50%)}.q-slider__label--v-standard{left:7px}.q-slider__label--v-switched{right:7px}.q-slider__text-container{min-height:25px;padding:2px 8px;border-radius:4px;background:currentColor;position:relative;text-align:center}.q-slider__text{color:#fff;font-size:12px}.q-slider--no-value .q-slider__inner,.q-slider--no-value .q-slider__selection,.q-slider--no-value .q-slider__thumb{opacity:0}.q-slider--focus .q-slider__focus-ring,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__focus-ring{background:currentColor;transform:scale3d(1.55,1.55,1);opacity:.25}.q-slider--focus .q-slider__inner,.q-slider--focus .q-slider__selection,.q-slider--focus .q-slider__thumb,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__inner,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__selection,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__thumb{opacity:1}.q-slider--inactive .q-slider__thumb--h{transition:left .28s,right .28s}.q-slider--inactive .q-slider__thumb--v{transition:top .28s,bottom .28s}.q-slider--inactive .q-slider__selection{transition:width .28s,left .28s,right .28s,height .28s,top .28s,bottom .28s}.q-slider--inactive .q-slider__text-container{transition:transform .28s}.q-slider--active{cursor:grabbing}.q-slider--active .q-slider__thumb-shape{transform:scale(1.5)}.q-slider--active .q-slider__focus-ring,.q-slider--active.q-slider--label .q-slider__thumb-shape{transform:scale(0)!important}body.desktop .q-slider.q-slider--enabled .q-slider__track-container:hover .q-slider__pin{opacity:1}.q-slider--label .q-slider--focus .q-slider__pin,.q-slider--label.q-slider--active .q-slider__pin,.q-slider--label.q-slider--label-always .q-slider__pin{opacity:1}.q-slider--dark .q-slider__track{background:rgba(255,255,255,.1)}.q-slider--dark .q-slider__inner{background:rgba(255,255,255,.1)}.q-slider--dark .q-slider__markers{color:rgba(255,255,255,.3)}.q-slider--dense .q-slider__track-container--h{padding:6px 0}.q-slider--dense .q-slider__track-container--v{padding:0 6px}.q-space{flex-grow:1!important}.q-spinner{vertical-align:middle}.q-spinner-mat{animation:q-spin 2s linear infinite;transform-origin:center center}.q-spinner-mat .path{stroke-dasharray:1,200;stroke-dashoffset:0;animation:q-mat-dash 1.5s ease-in-out infinite}@keyframes q-spin{0%{transform:rotate3d(0,0,1,0deg)}25%{transform:rotate3d(0,0,1,90deg)}50%{transform:rotate3d(0,0,1,180deg)}75%{transform:rotate3d(0,0,1,270deg)}100%{transform:rotate3d(0,0,1,359deg)}}@keyframes q-mat-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}.q-splitter__panel{position:relative;z-index:0}.q-splitter__panel>.q-splitter{width:100%;height:100%}.q-splitter__separator{background-color:rgba(0,0,0,.12);-webkit-user-select:none;user-select:none;position:relative;z-index:1}.q-splitter__separator-area>*{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.q-splitter--dark .q-splitter__separator{background-color:rgba(255,255,255,.28)}.q-splitter--vertical>.q-splitter__panel{height:100%}.q-splitter--vertical.q-splitter--active{cursor:col-resize}.q-splitter--vertical>.q-splitter__separator{width:1px}.q-splitter--vertical>.q-splitter__separator>div{left:-6px;right:-6px}.q-splitter--vertical.q-splitter--workable>.q-splitter__separator{cursor:col-resize}.q-splitter--horizontal>.q-splitter__panel{width:100%}.q-splitter--horizontal.q-splitter--active{cursor:row-resize}.q-splitter--horizontal>.q-splitter__separator{height:1px}.q-splitter--horizontal>.q-splitter__separator>div{top:-6px;bottom:-6px}.q-splitter--horizontal.q-splitter--workable>.q-splitter__separator{cursor:row-resize}.q-splitter__after,.q-splitter__before{overflow:auto}.q-stepper{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff}.q-stepper__title{font-size:14px;line-height:1.285714;letter-spacing:.1px}.q-stepper__caption{font-size:12px;line-height:1.16667}.q-stepper__dot{contain:layout;margin-right:8px;font-size:14px;width:24px;min-width:24px;height:24px;border-radius:50%;background:currentColor}.q-stepper__dot span{color:#fff}.q-stepper__tab{padding:8px 24px;font-size:14px;color:#9e9e9e;flex-direction:row}.q-stepper--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-stepper--dark .q-stepper__dot span{color:#000}.q-stepper__tab--navigation{-webkit-user-select:none;user-select:none;cursor:pointer}.q-stepper__tab--active,.q-stepper__tab--done{color:var(--q-primary)}.q-stepper__tab--active .q-stepper__dot,.q-stepper__tab--active .q-stepper__label,.q-stepper__tab--done .q-stepper__dot,.q-stepper__tab--done .q-stepper__label{text-shadow:0 0 0 currentColor}.q-stepper__tab--disabled .q-stepper__dot{background:rgba(0,0,0,.22)}.q-stepper__tab--disabled .q-stepper__label{color:rgba(0,0,0,.32)}.q-stepper__tab--error{color:var(--q-negative)}.q-stepper__tab--error-with-icon .q-stepper__dot{background:0 0!important}.q-stepper__tab--error-with-icon .q-stepper__dot span{color:currentColor;font-size:24px}.q-stepper__header{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-stepper__header--border{border-bottom:1px solid rgba(0,0,0,.12)}.q-stepper__header--standard-labels .q-stepper__tab{min-height:72px;justify-content:center}.q-stepper__header--standard-labels .q-stepper__tab:first-child{justify-content:flex-start}.q-stepper__header--standard-labels .q-stepper__tab:last-child{justify-content:flex-end}.q-stepper__header--standard-labels .q-stepper__tab:only-child{justify-content:center}.q-stepper__header--standard-labels .q-stepper__dot:after{display:none}.q-stepper__header--alternative-labels .q-stepper__tab{min-height:104px;padding:24px 32px;flex-direction:column;justify-content:flex-start}.q-stepper__header--alternative-labels .q-stepper__dot{margin-right:0}.q-stepper__header--alternative-labels .q-stepper__label{margin-top:8px;text-align:center}.q-stepper__header--alternative-labels .q-stepper__label:after,.q-stepper__header--alternative-labels .q-stepper__label:before{display:none}.q-stepper__header--contracted{min-height:72px}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab{min-height:72px}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab:first-child{align-items:flex-start}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab:last-child{align-items:flex-end}.q-stepper__header--contracted .q-stepper__tab{padding:24px 0}.q-stepper__header--contracted .q-stepper__tab:first-child .q-stepper__dot{transform:translateX(24px)}.q-stepper__header--contracted .q-stepper__tab:last-child .q-stepper__dot{transform:translateX(-24px)}.q-stepper__header--contracted .q-stepper__tab:not(:last-child) .q-stepper__dot:after{display:block!important}.q-stepper__header--contracted .q-stepper__dot{margin:0}.q-stepper__header--contracted .q-stepper__label{display:none}.q-stepper__nav{padding-top:24px}.q-stepper--flat{box-shadow:none}.q-stepper--bordered{border:1px solid rgba(0,0,0,.12)}.q-stepper--horizontal .q-stepper__step-inner{padding:24px}.q-stepper--horizontal .q-stepper__tab:first-child{border-top-left-radius:inherit}.q-stepper--horizontal .q-stepper__tab:last-child{border-top-right-radius:inherit}.q-stepper--horizontal .q-stepper__tab:first-child .q-stepper__dot:before,.q-stepper--horizontal .q-stepper__tab:last-child .q-stepper__dot:after,.q-stepper--horizontal .q-stepper__tab:last-child .q-stepper__label:after{display:none}.q-stepper--horizontal .q-stepper__tab{overflow:hidden}.q-stepper--horizontal .q-stepper__line{contain:layout}.q-stepper--horizontal .q-stepper__line:after,.q-stepper--horizontal .q-stepper__line:before{position:absolute;top:50%;height:1px;width:100vw;background:rgba(0,0,0,.12)}.q-stepper--horizontal .q-stepper__dot:after,.q-stepper--horizontal .q-stepper__label:after{content:"";left:100%;margin-left:8px}.q-stepper--horizontal .q-stepper__dot:before{content:"";right:100%;margin-right:8px}.q-stepper--horizontal>.q-stepper__nav{padding:0 24px 24px}.q-stepper--vertical{padding:16px 0}.q-stepper--vertical .q-stepper__tab{padding:12px 24px}.q-stepper--vertical .q-stepper__title{line-height:18px}.q-stepper--vertical .q-stepper__step-inner{padding:0 24px 32px 60px}.q-stepper--vertical>.q-stepper__nav{padding:24px 24px 0}.q-stepper--vertical .q-stepper__step{overflow:hidden}.q-stepper--vertical .q-stepper__dot{margin-right:12px}.q-stepper--vertical .q-stepper__dot:after,.q-stepper--vertical .q-stepper__dot:before{content:"";position:absolute;left:50%;width:1px;height:99999px;background:rgba(0,0,0,.12)}.q-stepper--vertical .q-stepper__dot:before{bottom:100%;margin-bottom:8px}.q-stepper--vertical .q-stepper__dot:after{top:100%;margin-top:8px}.q-stepper--vertical .q-stepper__step:first-child .q-stepper__dot:before,.q-stepper--vertical .q-stepper__step:last-child .q-stepper__dot:after{display:none}.q-stepper--vertical .q-stepper__step:last-child .q-stepper__step-inner{padding-bottom:8px}.q-stepper--dark .q-stepper__header--border,.q-stepper--dark.q-stepper--bordered{border-color:rgba(255,255,255,.28)}.q-stepper--dark.q-stepper--horizontal .q-stepper__line:after,.q-stepper--dark.q-stepper--horizontal .q-stepper__line:before{background:rgba(255,255,255,.28)}.q-stepper--dark.q-stepper--vertical .q-stepper__dot:after,.q-stepper--dark.q-stepper--vertical .q-stepper__dot:before{background:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled{color:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled .q-stepper__dot{background:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled .q-stepper__label{color:rgba(255,255,255,.54)}.q-tab-panels{background:#fff}.q-tab-panel{padding:16px}.q-markup-table{overflow:auto;background:#fff}.q-table{width:100%;max-width:100%;border-collapse:separate;border-spacing:0}.q-table tbody td,.q-table thead tr{height:48px}.q-table th{font-weight:500;font-size:12px;-webkit-user-select:none;user-select:none}.q-table th.sortable{cursor:pointer}.q-table th.sortable:hover .q-table__sort-icon{opacity:.64}.q-table th.sorted .q-table__sort-icon{opacity:.86!important}.q-table th.sort-desc .q-table__sort-icon{transform:rotate(180deg)}.q-table td,.q-table th{padding:7px 16px;background-color:inherit}.q-table td,.q-table th,.q-table thead{border-style:solid;border-width:0}.q-table tbody td{font-size:13px}.q-table__card{color:#000;background-color:#fff;border-radius:4px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-table__card .q-table__middle{flex:1 1 auto}.q-table__card .q-table__bottom,.q-table__card .q-table__top{flex:0 0 auto}.q-table__container{position:relative}.q-table__container>div:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-table__container>div:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.q-table__container>.q-inner-loading{border-radius:inherit!important}.q-table__top{padding:12px 16px}.q-table__top .q-table__control{flex-wrap:wrap}.q-table__title{font-size:20px;letter-spacing:.005em;font-weight:400}.q-table__separator{min-width:8px!important}.q-table__progress{height:0!important}.q-table__progress th{padding:0!important;border:0!important}.q-table__progress .q-linear-progress{position:absolute;bottom:0}.q-table__middle{max-width:100%}.q-table__bottom{min-height:50px;padding:4px 14px 4px 16px;font-size:12px}.q-table__bottom .q-table__control{min-height:24px}.q-table__bottom-nodata-icon{font-size:200%;margin-right:8px}.q-table__bottom-item{margin-right:16px}.q-table__control{display:flex;align-items:center}.q-table__sort-icon{transition:transform .3s cubic-bezier(.25, .8, .5, 1);opacity:0;font-size:120%}.q-table__sort-icon--center,.q-table__sort-icon--left{margin-left:4px}.q-table__sort-icon--right{margin-right:4px}.q-table--col-auto-width{width:1px}.q-table--dark,.q-table__card--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-table--flat{box-shadow:none}.q-table--bordered{border:1px solid rgba(0,0,0,.12)}.q-table--square{border-radius:0}.q-table__linear-progress{height:2px}.q-table--no-wrap td,.q-table--no-wrap th{white-space:nowrap}.q-table--grid{box-shadow:none;border-radius:4px}.q-table--grid .q-table__top{padding-bottom:4px}.q-table--grid .q-table__middle{min-height:2px;margin-bottom:4px}.q-table--grid .q-table__middle thead,.q-table--grid .q-table__middle thead th{border:0!important}.q-table--grid .q-table__linear-progress{bottom:0}.q-table--grid .q-table__bottom{border-top:0}.q-table--grid .q-table__grid-content{flex:1 1 auto}.q-table--grid.fullscreen{background:inherit}.q-table__grid-item-card{vertical-align:top;padding:12px}.q-table__grid-item-card .q-separator{margin:12px 0}.q-table__grid-item-row+.q-table__grid-item-row{margin-top:8px}.q-table__grid-item-title{opacity:.54;font-weight:500;font-size:12px}.q-table__grid-item-value{font-size:13px}.q-table__grid-item{padding:4px;transition:transform .3s cubic-bezier(.25, .8, .5, 1)}.q-table__grid-item--selected{transform:scale(.95)}.q-table--cell-separator tbody tr:not(:last-child)>td,.q-table--cell-separator thead th,.q-table--horizontal-separator tbody tr:not(:last-child)>td,.q-table--horizontal-separator thead th{border-bottom-width:1px}.q-table--cell-separator td,.q-table--cell-separator th,.q-table--vertical-separator td,.q-table--vertical-separator th{border-left-width:1px}.q-table--cell-separator thead tr:last-child th,.q-table--cell-separator.q-table--loading tr:nth-last-child(2) th,.q-table--vertical-separator thead tr:last-child th,.q-table--vertical-separator.q-table--loading tr:nth-last-child(2) th{border-bottom-width:1px}.q-table--cell-separator td:first-child,.q-table--cell-separator th:first-child,.q-table--vertical-separator td:first-child,.q-table--vertical-separator th:first-child{border-left:0}.q-table--cell-separator .q-table__top,.q-table--vertical-separator .q-table__top{border-bottom:1px solid rgba(0,0,0,.12)}.q-table--dense .q-table__top{padding:6px 16px}.q-table--dense .q-table__bottom{min-height:33px}.q-table--dense .q-table__sort-icon{font-size:110%}.q-table--dense .q-table td,.q-table--dense .q-table th{padding:4px 8px}.q-table--dense .q-table tbody td,.q-table--dense .q-table tbody tr,.q-table--dense .q-table thead tr{height:28px}.q-table--dense .q-table td:first-child,.q-table--dense .q-table th:first-child{padding-left:16px}.q-table--dense .q-table td:last-child,.q-table--dense .q-table th:last-child{padding-right:16px}.q-table--dense .q-table__bottom-item{margin-right:8px}.q-table--dense .q-table__select .q-field__control,.q-table--dense .q-table__select .q-field__native{min-height:24px;padding:0}.q-table--dense .q-table__select .q-field__marginal{height:24px}.q-table__bottom:not(.q-table__bottom--nodata){border-top:1px solid rgba(0,0,0,.12)}.q-table td,.q-table th,.q-table thead,.q-table tr{border-color:rgba(0,0,0,.12)}.q-table tbody td{position:relative}.q-table tbody td:after,.q-table tbody td:before{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none}.q-table tbody td:before{background:rgba(0,0,0,.03)}.q-table tbody td:after{background:rgba(0,0,0,.06)}.q-table tbody tr.selected td:after{content:""}body.desktop .q-table>tbody>tr:not(.q-tr--no-hover):hover>td:not(.q-td--no-hover):before{content:""}.q-table--dark,.q-table__card--dark{border-color:rgba(255,255,255,.28)}.q-table--dark .q-table__bottom,.q-table--dark td,.q-table--dark th,.q-table--dark thead,.q-table--dark tr{border-color:rgba(255,255,255,.28)}.q-table--dark tbody td:before{background:rgba(255,255,255,.07)}.q-table--dark tbody td:after{background:rgba(255,255,255,.1)}.q-table--dark.q-table--cell-separator .q-table__top,.q-table--dark.q-table--vertical-separator .q-table__top{border-color:rgba(255,255,255,.28)}.q-tab{padding:0 16px;min-height:48px;transition:color .3s,background-color .3s;text-transform:uppercase;white-space:nowrap;color:inherit;text-decoration:none}.q-tab--full{min-height:72px}.q-tab--no-caps{text-transform:none}.q-tab__content{height:inherit;padding:4px 0;min-width:40px}.q-tab__content--inline .q-tab__icon+.q-tab__label{padding-left:8px}.q-tab__content .q-chip--floating{top:0;right:-16px}.q-tab__icon{width:24px;height:24px;font-size:24px}.q-tab__label{font-size:14px;line-height:1.715em;font-weight:500}.q-tab .q-badge{top:3px;right:-12px}.q-tab__alert,.q-tab__alert-icon{position:absolute}.q-tab__alert{top:7px;right:-9px;height:10px;width:10px;border-radius:50%;background:currentColor}.q-tab__alert-icon{top:2px;right:-12px;font-size:18px}.q-tab__indicator{opacity:0;height:2px;background:currentColor}.q-tab--active .q-tab__indicator{opacity:1;transform-origin:left}.q-tab--inactive{opacity:.85}.q-tabs{position:relative;transition:color .3s,background-color .3s}.q-tabs--scrollable.q-tabs__arrows--outside.q-tabs--horizontal{padding-left:36px;padding-right:36px}.q-tabs--scrollable.q-tabs__arrows--outside.q-tabs--vertical{padding-top:36px;padding-bottom:36px}.q-tabs--scrollable.q-tabs__arrows--outside .q-tabs__arrow--faded{opacity:.3;pointer-events:none}.q-tabs--scrollable.q-tabs__arrows--inside .q-tabs__arrow--faded{display:none}.q-tabs--not-scrollable.q-tabs__arrows--outside,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows.q-tabs__arrows--outside{padding-left:0;padding-right:0}.q-tabs--not-scrollable .q-tabs__arrow,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows .q-tabs__arrow{display:none}.q-tabs--not-scrollable .q-tabs__content,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows .q-tabs__content{border-radius:inherit}.q-tabs__arrow{cursor:pointer;font-size:32px;min-width:36px;text-shadow:0 0 3px #fff,0 0 1px #fff,0 0 1px #000;transition:opacity .3s}.q-tabs__content{overflow:hidden;flex:1 1 auto}.q-tabs__content--align-center{justify-content:center}.q-tabs__content--align-right{justify-content:flex-end}.q-tabs__content--align-justify .q-tab{flex:1 1 auto}.q-tabs__offset{display:none}.q-tabs--horizontal .q-tabs__arrow{height:100%}.q-tabs--horizontal .q-tabs__arrow--left{top:0;left:0;bottom:0}.q-tabs--horizontal .q-tabs__arrow--right{top:0;right:0;bottom:0}.q-tabs--vertical{display:block!important;height:100%}.q-tabs--vertical .q-tabs__content{display:block!important;height:100%}.q-tabs--vertical .q-tabs__arrow{width:100%;height:36px;text-align:center}.q-tabs--vertical .q-tabs__arrow--left{top:0;left:0;right:0}.q-tabs--vertical .q-tabs__arrow--right{left:0;right:0;bottom:0}.q-tabs--vertical .q-tab{padding:0 8px}.q-tabs--vertical .q-tab__indicator{height:unset;width:2px}.q-tabs--vertical.q-tabs--not-scrollable .q-tabs__content{height:100%}.q-tabs--vertical.q-tabs--dense .q-tab__content{min-width:24px}.q-tabs--dense .q-tab{min-height:36px}.q-tabs--dense .q-tab--full{min-height:52px}.q-time{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff;outline:0;width:290px;min-width:290px;max-width:100%}.q-time--bordered{border:1px solid rgba(0,0,0,.12)}.q-time__header{border-top-left-radius:inherit;color:#fff;background-color:var(--q-primary);padding:16px;font-weight:300}.q-time__actions{padding:0 16px 16px}.q-time__header-label{font-size:28px;line-height:1;letter-spacing:-.00833em}.q-time__header-label>div+div{margin-left:4px}.q-time__link{opacity:.56;outline:0;transition:opacity .3s ease-out}.q-time__link--active,.q-time__link:focus,.q-time__link:hover{opacity:1}.q-time__header-ampm{font-size:16px;letter-spacing:.1em}.q-time__content{padding:16px}.q-time__content:before{content:"";display:block;padding-bottom:100%}.q-time__container-parent{padding:16px}.q-time__container-child{border-radius:50%;background:rgba(0,0,0,.12)}.q-time__clock{padding:24px;width:100%;height:100%;max-width:100%;max-height:100%;font-size:14px}.q-time__clock-circle{position:relative}.q-time__clock-center{height:6px;width:6px;margin:auto;border-radius:50%;min-height:0;background:currentColor}.q-time__clock-pointer{width:2px;height:50%;transform-origin:0 0;min-height:0;position:absolute;left:50%;right:0;bottom:0;color:var(--q-primary);background:currentColor;transform:translateX(-50%)}.q-time__clock-pointer:after,.q-time__clock-pointer:before{content:"";position:absolute;left:50%;border-radius:50%;background:currentColor;transform:translateX(-50%)}.q-time__clock-pointer:before{bottom:-4px;width:8px;height:8px}.q-time__clock-pointer:after{top:-3px;height:6px;width:6px}.q-time__clock-position{position:absolute;min-height:32px;width:32px;height:32px;font-size:12px;line-height:32px;margin:0;padding:0;transform:translate(-50%,-50%);border-radius:50%}.q-time__clock-position--disable{opacity:.4}.q-time__clock-position--active{background-color:var(--q-primary);color:#fff}.q-time__clock-pos-0{top:0;left:50%}.q-time__clock-pos-1{top:6.7%;left:75%}.q-time__clock-pos-2{top:25%;left:93.3%}.q-time__clock-pos-3{top:50%;left:100%}.q-time__clock-pos-4{top:75%;left:93.3%}.q-time__clock-pos-5{top:93.3%;left:75%}.q-time__clock-pos-6{top:100%;left:50%}.q-time__clock-pos-7{top:93.3%;left:25%}.q-time__clock-pos-8{top:75%;left:6.7%}.q-time__clock-pos-9{top:50%;left:0}.q-time__clock-pos-10{top:25%;left:6.7%}.q-time__clock-pos-11{top:6.7%;left:25%}.q-time__clock-pos-12{top:15%;left:50%}.q-time__clock-pos-13{top:19.69%;left:67.5%}.q-time__clock-pos-14{top:32.5%;left:80.31%}.q-time__clock-pos-15{top:50%;left:85%}.q-time__clock-pos-16{top:67.5%;left:80.31%}.q-time__clock-pos-17{top:80.31%;left:67.5%}.q-time__clock-pos-18{top:85%;left:50%}.q-time__clock-pos-19{top:80.31%;left:32.5%}.q-time__clock-pos-20{top:67.5%;left:19.69%}.q-time__clock-pos-21{top:50%;left:15%}.q-time__clock-pos-22{top:32.5%;left:19.69%}.q-time__clock-pos-23{top:19.69%;left:32.5%}.q-time__now-button{background-color:var(--q-primary);color:#fff;top:12px;right:12px}.q-time--readonly .q-time__content,.q-time--readonly .q-time__header-ampm,.q-time.disabled .q-time__content,.q-time.disabled .q-time__header-ampm{pointer-events:none}.q-time--portrait{display:inline-flex;flex-direction:column}.q-time--portrait .q-time__header{border-top-right-radius:inherit;min-height:86px}.q-time--portrait .q-time__header-ampm{margin-left:12px}.q-time--portrait.q-time--bordered .q-time__content{margin:1px 0}.q-time--landscape{display:inline-flex;align-items:stretch;min-width:420px}.q-time--landscape>div{display:flex;flex-direction:column;justify-content:center}.q-time--landscape .q-time__header{border-bottom-left-radius:inherit;min-width:156px}.q-time--landscape .q-time__header-ampm{margin-top:12px}.q-time--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-timeline{padding:0;width:100%;list-style:none}.q-timeline h6{line-height:inherit}.q-timeline--dark{color:#fff}.q-timeline--dark .q-timeline__subtitle{opacity:.7}.q-timeline__content{padding-bottom:24px}.q-timeline__title{margin-top:0;margin-bottom:16px}.q-timeline__subtitle{font-size:12px;margin-bottom:8px;opacity:.6;text-transform:uppercase;letter-spacing:1px;font-weight:700}.q-timeline__dot{position:absolute;top:0;bottom:0;width:15px}.q-timeline__dot:after,.q-timeline__dot:before{content:"";background:currentColor;display:block;position:absolute}.q-timeline__dot:before{border:3px solid transparent;border-radius:100%;height:15px;width:15px;top:4px;left:0;transition:background .3s ease-in-out,border .3s ease-in-out}.q-timeline__dot:after{width:3px;opacity:.4;top:24px;bottom:0;left:6px}.q-timeline__dot .q-icon{position:absolute;top:0;left:0;right:0;font-size:16px;height:38px;line-height:38px;width:100%;color:#fff}.q-timeline__dot .q-icon>img,.q-timeline__dot .q-icon>svg{width:1em;height:1em}.q-timeline__dot-img{position:absolute;top:4px;left:0;right:0;height:31px;width:31px;background:currentColor;border-radius:50%}.q-timeline__heading{position:relative}.q-timeline__heading:first-child .q-timeline__heading-title{padding-top:0}.q-timeline__heading:last-child .q-timeline__heading-title{padding-bottom:0}.q-timeline__heading-title{padding:32px 0;margin:0}.q-timeline__entry{position:relative;line-height:22px}.q-timeline__entry:last-child{padding-bottom:0!important}.q-timeline__entry:last-child .q-timeline__dot:after{content:none}.q-timeline__entry--icon .q-timeline__dot{width:31px}.q-timeline__entry--icon .q-timeline__dot:before{height:31px;width:31px}.q-timeline__entry--icon .q-timeline__dot:after{top:41px;left:14px}.q-timeline__entry--icon .q-timeline__subtitle{padding-top:8px}.q-timeline--dense--right .q-timeline__entry{padding-left:40px}.q-timeline--dense--right .q-timeline__entry--icon .q-timeline__dot{left:-8px}.q-timeline--dense--right .q-timeline__dot{left:0}.q-timeline--dense--left .q-timeline__heading{text-align:right}.q-timeline--dense--left .q-timeline__entry{padding-right:40px}.q-timeline--dense--left .q-timeline__entry--icon .q-timeline__dot{right:-8px}.q-timeline--dense--left .q-timeline__content,.q-timeline--dense--left .q-timeline__subtitle,.q-timeline--dense--left .q-timeline__title{text-align:right}.q-timeline--dense--left .q-timeline__dot{right:0}.q-timeline--comfortable{display:table}.q-timeline--comfortable .q-timeline__heading{display:table-row;font-size:200%}.q-timeline--comfortable .q-timeline__heading>div{display:table-cell}.q-timeline--comfortable .q-timeline__entry{display:table-row;padding:0}.q-timeline--comfortable .q-timeline__entry--icon .q-timeline__content{padding-top:8px}.q-timeline--comfortable .q-timeline__content,.q-timeline--comfortable .q-timeline__dot,.q-timeline--comfortable .q-timeline__subtitle{display:table-cell;vertical-align:top}.q-timeline--comfortable .q-timeline__subtitle{width:35%}.q-timeline--comfortable .q-timeline__dot{position:relative;min-width:31px}.q-timeline--comfortable--right .q-timeline__heading .q-timeline__heading-title{margin-left:-50px}.q-timeline--comfortable--right .q-timeline__subtitle{text-align:right;padding-right:30px}.q-timeline--comfortable--right .q-timeline__content{padding-left:30px}.q-timeline--comfortable--right .q-timeline__entry--icon .q-timeline__dot{left:-8px}.q-timeline--comfortable--left .q-timeline__heading{text-align:right}.q-timeline--comfortable--left .q-timeline__heading .q-timeline__heading-title{margin-right:-50px}.q-timeline--comfortable--left .q-timeline__subtitle{padding-left:30px}.q-timeline--comfortable--left .q-timeline__content{padding-right:30px}.q-timeline--comfortable--left .q-timeline__content,.q-timeline--comfortable--left .q-timeline__title{text-align:right}.q-timeline--comfortable--left .q-timeline__entry--icon .q-timeline__dot{right:0}.q-timeline--comfortable--left .q-timeline__dot{right:-8px}.q-timeline--loose .q-timeline__heading-title{text-align:center;margin-left:0}.q-timeline--loose .q-timeline__content,.q-timeline--loose .q-timeline__dot,.q-timeline--loose .q-timeline__entry,.q-timeline--loose .q-timeline__subtitle{display:block;margin:0;padding:0}.q-timeline--loose .q-timeline__dot{position:absolute;left:50%;margin-left:-7.15px}.q-timeline--loose .q-timeline__entry{padding-bottom:24px;overflow:hidden}.q-timeline--loose .q-timeline__entry--icon .q-timeline__dot{margin-left:-15px}.q-timeline--loose .q-timeline__entry--icon .q-timeline__subtitle{line-height:38px}.q-timeline--loose .q-timeline__entry--icon .q-timeline__content{padding-top:8px}.q-timeline--loose .q-timeline__entry--left .q-timeline__content,.q-timeline--loose .q-timeline__entry--right .q-timeline__subtitle{float:left;padding-right:30px;text-align:right}.q-timeline--loose .q-timeline__entry--left .q-timeline__subtitle,.q-timeline--loose .q-timeline__entry--right .q-timeline__content{float:right;text-align:left;padding-left:30px}.q-timeline--loose .q-timeline__content,.q-timeline--loose .q-timeline__subtitle{width:50%}.q-toggle{vertical-align:middle}.q-toggle__native{width:1px;height:1px}.q-toggle__track{height:.35em;border-radius:.175em;opacity:.38;background:currentColor}.q-toggle__thumb{top:.25em;left:.25em;width:.5em;height:.5em;transition:left .22s cubic-bezier(.4, 0, .2, 1);-webkit-user-select:none;user-select:none;z-index:0}.q-toggle__thumb:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:#fff;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.q-toggle__thumb .q-icon{font-size:.3em;min-width:1em;color:#000;opacity:.54;z-index:1}.q-toggle__inner{font-size:40px;width:1.4em;min-width:1.4em;height:1em;padding:.325em .3em;-webkit-print-color-adjust:exact}.q-toggle__inner--indet .q-toggle__thumb{left:.45em}.q-toggle__inner--truthy{color:var(--q-primary)}.q-toggle__inner--truthy .q-toggle__track{opacity:.54}.q-toggle__inner--truthy .q-toggle__thumb{left:.65em}.q-toggle__inner--truthy .q-toggle__thumb:after{background-color:currentColor}.q-toggle__inner--truthy .q-toggle__thumb .q-icon{color:#fff;opacity:1}.q-toggle.disabled{opacity:.75!important}.q-toggle--dark .q-toggle__inner{color:#fff}.q-toggle--dark .q-toggle__inner--truthy{color:var(--q-primary)}.q-toggle--dark .q-toggle__thumb:after{box-shadow:none}.q-toggle--dark .q-toggle__thumb:before{opacity:.32!important}.q-toggle--dense .q-toggle__inner{width:.8em;min-width:.8em;height:.5em;padding:.07625em 0}.q-toggle--dense .q-toggle__thumb{top:0;left:0}.q-toggle--dense .q-toggle__inner--indet .q-toggle__thumb{left:.15em}.q-toggle--dense .q-toggle__inner--truthy .q-toggle__thumb{left:.3em}.q-toggle--dense .q-toggle__label{padding-left:.5em}.q-toggle--dense.reverse .q-toggle__label{padding-left:0;padding-right:.5em}body.desktop .q-toggle:not(.disabled) .q-toggle__thumb:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1)}body.desktop .q-toggle:not(.disabled):focus .q-toggle__thumb:before,body.desktop .q-toggle:not(.disabled):hover .q-toggle__thumb:before{transform:scale3d(2,2,1)}body.desktop .q-toggle--dense:not(.disabled):focus .q-toggle__thumb:before,body.desktop .q-toggle--dense:not(.disabled):hover .q-toggle__thumb:before{transform:scale3d(1.5,1.5,1)}.q-toolbar{position:relative;padding:0 12px;min-height:50px;width:100%}.q-toolbar--inset{padding-left:58px}.q-toolbar .q-avatar{font-size:38px}.q-toolbar__title{flex:1 1 0%;min-width:1px;max-width:100%;font-size:21px;font-weight:400;letter-spacing:.01em;padding:0 12px}.q-toolbar__title:first-child{padding-left:0}.q-toolbar__title:last-child{padding-right:0}.q-tooltip--style{font-size:10px;color:#fafafa;background:#757575;border-radius:4px;text-transform:none;font-weight:400}.q-tooltip{z-index:9000;position:fixed!important;overflow-y:auto;overflow-x:hidden;padding:6px 10px;max-width:95vw;max-height:65vh}@media (max-width:599.98px){.q-tooltip{font-size:14px;padding:8px 16px}}.q-tree{position:relative;color:#9e9e9e}.q-tree__node{padding:0 0 3px 22px}.q-tree__node:after{content:"";position:absolute;top:-3px;bottom:0;width:2px;right:auto;left:-13px;border-left:1px solid currentColor}.q-tree__node:last-child:after{display:none}.q-tree__node--disabled{pointer-events:none}.q-tree__node--disabled .disabled{opacity:1!important}.q-tree__node--disabled>.disabled,.q-tree__node--disabled>div,.q-tree__node--disabled>i{opacity:.6!important}.q-tree__node--disabled>.disabled .q-tree__node--disabled>.disabled,.q-tree__node--disabled>.disabled .q-tree__node--disabled>div,.q-tree__node--disabled>.disabled .q-tree__node--disabled>i,.q-tree__node--disabled>div .q-tree__node--disabled>.disabled,.q-tree__node--disabled>div .q-tree__node--disabled>div,.q-tree__node--disabled>div .q-tree__node--disabled>i,.q-tree__node--disabled>i .q-tree__node--disabled>.disabled,.q-tree__node--disabled>i .q-tree__node--disabled>div,.q-tree__node--disabled>i .q-tree__node--disabled>i{opacity:1!important}.q-tree__node-header:before{content:"";position:absolute;top:-3px;bottom:50%;width:31px;left:-35px;border-left:1px solid currentColor;border-bottom:1px solid currentColor}.q-tree__children{padding-left:25px}.q-tree__node-body{padding:5px 0 8px 5px}.q-tree__node--parent{padding-left:2px}.q-tree__node--parent>.q-tree__node-header:before{width:15px;left:-15px}.q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body{padding:5px 0 8px 27px}.q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body:after{content:"";position:absolute;top:0;width:2px;height:100%;right:auto;left:12px;border-left:1px solid currentColor;bottom:50px}.q-tree__node--link{cursor:pointer}.q-tree__node-header{padding:4px;margin-top:3px;border-radius:4px;outline:0}.q-tree__node-header-content{color:#000;transition:color .3s}.q-tree__node--selected .q-tree__node-header-content{color:#9e9e9e}.q-tree__icon,.q-tree__node-header-content .q-icon{font-size:21px}.q-tree__img{height:42px;border-radius:2px}.q-tree__avatar,.q-tree__node-header-content .q-avatar{font-size:28px;border-radius:50%;width:28px;height:28px}.q-tree__arrow,.q-tree__spinner{font-size:16px;margin-right:4px}.q-tree__arrow{transition:transform .3s}.q-tree__arrow--rotate{transform:rotate3d(0,0,1,90deg)}.q-tree__tickbox{margin-right:4px}.q-tree>.q-tree__node{padding:0}.q-tree>.q-tree__node:after,.q-tree>.q-tree__node>.q-tree__node-header:before{display:none}.q-tree>.q-tree__node--child>.q-tree__node-header{padding-left:24px}.q-tree--dark .q-tree__node-header-content{color:#fff}.q-tree--no-connectors .q-tree__node-body:after,.q-tree--no-connectors .q-tree__node-header:before,.q-tree--no-connectors .q-tree__node:after{display:none!important}.q-tree--dense>.q-tree__node--child>.q-tree__node-header{padding-left:1px}.q-tree--dense .q-tree__arrow,.q-tree--dense .q-tree__spinner{margin-right:1px}.q-tree--dense .q-tree__img{height:32px}.q-tree--dense .q-tree__tickbox{margin-right:3px}.q-tree--dense .q-tree__node{padding:0}.q-tree--dense .q-tree__node:after{top:0;left:-8px}.q-tree--dense .q-tree__node-header{margin-top:0;padding:1px}.q-tree--dense .q-tree__node-header:before{top:0;left:-8px;width:8px}.q-tree--dense .q-tree__node--child{padding-left:17px}.q-tree--dense .q-tree__node--child>.q-tree__node-header:before{left:-25px;width:21px}.q-tree--dense .q-tree__node-body{padding:0 0 2px}.q-tree--dense .q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body{padding:0 0 2px 20px}.q-tree--dense .q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body:after{left:8px}.q-tree--dense .q-tree__children{padding-left:16px}[dir=rtl] .q-tree__arrow{transform:rotate3d(0,0,1,180deg)}[dir=rtl] .q-tree__arrow--rotate{transform:rotate3d(0,0,1,90deg)}.q-uploader{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;vertical-align:top;background:#fff;position:relative;width:320px;max-height:320px}.q-uploader--bordered{border:1px solid rgba(0,0,0,.12)}.q-uploader__input{opacity:0;width:100%;height:100%;cursor:pointer!important;z-index:1}.q-uploader__input::-webkit-file-upload-button{cursor:pointer}.q-uploader__file:before{content:"";border-top-left-radius:inherit;border-top-right-radius:inherit;position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;background:currentColor;opacity:.04}.q-uploader__header{position:relative;border-top-left-radius:inherit;border-top-right-radius:inherit;background-color:var(--q-primary);color:#fff;width:100%}.q-uploader__spinner{font-size:24px;margin-right:4px}.q-uploader__header-content{padding:8px}.q-uploader__dnd{outline:1px dashed currentColor;outline-offset:-4px;background:rgba(255,255,255,.6)}.q-uploader__overlay{font-size:36px;color:#000;background-color:rgba(255,255,255,.6)}.q-uploader__list{position:relative;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;padding:8px;min-height:60px;flex:1 1 auto}.q-uploader__file{border-radius:4px 4px 0 0;border:1px solid rgba(0,0,0,.12)}.q-uploader__file .q-circular-progress{font-size:24px}.q-uploader__file--img{color:#fff;height:200px;min-width:200px;background-position:50% 50%;background-repeat:no-repeat}.q-uploader__file--img:before{content:none}.q-uploader__file--img .q-circular-progress{color:#fff}.q-uploader__file--img .q-uploader__file-header{padding-bottom:24px;background:linear-gradient(to bottom,rgba(0,0,0,.7) 20%,rgba(255,255,255,0))}.q-uploader__file+.q-uploader__file{margin-top:8px}.q-uploader__file-header{position:relative;padding:4px 8px;border-top-left-radius:inherit;border-top-right-radius:inherit}.q-uploader__file-header-content{padding-right:8px}.q-uploader__file-status{font-size:24px;margin-right:4px}.q-uploader__title{font-size:14px;font-weight:700;line-height:1.285714;word-break:break-word}.q-uploader__subtitle{font-size:12px;line-height:1.5}.q-uploader--disable .q-uploader__header,.q-uploader--disable .q-uploader__list{pointer-events:none}.q-uploader--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-uploader--dark .q-uploader__file{border-color:rgba(255,255,255,.28)}.q-uploader--dark .q-uploader__dnd,.q-uploader--dark .q-uploader__overlay{background:rgba(255,255,255,.3)}.q-uploader--dark .q-uploader__overlay{color:#fff}img.responsive{max-width:100%;height:auto}.q-video{position:relative;overflow:hidden;border-radius:inherit}.q-video embed,.q-video iframe,.q-video object{width:100%;height:100%}.q-video--responsive{height:0}.q-video--responsive embed,.q-video--responsive iframe,.q-video--responsive object{position:absolute;top:0;left:0}.q-virtual-scroll:focus{outline:0}.q-virtual-scroll__content{outline:0;contain:content}.q-virtual-scroll__content>*{overflow-anchor:none}.q-virtual-scroll__content>[data-q-vs-anchor]{overflow-anchor:auto}.q-virtual-scroll__padding{background:linear-gradient(rgba(255,255,255,0),rgba(255,255,255,0) 20%,rgba(128,128,128,.03) 20%,rgba(128,128,128,.08) 50%,rgba(128,128,128,.03) 80%,rgba(255,255,255,0) 80%,rgba(255,255,255,0));background-size:var(--q-virtual-scroll-item-width,100%) var(--q-virtual-scroll-item-height,50px)}.q-table .q-virtual-scroll__padding tr{height:0!important}.q-table .q-virtual-scroll__padding td{padding:0!important}.q-virtual-scroll--horizontal{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:stretch}.q-virtual-scroll--horizontal .q-virtual-scroll__content{display:flex;flex-direction:row;flex-wrap:nowrap}.q-virtual-scroll--horizontal .q-virtual-scroll__content,.q-virtual-scroll--horizontal .q-virtual-scroll__content>*,.q-virtual-scroll--horizontal .q-virtual-scroll__padding{flex:0 0 auto}.q-virtual-scroll--horizontal .q-virtual-scroll__padding{background:linear-gradient(to left,rgba(255,255,255,0),rgba(255,255,255,0) 20%,rgba(128,128,128,.03) 20%,rgba(128,128,128,.08) 50%,rgba(128,128,128,.03) 80%,rgba(255,255,255,0) 80%,rgba(255,255,255,0));background-size:var(--q-virtual-scroll-item-width,50px) var(--q-virtual-scroll-item-height,100%)}.q-ripple{position:absolute;top:0;left:0;width:100%;height:100%;color:inherit;border-radius:inherit;z-index:0;pointer-events:none;overflow:hidden;contain:strict}.q-ripple__inner{position:absolute;top:0;left:0;opacity:0;color:inherit;border-radius:50%;background:currentColor;pointer-events:none;will-change:transform,opacity}.q-ripple__inner--enter{transition:transform 225ms cubic-bezier(.4, 0, .2, 1),opacity .1s cubic-bezier(.4, 0, .2, 1)}.q-ripple__inner--leave{transition:opacity .25s cubic-bezier(.4, 0, .2, 1)}.q-morph--internal,.q-morph--invisible{opacity:0!important;pointer-events:none!important;position:fixed!important;right:200vw!important;bottom:200vh!important}.q-bottom-sheet{padding-bottom:8px}.q-bottom-sheet__avatar{border-radius:50%}.q-bottom-sheet--list{width:400px}.q-bottom-sheet--list .q-icon,.q-bottom-sheet--list img{font-size:24px;width:24px;height:24px}.q-bottom-sheet--grid{width:700px}.q-bottom-sheet--grid .q-bottom-sheet__item{padding:8px;text-align:center;min-width:100px}.q-bottom-sheet--grid .q-bottom-sheet__empty-icon,.q-bottom-sheet--grid .q-icon,.q-bottom-sheet--grid img{font-size:48px;width:48px;height:48px;margin-bottom:8px}.q-bottom-sheet--grid .q-separator{margin:12px 0}.q-bottom-sheet__item{flex:0 0 33.3333%}@media (min-width:600px){.q-bottom-sheet__item{flex:0 0 25%}}.q-dialog-plugin{width:400px}.q-dialog-plugin__form{max-height:50vh}.q-dialog-plugin .q-card__section+.q-card__section{padding-top:0}.q-dialog-plugin--progress{text-align:center}.q-loading{color:#000;position:fixed!important}.q-loading__backdrop{position:fixed;top:0;right:0;bottom:0;left:0;opacity:.5;z-index:-1;background-color:#000;transition:background-color .28s}.q-loading__box{border-radius:4px;padding:18px;color:#fff;max-width:450px}.q-loading__message{margin:40px 20px 0;text-align:center}.q-notifications__list{z-index:9500;pointer-events:none;left:0;right:0;margin-bottom:10px;position:relative}.q-notifications__list--center{top:0;bottom:0}.q-notifications__list--top{top:0}.q-notifications__list--bottom{bottom:0}body.q-ios-padding .q-notifications__list--center,body.q-ios-padding .q-notifications__list--top{top:20px;top:env(safe-area-inset-top)}body.q-ios-padding .q-notifications__list--bottom,body.q-ios-padding .q-notifications__list--center{bottom:env(safe-area-inset-bottom)}.q-notification{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;pointer-events:all;display:inline-flex;margin:10px 10px 0;transition:transform 1s,opacity 1s;z-index:9500;flex-shrink:0;max-width:95vw;background:#323232;color:#fff;font-size:14px}.q-notification__icon{font-size:24px;flex:0 0 1em}.q-notification__icon--additional{margin-right:16px}.q-notification__avatar{font-size:32px}.q-notification__avatar--additional{margin-right:8px}.q-notification__spinner{font-size:32px}.q-notification__spinner--additional{margin-right:8px}.q-notification__message{padding:8px 0}.q-notification__caption{font-size:.9em;opacity:.7}.q-notification__actions{color:var(--q-primary)}.q-notification__badge{animation:q-notif-badge .42s;padding:4px 8px;position:absolute;box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12);background-color:var(--q-negative);color:#fff;border-radius:4px;font-size:12px;line-height:12px}.q-notification__badge--top-left,.q-notification__badge--top-right{top:-6px}.q-notification__badge--bottom-left,.q-notification__badge--bottom-right{bottom:-6px}.q-notification__badge--bottom-left,.q-notification__badge--top-left{left:-22px}.q-notification__badge--bottom-right,.q-notification__badge--top-right{right:-22px}.q-notification__progress{z-index:-1;position:absolute;height:3px;bottom:0;left:-10px;right:-10px;animation:q-notif-progress linear;background:currentColor;opacity:.3;border-radius:4px 4px 0 0;transform-origin:0 50%;transform:scaleX(0)}.q-notification--standard{padding:0 16px;min-height:48px}.q-notification--standard .q-notification__actions{padding:6px 0 6px 8px;margin-right:-8px}.q-notification--multi-line{min-height:68px;padding:8px 16px}.q-notification--multi-line .q-notification__badge--top-left,.q-notification--multi-line .q-notification__badge--top-right{top:-15px}.q-notification--multi-line .q-notification__badge--bottom-left,.q-notification--multi-line .q-notification__badge--bottom-right{bottom:-15px}.q-notification--multi-line .q-notification__progress{bottom:-8px}.q-notification--multi-line .q-notification__actions{padding:0}.q-notification--multi-line .q-notification__actions--with-media{padding-left:25px}.q-notification--top-enter-from,.q-notification--top-leave-to,.q-notification--top-left-enter-from,.q-notification--top-left-leave-to,.q-notification--top-right-enter-from,.q-notification--top-right-leave-to{opacity:0;transform:translateY(-50px);z-index:9499}.q-notification--center-enter-from,.q-notification--center-leave-to,.q-notification--left-enter-from,.q-notification--left-leave-to,.q-notification--right-enter-from,.q-notification--right-leave-to{opacity:0;transform:rotateX(90deg);z-index:9499}.q-notification--bottom-enter-from,.q-notification--bottom-leave-to,.q-notification--bottom-left-enter-from,.q-notification--bottom-left-leave-to,.q-notification--bottom-right-enter-from,.q-notification--bottom-right-leave-to{opacity:0;transform:translateY(50px);z-index:9499}.q-notification--bottom-leave-active,.q-notification--bottom-left-leave-active,.q-notification--bottom-right-leave-active,.q-notification--center-leave-active,.q-notification--left-leave-active,.q-notification--right-leave-active,.q-notification--top-leave-active,.q-notification--top-left-leave-active,.q-notification--top-right-leave-active{position:absolute;z-index:9499;margin-left:0;margin-right:0}.q-notification--center-leave-active,.q-notification--top-leave-active{top:0}.q-notification--bottom-leave-active,.q-notification--bottom-left-leave-active,.q-notification--bottom-right-leave-active{bottom:0}@media (min-width:600px){.q-notification{max-width:65vw}}@keyframes q-notif-badge{15%{transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}}@keyframes q-notif-progress{0%{transform:scaleX(1)}100%{transform:scaleX(0)}}:root{--animate-duration:0.3s;--animate-delay:0.3s;--animate-repeat:1}.animated{animation-duration:var(--animate-duration);animation-fill-mode:both}.animated.infinite{animation-iteration-count:infinite}.animated.hinge{animation-duration:2s}.animated.repeat-1{animation-iteration-count:var(--animate-repeat)}.animated.repeat-2{animation-iteration-count:calc(var(--animate-repeat) * 2)}.animated.repeat-3{animation-iteration-count:calc(var(--animate-repeat) * 3)}.animated.delay-1s{animation-delay:var(--animate-delay)}.animated.delay-2s{animation-delay:calc(var(--animate-delay) * 2)}.animated.delay-3s{animation-delay:calc(var(--animate-delay) * 3)}.animated.delay-4s{animation-delay:calc(var(--animate-delay) * 4)}.animated.delay-5s{animation-delay:calc(var(--animate-delay) * 5)}.animated.faster{animation-duration:calc(var(--animate-duration) / 2)}.animated.fast{animation-duration:calc(var(--animate-duration) * .8)}.animated.slow{animation-duration:calc(var(--animate-duration) * 2)}.animated.slower{animation-duration:calc(var(--animate-duration) * 3)}@media print,(prefers-reduced-motion:reduce){.animated{animation-duration:1ms!important;transition-duration:1ms!important;animation-iteration-count:1!important}.animated[class*=Out]{opacity:0}}.q-animate--scale{animation:q-scale .15s;animation-timing-function:cubic-bezier(0.25,0.8,0.25,1)}@keyframes q-scale{0%{transform:scale(1)}50%{transform:scale(1.04)}100%{transform:scale(1)}}.q-animate--fade{animation:q-fade .2s}@keyframes q-fade{0%{opacity:0}100%{opacity:1}}:root{--q-primary:#1976D2;--q-secondary:#26A69A;--q-accent:#9C27B0;--q-positive:#21BA45;--q-negative:#C10015;--q-info:#31CCEC;--q-warning:#F2C037;--q-dark:#1d1d1d;--q-dark-page:#121212}.text-dark{color:var(--q-dark)!important}.bg-dark{background:var(--q-dark)!important}.text-primary{color:var(--q-primary)!important}.bg-primary{background:var(--q-primary)!important}.text-secondary{color:var(--q-secondary)!important}.bg-secondary{background:var(--q-secondary)!important}.text-accent{color:var(--q-accent)!important}.bg-accent{background:var(--q-accent)!important}.text-positive{color:var(--q-positive)!important}.bg-positive{background:var(--q-positive)!important}.text-negative{color:var(--q-negative)!important}.bg-negative{background:var(--q-negative)!important}.text-info{color:var(--q-info)!important}.bg-info{background:var(--q-info)!important}.text-warning{color:var(--q-warning)!important}.bg-warning{background:var(--q-warning)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.text-transparent{color:transparent!important}.bg-transparent{background:0 0!important}.text-separator{color:rgba(0,0,0,.12)!important}.bg-separator{background:rgba(0,0,0,.12)!important}.text-dark-separator{color:rgba(255,255,255,.28)!important}.bg-dark-separator{background:rgba(255,255,255,.28)!important}.text-red{color:#f44336!important}.text-red-1{color:#ffebee!important}.text-red-2{color:#ffcdd2!important}.text-red-3{color:#ef9a9a!important}.text-red-4{color:#e57373!important}.text-red-5{color:#ef5350!important}.text-red-6{color:#f44336!important}.text-red-7{color:#e53935!important}.text-red-8{color:#d32f2f!important}.text-red-9{color:#c62828!important}.text-red-10{color:#b71c1c!important}.text-red-11{color:#ff8a80!important}.text-red-12{color:#ff5252!important}.text-red-13{color:#ff1744!important}.text-red-14{color:#d50000!important}.text-pink{color:#e91e63!important}.text-pink-1{color:#fce4ec!important}.text-pink-2{color:#f8bbd0!important}.text-pink-3{color:#f48fb1!important}.text-pink-4{color:#f06292!important}.text-pink-5{color:#ec407a!important}.text-pink-6{color:#e91e63!important}.text-pink-7{color:#d81b60!important}.text-pink-8{color:#c2185b!important}.text-pink-9{color:#ad1457!important}.text-pink-10{color:#880e4f!important}.text-pink-11{color:#ff80ab!important}.text-pink-12{color:#ff4081!important}.text-pink-13{color:#f50057!important}.text-pink-14{color:#c51162!important}.text-purple{color:#9c27b0!important}.text-purple-1{color:#f3e5f5!important}.text-purple-2{color:#e1bee7!important}.text-purple-3{color:#ce93d8!important}.text-purple-4{color:#ba68c8!important}.text-purple-5{color:#ab47bc!important}.text-purple-6{color:#9c27b0!important}.text-purple-7{color:#8e24aa!important}.text-purple-8{color:#7b1fa2!important}.text-purple-9{color:#6a1b9a!important}.text-purple-10{color:#4a148c!important}.text-purple-11{color:#ea80fc!important}.text-purple-12{color:#e040fb!important}.text-purple-13{color:#d500f9!important}.text-purple-14{color:#a0f!important}.text-deep-purple{color:#673ab7!important}.text-deep-purple-1{color:#ede7f6!important}.text-deep-purple-2{color:#d1c4e9!important}.text-deep-purple-3{color:#b39ddb!important}.text-deep-purple-4{color:#9575cd!important}.text-deep-purple-5{color:#7e57c2!important}.text-deep-purple-6{color:#673ab7!important}.text-deep-purple-7{color:#5e35b1!important}.text-deep-purple-8{color:#512da8!important}.text-deep-purple-9{color:#4527a0!important}.text-deep-purple-10{color:#311b92!important}.text-deep-purple-11{color:#b388ff!important}.text-deep-purple-12{color:#7c4dff!important}.text-deep-purple-13{color:#651fff!important}.text-deep-purple-14{color:#6200ea!important}.text-indigo{color:#3f51b5!important}.text-indigo-1{color:#e8eaf6!important}.text-indigo-2{color:#c5cae9!important}.text-indigo-3{color:#9fa8da!important}.text-indigo-4{color:#7986cb!important}.text-indigo-5{color:#5c6bc0!important}.text-indigo-6{color:#3f51b5!important}.text-indigo-7{color:#3949ab!important}.text-indigo-8{color:#303f9f!important}.text-indigo-9{color:#283593!important}.text-indigo-10{color:#1a237e!important}.text-indigo-11{color:#8c9eff!important}.text-indigo-12{color:#536dfe!important}.text-indigo-13{color:#3d5afe!important}.text-indigo-14{color:#304ffe!important}.text-blue{color:#2196f3!important}.text-blue-1{color:#e3f2fd!important}.text-blue-2{color:#bbdefb!important}.text-blue-3{color:#90caf9!important}.text-blue-4{color:#64b5f6!important}.text-blue-5{color:#42a5f5!important}.text-blue-6{color:#2196f3!important}.text-blue-7{color:#1e88e5!important}.text-blue-8{color:#1976d2!important}.text-blue-9{color:#1565c0!important}.text-blue-10{color:#0d47a1!important}.text-blue-11{color:#82b1ff!important}.text-blue-12{color:#448aff!important}.text-blue-13{color:#2979ff!important}.text-blue-14{color:#2962ff!important}.text-light-blue{color:#03a9f4!important}.text-light-blue-1{color:#e1f5fe!important}.text-light-blue-2{color:#b3e5fc!important}.text-light-blue-3{color:#81d4fa!important}.text-light-blue-4{color:#4fc3f7!important}.text-light-blue-5{color:#29b6f6!important}.text-light-blue-6{color:#03a9f4!important}.text-light-blue-7{color:#039be5!important}.text-light-blue-8{color:#0288d1!important}.text-light-blue-9{color:#0277bd!important}.text-light-blue-10{color:#01579b!important}.text-light-blue-11{color:#80d8ff!important}.text-light-blue-12{color:#40c4ff!important}.text-light-blue-13{color:#00b0ff!important}.text-light-blue-14{color:#0091ea!important}.text-cyan{color:#00bcd4!important}.text-cyan-1{color:#e0f7fa!important}.text-cyan-2{color:#b2ebf2!important}.text-cyan-3{color:#80deea!important}.text-cyan-4{color:#4dd0e1!important}.text-cyan-5{color:#26c6da!important}.text-cyan-6{color:#00bcd4!important}.text-cyan-7{color:#00acc1!important}.text-cyan-8{color:#0097a7!important}.text-cyan-9{color:#00838f!important}.text-cyan-10{color:#006064!important}.text-cyan-11{color:#84ffff!important}.text-cyan-12{color:#18ffff!important}.text-cyan-13{color:#00e5ff!important}.text-cyan-14{color:#00b8d4!important}.text-teal{color:#009688!important}.text-teal-1{color:#e0f2f1!important}.text-teal-2{color:#b2dfdb!important}.text-teal-3{color:#80cbc4!important}.text-teal-4{color:#4db6ac!important}.text-teal-5{color:#26a69a!important}.text-teal-6{color:#009688!important}.text-teal-7{color:#00897b!important}.text-teal-8{color:#00796b!important}.text-teal-9{color:#00695c!important}.text-teal-10{color:#004d40!important}.text-teal-11{color:#a7ffeb!important}.text-teal-12{color:#64ffda!important}.text-teal-13{color:#1de9b6!important}.text-teal-14{color:#00bfa5!important}.text-green{color:#4caf50!important}.text-green-1{color:#e8f5e9!important}.text-green-2{color:#c8e6c9!important}.text-green-3{color:#a5d6a7!important}.text-green-4{color:#81c784!important}.text-green-5{color:#66bb6a!important}.text-green-6{color:#4caf50!important}.text-green-7{color:#43a047!important}.text-green-8{color:#388e3c!important}.text-green-9{color:#2e7d32!important}.text-green-10{color:#1b5e20!important}.text-green-11{color:#b9f6ca!important}.text-green-12{color:#69f0ae!important}.text-green-13{color:#00e676!important}.text-green-14{color:#00c853!important}.text-light-green{color:#8bc34a!important}.text-light-green-1{color:#f1f8e9!important}.text-light-green-2{color:#dcedc8!important}.text-light-green-3{color:#c5e1a5!important}.text-light-green-4{color:#aed581!important}.text-light-green-5{color:#9ccc65!important}.text-light-green-6{color:#8bc34a!important}.text-light-green-7{color:#7cb342!important}.text-light-green-8{color:#689f38!important}.text-light-green-9{color:#558b2f!important}.text-light-green-10{color:#33691e!important}.text-light-green-11{color:#ccff90!important}.text-light-green-12{color:#b2ff59!important}.text-light-green-13{color:#76ff03!important}.text-light-green-14{color:#64dd17!important}.text-lime{color:#cddc39!important}.text-lime-1{color:#f9fbe7!important}.text-lime-2{color:#f0f4c3!important}.text-lime-3{color:#e6ee9c!important}.text-lime-4{color:#dce775!important}.text-lime-5{color:#d4e157!important}.text-lime-6{color:#cddc39!important}.text-lime-7{color:#c0ca33!important}.text-lime-8{color:#afb42b!important}.text-lime-9{color:#9e9d24!important}.text-lime-10{color:#827717!important}.text-lime-11{color:#f4ff81!important}.text-lime-12{color:#eeff41!important}.text-lime-13{color:#c6ff00!important}.text-lime-14{color:#aeea00!important}.text-yellow{color:#ffeb3b!important}.text-yellow-1{color:#fffde7!important}.text-yellow-2{color:#fff9c4!important}.text-yellow-3{color:#fff59d!important}.text-yellow-4{color:#fff176!important}.text-yellow-5{color:#ffee58!important}.text-yellow-6{color:#ffeb3b!important}.text-yellow-7{color:#fdd835!important}.text-yellow-8{color:#fbc02d!important}.text-yellow-9{color:#f9a825!important}.text-yellow-10{color:#f57f17!important}.text-yellow-11{color:#ffff8d!important}.text-yellow-12{color:#ff0!important}.text-yellow-13{color:#ffea00!important}.text-yellow-14{color:#ffd600!important}.text-amber{color:#ffc107!important}.text-amber-1{color:#fff8e1!important}.text-amber-2{color:#ffecb3!important}.text-amber-3{color:#ffe082!important}.text-amber-4{color:#ffd54f!important}.text-amber-5{color:#ffca28!important}.text-amber-6{color:#ffc107!important}.text-amber-7{color:#ffb300!important}.text-amber-8{color:#ffa000!important}.text-amber-9{color:#ff8f00!important}.text-amber-10{color:#ff6f00!important}.text-amber-11{color:#ffe57f!important}.text-amber-12{color:#ffd740!important}.text-amber-13{color:#ffc400!important}.text-amber-14{color:#ffab00!important}.text-orange{color:#ff9800!important}.text-orange-1{color:#fff3e0!important}.text-orange-2{color:#ffe0b2!important}.text-orange-3{color:#ffcc80!important}.text-orange-4{color:#ffb74d!important}.text-orange-5{color:#ffa726!important}.text-orange-6{color:#ff9800!important}.text-orange-7{color:#fb8c00!important}.text-orange-8{color:#f57c00!important}.text-orange-9{color:#ef6c00!important}.text-orange-10{color:#e65100!important}.text-orange-11{color:#ffd180!important}.text-orange-12{color:#ffab40!important}.text-orange-13{color:#ff9100!important}.text-orange-14{color:#ff6d00!important}.text-deep-orange{color:#ff5722!important}.text-deep-orange-1{color:#fbe9e7!important}.text-deep-orange-2{color:#ffccbc!important}.text-deep-orange-3{color:#ffab91!important}.text-deep-orange-4{color:#ff8a65!important}.text-deep-orange-5{color:#ff7043!important}.text-deep-orange-6{color:#ff5722!important}.text-deep-orange-7{color:#f4511e!important}.text-deep-orange-8{color:#e64a19!important}.text-deep-orange-9{color:#d84315!important}.text-deep-orange-10{color:#bf360c!important}.text-deep-orange-11{color:#ff9e80!important}.text-deep-orange-12{color:#ff6e40!important}.text-deep-orange-13{color:#ff3d00!important}.text-deep-orange-14{color:#dd2c00!important}.text-brown{color:#795548!important}.text-brown-1{color:#efebe9!important}.text-brown-2{color:#d7ccc8!important}.text-brown-3{color:#bcaaa4!important}.text-brown-4{color:#a1887f!important}.text-brown-5{color:#8d6e63!important}.text-brown-6{color:#795548!important}.text-brown-7{color:#6d4c41!important}.text-brown-8{color:#5d4037!important}.text-brown-9{color:#4e342e!important}.text-brown-10{color:#3e2723!important}.text-brown-11{color:#d7ccc8!important}.text-brown-12{color:#bcaaa4!important}.text-brown-13{color:#8d6e63!important}.text-brown-14{color:#5d4037!important}.text-grey{color:#9e9e9e!important}.text-grey-1{color:#fafafa!important}.text-grey-2{color:#f5f5f5!important}.text-grey-3{color:#eee!important}.text-grey-4{color:#e0e0e0!important}.text-grey-5{color:#bdbdbd!important}.text-grey-6{color:#9e9e9e!important}.text-grey-7{color:#757575!important}.text-grey-8{color:#616161!important}.text-grey-9{color:#424242!important}.text-grey-10{color:#212121!important}.text-grey-11{color:#f5f5f5!important}.text-grey-12{color:#eee!important}.text-grey-13{color:#bdbdbd!important}.text-grey-14{color:#616161!important}.text-blue-grey{color:#607d8b!important}.text-blue-grey-1{color:#eceff1!important}.text-blue-grey-2{color:#cfd8dc!important}.text-blue-grey-3{color:#b0bec5!important}.text-blue-grey-4{color:#90a4ae!important}.text-blue-grey-5{color:#78909c!important}.text-blue-grey-6{color:#607d8b!important}.text-blue-grey-7{color:#546e7a!important}.text-blue-grey-8{color:#455a64!important}.text-blue-grey-9{color:#37474f!important}.text-blue-grey-10{color:#263238!important}.text-blue-grey-11{color:#cfd8dc!important}.text-blue-grey-12{color:#b0bec5!important}.text-blue-grey-13{color:#78909c!important}.text-blue-grey-14{color:#455a64!important}.bg-red{background:#f44336!important}.bg-red-1{background:#ffebee!important}.bg-red-2{background:#ffcdd2!important}.bg-red-3{background:#ef9a9a!important}.bg-red-4{background:#e57373!important}.bg-red-5{background:#ef5350!important}.bg-red-6{background:#f44336!important}.bg-red-7{background:#e53935!important}.bg-red-8{background:#d32f2f!important}.bg-red-9{background:#c62828!important}.bg-red-10{background:#b71c1c!important}.bg-red-11{background:#ff8a80!important}.bg-red-12{background:#ff5252!important}.bg-red-13{background:#ff1744!important}.bg-red-14{background:#d50000!important}.bg-pink{background:#e91e63!important}.bg-pink-1{background:#fce4ec!important}.bg-pink-2{background:#f8bbd0!important}.bg-pink-3{background:#f48fb1!important}.bg-pink-4{background:#f06292!important}.bg-pink-5{background:#ec407a!important}.bg-pink-6{background:#e91e63!important}.bg-pink-7{background:#d81b60!important}.bg-pink-8{background:#c2185b!important}.bg-pink-9{background:#ad1457!important}.bg-pink-10{background:#880e4f!important}.bg-pink-11{background:#ff80ab!important}.bg-pink-12{background:#ff4081!important}.bg-pink-13{background:#f50057!important}.bg-pink-14{background:#c51162!important}.bg-purple{background:#9c27b0!important}.bg-purple-1{background:#f3e5f5!important}.bg-purple-2{background:#e1bee7!important}.bg-purple-3{background:#ce93d8!important}.bg-purple-4{background:#ba68c8!important}.bg-purple-5{background:#ab47bc!important}.bg-purple-6{background:#9c27b0!important}.bg-purple-7{background:#8e24aa!important}.bg-purple-8{background:#7b1fa2!important}.bg-purple-9{background:#6a1b9a!important}.bg-purple-10{background:#4a148c!important}.bg-purple-11{background:#ea80fc!important}.bg-purple-12{background:#e040fb!important}.bg-purple-13{background:#d500f9!important}.bg-purple-14{background:#a0f!important}.bg-deep-purple{background:#673ab7!important}.bg-deep-purple-1{background:#ede7f6!important}.bg-deep-purple-2{background:#d1c4e9!important}.bg-deep-purple-3{background:#b39ddb!important}.bg-deep-purple-4{background:#9575cd!important}.bg-deep-purple-5{background:#7e57c2!important}.bg-deep-purple-6{background:#673ab7!important}.bg-deep-purple-7{background:#5e35b1!important}.bg-deep-purple-8{background:#512da8!important}.bg-deep-purple-9{background:#4527a0!important}.bg-deep-purple-10{background:#311b92!important}.bg-deep-purple-11{background:#b388ff!important}.bg-deep-purple-12{background:#7c4dff!important}.bg-deep-purple-13{background:#651fff!important}.bg-deep-purple-14{background:#6200ea!important}.bg-indigo{background:#3f51b5!important}.bg-indigo-1{background:#e8eaf6!important}.bg-indigo-2{background:#c5cae9!important}.bg-indigo-3{background:#9fa8da!important}.bg-indigo-4{background:#7986cb!important}.bg-indigo-5{background:#5c6bc0!important}.bg-indigo-6{background:#3f51b5!important}.bg-indigo-7{background:#3949ab!important}.bg-indigo-8{background:#303f9f!important}.bg-indigo-9{background:#283593!important}.bg-indigo-10{background:#1a237e!important}.bg-indigo-11{background:#8c9eff!important}.bg-indigo-12{background:#536dfe!important}.bg-indigo-13{background:#3d5afe!important}.bg-indigo-14{background:#304ffe!important}.bg-blue{background:#2196f3!important}.bg-blue-1{background:#e3f2fd!important}.bg-blue-2{background:#bbdefb!important}.bg-blue-3{background:#90caf9!important}.bg-blue-4{background:#64b5f6!important}.bg-blue-5{background:#42a5f5!important}.bg-blue-6{background:#2196f3!important}.bg-blue-7{background:#1e88e5!important}.bg-blue-8{background:#1976d2!important}.bg-blue-9{background:#1565c0!important}.bg-blue-10{background:#0d47a1!important}.bg-blue-11{background:#82b1ff!important}.bg-blue-12{background:#448aff!important}.bg-blue-13{background:#2979ff!important}.bg-blue-14{background:#2962ff!important}.bg-light-blue{background:#03a9f4!important}.bg-light-blue-1{background:#e1f5fe!important}.bg-light-blue-2{background:#b3e5fc!important}.bg-light-blue-3{background:#81d4fa!important}.bg-light-blue-4{background:#4fc3f7!important}.bg-light-blue-5{background:#29b6f6!important}.bg-light-blue-6{background:#03a9f4!important}.bg-light-blue-7{background:#039be5!important}.bg-light-blue-8{background:#0288d1!important}.bg-light-blue-9{background:#0277bd!important}.bg-light-blue-10{background:#01579b!important}.bg-light-blue-11{background:#80d8ff!important}.bg-light-blue-12{background:#40c4ff!important}.bg-light-blue-13{background:#00b0ff!important}.bg-light-blue-14{background:#0091ea!important}.bg-cyan{background:#00bcd4!important}.bg-cyan-1{background:#e0f7fa!important}.bg-cyan-2{background:#b2ebf2!important}.bg-cyan-3{background:#80deea!important}.bg-cyan-4{background:#4dd0e1!important}.bg-cyan-5{background:#26c6da!important}.bg-cyan-6{background:#00bcd4!important}.bg-cyan-7{background:#00acc1!important}.bg-cyan-8{background:#0097a7!important}.bg-cyan-9{background:#00838f!important}.bg-cyan-10{background:#006064!important}.bg-cyan-11{background:#84ffff!important}.bg-cyan-12{background:#18ffff!important}.bg-cyan-13{background:#00e5ff!important}.bg-cyan-14{background:#00b8d4!important}.bg-teal{background:#009688!important}.bg-teal-1{background:#e0f2f1!important}.bg-teal-2{background:#b2dfdb!important}.bg-teal-3{background:#80cbc4!important}.bg-teal-4{background:#4db6ac!important}.bg-teal-5{background:#26a69a!important}.bg-teal-6{background:#009688!important}.bg-teal-7{background:#00897b!important}.bg-teal-8{background:#00796b!important}.bg-teal-9{background:#00695c!important}.bg-teal-10{background:#004d40!important}.bg-teal-11{background:#a7ffeb!important}.bg-teal-12{background:#64ffda!important}.bg-teal-13{background:#1de9b6!important}.bg-teal-14{background:#00bfa5!important}.bg-green{background:#4caf50!important}.bg-green-1{background:#e8f5e9!important}.bg-green-2{background:#c8e6c9!important}.bg-green-3{background:#a5d6a7!important}.bg-green-4{background:#81c784!important}.bg-green-5{background:#66bb6a!important}.bg-green-6{background:#4caf50!important}.bg-green-7{background:#43a047!important}.bg-green-8{background:#388e3c!important}.bg-green-9{background:#2e7d32!important}.bg-green-10{background:#1b5e20!important}.bg-green-11{background:#b9f6ca!important}.bg-green-12{background:#69f0ae!important}.bg-green-13{background:#00e676!important}.bg-green-14{background:#00c853!important}.bg-light-green{background:#8bc34a!important}.bg-light-green-1{background:#f1f8e9!important}.bg-light-green-2{background:#dcedc8!important}.bg-light-green-3{background:#c5e1a5!important}.bg-light-green-4{background:#aed581!important}.bg-light-green-5{background:#9ccc65!important}.bg-light-green-6{background:#8bc34a!important}.bg-light-green-7{background:#7cb342!important}.bg-light-green-8{background:#689f38!important}.bg-light-green-9{background:#558b2f!important}.bg-light-green-10{background:#33691e!important}.bg-light-green-11{background:#ccff90!important}.bg-light-green-12{background:#b2ff59!important}.bg-light-green-13{background:#76ff03!important}.bg-light-green-14{background:#64dd17!important}.bg-lime{background:#cddc39!important}.bg-lime-1{background:#f9fbe7!important}.bg-lime-2{background:#f0f4c3!important}.bg-lime-3{background:#e6ee9c!important}.bg-lime-4{background:#dce775!important}.bg-lime-5{background:#d4e157!important}.bg-lime-6{background:#cddc39!important}.bg-lime-7{background:#c0ca33!important}.bg-lime-8{background:#afb42b!important}.bg-lime-9{background:#9e9d24!important}.bg-lime-10{background:#827717!important}.bg-lime-11{background:#f4ff81!important}.bg-lime-12{background:#eeff41!important}.bg-lime-13{background:#c6ff00!important}.bg-lime-14{background:#aeea00!important}.bg-yellow{background:#ffeb3b!important}.bg-yellow-1{background:#fffde7!important}.bg-yellow-2{background:#fff9c4!important}.bg-yellow-3{background:#fff59d!important}.bg-yellow-4{background:#fff176!important}.bg-yellow-5{background:#ffee58!important}.bg-yellow-6{background:#ffeb3b!important}.bg-yellow-7{background:#fdd835!important}.bg-yellow-8{background:#fbc02d!important}.bg-yellow-9{background:#f9a825!important}.bg-yellow-10{background:#f57f17!important}.bg-yellow-11{background:#ffff8d!important}.bg-yellow-12{background:#ff0!important}.bg-yellow-13{background:#ffea00!important}.bg-yellow-14{background:#ffd600!important}.bg-amber{background:#ffc107!important}.bg-amber-1{background:#fff8e1!important}.bg-amber-2{background:#ffecb3!important}.bg-amber-3{background:#ffe082!important}.bg-amber-4{background:#ffd54f!important}.bg-amber-5{background:#ffca28!important}.bg-amber-6{background:#ffc107!important}.bg-amber-7{background:#ffb300!important}.bg-amber-8{background:#ffa000!important}.bg-amber-9{background:#ff8f00!important}.bg-amber-10{background:#ff6f00!important}.bg-amber-11{background:#ffe57f!important}.bg-amber-12{background:#ffd740!important}.bg-amber-13{background:#ffc400!important}.bg-amber-14{background:#ffab00!important}.bg-orange{background:#ff9800!important}.bg-orange-1{background:#fff3e0!important}.bg-orange-2{background:#ffe0b2!important}.bg-orange-3{background:#ffcc80!important}.bg-orange-4{background:#ffb74d!important}.bg-orange-5{background:#ffa726!important}.bg-orange-6{background:#ff9800!important}.bg-orange-7{background:#fb8c00!important}.bg-orange-8{background:#f57c00!important}.bg-orange-9{background:#ef6c00!important}.bg-orange-10{background:#e65100!important}.bg-orange-11{background:#ffd180!important}.bg-orange-12{background:#ffab40!important}.bg-orange-13{background:#ff9100!important}.bg-orange-14{background:#ff6d00!important}.bg-deep-orange{background:#ff5722!important}.bg-deep-orange-1{background:#fbe9e7!important}.bg-deep-orange-2{background:#ffccbc!important}.bg-deep-orange-3{background:#ffab91!important}.bg-deep-orange-4{background:#ff8a65!important}.bg-deep-orange-5{background:#ff7043!important}.bg-deep-orange-6{background:#ff5722!important}.bg-deep-orange-7{background:#f4511e!important}.bg-deep-orange-8{background:#e64a19!important}.bg-deep-orange-9{background:#d84315!important}.bg-deep-orange-10{background:#bf360c!important}.bg-deep-orange-11{background:#ff9e80!important}.bg-deep-orange-12{background:#ff6e40!important}.bg-deep-orange-13{background:#ff3d00!important}.bg-deep-orange-14{background:#dd2c00!important}.bg-brown{background:#795548!important}.bg-brown-1{background:#efebe9!important}.bg-brown-2{background:#d7ccc8!important}.bg-brown-3{background:#bcaaa4!important}.bg-brown-4{background:#a1887f!important}.bg-brown-5{background:#8d6e63!important}.bg-brown-6{background:#795548!important}.bg-brown-7{background:#6d4c41!important}.bg-brown-8{background:#5d4037!important}.bg-brown-9{background:#4e342e!important}.bg-brown-10{background:#3e2723!important}.bg-brown-11{background:#d7ccc8!important}.bg-brown-12{background:#bcaaa4!important}.bg-brown-13{background:#8d6e63!important}.bg-brown-14{background:#5d4037!important}.bg-grey{background:#9e9e9e!important}.bg-grey-1{background:#fafafa!important}.bg-grey-2{background:#f5f5f5!important}.bg-grey-3{background:#eee!important}.bg-grey-4{background:#e0e0e0!important}.bg-grey-5{background:#bdbdbd!important}.bg-grey-6{background:#9e9e9e!important}.bg-grey-7{background:#757575!important}.bg-grey-8{background:#616161!important}.bg-grey-9{background:#424242!important}.bg-grey-10{background:#212121!important}.bg-grey-11{background:#f5f5f5!important}.bg-grey-12{background:#eee!important}.bg-grey-13{background:#bdbdbd!important}.bg-grey-14{background:#616161!important}.bg-blue-grey{background:#607d8b!important}.bg-blue-grey-1{background:#eceff1!important}.bg-blue-grey-2{background:#cfd8dc!important}.bg-blue-grey-3{background:#b0bec5!important}.bg-blue-grey-4{background:#90a4ae!important}.bg-blue-grey-5{background:#78909c!important}.bg-blue-grey-6{background:#607d8b!important}.bg-blue-grey-7{background:#546e7a!important}.bg-blue-grey-8{background:#455a64!important}.bg-blue-grey-9{background:#37474f!important}.bg-blue-grey-10{background:#263238!important}.bg-blue-grey-11{background:#cfd8dc!important}.bg-blue-grey-12{background:#b0bec5!important}.bg-blue-grey-13{background:#78909c!important}.bg-blue-grey-14{background:#455a64!important}.shadow-transition{transition:box-shadow .28s cubic-bezier(.4, 0, .2, 1)!important}.shadow-1{box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}.shadow-up-1{box-shadow:0 -1px 3px rgba(0,0,0,.2),0 -1px 1px rgba(0,0,0,.14),0 -2px 1px -1px rgba(0,0,0,.12)}.shadow-2{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.shadow-up-2{box-shadow:0 -1px 5px rgba(0,0,0,.2),0 -2px 2px rgba(0,0,0,.14),0 -3px 1px -2px rgba(0,0,0,.12)}.shadow-3{box-shadow:0 1px 8px rgba(0,0,0,.2),0 3px 4px rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.12)}.shadow-up-3{box-shadow:0 -1px 8px rgba(0,0,0,.2),0 -3px 4px rgba(0,0,0,.14),0 -3px 3px -2px rgba(0,0,0,.12)}.shadow-4{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px rgba(0,0,0,.14),0 1px 10px rgba(0,0,0,.12)}.shadow-up-4{box-shadow:0 -2px 4px -1px rgba(0,0,0,.2),0 -4px 5px rgba(0,0,0,.14),0 -1px 10px rgba(0,0,0,.12)}.shadow-5{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px rgba(0,0,0,.14),0 1px 14px rgba(0,0,0,.12)}.shadow-up-5{box-shadow:0 -3px 5px -1px rgba(0,0,0,.2),0 -5px 8px rgba(0,0,0,.14),0 -1px 14px rgba(0,0,0,.12)}.shadow-6{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px rgba(0,0,0,.14),0 1px 18px rgba(0,0,0,.12)}.shadow-up-6{box-shadow:0 -3px 5px -1px rgba(0,0,0,.2),0 -6px 10px rgba(0,0,0,.14),0 -1px 18px rgba(0,0,0,.12)}.shadow-7{box-shadow:0 4px 5px -2px rgba(0,0,0,.2),0 7px 10px 1px rgba(0,0,0,.14),0 2px 16px 1px rgba(0,0,0,.12)}.shadow-up-7{box-shadow:0 -4px 5px -2px rgba(0,0,0,.2),0 -7px 10px 1px rgba(0,0,0,.14),0 -2px 16px 1px rgba(0,0,0,.12)}.shadow-8{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.shadow-up-8{box-shadow:0 -5px 5px -3px rgba(0,0,0,.2),0 -8px 10px 1px rgba(0,0,0,.14),0 -3px 14px 2px rgba(0,0,0,.12)}.shadow-9{box-shadow:0 5px 6px -3px rgba(0,0,0,.2),0 9px 12px 1px rgba(0,0,0,.14),0 3px 16px 2px rgba(0,0,0,.12)}.shadow-up-9{box-shadow:0 -5px 6px -3px rgba(0,0,0,.2),0 -9px 12px 1px rgba(0,0,0,.14),0 -3px 16px 2px rgba(0,0,0,.12)}.shadow-10{box-shadow:0 6px 6px -3px rgba(0,0,0,.2),0 10px 14px 1px rgba(0,0,0,.14),0 4px 18px 3px rgba(0,0,0,.12)}.shadow-up-10{box-shadow:0 -6px 6px -3px rgba(0,0,0,.2),0 -10px 14px 1px rgba(0,0,0,.14),0 -4px 18px 3px rgba(0,0,0,.12)}.shadow-11{box-shadow:0 6px 7px -4px rgba(0,0,0,.2),0 11px 15px 1px rgba(0,0,0,.14),0 4px 20px 3px rgba(0,0,0,.12)}.shadow-up-11{box-shadow:0 -6px 7px -4px rgba(0,0,0,.2),0 -11px 15px 1px rgba(0,0,0,.14),0 -4px 20px 3px rgba(0,0,0,.12)}.shadow-12{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 12px 17px 2px rgba(0,0,0,.14),0 5px 22px 4px rgba(0,0,0,.12)}.shadow-up-12{box-shadow:0 -7px 8px -4px rgba(0,0,0,.2),0 -12px 17px 2px rgba(0,0,0,.14),0 -5px 22px 4px rgba(0,0,0,.12)}.shadow-13{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12)}.shadow-up-13{box-shadow:0 -7px 8px -4px rgba(0,0,0,.2),0 -13px 19px 2px rgba(0,0,0,.14),0 -5px 24px 4px rgba(0,0,0,.12)}.shadow-14{box-shadow:0 7px 9px -4px rgba(0,0,0,.2),0 14px 21px 2px rgba(0,0,0,.14),0 5px 26px 4px rgba(0,0,0,.12)}.shadow-up-14{box-shadow:0 -7px 9px -4px rgba(0,0,0,.2),0 -14px 21px 2px rgba(0,0,0,.14),0 -5px 26px 4px rgba(0,0,0,.12)}.shadow-15{box-shadow:0 8px 9px -5px rgba(0,0,0,.2),0 15px 22px 2px rgba(0,0,0,.14),0 6px 28px 5px rgba(0,0,0,.12)}.shadow-up-15{box-shadow:0 -8px 9px -5px rgba(0,0,0,.2),0 -15px 22px 2px rgba(0,0,0,.14),0 -6px 28px 5px rgba(0,0,0,.12)}.shadow-16{box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.shadow-up-16{box-shadow:0 -8px 10px -5px rgba(0,0,0,.2),0 -16px 24px 2px rgba(0,0,0,.14),0 -6px 30px 5px rgba(0,0,0,.12)}.shadow-17{box-shadow:0 8px 11px -5px rgba(0,0,0,.2),0 17px 26px 2px rgba(0,0,0,.14),0 6px 32px 5px rgba(0,0,0,.12)}.shadow-up-17{box-shadow:0 -8px 11px -5px rgba(0,0,0,.2),0 -17px 26px 2px rgba(0,0,0,.14),0 -6px 32px 5px rgba(0,0,0,.12)}.shadow-18{box-shadow:0 9px 11px -5px rgba(0,0,0,.2),0 18px 28px 2px rgba(0,0,0,.14),0 7px 34px 6px rgba(0,0,0,.12)}.shadow-up-18{box-shadow:0 -9px 11px -5px rgba(0,0,0,.2),0 -18px 28px 2px rgba(0,0,0,.14),0 -7px 34px 6px rgba(0,0,0,.12)}.shadow-19{box-shadow:0 9px 12px -6px rgba(0,0,0,.2),0 19px 29px 2px rgba(0,0,0,.14),0 7px 36px 6px rgba(0,0,0,.12)}.shadow-up-19{box-shadow:0 -9px 12px -6px rgba(0,0,0,.2),0 -19px 29px 2px rgba(0,0,0,.14),0 -7px 36px 6px rgba(0,0,0,.12)}.shadow-20{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 20px 31px 3px rgba(0,0,0,.14),0 8px 38px 7px rgba(0,0,0,.12)}.shadow-up-20{box-shadow:0 -10px 13px -6px rgba(0,0,0,.2),0 -20px 31px 3px rgba(0,0,0,.14),0 -8px 38px 7px rgba(0,0,0,.12)}.shadow-21{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 21px 33px 3px rgba(0,0,0,.14),0 8px 40px 7px rgba(0,0,0,.12)}.shadow-up-21{box-shadow:0 -10px 13px -6px rgba(0,0,0,.2),0 -21px 33px 3px rgba(0,0,0,.14),0 -8px 40px 7px rgba(0,0,0,.12)}.shadow-22{box-shadow:0 10px 14px -6px rgba(0,0,0,.2),0 22px 35px 3px rgba(0,0,0,.14),0 8px 42px 7px rgba(0,0,0,.12)}.shadow-up-22{box-shadow:0 -10px 14px -6px rgba(0,0,0,.2),0 -22px 35px 3px rgba(0,0,0,.14),0 -8px 42px 7px rgba(0,0,0,.12)}.shadow-23{box-shadow:0 11px 14px -7px rgba(0,0,0,.2),0 23px 36px 3px rgba(0,0,0,.14),0 9px 44px 8px rgba(0,0,0,.12)}.shadow-up-23{box-shadow:0 -11px 14px -7px rgba(0,0,0,.2),0 -23px 36px 3px rgba(0,0,0,.14),0 -9px 44px 8px rgba(0,0,0,.12)}.shadow-24{box-shadow:0 11px 15px -7px rgba(0,0,0,.2),0 24px 38px 3px rgba(0,0,0,.14),0 9px 46px 8px rgba(0,0,0,.12)}.shadow-up-24{box-shadow:0 -11px 15px -7px rgba(0,0,0,.2),0 -24px 38px 3px rgba(0,0,0,.14),0 -9px 46px 8px rgba(0,0,0,.12)}.inset-shadow{box-shadow:0 7px 9px -7px rgba(0,0,0,.7) inset}.inset-shadow-down{box-shadow:0 -7px 9px -7px rgba(0,0,0,.7) inset}body.body--dark .shadow-1{box-shadow:0 1px 3px rgba(255,255,255,.2),0 1px 1px rgba(255,255,255,.14),0 2px 1px -1px rgba(255,255,255,.12)}body.body--dark .shadow-up-1{box-shadow:0 -1px 3px rgba(255,255,255,.2),0 -1px 1px rgba(255,255,255,.14),0 -2px 1px -1px rgba(255,255,255,.12)}body.body--dark .shadow-2{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}body.body--dark .shadow-up-2{box-shadow:0 -1px 5px rgba(255,255,255,.2),0 -2px 2px rgba(255,255,255,.14),0 -3px 1px -2px rgba(255,255,255,.12)}body.body--dark .shadow-3{box-shadow:0 1px 8px rgba(255,255,255,.2),0 3px 4px rgba(255,255,255,.14),0 3px 3px -2px rgba(255,255,255,.12)}body.body--dark .shadow-up-3{box-shadow:0 -1px 8px rgba(255,255,255,.2),0 -3px 4px rgba(255,255,255,.14),0 -3px 3px -2px rgba(255,255,255,.12)}body.body--dark .shadow-4{box-shadow:0 2px 4px -1px rgba(255,255,255,.2),0 4px 5px rgba(255,255,255,.14),0 1px 10px rgba(255,255,255,.12)}body.body--dark .shadow-up-4{box-shadow:0 -2px 4px -1px rgba(255,255,255,.2),0 -4px 5px rgba(255,255,255,.14),0 -1px 10px rgba(255,255,255,.12)}body.body--dark .shadow-5{box-shadow:0 3px 5px -1px rgba(255,255,255,.2),0 5px 8px rgba(255,255,255,.14),0 1px 14px rgba(255,255,255,.12)}body.body--dark .shadow-up-5{box-shadow:0 -3px 5px -1px rgba(255,255,255,.2),0 -5px 8px rgba(255,255,255,.14),0 -1px 14px rgba(255,255,255,.12)}body.body--dark .shadow-6{box-shadow:0 3px 5px -1px rgba(255,255,255,.2),0 6px 10px rgba(255,255,255,.14),0 1px 18px rgba(255,255,255,.12)}body.body--dark .shadow-up-6{box-shadow:0 -3px 5px -1px rgba(255,255,255,.2),0 -6px 10px rgba(255,255,255,.14),0 -1px 18px rgba(255,255,255,.12)}body.body--dark .shadow-7{box-shadow:0 4px 5px -2px rgba(255,255,255,.2),0 7px 10px 1px rgba(255,255,255,.14),0 2px 16px 1px rgba(255,255,255,.12)}body.body--dark .shadow-up-7{box-shadow:0 -4px 5px -2px rgba(255,255,255,.2),0 -7px 10px 1px rgba(255,255,255,.14),0 -2px 16px 1px rgba(255,255,255,.12)}body.body--dark .shadow-8{box-shadow:0 5px 5px -3px rgba(255,255,255,.2),0 8px 10px 1px rgba(255,255,255,.14),0 3px 14px 2px rgba(255,255,255,.12)}body.body--dark .shadow-up-8{box-shadow:0 -5px 5px -3px rgba(255,255,255,.2),0 -8px 10px 1px rgba(255,255,255,.14),0 -3px 14px 2px rgba(255,255,255,.12)}body.body--dark .shadow-9{box-shadow:0 5px 6px -3px rgba(255,255,255,.2),0 9px 12px 1px rgba(255,255,255,.14),0 3px 16px 2px rgba(255,255,255,.12)}body.body--dark .shadow-up-9{box-shadow:0 -5px 6px -3px rgba(255,255,255,.2),0 -9px 12px 1px rgba(255,255,255,.14),0 -3px 16px 2px rgba(255,255,255,.12)}body.body--dark .shadow-10{box-shadow:0 6px 6px -3px rgba(255,255,255,.2),0 10px 14px 1px rgba(255,255,255,.14),0 4px 18px 3px rgba(255,255,255,.12)}body.body--dark .shadow-up-10{box-shadow:0 -6px 6px -3px rgba(255,255,255,.2),0 -10px 14px 1px rgba(255,255,255,.14),0 -4px 18px 3px rgba(255,255,255,.12)}body.body--dark .shadow-11{box-shadow:0 6px 7px -4px rgba(255,255,255,.2),0 11px 15px 1px rgba(255,255,255,.14),0 4px 20px 3px rgba(255,255,255,.12)}body.body--dark .shadow-up-11{box-shadow:0 -6px 7px -4px rgba(255,255,255,.2),0 -11px 15px 1px rgba(255,255,255,.14),0 -4px 20px 3px rgba(255,255,255,.12)}body.body--dark .shadow-12{box-shadow:0 7px 8px -4px rgba(255,255,255,.2),0 12px 17px 2px rgba(255,255,255,.14),0 5px 22px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-12{box-shadow:0 -7px 8px -4px rgba(255,255,255,.2),0 -12px 17px 2px rgba(255,255,255,.14),0 -5px 22px 4px rgba(255,255,255,.12)}body.body--dark .shadow-13{box-shadow:0 7px 8px -4px rgba(255,255,255,.2),0 13px 19px 2px rgba(255,255,255,.14),0 5px 24px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-13{box-shadow:0 -7px 8px -4px rgba(255,255,255,.2),0 -13px 19px 2px rgba(255,255,255,.14),0 -5px 24px 4px rgba(255,255,255,.12)}body.body--dark .shadow-14{box-shadow:0 7px 9px -4px rgba(255,255,255,.2),0 14px 21px 2px rgba(255,255,255,.14),0 5px 26px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-14{box-shadow:0 -7px 9px -4px rgba(255,255,255,.2),0 -14px 21px 2px rgba(255,255,255,.14),0 -5px 26px 4px rgba(255,255,255,.12)}body.body--dark .shadow-15{box-shadow:0 8px 9px -5px rgba(255,255,255,.2),0 15px 22px 2px rgba(255,255,255,.14),0 6px 28px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-15{box-shadow:0 -8px 9px -5px rgba(255,255,255,.2),0 -15px 22px 2px rgba(255,255,255,.14),0 -6px 28px 5px rgba(255,255,255,.12)}body.body--dark .shadow-16{box-shadow:0 8px 10px -5px rgba(255,255,255,.2),0 16px 24px 2px rgba(255,255,255,.14),0 6px 30px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-16{box-shadow:0 -8px 10px -5px rgba(255,255,255,.2),0 -16px 24px 2px rgba(255,255,255,.14),0 -6px 30px 5px rgba(255,255,255,.12)}body.body--dark .shadow-17{box-shadow:0 8px 11px -5px rgba(255,255,255,.2),0 17px 26px 2px rgba(255,255,255,.14),0 6px 32px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-17{box-shadow:0 -8px 11px -5px rgba(255,255,255,.2),0 -17px 26px 2px rgba(255,255,255,.14),0 -6px 32px 5px rgba(255,255,255,.12)}body.body--dark .shadow-18{box-shadow:0 9px 11px -5px rgba(255,255,255,.2),0 18px 28px 2px rgba(255,255,255,.14),0 7px 34px 6px rgba(255,255,255,.12)}body.body--dark .shadow-up-18{box-shadow:0 -9px 11px -5px rgba(255,255,255,.2),0 -18px 28px 2px rgba(255,255,255,.14),0 -7px 34px 6px rgba(255,255,255,.12)}body.body--dark .shadow-19{box-shadow:0 9px 12px -6px rgba(255,255,255,.2),0 19px 29px 2px rgba(255,255,255,.14),0 7px 36px 6px rgba(255,255,255,.12)}body.body--dark .shadow-up-19{box-shadow:0 -9px 12px -6px rgba(255,255,255,.2),0 -19px 29px 2px rgba(255,255,255,.14),0 -7px 36px 6px rgba(255,255,255,.12)}body.body--dark .shadow-20{box-shadow:0 10px 13px -6px rgba(255,255,255,.2),0 20px 31px 3px rgba(255,255,255,.14),0 8px 38px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-20{box-shadow:0 -10px 13px -6px rgba(255,255,255,.2),0 -20px 31px 3px rgba(255,255,255,.14),0 -8px 38px 7px rgba(255,255,255,.12)}body.body--dark .shadow-21{box-shadow:0 10px 13px -6px rgba(255,255,255,.2),0 21px 33px 3px rgba(255,255,255,.14),0 8px 40px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-21{box-shadow:0 -10px 13px -6px rgba(255,255,255,.2),0 -21px 33px 3px rgba(255,255,255,.14),0 -8px 40px 7px rgba(255,255,255,.12)}body.body--dark .shadow-22{box-shadow:0 10px 14px -6px rgba(255,255,255,.2),0 22px 35px 3px rgba(255,255,255,.14),0 8px 42px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-22{box-shadow:0 -10px 14px -6px rgba(255,255,255,.2),0 -22px 35px 3px rgba(255,255,255,.14),0 -8px 42px 7px rgba(255,255,255,.12)}body.body--dark .shadow-23{box-shadow:0 11px 14px -7px rgba(255,255,255,.2),0 23px 36px 3px rgba(255,255,255,.14),0 9px 44px 8px rgba(255,255,255,.12)}body.body--dark .shadow-up-23{box-shadow:0 -11px 14px -7px rgba(255,255,255,.2),0 -23px 36px 3px rgba(255,255,255,.14),0 -9px 44px 8px rgba(255,255,255,.12)}body.body--dark .shadow-24{box-shadow:0 11px 15px -7px rgba(255,255,255,.2),0 24px 38px 3px rgba(255,255,255,.14),0 9px 46px 8px rgba(255,255,255,.12)}body.body--dark .shadow-up-24{box-shadow:0 -11px 15px -7px rgba(255,255,255,.2),0 -24px 38px 3px rgba(255,255,255,.14),0 -9px 46px 8px rgba(255,255,255,.12)}body.body--dark .inset-shadow{box-shadow:0 7px 9px -7px rgba(255,255,255,.7) inset}body.body--dark .inset-shadow-down{box-shadow:0 -7px 9px -7px rgba(255,255,255,.7) inset}.no-shadow,.shadow-0{box-shadow:none!important}.z-marginals{z-index:2000}.z-notify{z-index:9500}.z-fullscreen{z-index:6000}.z-inherit{z-index:inherit!important}.column,.flex,.row{display:flex;flex-wrap:wrap}.column.inline,.flex.inline,.row.inline{display:inline-flex}.row.reverse{flex-direction:row-reverse}.column{flex-direction:column}.column.reverse{flex-direction:column-reverse}.wrap{flex-wrap:wrap}.no-wrap{flex-wrap:nowrap}.reverse-wrap{flex-wrap:wrap-reverse}.order-first{order:-10000}.order-last{order:10000}.order-none{order:0}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.flex-center,.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.flex-center,.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-center{align-content:center}.content-stretch{align-content:stretch}.content-between{align-content:space-between}.content-around{align-content:space-around}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-baseline{align-self:baseline}.self-stretch{align-self:stretch}.q-gutter-none,.q-gutter-x-none{margin-left:0}.q-gutter-none>*,.q-gutter-x-none>*{margin-left:0}.q-gutter-none,.q-gutter-y-none{margin-top:0}.q-gutter-none>*,.q-gutter-y-none>*{margin-top:0}.q-col-gutter-none,.q-col-gutter-x-none{margin-left:0}.q-col-gutter-none>*,.q-col-gutter-x-none>*{padding-left:0}.q-col-gutter-none,.q-col-gutter-y-none{margin-top:0}.q-col-gutter-none>*,.q-col-gutter-y-none>*{padding-top:0}.q-gutter-x-xs,.q-gutter-xs{margin-left:-4px}.q-gutter-x-xs>*,.q-gutter-xs>*{margin-left:4px}.q-gutter-xs,.q-gutter-y-xs{margin-top:-4px}.q-gutter-xs>*,.q-gutter-y-xs>*{margin-top:4px}.q-col-gutter-x-xs,.q-col-gutter-xs{margin-left:-4px}.q-col-gutter-x-xs>*,.q-col-gutter-xs>*{padding-left:4px}.q-col-gutter-xs,.q-col-gutter-y-xs{margin-top:-4px}.q-col-gutter-xs>*,.q-col-gutter-y-xs>*{padding-top:4px}.q-gutter-sm,.q-gutter-x-sm{margin-left:-8px}.q-gutter-sm>*,.q-gutter-x-sm>*{margin-left:8px}.q-gutter-sm,.q-gutter-y-sm{margin-top:-8px}.q-gutter-sm>*,.q-gutter-y-sm>*{margin-top:8px}.q-col-gutter-sm,.q-col-gutter-x-sm{margin-left:-8px}.q-col-gutter-sm>*,.q-col-gutter-x-sm>*{padding-left:8px}.q-col-gutter-sm,.q-col-gutter-y-sm{margin-top:-8px}.q-col-gutter-sm>*,.q-col-gutter-y-sm>*{padding-top:8px}.q-gutter-md,.q-gutter-x-md{margin-left:-16px}.q-gutter-md>*,.q-gutter-x-md>*{margin-left:16px}.q-gutter-md,.q-gutter-y-md{margin-top:-16px}.q-gutter-md>*,.q-gutter-y-md>*{margin-top:16px}.q-col-gutter-md,.q-col-gutter-x-md{margin-left:-16px}.q-col-gutter-md>*,.q-col-gutter-x-md>*{padding-left:16px}.q-col-gutter-md,.q-col-gutter-y-md{margin-top:-16px}.q-col-gutter-md>*,.q-col-gutter-y-md>*{padding-top:16px}.q-gutter-lg,.q-gutter-x-lg{margin-left:-24px}.q-gutter-lg>*,.q-gutter-x-lg>*{margin-left:24px}.q-gutter-lg,.q-gutter-y-lg{margin-top:-24px}.q-gutter-lg>*,.q-gutter-y-lg>*{margin-top:24px}.q-col-gutter-lg,.q-col-gutter-x-lg{margin-left:-24px}.q-col-gutter-lg>*,.q-col-gutter-x-lg>*{padding-left:24px}.q-col-gutter-lg,.q-col-gutter-y-lg{margin-top:-24px}.q-col-gutter-lg>*,.q-col-gutter-y-lg>*{padding-top:24px}.q-gutter-x-xl,.q-gutter-xl{margin-left:-48px}.q-gutter-x-xl>*,.q-gutter-xl>*{margin-left:48px}.q-gutter-xl,.q-gutter-y-xl{margin-top:-48px}.q-gutter-xl>*,.q-gutter-y-xl>*{margin-top:48px}.q-col-gutter-x-xl,.q-col-gutter-xl{margin-left:-48px}.q-col-gutter-x-xl>*,.q-col-gutter-xl>*{padding-left:48px}.q-col-gutter-xl,.q-col-gutter-y-xl{margin-top:-48px}.q-col-gutter-xl>*,.q-col-gutter-y-xl>*{padding-top:48px}@media (min-width:0){.flex>.col,.flex>.col-0,.flex>.col-1,.flex>.col-10,.flex>.col-11,.flex>.col-12,.flex>.col-2,.flex>.col-3,.flex>.col-4,.flex>.col-5,.flex>.col-6,.flex>.col-7,.flex>.col-8,.flex>.col-9,.flex>.col-auto,.flex>.col-grow,.flex>.col-shrink,.flex>.col-xs,.flex>.col-xs-0,.flex>.col-xs-1,.flex>.col-xs-10,.flex>.col-xs-11,.flex>.col-xs-12,.flex>.col-xs-2,.flex>.col-xs-3,.flex>.col-xs-4,.flex>.col-xs-5,.flex>.col-xs-6,.flex>.col-xs-7,.flex>.col-xs-8,.flex>.col-xs-9,.flex>.col-xs-auto,.flex>.col-xs-grow,.flex>.col-xs-shrink,.row>.col,.row>.col-0,.row>.col-1,.row>.col-10,.row>.col-11,.row>.col-12,.row>.col-2,.row>.col-3,.row>.col-4,.row>.col-5,.row>.col-6,.row>.col-7,.row>.col-8,.row>.col-9,.row>.col-auto,.row>.col-grow,.row>.col-shrink,.row>.col-xs,.row>.col-xs-0,.row>.col-xs-1,.row>.col-xs-10,.row>.col-xs-11,.row>.col-xs-12,.row>.col-xs-2,.row>.col-xs-3,.row>.col-xs-4,.row>.col-xs-5,.row>.col-xs-6,.row>.col-xs-7,.row>.col-xs-8,.row>.col-xs-9,.row>.col-xs-auto,.row>.col-xs-grow,.row>.col-xs-shrink{width:auto;min-width:0;max-width:100%}.column>.col,.column>.col-0,.column>.col-1,.column>.col-10,.column>.col-11,.column>.col-12,.column>.col-2,.column>.col-3,.column>.col-4,.column>.col-5,.column>.col-6,.column>.col-7,.column>.col-8,.column>.col-9,.column>.col-auto,.column>.col-grow,.column>.col-shrink,.column>.col-xs,.column>.col-xs-0,.column>.col-xs-1,.column>.col-xs-10,.column>.col-xs-11,.column>.col-xs-12,.column>.col-xs-2,.column>.col-xs-3,.column>.col-xs-4,.column>.col-xs-5,.column>.col-xs-6,.column>.col-xs-7,.column>.col-xs-8,.column>.col-xs-9,.column>.col-xs-auto,.column>.col-xs-grow,.column>.col-xs-shrink,.flex>.col,.flex>.col-0,.flex>.col-1,.flex>.col-10,.flex>.col-11,.flex>.col-12,.flex>.col-2,.flex>.col-3,.flex>.col-4,.flex>.col-5,.flex>.col-6,.flex>.col-7,.flex>.col-8,.flex>.col-9,.flex>.col-auto,.flex>.col-grow,.flex>.col-shrink,.flex>.col-xs,.flex>.col-xs-0,.flex>.col-xs-1,.flex>.col-xs-10,.flex>.col-xs-11,.flex>.col-xs-12,.flex>.col-xs-2,.flex>.col-xs-3,.flex>.col-xs-4,.flex>.col-xs-5,.flex>.col-xs-6,.flex>.col-xs-7,.flex>.col-xs-8,.flex>.col-xs-9,.flex>.col-xs-auto,.flex>.col-xs-grow,.flex>.col-xs-shrink{height:auto;min-height:0;max-height:100%}.col,.col-xs{flex:10000 1 0%}.col-0,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-xs-0,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-auto{flex:0 0 auto}.col-grow,.col-xs-grow{flex:1 0 auto}.col-shrink,.col-xs-shrink{flex:0 1 auto}.row>.col-0,.row>.col-xs-0{height:auto;width:0%}.row>.offset-0,.row>.offset-xs-0{margin-left:0}.column>.col-0,.column>.col-xs-0{height:0%;width:auto}.row>.col-1,.row>.col-xs-1{height:auto;width:8.3333%}.row>.offset-1,.row>.offset-xs-1{margin-left:8.3333%}.column>.col-1,.column>.col-xs-1{height:8.3333%;width:auto}.row>.col-2,.row>.col-xs-2{height:auto;width:16.6667%}.row>.offset-2,.row>.offset-xs-2{margin-left:16.6667%}.column>.col-2,.column>.col-xs-2{height:16.6667%;width:auto}.row>.col-3,.row>.col-xs-3{height:auto;width:25%}.row>.offset-3,.row>.offset-xs-3{margin-left:25%}.column>.col-3,.column>.col-xs-3{height:25%;width:auto}.row>.col-4,.row>.col-xs-4{height:auto;width:33.3333%}.row>.offset-4,.row>.offset-xs-4{margin-left:33.3333%}.column>.col-4,.column>.col-xs-4{height:33.3333%;width:auto}.row>.col-5,.row>.col-xs-5{height:auto;width:41.6667%}.row>.offset-5,.row>.offset-xs-5{margin-left:41.6667%}.column>.col-5,.column>.col-xs-5{height:41.6667%;width:auto}.row>.col-6,.row>.col-xs-6{height:auto;width:50%}.row>.offset-6,.row>.offset-xs-6{margin-left:50%}.column>.col-6,.column>.col-xs-6{height:50%;width:auto}.row>.col-7,.row>.col-xs-7{height:auto;width:58.3333%}.row>.offset-7,.row>.offset-xs-7{margin-left:58.3333%}.column>.col-7,.column>.col-xs-7{height:58.3333%;width:auto}.row>.col-8,.row>.col-xs-8{height:auto;width:66.6667%}.row>.offset-8,.row>.offset-xs-8{margin-left:66.6667%}.column>.col-8,.column>.col-xs-8{height:66.6667%;width:auto}.row>.col-9,.row>.col-xs-9{height:auto;width:75%}.row>.offset-9,.row>.offset-xs-9{margin-left:75%}.column>.col-9,.column>.col-xs-9{height:75%;width:auto}.row>.col-10,.row>.col-xs-10{height:auto;width:83.3333%}.row>.offset-10,.row>.offset-xs-10{margin-left:83.3333%}.column>.col-10,.column>.col-xs-10{height:83.3333%;width:auto}.row>.col-11,.row>.col-xs-11{height:auto;width:91.6667%}.row>.offset-11,.row>.offset-xs-11{margin-left:91.6667%}.column>.col-11,.column>.col-xs-11{height:91.6667%;width:auto}.row>.col-12,.row>.col-xs-12{height:auto;width:100%}.row>.offset-12,.row>.offset-xs-12{margin-left:100%}.column>.col-12,.column>.col-xs-12{height:100%;width:auto}.row>.col-all{height:auto;flex:0 0 100%}}@media (min-width:600px){.flex>.col-sm,.flex>.col-sm-0,.flex>.col-sm-1,.flex>.col-sm-10,.flex>.col-sm-11,.flex>.col-sm-12,.flex>.col-sm-2,.flex>.col-sm-3,.flex>.col-sm-4,.flex>.col-sm-5,.flex>.col-sm-6,.flex>.col-sm-7,.flex>.col-sm-8,.flex>.col-sm-9,.flex>.col-sm-auto,.flex>.col-sm-grow,.flex>.col-sm-shrink,.row>.col-sm,.row>.col-sm-0,.row>.col-sm-1,.row>.col-sm-10,.row>.col-sm-11,.row>.col-sm-12,.row>.col-sm-2,.row>.col-sm-3,.row>.col-sm-4,.row>.col-sm-5,.row>.col-sm-6,.row>.col-sm-7,.row>.col-sm-8,.row>.col-sm-9,.row>.col-sm-auto,.row>.col-sm-grow,.row>.col-sm-shrink{width:auto;min-width:0;max-width:100%}.column>.col-sm,.column>.col-sm-0,.column>.col-sm-1,.column>.col-sm-10,.column>.col-sm-11,.column>.col-sm-12,.column>.col-sm-2,.column>.col-sm-3,.column>.col-sm-4,.column>.col-sm-5,.column>.col-sm-6,.column>.col-sm-7,.column>.col-sm-8,.column>.col-sm-9,.column>.col-sm-auto,.column>.col-sm-grow,.column>.col-sm-shrink,.flex>.col-sm,.flex>.col-sm-0,.flex>.col-sm-1,.flex>.col-sm-10,.flex>.col-sm-11,.flex>.col-sm-12,.flex>.col-sm-2,.flex>.col-sm-3,.flex>.col-sm-4,.flex>.col-sm-5,.flex>.col-sm-6,.flex>.col-sm-7,.flex>.col-sm-8,.flex>.col-sm-9,.flex>.col-sm-auto,.flex>.col-sm-grow,.flex>.col-sm-shrink{height:auto;min-height:0;max-height:100%}.col-sm{flex:10000 1 0%}.col-sm-0,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto{flex:0 0 auto}.col-sm-grow{flex:1 0 auto}.col-sm-shrink{flex:0 1 auto}.row>.col-sm-0{height:auto;width:0%}.row>.offset-sm-0{margin-left:0}.column>.col-sm-0{height:0%;width:auto}.row>.col-sm-1{height:auto;width:8.3333%}.row>.offset-sm-1{margin-left:8.3333%}.column>.col-sm-1{height:8.3333%;width:auto}.row>.col-sm-2{height:auto;width:16.6667%}.row>.offset-sm-2{margin-left:16.6667%}.column>.col-sm-2{height:16.6667%;width:auto}.row>.col-sm-3{height:auto;width:25%}.row>.offset-sm-3{margin-left:25%}.column>.col-sm-3{height:25%;width:auto}.row>.col-sm-4{height:auto;width:33.3333%}.row>.offset-sm-4{margin-left:33.3333%}.column>.col-sm-4{height:33.3333%;width:auto}.row>.col-sm-5{height:auto;width:41.6667%}.row>.offset-sm-5{margin-left:41.6667%}.column>.col-sm-5{height:41.6667%;width:auto}.row>.col-sm-6{height:auto;width:50%}.row>.offset-sm-6{margin-left:50%}.column>.col-sm-6{height:50%;width:auto}.row>.col-sm-7{height:auto;width:58.3333%}.row>.offset-sm-7{margin-left:58.3333%}.column>.col-sm-7{height:58.3333%;width:auto}.row>.col-sm-8{height:auto;width:66.6667%}.row>.offset-sm-8{margin-left:66.6667%}.column>.col-sm-8{height:66.6667%;width:auto}.row>.col-sm-9{height:auto;width:75%}.row>.offset-sm-9{margin-left:75%}.column>.col-sm-9{height:75%;width:auto}.row>.col-sm-10{height:auto;width:83.3333%}.row>.offset-sm-10{margin-left:83.3333%}.column>.col-sm-10{height:83.3333%;width:auto}.row>.col-sm-11{height:auto;width:91.6667%}.row>.offset-sm-11{margin-left:91.6667%}.column>.col-sm-11{height:91.6667%;width:auto}.row>.col-sm-12{height:auto;width:100%}.row>.offset-sm-12{margin-left:100%}.column>.col-sm-12{height:100%;width:auto}}@media (min-width:1024px){.flex>.col-md,.flex>.col-md-0,.flex>.col-md-1,.flex>.col-md-10,.flex>.col-md-11,.flex>.col-md-12,.flex>.col-md-2,.flex>.col-md-3,.flex>.col-md-4,.flex>.col-md-5,.flex>.col-md-6,.flex>.col-md-7,.flex>.col-md-8,.flex>.col-md-9,.flex>.col-md-auto,.flex>.col-md-grow,.flex>.col-md-shrink,.row>.col-md,.row>.col-md-0,.row>.col-md-1,.row>.col-md-10,.row>.col-md-11,.row>.col-md-12,.row>.col-md-2,.row>.col-md-3,.row>.col-md-4,.row>.col-md-5,.row>.col-md-6,.row>.col-md-7,.row>.col-md-8,.row>.col-md-9,.row>.col-md-auto,.row>.col-md-grow,.row>.col-md-shrink{width:auto;min-width:0;max-width:100%}.column>.col-md,.column>.col-md-0,.column>.col-md-1,.column>.col-md-10,.column>.col-md-11,.column>.col-md-12,.column>.col-md-2,.column>.col-md-3,.column>.col-md-4,.column>.col-md-5,.column>.col-md-6,.column>.col-md-7,.column>.col-md-8,.column>.col-md-9,.column>.col-md-auto,.column>.col-md-grow,.column>.col-md-shrink,.flex>.col-md,.flex>.col-md-0,.flex>.col-md-1,.flex>.col-md-10,.flex>.col-md-11,.flex>.col-md-12,.flex>.col-md-2,.flex>.col-md-3,.flex>.col-md-4,.flex>.col-md-5,.flex>.col-md-6,.flex>.col-md-7,.flex>.col-md-8,.flex>.col-md-9,.flex>.col-md-auto,.flex>.col-md-grow,.flex>.col-md-shrink{height:auto;min-height:0;max-height:100%}.col-md{flex:10000 1 0%}.col-md-0,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto{flex:0 0 auto}.col-md-grow{flex:1 0 auto}.col-md-shrink{flex:0 1 auto}.row>.col-md-0{height:auto;width:0%}.row>.offset-md-0{margin-left:0}.column>.col-md-0{height:0%;width:auto}.row>.col-md-1{height:auto;width:8.3333%}.row>.offset-md-1{margin-left:8.3333%}.column>.col-md-1{height:8.3333%;width:auto}.row>.col-md-2{height:auto;width:16.6667%}.row>.offset-md-2{margin-left:16.6667%}.column>.col-md-2{height:16.6667%;width:auto}.row>.col-md-3{height:auto;width:25%}.row>.offset-md-3{margin-left:25%}.column>.col-md-3{height:25%;width:auto}.row>.col-md-4{height:auto;width:33.3333%}.row>.offset-md-4{margin-left:33.3333%}.column>.col-md-4{height:33.3333%;width:auto}.row>.col-md-5{height:auto;width:41.6667%}.row>.offset-md-5{margin-left:41.6667%}.column>.col-md-5{height:41.6667%;width:auto}.row>.col-md-6{height:auto;width:50%}.row>.offset-md-6{margin-left:50%}.column>.col-md-6{height:50%;width:auto}.row>.col-md-7{height:auto;width:58.3333%}.row>.offset-md-7{margin-left:58.3333%}.column>.col-md-7{height:58.3333%;width:auto}.row>.col-md-8{height:auto;width:66.6667%}.row>.offset-md-8{margin-left:66.6667%}.column>.col-md-8{height:66.6667%;width:auto}.row>.col-md-9{height:auto;width:75%}.row>.offset-md-9{margin-left:75%}.column>.col-md-9{height:75%;width:auto}.row>.col-md-10{height:auto;width:83.3333%}.row>.offset-md-10{margin-left:83.3333%}.column>.col-md-10{height:83.3333%;width:auto}.row>.col-md-11{height:auto;width:91.6667%}.row>.offset-md-11{margin-left:91.6667%}.column>.col-md-11{height:91.6667%;width:auto}.row>.col-md-12{height:auto;width:100%}.row>.offset-md-12{margin-left:100%}.column>.col-md-12{height:100%;width:auto}}@media (min-width:1440px){.flex>.col-lg,.flex>.col-lg-0,.flex>.col-lg-1,.flex>.col-lg-10,.flex>.col-lg-11,.flex>.col-lg-12,.flex>.col-lg-2,.flex>.col-lg-3,.flex>.col-lg-4,.flex>.col-lg-5,.flex>.col-lg-6,.flex>.col-lg-7,.flex>.col-lg-8,.flex>.col-lg-9,.flex>.col-lg-auto,.flex>.col-lg-grow,.flex>.col-lg-shrink,.row>.col-lg,.row>.col-lg-0,.row>.col-lg-1,.row>.col-lg-10,.row>.col-lg-11,.row>.col-lg-12,.row>.col-lg-2,.row>.col-lg-3,.row>.col-lg-4,.row>.col-lg-5,.row>.col-lg-6,.row>.col-lg-7,.row>.col-lg-8,.row>.col-lg-9,.row>.col-lg-auto,.row>.col-lg-grow,.row>.col-lg-shrink{width:auto;min-width:0;max-width:100%}.column>.col-lg,.column>.col-lg-0,.column>.col-lg-1,.column>.col-lg-10,.column>.col-lg-11,.column>.col-lg-12,.column>.col-lg-2,.column>.col-lg-3,.column>.col-lg-4,.column>.col-lg-5,.column>.col-lg-6,.column>.col-lg-7,.column>.col-lg-8,.column>.col-lg-9,.column>.col-lg-auto,.column>.col-lg-grow,.column>.col-lg-shrink,.flex>.col-lg,.flex>.col-lg-0,.flex>.col-lg-1,.flex>.col-lg-10,.flex>.col-lg-11,.flex>.col-lg-12,.flex>.col-lg-2,.flex>.col-lg-3,.flex>.col-lg-4,.flex>.col-lg-5,.flex>.col-lg-6,.flex>.col-lg-7,.flex>.col-lg-8,.flex>.col-lg-9,.flex>.col-lg-auto,.flex>.col-lg-grow,.flex>.col-lg-shrink{height:auto;min-height:0;max-height:100%}.col-lg{flex:10000 1 0%}.col-lg-0,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto{flex:0 0 auto}.col-lg-grow{flex:1 0 auto}.col-lg-shrink{flex:0 1 auto}.row>.col-lg-0{height:auto;width:0%}.row>.offset-lg-0{margin-left:0}.column>.col-lg-0{height:0%;width:auto}.row>.col-lg-1{height:auto;width:8.3333%}.row>.offset-lg-1{margin-left:8.3333%}.column>.col-lg-1{height:8.3333%;width:auto}.row>.col-lg-2{height:auto;width:16.6667%}.row>.offset-lg-2{margin-left:16.6667%}.column>.col-lg-2{height:16.6667%;width:auto}.row>.col-lg-3{height:auto;width:25%}.row>.offset-lg-3{margin-left:25%}.column>.col-lg-3{height:25%;width:auto}.row>.col-lg-4{height:auto;width:33.3333%}.row>.offset-lg-4{margin-left:33.3333%}.column>.col-lg-4{height:33.3333%;width:auto}.row>.col-lg-5{height:auto;width:41.6667%}.row>.offset-lg-5{margin-left:41.6667%}.column>.col-lg-5{height:41.6667%;width:auto}.row>.col-lg-6{height:auto;width:50%}.row>.offset-lg-6{margin-left:50%}.column>.col-lg-6{height:50%;width:auto}.row>.col-lg-7{height:auto;width:58.3333%}.row>.offset-lg-7{margin-left:58.3333%}.column>.col-lg-7{height:58.3333%;width:auto}.row>.col-lg-8{height:auto;width:66.6667%}.row>.offset-lg-8{margin-left:66.6667%}.column>.col-lg-8{height:66.6667%;width:auto}.row>.col-lg-9{height:auto;width:75%}.row>.offset-lg-9{margin-left:75%}.column>.col-lg-9{height:75%;width:auto}.row>.col-lg-10{height:auto;width:83.3333%}.row>.offset-lg-10{margin-left:83.3333%}.column>.col-lg-10{height:83.3333%;width:auto}.row>.col-lg-11{height:auto;width:91.6667%}.row>.offset-lg-11{margin-left:91.6667%}.column>.col-lg-11{height:91.6667%;width:auto}.row>.col-lg-12{height:auto;width:100%}.row>.offset-lg-12{margin-left:100%}.column>.col-lg-12{height:100%;width:auto}}@media (min-width:1920px){.flex>.col-xl,.flex>.col-xl-0,.flex>.col-xl-1,.flex>.col-xl-10,.flex>.col-xl-11,.flex>.col-xl-12,.flex>.col-xl-2,.flex>.col-xl-3,.flex>.col-xl-4,.flex>.col-xl-5,.flex>.col-xl-6,.flex>.col-xl-7,.flex>.col-xl-8,.flex>.col-xl-9,.flex>.col-xl-auto,.flex>.col-xl-grow,.flex>.col-xl-shrink,.row>.col-xl,.row>.col-xl-0,.row>.col-xl-1,.row>.col-xl-10,.row>.col-xl-11,.row>.col-xl-12,.row>.col-xl-2,.row>.col-xl-3,.row>.col-xl-4,.row>.col-xl-5,.row>.col-xl-6,.row>.col-xl-7,.row>.col-xl-8,.row>.col-xl-9,.row>.col-xl-auto,.row>.col-xl-grow,.row>.col-xl-shrink{width:auto;min-width:0;max-width:100%}.column>.col-xl,.column>.col-xl-0,.column>.col-xl-1,.column>.col-xl-10,.column>.col-xl-11,.column>.col-xl-12,.column>.col-xl-2,.column>.col-xl-3,.column>.col-xl-4,.column>.col-xl-5,.column>.col-xl-6,.column>.col-xl-7,.column>.col-xl-8,.column>.col-xl-9,.column>.col-xl-auto,.column>.col-xl-grow,.column>.col-xl-shrink,.flex>.col-xl,.flex>.col-xl-0,.flex>.col-xl-1,.flex>.col-xl-10,.flex>.col-xl-11,.flex>.col-xl-12,.flex>.col-xl-2,.flex>.col-xl-3,.flex>.col-xl-4,.flex>.col-xl-5,.flex>.col-xl-6,.flex>.col-xl-7,.flex>.col-xl-8,.flex>.col-xl-9,.flex>.col-xl-auto,.flex>.col-xl-grow,.flex>.col-xl-shrink{height:auto;min-height:0;max-height:100%}.col-xl{flex:10000 1 0%}.col-xl-0,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{flex:0 0 auto}.col-xl-grow{flex:1 0 auto}.col-xl-shrink{flex:0 1 auto}.row>.col-xl-0{height:auto;width:0%}.row>.offset-xl-0{margin-left:0}.column>.col-xl-0{height:0%;width:auto}.row>.col-xl-1{height:auto;width:8.3333%}.row>.offset-xl-1{margin-left:8.3333%}.column>.col-xl-1{height:8.3333%;width:auto}.row>.col-xl-2{height:auto;width:16.6667%}.row>.offset-xl-2{margin-left:16.6667%}.column>.col-xl-2{height:16.6667%;width:auto}.row>.col-xl-3{height:auto;width:25%}.row>.offset-xl-3{margin-left:25%}.column>.col-xl-3{height:25%;width:auto}.row>.col-xl-4{height:auto;width:33.3333%}.row>.offset-xl-4{margin-left:33.3333%}.column>.col-xl-4{height:33.3333%;width:auto}.row>.col-xl-5{height:auto;width:41.6667%}.row>.offset-xl-5{margin-left:41.6667%}.column>.col-xl-5{height:41.6667%;width:auto}.row>.col-xl-6{height:auto;width:50%}.row>.offset-xl-6{margin-left:50%}.column>.col-xl-6{height:50%;width:auto}.row>.col-xl-7{height:auto;width:58.3333%}.row>.offset-xl-7{margin-left:58.3333%}.column>.col-xl-7{height:58.3333%;width:auto}.row>.col-xl-8{height:auto;width:66.6667%}.row>.offset-xl-8{margin-left:66.6667%}.column>.col-xl-8{height:66.6667%;width:auto}.row>.col-xl-9{height:auto;width:75%}.row>.offset-xl-9{margin-left:75%}.column>.col-xl-9{height:75%;width:auto}.row>.col-xl-10{height:auto;width:83.3333%}.row>.offset-xl-10{margin-left:83.3333%}.column>.col-xl-10{height:83.3333%;width:auto}.row>.col-xl-11{height:auto;width:91.6667%}.row>.offset-xl-11{margin-left:91.6667%}.column>.col-xl-11{height:91.6667%;width:auto}.row>.col-xl-12{height:auto;width:100%}.row>.offset-xl-12{margin-left:100%}.column>.col-xl-12{height:100%;width:auto}}.rounded-borders{border-radius:4px}.border-radius-inherit{border-radius:inherit}.no-transition{transition:none!important}.transition-0{transition:0s!important}.glossy{background-image:linear-gradient(to bottom,rgba(255,255,255,.3),rgba(255,255,255,0) 50%,rgba(0,0,0,.12) 51%,rgba(0,0,0,.04))!important}.q-placeholder::placeholder{color:inherit;opacity:.7}.q-body--fullscreen-mixin,.q-body--prevent-scroll{position:fixed!important}.q-body--force-scrollbar-x{overflow-x:scroll}.q-body--force-scrollbar-y{overflow-y:scroll}.q-no-input-spinner{-moz-appearance:textfield!important}.q-no-input-spinner::-webkit-inner-spin-button,.q-no-input-spinner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.q-link{outline:0;text-decoration:none}.q-link--focusable:focus-visible{-webkit-text-decoration:underline dashed currentColor 1px;text-decoration:underline dashed currentColor 1px}body.electron .q-electron-drag{-webkit-user-select:none;-webkit-app-region:drag}body.electron .q-electron-drag .q-btn-item,body.electron .q-electron-drag--exception{-webkit-app-region:no-drag}img.responsive{max-width:100%;height:auto}.non-selectable{-webkit-user-select:none!important;user-select:none!important}.scroll,body.mobile .scroll--mobile{overflow:auto}.scroll,.scroll-x,.scroll-y{-webkit-overflow-scrolling:touch;will-change:scroll-position}.scroll-x{overflow-x:auto}.scroll-y{overflow-y:auto}.no-scroll{overflow:hidden!important}.no-pointer-events,.no-pointer-events--children,.no-pointer-events--children *{pointer-events:none!important}.all-pointer-events{pointer-events:all!important}.cursor-pointer{cursor:pointer!important}.cursor-not-allowed{cursor:not-allowed!important}.cursor-inherit{cursor:inherit!important}.cursor-none{cursor:none!important}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled=true]{cursor:default}.rotate-45{transform:rotate(45deg)}.rotate-90{transform:rotate(90deg)}.rotate-135{transform:rotate(135deg)}.rotate-180{transform:rotate(180deg)}.rotate-225{transform:rotate(225deg)}.rotate-270{transform:rotate(270deg)}.rotate-315{transform:rotate(315deg)}.flip-horizontal{transform:scaleX(-1)}.flip-vertical{transform:scaleY(-1)}.float-left{float:left}.float-right{float:right}.relative-position{position:relative}.fixed,.fixed-bottom,.fixed-bottom-left,.fixed-bottom-right,.fixed-center,.fixed-full,.fixed-left,.fixed-right,.fixed-top,.fixed-top-left,.fixed-top-right,.fullscreen{position:fixed}.absolute,.absolute-bottom,.absolute-bottom-left,.absolute-bottom-right,.absolute-center,.absolute-full,.absolute-left,.absolute-right,.absolute-top,.absolute-top-left,.absolute-top-right{position:absolute}.absolute-top,.fixed-top{top:0;left:0;right:0}.absolute-right,.fixed-right{top:0;right:0;bottom:0}.absolute-bottom,.fixed-bottom{right:0;bottom:0;left:0}.absolute-left,.fixed-left{top:0;bottom:0;left:0}.absolute-top-left,.fixed-top-left{top:0;left:0}.absolute-top-right,.fixed-top-right{top:0;right:0}.absolute-bottom-left,.fixed-bottom-left{bottom:0;left:0}.absolute-bottom-right,.fixed-bottom-right{bottom:0;right:0}.fullscreen{z-index:6000;border-radius:0!important;max-width:100vw;max-height:100vh}body.q-ios-padding .fullscreen{padding-top:20px!important;padding-top:env(safe-area-inset-top)!important;padding-bottom:env(safe-area-inset-bottom)!important}.absolute-full,.fixed-full,.fullscreen{top:0;right:0;bottom:0;left:0}.absolute-center,.fixed-center{top:50%;left:50%;transform:translate(-50%,-50%)}.vertical-top{vertical-align:top!important}.vertical-middle{vertical-align:middle!important}.vertical-bottom{vertical-align:bottom!important}.on-left{margin-right:12px}.on-right{margin-left:12px}.q-position-engine{margin-top:var(--q-pe-top,0)!important;margin-left:var(--q-pe-left,0)!important;will-change:auto;visibility:collapse}:root{--q-size-xs:0;--q-size-sm:600px;--q-size-md:1024px;--q-size-lg:1440px;--q-size-xl:1920px}.fit{width:100%!important;height:100%!important}.full-height{height:100%!important}.full-width{width:100%!important;margin-left:0!important;margin-right:0!important}.window-height{margin-top:0!important;margin-bottom:0!important;height:100vh!important}.window-width{margin-left:0!important;margin-right:0!important;width:100vw!important}.block{display:block!important}.inline-block{display:inline-block!important}.q-pa-none{padding:0 0}.q-pl-none{padding-left:0}.q-pr-none{padding-right:0}.q-pt-none{padding-top:0}.q-pb-none{padding-bottom:0}.q-px-none{padding-left:0;padding-right:0}.q-py-none{padding-top:0;padding-bottom:0}.q-ma-none{margin:0 0}.q-ml-none{margin-left:0}.q-mr-none{margin-right:0}.q-mt-none{margin-top:0}.q-mb-none{margin-bottom:0}.q-mx-none{margin-left:0;margin-right:0}.q-my-none{margin-top:0;margin-bottom:0}.q-pa-xs{padding:4px 4px}.q-pl-xs{padding-left:4px}.q-pr-xs{padding-right:4px}.q-pt-xs{padding-top:4px}.q-pb-xs{padding-bottom:4px}.q-px-xs{padding-left:4px;padding-right:4px}.q-py-xs{padding-top:4px;padding-bottom:4px}.q-ma-xs{margin:4px 4px}.q-ml-xs{margin-left:4px}.q-mr-xs{margin-right:4px}.q-mt-xs{margin-top:4px}.q-mb-xs{margin-bottom:4px}.q-mx-xs{margin-left:4px;margin-right:4px}.q-my-xs{margin-top:4px;margin-bottom:4px}.q-pa-sm{padding:8px 8px}.q-pl-sm{padding-left:8px}.q-pr-sm{padding-right:8px}.q-pt-sm{padding-top:8px}.q-pb-sm{padding-bottom:8px}.q-px-sm{padding-left:8px;padding-right:8px}.q-py-sm{padding-top:8px;padding-bottom:8px}.q-ma-sm{margin:8px 8px}.q-ml-sm{margin-left:8px}.q-mr-sm{margin-right:8px}.q-mt-sm{margin-top:8px}.q-mb-sm{margin-bottom:8px}.q-mx-sm{margin-left:8px;margin-right:8px}.q-my-sm{margin-top:8px;margin-bottom:8px}.q-pa-md{padding:16px 16px}.q-pl-md{padding-left:16px}.q-pr-md{padding-right:16px}.q-pt-md{padding-top:16px}.q-pb-md{padding-bottom:16px}.q-px-md{padding-left:16px;padding-right:16px}.q-py-md{padding-top:16px;padding-bottom:16px}.q-ma-md{margin:16px 16px}.q-ml-md{margin-left:16px}.q-mr-md{margin-right:16px}.q-mt-md{margin-top:16px}.q-mb-md{margin-bottom:16px}.q-mx-md{margin-left:16px;margin-right:16px}.q-my-md{margin-top:16px;margin-bottom:16px}.q-pa-lg{padding:24px 24px}.q-pl-lg{padding-left:24px}.q-pr-lg{padding-right:24px}.q-pt-lg{padding-top:24px}.q-pb-lg{padding-bottom:24px}.q-px-lg{padding-left:24px;padding-right:24px}.q-py-lg{padding-top:24px;padding-bottom:24px}.q-ma-lg{margin:24px 24px}.q-ml-lg{margin-left:24px}.q-mr-lg{margin-right:24px}.q-mt-lg{margin-top:24px}.q-mb-lg{margin-bottom:24px}.q-mx-lg{margin-left:24px;margin-right:24px}.q-my-lg{margin-top:24px;margin-bottom:24px}.q-pa-xl{padding:48px 48px}.q-pl-xl{padding-left:48px}.q-pr-xl{padding-right:48px}.q-pt-xl{padding-top:48px}.q-pb-xl{padding-bottom:48px}.q-px-xl{padding-left:48px;padding-right:48px}.q-py-xl{padding-top:48px;padding-bottom:48px}.q-ma-xl{margin:48px 48px}.q-ml-xl{margin-left:48px}.q-mr-xl{margin-right:48px}.q-mt-xl{margin-top:48px}.q-mb-xl{margin-bottom:48px}.q-mx-xl{margin-left:48px;margin-right:48px}.q-my-xl{margin-top:48px;margin-bottom:48px}.q-mt-auto,.q-my-auto{margin-top:auto}.q-ml-auto{margin-left:auto}.q-mb-auto,.q-my-auto{margin-bottom:auto}.q-mr-auto{margin-right:auto}.q-mx-auto{margin-left:auto;margin-right:auto}.q-touch{-webkit-user-select:none;user-select:none;user-drag:none;-khtml-user-drag:none;-webkit-user-drag:none}.q-touch-x{touch-action:pan-x}.q-touch-y{touch-action:pan-y}:root{--q-transition-duration:.3s}.q-transition--fade-enter-active,.q-transition--fade-leave-active,.q-transition--flip-enter-active,.q-transition--flip-leave-active,.q-transition--jump-down-enter-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-enter-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-enter-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-enter-active,.q-transition--jump-up-leave-active,.q-transition--rotate-enter-active,.q-transition--rotate-leave-active,.q-transition--scale-enter-active,.q-transition--scale-leave-active,.q-transition--slide-down-enter-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-enter-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-enter-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-enter-active,.q-transition--slide-up-leave-active{--q-transition-duration:.3s;--q-transition-easing:cubic-bezier(0.215,0.61,0.355,1)}.q-transition--fade-leave-active,.q-transition--flip-leave-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-leave-active,.q-transition--rotate-leave-active,.q-transition--scale-leave-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-leave-active{position:absolute}.q-transition--slide-down-enter-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-enter-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-enter-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-enter-active,.q-transition--slide-up-leave-active{transition:transform var(--q-transition-duration) var(--q-transition-easing)}.q-transition--slide-right-enter-from{transform:translate3d(-100%,0,0)}.q-transition--slide-right-leave-to{transform:translate3d(100%,0,0)}.q-transition--slide-left-enter-from{transform:translate3d(100%,0,0)}.q-transition--slide-left-leave-to{transform:translate3d(-100%,0,0)}.q-transition--slide-up-enter-from{transform:translate3d(0,100%,0)}.q-transition--slide-up-leave-to{transform:translate3d(0,-100%,0)}.q-transition--slide-down-enter-from{transform:translate3d(0,-100%,0)}.q-transition--slide-down-leave-to{transform:translate3d(0,100%,0)}.q-transition--jump-down-enter-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-enter-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-enter-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-enter-active,.q-transition--jump-up-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration)}.q-transition--jump-down-enter-from,.q-transition--jump-down-leave-to,.q-transition--jump-left-enter-from,.q-transition--jump-left-leave-to,.q-transition--jump-right-enter-from,.q-transition--jump-right-leave-to,.q-transition--jump-up-enter-from,.q-transition--jump-up-leave-to{opacity:0}.q-transition--jump-right-enter-from{transform:translate3d(-15px,0,0)}.q-transition--jump-right-leave-to{transform:translate3d(15px,0,0)}.q-transition--jump-left-enter-from{transform:translate3d(15px,0,0)}.q-transition--jump-left-leave-to{transform:translateX(-15px)}.q-transition--jump-up-enter-from{transform:translate3d(0,15px,0)}.q-transition--jump-up-leave-to{transform:translate3d(0,-15px,0)}.q-transition--jump-down-enter-from{transform:translate3d(0,-15px,0)}.q-transition--jump-down-leave-to{transform:translate3d(0,15px,0)}.q-transition--fade-enter-active,.q-transition--fade-leave-active{transition:opacity var(--q-transition-duration) ease-out}.q-transition--fade-enter-from,.q-transition--fade-leave-to{opacity:0}.q-transition--scale-enter-active,.q-transition--scale-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration) var(--q-transition-easing)}.q-transition--scale-enter-from,.q-transition--scale-leave-to{opacity:0;transform:scale3d(0,0,1)}.q-transition--rotate-enter-active,.q-transition--rotate-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration) var(--q-transition-easing);transform-style:preserve-3d}.q-transition--rotate-enter-from,.q-transition--rotate-leave-to{opacity:0;transform:scale3d(0,0,1) rotate3d(0,0,1,90deg)}.q-transition--flip-down-enter-active,.q-transition--flip-down-leave-active,.q-transition--flip-left-enter-active,.q-transition--flip-left-leave-active,.q-transition--flip-right-enter-active,.q-transition--flip-right-leave-active,.q-transition--flip-up-enter-active,.q-transition--flip-up-leave-active{transition:transform var(--q-transition-duration);backface-visibility:hidden}.q-transition--flip-down-enter-to,.q-transition--flip-down-leave-from,.q-transition--flip-left-enter-to,.q-transition--flip-left-leave-from,.q-transition--flip-right-enter-to,.q-transition--flip-right-leave-from,.q-transition--flip-up-enter-to,.q-transition--flip-up-leave-from{transform:perspective(400px) rotate3d(1,1,0,0deg)}.q-transition--flip-right-enter-from{transform:perspective(400px) rotate3d(0,1,0,-180deg)}.q-transition--flip-right-leave-to{transform:perspective(400px) rotate3d(0,1,0,180deg)}.q-transition--flip-left-enter-from{transform:perspective(400px) rotate3d(0,1,0,180deg)}.q-transition--flip-left-leave-to{transform:perspective(400px) rotate3d(0,1,0,-180deg)}.q-transition--flip-up-enter-from{transform:perspective(400px) rotate3d(1,0,0,-180deg)}.q-transition--flip-up-leave-to{transform:perspective(400px) rotate3d(1,0,0,180deg)}.q-transition--flip-down-enter-from{transform:perspective(400px) rotate3d(1,0,0,180deg)}.q-transition--flip-down-leave-to{transform:perspective(400px) rotate3d(1,0,0,-180deg)}body{min-width:100px;min-height:100%;font-family:Roboto,"-apple-system","Helvetica Neue",Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;line-height:1.5;font-size:14px}h1{font-size:6rem;font-weight:300;line-height:6rem;letter-spacing:-.01562em}h2{font-size:3.75rem;font-weight:300;line-height:3.75rem;letter-spacing:-.00833em}h3{font-size:3rem;font-weight:400;line-height:3.125rem;letter-spacing:normal}h4{font-size:2.125rem;font-weight:400;line-height:2.5rem;letter-spacing:.00735em}h5{font-size:1.5rem;font-weight:400;line-height:2rem;letter-spacing:normal}h6{font-size:1.25rem;font-weight:500;line-height:2rem;letter-spacing:.0125em}p{margin:0 0 16px}.text-h1{font-size:6rem;font-weight:300;line-height:6rem;letter-spacing:-.01562em}.text-h2{font-size:3.75rem;font-weight:300;line-height:3.75rem;letter-spacing:-.00833em}.text-h3{font-size:3rem;font-weight:400;line-height:3.125rem;letter-spacing:normal}.text-h4{font-size:2.125rem;font-weight:400;line-height:2.5rem;letter-spacing:.00735em}.text-h5{font-size:1.5rem;font-weight:400;line-height:2rem;letter-spacing:normal}.text-h6{font-size:1.25rem;font-weight:500;line-height:2rem;letter-spacing:.0125em}.text-subtitle1{font-size:1rem;font-weight:400;line-height:1.75rem;letter-spacing:.00937em}.text-subtitle2{font-size:.875rem;font-weight:500;line-height:1.375rem;letter-spacing:.00714em}.text-body1{font-size:1rem;font-weight:400;line-height:1.5rem;letter-spacing:.03125em}.text-body2{font-size:.875rem;font-weight:400;line-height:1.25rem;letter-spacing:.01786em}.text-overline{font-size:.75rem;font-weight:500;line-height:2rem;letter-spacing:.16667em}.text-caption{font-size:.75rem;font-weight:400;line-height:1.25rem;letter-spacing:.03333em}.text-uppercase{text-transform:uppercase}.text-lowercase{text-transform:lowercase}.text-capitalize{text-transform:capitalize}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.text-justify{text-align:justify;hyphens:auto}.text-italic{font-style:italic}.text-bold{font-weight:700}.text-no-wrap{white-space:nowrap}.text-strike{text-decoration:line-through}.text-weight-thin{font-weight:100}.text-weight-light{font-weight:300}.text-weight-regular{font-weight:400}.text-weight-medium{font-weight:500}.text-weight-bold{font-weight:700}.text-weight-bolder{font-weight:900}small{font-size:80%}big{font-size:170%}sub{bottom:-.25em}sup{top:-.5em}.no-margin{margin:0!important}.no-padding{padding:0!important}.no-border{border:0!important}.no-border-radius{border-radius:0!important}.no-box-shadow{box-shadow:none!important}.no-outline{outline:0!important}.ellipsis{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ellipsis-2-lines,.ellipsis-3-lines{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.ellipsis-2-lines{-webkit-line-clamp:2}.ellipsis-3-lines{-webkit-line-clamp:3}.readonly{cursor:default!important}.disabled,.disabled *,[disabled],[disabled] *{outline:0!important;cursor:not-allowed!important}.disabled,[disabled]{opacity:.6!important}.hidden{display:none!important}.invisible,.invisible *{visibility:hidden!important;transition:none!important;animation:none!important}.transparent{background:0 0!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-hidden-y{overflow-y:hidden!important}.hide-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.hide-scrollbar::-webkit-scrollbar{width:0;height:0;display:none}.dimmed:after,.light-dimmed:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0}.dimmed:after{background:rgba(0,0,0,.4)!important}.light-dimmed:after{background:rgba(255,255,255,.6)!important}.z-top{z-index:7000!important}.z-max{z-index:9998!important}body.desktop .desktop-hide,body:not(.desktop) .desktop-only{display:none!important}body.mobile .mobile-hide,body:not(.mobile) .mobile-only{display:none!important}body.native-mobile .native-mobile-hide,body:not(.native-mobile) .native-mobile-only{display:none!important}body.cordova .cordova-hide,body:not(.cordova) .cordova-only{display:none!important}body.capacitor .capacitor-hide,body:not(.capacitor) .capacitor-only{display:none!important}body.electron .electron-hide,body:not(.electron) .electron-only{display:none!important}body.touch .touch-hide,body:not(.touch) .touch-only{display:none!important}body.within-iframe .within-iframe-hide,body:not(.within-iframe) .within-iframe-only{display:none!important}body.platform-ios .platform-ios-hide,body:not(.platform-ios) .platform-ios-only{display:none!important}body.platform-android .platform-android-hide,body:not(.platform-android) .platform-android-only{display:none!important}@media all and (orientation:portrait){.orientation-landscape{display:none!important}}@media all and (orientation:landscape){.orientation-portrait{display:none!important}}@media screen{.print-only{display:none!important}}@media print{.print-hide{display:none!important}}@media (max-width:599.98px){.gt-lg,.gt-md,.gt-sm,.gt-xs,.lg,.md,.sm,.xl,.xs-hide{display:none!important}}@media (min-width:600px) and (max-width:1023.98px){.gt-lg,.gt-md,.gt-sm,.lg,.lt-sm,.md,.sm-hide,.xl,.xs{display:none!important}}@media (min-width:1024px) and (max-width:1439.98px){.gt-lg,.gt-md,.lg,.lt-md,.lt-sm,.md-hide,.sm,.xl,.xs{display:none!important}}@media (min-width:1440px) and (max-width:1919.98px){.gt-lg,.lg-hide,.lt-lg,.lt-md,.lt-sm,.md,.sm,.xl,.xs{display:none!important}}@media (min-width:1920px){.lg,.lt-lg,.lt-md,.lt-sm,.lt-xl,.md,.sm,.xl-hide,.xs{display:none!important}}.q-focus-helper,.q-focusable,.q-hoverable,.q-manual-focusable{outline:0}body.desktop .q-focus-helper{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;border-radius:inherit;opacity:0;transition:background-color .3s cubic-bezier(.25, .8, .5, 1),opacity .4s cubic-bezier(.25, .8, .5, 1)}body.desktop .q-focus-helper:after,body.desktop .q-focus-helper:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;border-radius:inherit;transition:background-color .3s cubic-bezier(.25, .8, .5, 1),opacity .6s cubic-bezier(.25, .8, .5, 1)}body.desktop .q-focus-helper:before{background:#000}body.desktop .q-focus-helper:after{background:#fff}body.desktop .q-focus-helper--rounded{border-radius:4px}body.desktop .q-focus-helper--round{border-radius:50%}body.desktop .q-focusable:focus>.q-focus-helper,body.desktop .q-hoverable:hover>.q-focus-helper,body.desktop .q-manual-focusable--focused>.q-focus-helper{background:currentColor;opacity:.15}body.desktop .q-focusable:focus>.q-focus-helper:before,body.desktop .q-hoverable:hover>.q-focus-helper:before,body.desktop .q-manual-focusable--focused>.q-focus-helper:before{opacity:.1}body.desktop .q-focusable:focus>.q-focus-helper:after,body.desktop .q-hoverable:hover>.q-focus-helper:after,body.desktop .q-manual-focusable--focused>.q-focus-helper:after{opacity:.4}body.desktop .q-focusable:focus>.q-focus-helper,body.desktop .q-manual-focusable--focused>.q-focus-helper{opacity:.22}body.body--dark{color:#fff;background:var(--q-dark-page)}.q-dark{color:#fff;background:var(--q-dark)}body[data-theme=classic].neon-border .q-card,body[data-theme=classic].neon-border .q-card.q-card--dark,body[data-theme=classic].neon-border .q-date,body[data-theme=classic].neon-border .q-date--dark{border:2px solid #673ab7;box-shadow:none}body[data-theme=bitcoin].neon-border .q-card,body[data-theme=bitcoin].neon-border .q-card.q-card--dark,body[data-theme=bitcoin].neon-border .q-date,body[data-theme=bitcoin].neon-border .q-date--dark{border:2px solid #ea611d;box-shadow:none}body[data-theme=freedom].neon-border .q-card,body[data-theme=freedom].neon-border .q-card.q-card--dark,body[data-theme=freedom].neon-border .q-date,body[data-theme=freedom].neon-border .q-date--dark{border:2px solid #e22156;box-shadow:none}body[data-theme=cyber].neon-border .q-card,body[data-theme=cyber].neon-border .q-card.q-card--dark,body[data-theme=cyber].neon-border .q-date,body[data-theme=cyber].neon-border .q-date--dark{border:2px solid #7cb342;box-shadow:none}body[data-theme=mint].neon-border .q-card,body[data-theme=mint].neon-border .q-card.q-card--dark,body[data-theme=mint].neon-border .q-date,body[data-theme=mint].neon-border .q-date--dark{border:2px solid #3ab77d;box-shadow:none}body[data-theme=autumn].neon-border .q-card,body[data-theme=autumn].neon-border .q-card.q-card--dark,body[data-theme=autumn].neon-border .q-date,body[data-theme=autumn].neon-border .q-date--dark{border:2px solid #b7763a;box-shadow:none}body[data-theme=flamingo].neon-border .q-card,body[data-theme=flamingo].neon-border .q-card.q-card--dark,body[data-theme=flamingo].neon-border .q-date,body[data-theme=flamingo].neon-border .q-date--dark{border:2px solid #f0f;box-shadow:none}body[data-theme=monochrome].neon-border .q-card,body[data-theme=monochrome].neon-border .q-card.q-card--dark,body[data-theme=monochrome].neon-border .q-date,body[data-theme=monochrome].neon-border .q-date--dark{border:2px solid #494949;box-shadow:none}body[data-theme=salvador].neon-border .q-card,body[data-theme=salvador].neon-border .q-card.q-card--dark,body[data-theme=salvador].neon-border .q-date,body[data-theme=salvador].neon-border .q-date--dark{border:2px solid #1976d2;box-shadow:none}body.hard-border .q-card,body.hard-border .q-card.q-card--dark,body.hard-border .q-date,body.hard-border .q-date--dark{box-shadow:0 0 0 1px rgba(0,0,0,.12),0 0 0 1px rgba(255,255,255,.2784313725);border:none}body.retro-border .q-card,body.retro-border .q-card.q-card--dark,body.retro-border .q-date,body.retro-border .q-date--dark{border:none;box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}body.no-border .q-card,body.no-border .q-card.q-card--dark,body.no-border .q-date,body.no-border .q-date--dark{border:none;box-shadow:none}body[data-theme=classic]{--q-primary:#673ab7;--q-secondary:#9c27b0;--q-dark-page:#1f2234}body[data-theme=classic] [data-theme=classic] .q-card--dark,body[data-theme=classic] [data-theme=classic] .q-stepper--dark{background:#333646!important}body[data-theme=bitcoin]{--q-primary:#ea611d;--q-secondary:#e56f35;--q-dark-page:#2d293b}body[data-theme=bitcoin] [data-theme=bitcoin] .q-card--dark,body[data-theme=bitcoin] [data-theme=bitcoin] .q-stepper--dark{background:#333646!important}body[data-theme=freedom]{--q-primary:#e22156;--q-secondary:#b91a45;--q-dark-page:#462f36}body[data-theme=freedom] [data-theme=freedom] .q-card--dark,body[data-theme=freedom] [data-theme=freedom] .q-stepper--dark{background:#47393d!important}body[data-theme=cyber]{--q-primary:#7cb342;--q-secondary:#558b2f;--q-dark-page:#000}body[data-theme=cyber] [data-theme=cyber] .q-card--dark,body[data-theme=cyber] [data-theme=cyber] .q-stepper--dark{background:#1f2915!important}body[data-theme=mint]{--q-primary:#3ab77d;--q-secondary:#27b065;--q-dark-page:#1f342b}body[data-theme=mint] [data-theme=mint] .q-card--dark,body[data-theme=mint] [data-theme=mint] .q-stepper--dark{background:#334642!important}body[data-theme=autumn]{--q-primary:#b7763a;--q-secondary:#b07927;--q-dark-page:#34291f}body[data-theme=autumn] [data-theme=autumn] .q-card--dark,body[data-theme=autumn] [data-theme=autumn] .q-stepper--dark{background:#463f33!important}body[data-theme=flamingo]{--q-primary:#ff00ff;--q-secondary:#fda3fd;--q-dark-page:#2f032f}body[data-theme=flamingo] [data-theme=flamingo] .q-card--dark,body[data-theme=flamingo] [data-theme=flamingo] .q-stepper--dark{background:#bc23bc!important}body[data-theme=monochrome]{--q-primary:#494949;--q-secondary:#6b6b6b;--q-dark-page:#000}body[data-theme=monochrome] [data-theme=monochrome] .q-card--dark,body[data-theme=monochrome] [data-theme=monochrome] .q-stepper--dark{background:#272727!important}body[data-theme=salvador]{--q-primary:#1976d2;--q-secondary:#26a69a;--q-dark-page:#253647}body[data-theme=salvador] [data-theme=salvador] .q-card--dark,body[data-theme=salvador] [data-theme=salvador] .q-stepper--dark{background:#343d47!important}body.gradient-bg{background-image:linear-gradient(to bottom right,#fff,var(--q-primary));background-attachment:fixed}body.gradient-bg.body--dark{background-image:linear-gradient(to bottom right,var(--q-dark-page),#0a0a0a);background-attachment:fixed}body.bg-image::before{content:"";position:fixed;z-index:-1;top:0;left:0;width:100%;height:100%;filter:blur(8px);background-image:var(--background);background-size:cover;background-position:center;background-repeat:no-repeat}body.bg-image .q-page-container{backdrop-filter:none}body.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark),body.body--dark .q-drawer,body.body--dark .q-header{--q-dark:rgba(29, 29, 29, 0.3);background-color:var(--q-dark);backdrop-filter:blur(6px) brightness(0.8)}body.rounded-ui .q-btn,body.rounded-ui .q-card{border-radius:10px}body[data-theme=classic].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(103,58,183,.08),rgba(156,39,176,.06))}body[data-theme=classic].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(103,58,183,.06),rgba(156,39,176,.04))}body[data-theme=classic].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(38.6192771084,42.356626506,64.7807228916),rgba(103,58,183,.07))}body[data-theme=classic].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(36.7144578313,40.2674698795,61.5855421687),rgba(103,58,183,.05))}body[data-theme=bitcoin].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(234,97,29,.08),rgba(229,111,53,.06))}body[data-theme=bitcoin].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(234,97,29,.06),rgba(229,111,53,.04))}body[data-theme=bitcoin].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(54.18,49.364,71.036),rgba(234,97,29,.07))}body[data-theme=bitcoin].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(51.885,47.273,68.027),rgba(234,97,29,.05))}body[data-theme=freedom].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(226,33,86,.08),rgba(185,26,69,.06))}body[data-theme=freedom].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(226,33,86,.06),rgba(185,26,69,.04))}body[data-theme=freedom].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(82.2051282051,55.1948717949,63.4153846154),rgba(226,33,86,.07))}body[data-theme=freedom].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(79.1538461538,53.1461538462,61.0615384615),rgba(226,33,86,.05))}body[data-theme=cyber].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(124,179,66,.08),rgba(85,139,47,.06))}body[data-theme=cyber].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(124,179,66,.06),rgba(85,139,47,.04))}body[data-theme=cyber].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(10.2,10.2,10.2),rgba(124,179,66,.07))}body[data-theme=cyber].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(7.65,7.65,7.65),rgba(124,179,66,.05))}body[data-theme=mint].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(58,183,125,.08),rgba(39,176,101,.06))}body[data-theme=mint].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(58,183,125,.06),rgba(39,176,101,.04))}body[data-theme=mint].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(38.6192771084,64.7807228916,53.5686746988),rgba(58,183,125,.07))}body[data-theme=mint].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(36.7144578313,61.5855421687,50.9265060241),rgba(58,183,125,.05))}body[data-theme=autumn].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(183,118,58,.08),rgba(176,121,39,.06))}body[data-theme=autumn].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(183,118,58,.06),rgba(176,121,39,.04))}body[data-theme=autumn].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(64.7807228916,51.0771084337,38.6192771084),rgba(183,118,58,.07))}body[data-theme=autumn].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(61.5855421687,48.5578313253,36.7144578313),rgba(183,118,58,.05))}body[data-theme=flamingo].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(255,0,255,.08),rgba(253,163,253,.06))}body[data-theme=flamingo].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(255,0,255,.06),rgba(253,163,253,.04))}body[data-theme=flamingo].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(66.176,4.224,66.176),rgba(255,0,255,.07))}body[data-theme=flamingo].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(61.382,3.918,61.382),rgba(255,0,255,.05))}body[data-theme=monochrome].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(73,73,73,.08),rgba(107,107,107,.06))}body[data-theme=monochrome].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(73,73,73,.06),rgba(107,107,107,.04))}body[data-theme=monochrome].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(10.2,10.2,10.2),rgba(73,73,73,.07))}body[data-theme=monochrome].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(7.65,7.65,7.65),rgba(73,73,73,.05))}body[data-theme=salvador].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(25,118,210,.08),rgba(38,166,154,.06))}body[data-theme=salvador].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(25,118,210,.06),rgba(38,166,154,.04))}body[data-theme=salvador].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(43.9888888889,64.2,84.4111111111),rgba(25,118,210,.07))}body[data-theme=salvador].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(42.2416666667,61.65,81.0583333333),rgba(25,118,210,.05))}body.card-shadow .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){filter:drop-shadow(0 10px 24px rgba(0, 0, 0, .18))}body.card-shadow.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){filter:drop-shadow(0 12px 28px rgba(0, 0, 0, .45))}:root{--size:100px;--gap:25px}.home .wrapper{display:flex;flex-direction:column;gap:var(--gap);margin:auto;max-width:100%}.home .marquee{display:flex;overflow:hidden;user-select:none;gap:var(--gap);height:max-content;mask-image:linear-gradient(to right,hsla(0,0%,0%,0),hsl(0,0%,0%) 20%,hsl(0,0%,0%) 80%,hsla(0,0%,0%,0))}.home .marquee__group{flex-shrink:0;display:flex;align-items:center;justify-content:space-around;gap:var(--gap);min-width:100%;animation:scroll-x 60s linear infinite}.home .marquee:hover .marquee__group{animation-play-state:paused}.home .marquee__group div{width:var(--size)}@keyframes scroll-x{from{transform:translateX(0)}to{transform:translateX(calc(-100% - var(--gap)))}}[v-cloak]{display:none}body.body--dark .q-table--dark{background:0 0}body.body--dark .q-field--error .q-field__messages,body.body--dark .q-field--error .text-negative{color:#ff0!important}.lnbits-drawer__q-list .q-item{padding-top:5px!important;padding-bottom:5px!important;border-top-right-radius:3px;border-bottom-right-radius:3px}.lnbits-drawer__q-list .q-item.q-item--active{color:inherit;font-weight:700}.lnbits__dialog-card{width:500px}.blur-and-disable{filter:blur(4px);pointer-events:none;user-select:none;opacity:.6}.lnbits__table-bordered td,.lnbits__table-bordered th{border:1px solid #000;border-collapse:collapse}.q-table--dense .q-table__bottom,.q-table--dense td:first-child,.q-table--dense th:first-child{padding-left:6px!important}.q-table--dense .q-table__bottom,.q-table--dense td:last-child,.q-table--dense th:last-child{padding-right:6px!important}a.inherit{color:inherit;text-decoration:none}video{border-radius:3px}.material-icons{font-family:"Material Icons";font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-moz-font-feature-settings:"liga";-moz-osx-font-smoothing:grayscale}.q-rating__icon{font-size:1em}.text-wrap{word-break:break-word}.q-card code{overflow-wrap:break-word}.qrcode__wrapper{position:relative;display:flex;align-items:center;justify-content:center;margin:0 auto}.qrcode__wrapper canvas{width:100%!important;height:100%!important;max-width:320px}.qrcode__image{position:absolute;max-width:52px;width:15%;overflow:hidden;background:#fff;overflow:hidden;padding:.2rem;border-radius:.2rem}.whitespace-pre-line{white-space:pre-line}.q-carousel__slide{background-size:contain;background-repeat:no-repeat}.q-dialog__inner--minimized{padding:12px}.first-install{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%}.first-install .grid{display:block}.first-install .hero-wrapper{display:none}.first-install .hero{display:block;height:100%;max-width:250px;background-image:url(/static/images/logos/lnbits.svg);background-position:center;background-size:contain;background-repeat:no-repeat}@media (min-width:992px){.first-install .grid{display:grid;grid-template-columns:1fr 1fr;grid-gap:1rem}.first-install .hero-wrapper{display:block;position:relative;height:100%;padding:1rem}}.wallet-list-card{margin-top:1px;margin-right:1rem}.wallet-list-card:first-child{margin-left:1px}@media (max-width:1024px){.wallet-card{background:0 0!important;box-shadow:none!important;border:none!important}.mobile-simple .wallet-wrapper{position:fixed!important;top:50%!important;left:50%!important;transform:translate(-50%,-50%)!important}.mobile-simple .wallet-card{width:90%!important}}.error-code{font-size:clamp(15vh, 20vw, 30vh)}.error-message{font-size:clamp(1.5rem, 3vw, 3.75rem);font-weight:300;opacity:.4} \ No newline at end of file +*,:after,:before{box-sizing:inherit;-webkit-tap-highlight-color:transparent;-moz-tap-highlight-color:transparent}#q-app,body,html{width:100%;direction:ltr}body.platform-ios.within-iframe,body.platform-ios.within-iframe #q-app{width:100px;min-width:100%}body,html{margin:0;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}img{border-style:none}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;font-family:inherit;margin:0}optgroup{font-weight:700}button,input,select{overflow:visible;text-transform:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button:-moz-focusring,input:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.q-icon{line-height:1;width:1em;height:1em;flex-shrink:0;letter-spacing:normal;text-transform:none;white-space:nowrap;word-wrap:normal;direction:ltr;text-align:center;position:relative;box-sizing:content-box;fill:currentColor}.q-icon:after,.q-icon:before{width:100%;height:100%;display:flex!important;align-items:center;justify-content:center}.q-icon>img,.q-icon>svg{width:100%;height:100%}.q-icon>div{box-sizing:border-box}.material-icons,.material-icons-outlined,.material-icons-round,.material-icons-sharp,.material-symbols-outlined,.material-symbols-rounded,.material-symbols-sharp,.q-icon{user-select:none;cursor:inherit;font-size:inherit;display:inline-flex;align-items:center;justify-content:center;vertical-align:middle}.q-panel{height:100%;width:100%}.q-panel>div{height:100%;width:100%}.q-panel-parent{overflow:hidden;position:relative}.q-loading-bar{position:fixed;z-index:9998;transition:transform .5s cubic-bezier(0, 0, .2, 1),opacity .5s;background:#f44336}.q-loading-bar--top{left:0;right:0;top:0;width:100%}.q-loading-bar--bottom{left:0;right:0;bottom:0;width:100%}.q-loading-bar--right{top:0;bottom:0;right:0;height:100%}.q-loading-bar--left{top:0;bottom:0;left:0;height:100%}.q-avatar{position:relative;vertical-align:middle;display:inline-block;border-radius:50%;font-size:48px;height:1em;width:1em}.q-avatar__content{font-size:.5em;line-height:.5em}.q-avatar img:not(.q-icon):not(.q-img__image),.q-avatar__content{border-radius:inherit;height:inherit;width:inherit}.q-avatar--square{border-radius:0}.q-badge{background-color:var(--q-primary);color:#fff;padding:2px 6px;border-radius:4px;font-size:12px;line-height:1;min-height:12px;font-weight:400;vertical-align:baseline}.q-badge--single-line{white-space:nowrap}.q-badge--multi-line{word-break:break-all;word-wrap:break-word}.q-badge--floating{position:absolute;top:-4px;right:-3px;cursor:inherit}.q-badge--transparent{opacity:.8}.q-badge--outline{background-color:transparent;border:1px solid currentColor}.q-badge--rounded{border-radius:1em}.q-banner{min-height:54px;padding:8px 16px;background:#fff}.q-banner--top-padding{padding-top:14px}.q-banner__avatar{min-width:1px!important}.q-banner__avatar>.q-avatar{font-size:46px}.q-banner__avatar>.q-icon{font-size:40px}.q-banner__avatar:not(:empty)+.q-banner__content{padding-left:16px}.q-banner__actions.col-auto{padding-left:16px}.q-banner__actions.col-all .q-btn-item{margin:4px 0 0 4px}.q-banner--dense{min-height:32px;padding:8px}.q-banner--dense.q-banner--top-padding{padding-top:12px}.q-banner--dense .q-banner__avatar>.q-avatar,.q-banner--dense .q-banner__avatar>.q-icon{font-size:28px}.q-banner--dense .q-banner__avatar:not(:empty)+.q-banner__content{padding-left:8px}.q-banner--dense .q-banner__actions.col-auto{padding-left:8px}.q-bar{background:rgba(0,0,0,.2)}.q-bar>.q-icon{margin-left:2px}.q-bar>div,.q-bar>div+.q-icon{margin-left:8px}.q-bar>.q-btn{margin-left:2px}.q-bar>.q-btn:first-child,.q-bar>.q-icon:first-child,.q-bar>div:first-child{margin-left:0}.q-bar--standard{padding:0 12px;height:32px;font-size:18px}.q-bar--standard>div{font-size:16px}.q-bar--standard .q-btn{font-size:11px}.q-bar--dense{padding:0 8px;height:24px;font-size:14px}.q-bar--dense .q-btn{font-size:8px}.q-bar--dark{background:rgba(255,255,255,.15)}.q-breadcrumbs__el{color:inherit}.q-breadcrumbs__el-icon{font-size:125%}.q-breadcrumbs__el-icon--with-label{margin-right:8px}[dir=rtl] .q-breadcrumbs__separator .q-icon{transform:scaleX(-1)}.q-btn{display:inline-flex;flex-direction:column;align-items:stretch;position:relative;outline:0;border:0;vertical-align:middle;font-size:14px;line-height:1.715em;text-decoration:none;color:inherit;background:0 0;font-weight:500;text-transform:uppercase;text-align:center;width:auto;height:auto;cursor:default;padding:4px 16px;min-height:2.572em}.q-btn .q-icon,.q-btn .q-spinner{font-size:1.715em}.q-btn.disabled{opacity:.7!important}.q-btn:before{content:"";display:block;position:absolute;left:0;right:0;top:0;bottom:0;border-radius:inherit;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-btn--actionable{cursor:pointer}.q-btn--actionable.q-btn--standard:before{transition:box-shadow .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--actionable.q-btn--standard.q-btn--active:before,.q-btn--actionable.q-btn--standard:active:before{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px rgba(0,0,0,.14),0 1px 14px rgba(0,0,0,.12)}.q-btn--no-uppercase{text-transform:none}.q-btn--rectangle{border-radius:3px}.q-btn--outline{background:0 0!important}.q-btn--outline:before{border:1px solid currentColor}.q-btn--push{border-radius:7px}.q-btn--push:before{border-bottom:3px solid rgba(0,0,0,.15)}.q-btn--push.q-btn--actionable{transition:transform .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--push.q-btn--actionable:before{transition:border-width .3s cubic-bezier(.25, .8, .5, 1)}.q-btn--push.q-btn--actionable.q-btn--active,.q-btn--push.q-btn--actionable:active{transform:translateY(2px)}.q-btn--push.q-btn--actionable.q-btn--active:before,.q-btn--push.q-btn--actionable:active:before{border-bottom-width:0}.q-btn--rounded{border-radius:28px}.q-btn--round{border-radius:50%;padding:0;min-width:3em;min-height:3em}.q-btn--square{border-radius:0}.q-btn--flat:before,.q-btn--outline:before,.q-btn--unelevated:before{box-shadow:none}.q-btn--dense{padding:.285em;min-height:2em}.q-btn--dense.q-btn--round{padding:0;min-height:2.4em;min-width:2.4em}.q-btn--dense .on-left{margin-right:6px}.q-btn--dense .on-right{margin-left:6px}.q-btn--fab .q-icon,.q-btn--fab-mini .q-icon{font-size:24px}.q-btn--fab{padding:16px;min-height:56px;min-width:56px}.q-btn--fab .q-icon{margin:auto}.q-btn--fab-mini{padding:8px;min-height:40px;min-width:40px}.q-btn__content{transition:opacity .3s;z-index:0}.q-btn__content--hidden{opacity:0;pointer-events:none}.q-btn__progress{border-radius:inherit;z-index:0}.q-btn__progress-indicator{z-index:-1;transform:translateX(-100%);background:rgba(255,255,255,.25)}.q-btn__progress--dark .q-btn__progress-indicator{background:rgba(0,0,0,.2)}.q-btn--flat .q-btn__progress-indicator,.q-btn--outline .q-btn__progress-indicator{opacity:.2;background:currentColor}.q-btn-dropdown--split .q-btn-dropdown__arrow-container{padding:0 4px}.q-btn-dropdown--split .q-btn-dropdown__arrow-container.q-btn--outline{border-left:1px solid currentColor}.q-btn-dropdown--split .q-btn-dropdown__arrow-container:not(.q-btn--outline){border-left:1px solid rgba(255,255,255,.3)}.q-btn-dropdown--simple *+.q-btn-dropdown__arrow{margin-left:8px}.q-btn-dropdown__arrow{transition:transform .28s}.q-btn-dropdown--current{flex-grow:1}.q-btn-group{border-radius:3px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);vertical-align:middle}.q-btn-group>.q-btn-item{border-radius:inherit;align-self:stretch}.q-btn-group>.q-btn-item:before{box-shadow:none}.q-btn-group>.q-btn-item .q-badge--floating{right:0}.q-btn-group>.q-btn-group{box-shadow:none}.q-btn-group>.q-btn-group:first-child>.q-btn:first-child{border-top-left-radius:inherit;border-bottom-left-radius:inherit}.q-btn-group>.q-btn-group:last-child>.q-btn:last-child{border-top-right-radius:inherit;border-bottom-right-radius:inherit}.q-btn-group>.q-btn-group:not(:first-child)>.q-btn:first-child:before{border-left:0}.q-btn-group>.q-btn-group:not(:last-child)>.q-btn:last-child:before{border-right:0}.q-btn-group>.q-btn-item:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.q-btn-group>.q-btn-item:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.q-btn-group>.q-btn-item.q-btn--standard:before{z-index:-1}.q-btn-group--push{border-radius:7px}.q-btn-group--push>.q-btn--push.q-btn--actionable{transform:none}.q-btn-group--push>.q-btn--push.q-btn--actionable .q-btn__content{transition:margin-top .3s cubic-bezier(.25, .8, .5, 1),margin-bottom .3s cubic-bezier(.25, .8, .5, 1)}.q-btn-group--push>.q-btn--push.q-btn--actionable.q-btn--active .q-btn__content,.q-btn-group--push>.q-btn--push.q-btn--actionable:active .q-btn__content{margin-top:2px;margin-bottom:-2px}.q-btn-group--rounded{border-radius:28px}.q-btn-group--square{border-radius:0}.q-btn-group--flat,.q-btn-group--outline,.q-btn-group--unelevated{box-shadow:none}.q-btn-group--outline>.q-separator{display:none}.q-btn-group--outline>.q-btn-item+.q-btn-item:before{border-left:0}.q-btn-group--outline>.q-btn-item:not(:last-child):before{border-right:0}.q-btn-group--stretch{align-self:stretch;border-radius:0}.q-btn-group--glossy>.q-btn-item{background-image:linear-gradient(to bottom,rgba(255,255,255,.3),rgba(255,255,255,0) 50%,rgba(0,0,0,.12) 51%,rgba(0,0,0,.04))!important}.q-btn-group--spread>.q-btn-group{display:flex!important}.q-btn-group--spread>.q-btn-group>.q-btn-item:not(.q-btn-dropdown__arrow-container),.q-btn-group--spread>.q-btn-item{width:auto;min-width:0;max-width:100%;flex:10000 1 0%}.q-btn-toggle{position:relative}.q-card{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;vertical-align:top;background:#fff;position:relative}.q-card>div:not(.q--avoid-card-border),.q-card>img:not(.q--avoid-card-border){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.q-card>div:nth-child(1of:not(.q--avoid-card-border)),.q-card>img:nth-child(1of:not(.q--avoid-card-border)){border-top:0;border-top-left-radius:inherit;border-top-right-radius:inherit}.q-card>div:nth-last-child(1of:not(.q--avoid-card-border)),.q-card>img:nth-last-child(1of:not(.q--avoid-card-border)){border-bottom:0;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.q-card>div:not(.q--avoid-card-border){border-left:0;border-right:0;box-shadow:none}.q-card--bordered{border:1px solid rgba(0,0,0,.12)}.q-card--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-card__section{position:relative}.q-card__section--vert{padding:16px}.q-card__section--horiz>div:not(.q--avoid-card-border),.q-card__section--horiz>img:not(.q--avoid-card-border){border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0}.q-card__section--horiz>div:nth-child(1of:not(.q--avoid-card-border)),.q-card__section--horiz>img:nth-child(1of:not(.q--avoid-card-border)){border-top-left-radius:inherit;border-bottom-left-radius:inherit}.q-card__section--horiz>div:nth-last-child(1of:not(.q--avoid-card-border)),.q-card__section--horiz>img:nth-last-child(1of:not(.q--avoid-card-border)){border-top-right-radius:inherit;border-bottom-right-radius:inherit}.q-card__section--horiz>div:not(.q--avoid-card-border){border-top:0;border-bottom:0;box-shadow:none}.q-card__actions{padding:8px;align-items:center}.q-card__actions .q-btn--rectangle{padding:0 8px}.q-card__actions--horiz>.q-btn-group+.q-btn-item,.q-card__actions--horiz>.q-btn-item+.q-btn-group,.q-card__actions--horiz>.q-btn-item+.q-btn-item{margin-left:8px}.q-card__actions--vert>.q-btn-item.q-btn--round{align-self:center}.q-card__actions--vert>.q-btn-group+.q-btn-item,.q-card__actions--vert>.q-btn-item+.q-btn-group,.q-card__actions--vert>.q-btn-item+.q-btn-item{margin-top:4px}.q-card__actions--vert>.q-btn-group>.q-btn-item{flex-grow:1}.q-card>img{display:block;width:100%;max-width:100%;border:0}.q-carousel{background-color:#fff;height:400px}.q-carousel__slide{min-height:100%;background-size:cover;background-position:50%}.q-carousel .q-carousel--padding,.q-carousel__slide{padding:16px}.q-carousel__slides-container{height:100%}.q-carousel__control{color:#fff}.q-carousel__arrow{pointer-events:none}.q-carousel__arrow .q-icon{font-size:28px}.q-carousel__arrow .q-btn{pointer-events:all}.q-carousel__next-arrow--horizontal,.q-carousel__prev-arrow--horizontal{top:16px;bottom:16px}.q-carousel__prev-arrow--horizontal{left:16px}.q-carousel__next-arrow--horizontal{right:16px}.q-carousel__next-arrow--vertical,.q-carousel__prev-arrow--vertical{left:16px;right:16px}.q-carousel__prev-arrow--vertical{top:16px}.q-carousel__next-arrow--vertical{bottom:16px}.q-carousel__navigation--bottom,.q-carousel__navigation--top{left:16px;right:16px;overflow-x:auto;overflow-y:hidden}.q-carousel__navigation--top{top:16px}.q-carousel__navigation--bottom{bottom:16px}.q-carousel__navigation--left,.q-carousel__navigation--right{top:16px;bottom:16px;overflow-x:hidden;overflow-y:auto}.q-carousel__navigation--left>.q-carousel__navigation-inner,.q-carousel__navigation--right>.q-carousel__navigation-inner{flex-direction:column}.q-carousel__navigation--left{left:16px}.q-carousel__navigation--right{right:16px}.q-carousel__navigation-inner{flex:1 1 auto}.q-carousel__navigation .q-btn{margin:6px 4px;padding:5px}.q-carousel__navigation-icon--inactive{opacity:.7}.q-carousel .q-carousel__thumbnail{margin:2px;height:50px;width:auto;display:inline-block;cursor:pointer;border:1px solid transparent;border-radius:4px;vertical-align:middle;opacity:.7;transition:opacity .3s}.q-carousel .q-carousel__thumbnail--active,.q-carousel .q-carousel__thumbnail:hover{opacity:1}.q-carousel .q-carousel__thumbnail--active{border-color:currentColor;cursor:default}.q-carousel--arrows-vertical .q-carousel--padding,.q-carousel--arrows-vertical.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-top .q-carousel--padding,.q-carousel--navigation-top.q-carousel--with-padding .q-carousel__slide{padding-top:60px}.q-carousel--arrows-vertical .q-carousel--padding,.q-carousel--arrows-vertical.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-bottom .q-carousel--padding,.q-carousel--navigation-bottom.q-carousel--with-padding .q-carousel__slide{padding-bottom:60px}.q-carousel--arrows-horizontal .q-carousel--padding,.q-carousel--arrows-horizontal.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-left .q-carousel--padding,.q-carousel--navigation-left.q-carousel--with-padding .q-carousel__slide{padding-left:60px}.q-carousel--arrows-horizontal .q-carousel--padding,.q-carousel--arrows-horizontal.q-carousel--with-padding .q-carousel__slide,.q-carousel--navigation-right .q-carousel--padding,.q-carousel--navigation-right.q-carousel--with-padding .q-carousel__slide{padding-right:60px}.q-carousel.fullscreen{height:100%}.q-message-name{font-size:small}.q-message-label{margin:24px 0;text-align:center;font-size:small}.q-message-stamp{color:inherit;margin-top:4px;opacity:.6;display:none;font-size:small}.q-message-avatar{border-radius:50%;width:48px;height:48px;min-width:48px}.q-message{margin-bottom:8px}.q-message:first-child .q-message-label{margin-top:0}.q-message-avatar--received{margin-right:8px}.q-message-text--received{color:#81c784;border-radius:4px 4px 4px 0}.q-message-text--received:last-child:before{right:100%;border-right:0 solid transparent;border-left:8px solid transparent;border-bottom:8px solid currentColor}.q-message-text-content--received{color:#000}.q-message-name--sent{text-align:right}.q-message-avatar--sent{margin-left:8px}.q-message-container--sent{flex-direction:row-reverse}.q-message-text--sent{color:#e0e0e0;border-radius:4px 4px 0 4px}.q-message-text--sent:last-child:before{left:100%;border-left:0 solid transparent;border-right:8px solid transparent;border-bottom:8px solid currentColor}.q-message-text-content--sent{color:#000}.q-message-text{background:currentColor;padding:8px;line-height:1.2;word-break:break-word;position:relative}.q-message-text+.q-message-text{margin-top:3px}.q-message-text:last-child{min-height:48px}.q-message-text:last-child .q-message-stamp{display:block}.q-message-text:last-child:before{content:"";position:absolute;bottom:0;width:0;height:0}.q-checkbox{vertical-align:middle}.q-checkbox__native{width:1px;height:1px}.q-checkbox__bg,.q-checkbox__icon-container{user-select:none}.q-checkbox__bg{top:25%;left:25%;width:50%;height:50%;border:2px solid currentColor;border-radius:2px;transition:background .22s cubic-bezier(0, 0, .2, 1) 0s;-webkit-print-color-adjust:exact}.q-checkbox__icon{color:currentColor;font-size:.5em}.q-checkbox__svg{color:#fff}.q-checkbox__truthy{stroke:currentColor;stroke-width:3.12px;stroke-dashoffset:29.78334;stroke-dasharray:29.78334}.q-checkbox__indet{fill:currentColor;transform-origin:50% 50%;transform:rotate(-280deg) scale(0)}.q-checkbox__inner{font-size:40px;width:1em;min-width:1em;height:1em;outline:0;border-radius:50%;color:rgba(0,0,0,.54)}.q-checkbox__inner--indet,.q-checkbox__inner--truthy{color:var(--q-primary)}.q-checkbox__inner--indet .q-checkbox__bg,.q-checkbox__inner--truthy .q-checkbox__bg{background:currentColor}.q-checkbox__inner--truthy path{stroke-dashoffset:0;transition:stroke-dashoffset .18s cubic-bezier(.4, 0, .6, 1) 0s}.q-checkbox__inner--indet .q-checkbox__indet{transform:rotate(0) scale(1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}.q-checkbox.disabled{opacity:.75!important}.q-checkbox--dark .q-checkbox__inner{color:rgba(255,255,255,.7)}.q-checkbox--dark .q-checkbox__inner:before{opacity:.32!important}.q-checkbox--dark .q-checkbox__inner--indet,.q-checkbox--dark .q-checkbox__inner--truthy{color:var(--q-primary)}.q-checkbox--dense .q-checkbox__inner{width:.5em;min-width:.5em;height:.5em}.q-checkbox--dense .q-checkbox__bg{left:5%;top:5%;width:90%;height:90%}.q-checkbox--dense .q-checkbox__label{padding-left:.5em}.q-checkbox--dense.reverse .q-checkbox__label{padding-left:0;padding-right:.5em}body.desktop .q-checkbox:not(.disabled) .q-checkbox__inner:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1)}body.desktop .q-checkbox:not(.disabled):focus .q-checkbox__inner:before,body.desktop .q-checkbox:not(.disabled):hover .q-checkbox__inner:before{transform:scale3d(1,1,1)}body.desktop .q-checkbox--dense:not(.disabled):focus .q-checkbox__inner:before,body.desktop .q-checkbox--dense:not(.disabled):hover .q-checkbox__inner:before{transform:scale3d(1.4,1.4,1)}.q-chip{vertical-align:middle;border-radius:16px;outline:0;position:relative;height:2em;max-width:100%;margin:4px;background:#e0e0e0;color:rgba(0,0,0,.87);font-size:14px;padding:.5em .9em}.q-chip--colored .q-chip__icon,.q-chip--dark .q-chip__icon{color:inherit}.q-chip .q-avatar{font-size:2em;margin-left:-.45em;margin-right:.2em;border-radius:16px}.q-chip--outline{background:0 0!important;border:1px solid currentColor}.q-chip--outline .q-avatar{margin-left:calc(-.45em - 1px)}.q-chip--selected .q-avatar{display:none}.q-chip__icon{color:rgba(0,0,0,.54);font-size:1.5em;margin:-.2em}.q-chip__icon--left{margin-right:.2em}.q-chip__icon--right{margin-left:.2em}.q-chip__icon--remove{margin-left:.1em;margin-right:-.5em;opacity:.6;outline:0}.q-chip__icon--remove:focus,.q-chip__icon--remove:hover{opacity:1}.q-chip__content{white-space:nowrap}.q-chip--dense{border-radius:12px;padding:0 .4em;height:1.5em}.q-chip--dense .q-avatar{font-size:1.5em;margin-left:-.27em;margin-right:.1em;border-radius:12px}.q-chip--dense .q-chip__icon{font-size:1.25em}.q-chip--dense .q-chip__icon--left{margin-right:.195em}.q-chip--dense .q-chip__icon--remove{margin-right:-.25em}.q-chip--square{border-radius:4px}.q-chip--square .q-avatar{border-radius:3px 0 0 3px}body.desktop .q-chip--clickable:focus{box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}body.desktop.body--dark .q-chip--clickable:focus{box-shadow:0 1px 3px rgba(255,255,255,.2),0 1px 1px rgba(255,255,255,.14),0 2px 1px -1px rgba(255,255,255,.12)}.q-circular-progress{display:inline-block;position:relative;vertical-align:middle;width:1em;height:1em;line-height:1}.q-circular-progress.q-focusable{border-radius:50%}.q-circular-progress__svg{width:100%;height:100%}.q-circular-progress__text{font-size:.25em}.q-circular-progress--indeterminate .q-circular-progress__svg{transform-origin:50% 50%;animation:q-spin 2s linear infinite}.q-circular-progress--indeterminate .q-circular-progress__circle{stroke-dasharray:1 400;stroke-dashoffset:0;animation:q-circular-progress-circle 1.5s ease-in-out infinite}@keyframes q-circular-progress-circle{0%{stroke-dasharray:1,400;stroke-dashoffset:0}50%{stroke-dasharray:400,400;stroke-dashoffset:-100}100%{stroke-dasharray:400,400;stroke-dashoffset:-300}}.q-color-picker{overflow:hidden;background:#fff;max-width:350px;vertical-align:top;min-width:180px;border-radius:4px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-color-picker .q-tab{padding:0!important}.q-color-picker--bordered{border:1px solid rgba(0,0,0,.12)}.q-color-picker__header-tabs{height:32px}.q-color-picker__header-banner{height:36px}.q-color-picker__header input{line-height:24px;border:0}.q-color-picker__header .q-tab{min-height:32px!important;height:32px!important}.q-color-picker__header .q-tab--inactive{background:linear-gradient(to top,rgba(0,0,0,.3) 0,rgba(0,0,0,.15) 25%,rgba(0,0,0,.1))}.q-color-picker__error-icon{bottom:2px;right:2px;font-size:24px;opacity:0;transition:opacity .3s ease-in}.q-color-picker__header-content{position:relative;background:#fff}.q-color-picker__header-content--light{color:#000}.q-color-picker__header-content--dark{color:#fff}.q-color-picker__header-content--dark .q-tab--inactive:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;background:rgba(255,255,255,.2)}.q-color-picker__header-banner{height:36px}.q-color-picker__header-bg{background:#fff;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAH0lEQVQoU2NkYGAwZkAFZ5G5jPRRgOYEVDeB3EBjBQBOZwTVugIGyAAAAABJRU5ErkJggg==")!important}.q-color-picker__footer{height:36px}.q-color-picker__footer .q-tab{min-height:36px!important;height:36px!important}.q-color-picker__footer .q-tab--inactive{background:linear-gradient(to bottom,rgba(0,0,0,.3) 0,rgba(0,0,0,.15) 25%,rgba(0,0,0,.1))}.q-color-picker__spectrum{width:100%;height:100%}.q-color-picker__spectrum-tab{padding:0!important}.q-color-picker__spectrum-white{background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.q-color-picker__spectrum-black{background:linear-gradient(to top,#000,rgba(0,0,0,0))}.q-color-picker__spectrum-circle{width:10px;height:10px;box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;transform:translate(-5px,-5px)}.q-color-picker__hue .q-slider__track{background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)!important;opacity:1}.q-color-picker__alpha .q-slider__track-container{padding-top:0}.q-color-picker__alpha .q-slider__track:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:linear-gradient(90deg,rgba(255,255,255,0),#757575)}.q-color-picker__sliders{padding:0 16px}.q-color-picker__sliders .q-slider__thumb{color:#424242}.q-color-picker__sliders .q-slider__thumb path{stroke-width:2px;fill:transparent}.q-color-picker__sliders .q-slider--active path{stroke-width:3px}.q-color-picker__tune-tab .q-slider{margin-left:18px;margin-right:18px}.q-color-picker__tune-tab input{font-size:11px;border:1px solid #e0e0e0;border-radius:4px;width:3.5em}.q-color-picker__palette-tab{padding:0!important}.q-color-picker__palette-rows--editable .q-color-picker__cube{cursor:pointer}.q-color-picker__cube{padding-bottom:10%;width:10%!important}.q-color-picker input{color:inherit;background:0 0;outline:0;text-align:center}.q-color-picker .q-tabs{overflow:hidden}.q-color-picker .q-tab--active{box-shadow:0 0 14px 3px rgba(0,0,0,.2)}.q-color-picker .q-tab--active .q-focus-helper{display:none}.q-color-picker .q-tab__indicator{display:none}.q-color-picker .q-tab-panels{background:inherit}.q-color-picker--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-color-picker--dark .q-color-picker__tune-tab input{border:1px solid rgba(255,255,255,.3)}.q-color-picker--dark .q-slider__thumb{color:#fafafa}.q-date{display:inline-flex;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff;width:290px;min-width:290px;max-width:100%}.q-date--bordered{border:1px solid rgba(0,0,0,.12)}.q-date__header{border-top-left-radius:inherit;color:#fff;background-color:var(--q-primary);padding:16px}.q-date__actions{padding:0 16px 16px}.q-date__content,.q-date__main{outline:0}.q-date__content .q-btn{font-weight:400}.q-date__header-link{opacity:.64;outline:0;transition:opacity .3s ease-out}.q-date__header-link--active,.q-date__header-link:focus,.q-date__header-link:hover{opacity:1}.q-date__header-subtitle{font-size:14px;line-height:1.75;letter-spacing:.00938em}.q-date__header-title-label{font-size:24px;line-height:1.2;letter-spacing:.00735em}.q-date__view{height:100%;width:100%;min-height:290px;padding:16px}.q-date__navigation{height:12.5%}.q-date__navigation>div:first-child{width:8%;min-width:24px;justify-content:flex-end}.q-date__navigation>div:last-child{width:8%;min-width:24px;justify-content:flex-start}.q-date__calendar-weekdays{height:12.5%}.q-date__calendar-weekdays>div{opacity:.38;font-size:12px}.q-date__calendar-item{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;width:14.285%!important;height:12.5%!important;position:relative;padding:1px}.q-date__calendar-item:after{content:"";position:absolute;pointer-events:none;top:1px;right:0;bottom:1px;left:0;border-style:dashed;border-color:transparent;border-width:1px}.q-date__calendar-item button,.q-date__calendar-item>div{width:30px;height:30px;border-radius:50%}.q-date__calendar-item>div{line-height:30px;text-align:center}.q-date__calendar-item>button{line-height:22px}.q-date__calendar-item--out{opacity:.18}.q-date__calendar-item--fill{visibility:hidden}.q-date__range-from:before,.q-date__range-to:before,.q-date__range:before{content:"";background-color:currentColor;position:absolute;top:1px;bottom:1px;left:0;right:0;opacity:.3}.q-date__range-from:nth-child(7n-6):before,.q-date__range-to:nth-child(7n-6):before,.q-date__range:nth-child(7n-6):before{border-top-left-radius:0;border-bottom-left-radius:0}.q-date__range-from:nth-child(7n):before,.q-date__range-to:nth-child(7n):before,.q-date__range:nth-child(7n):before{border-top-right-radius:0;border-bottom-right-radius:0}.q-date__range-from:before{left:50%}.q-date__range-to:before{right:50%}.q-date__edit-range:after{border-color:currentColor transparent}.q-date__edit-range:nth-child(7n-6):after{border-top-left-radius:0;border-bottom-left-radius:0}.q-date__edit-range:nth-child(7n):after{border-top-right-radius:0;border-bottom-right-radius:0}.q-date__edit-range-from-to:after,.q-date__edit-range-from:after{left:4px;border-left-color:currentColor;border-top-color:currentColor;border-bottom-color:currentColor;border-top-left-radius:28px;border-bottom-left-radius:28px}.q-date__edit-range-from-to:after,.q-date__edit-range-to:after{right:4px;border-right-color:currentColor;border-top-color:currentColor;border-bottom-color:currentColor;border-top-right-radius:28px;border-bottom-right-radius:28px}.q-date__calendar-days-container{height:75%;min-height:192px}.q-date__calendar-days>div{height:16.66%!important}.q-date__event{position:absolute;bottom:2px;left:50%;height:5px;width:8px;border-radius:5px;background-color:var(--q-secondary);transform:translate3d(-50%,0,0)}.q-date__today{box-shadow:0 0 1px 0 currentColor}.q-date__years-content{padding:0 8px}.q-date__months-item,.q-date__years-item{flex:0 0 33.3333%}.q-date--readonly .q-date__content,.q-date--readonly .q-date__header,.q-date.disabled .q-date__content,.q-date.disabled .q-date__header{pointer-events:none}.q-date--readonly .q-date__navigation{display:none}.q-date--portrait{flex-direction:column}.q-date--portrait-standard .q-date__content{height:calc(100% - 86px)}.q-date--portrait-standard .q-date__header{border-top-right-radius:inherit;height:86px}.q-date--portrait-standard .q-date__header-title{align-items:center;height:30px}.q-date--portrait-minimal .q-date__content{height:100%}.q-date--landscape{flex-direction:row;align-items:stretch;min-width:420px}.q-date--landscape>div{display:flex;flex-direction:column}.q-date--landscape .q-date__content{height:100%}.q-date--landscape-standard{min-width:420px}.q-date--landscape-standard .q-date__header{border-bottom-left-radius:inherit;min-width:110px;width:110px}.q-date--landscape-standard .q-date__header-title{flex-direction:column}.q-date--landscape-standard .q-date__header-today{margin-top:12px;margin-left:-8px}.q-date--landscape-minimal{width:310px}.q-date--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12);border-color:rgba(255,255,255,.28)}.q-dialog__title{font-size:1.25rem;font-weight:500;line-height:1.6;letter-spacing:.0125em}.q-dialog__progress{font-size:4rem}.q-dialog__inner{outline:0}.q-dialog__inner>div{pointer-events:all;overflow:auto;-webkit-overflow-scrolling:touch;will-change:scroll-position;border-radius:4px}.q-dialog__inner--square>div{border-radius:0!important}.q-dialog__inner>.q-card>.q-card__actions .q-btn--rectangle{min-width:64px}.q-dialog__inner--minimized{padding:24px}.q-dialog__inner--minimized>div{max-height:calc(100vh - 48px)}.q-dialog__inner--maximized>div{height:100%;width:100%;max-height:100vh;max-width:100vw;border-radius:0!important;top:0!important;left:0!important}.q-dialog__inner--bottom,.q-dialog__inner--top{padding-top:0!important;padding-bottom:0!important}.q-dialog__inner--left,.q-dialog__inner--right{padding-right:0!important;padding-left:0!important}.q-dialog__inner--left:not(.q-dialog__inner--animating)>div,.q-dialog__inner--top:not(.q-dialog__inner--animating)>div{border-top-left-radius:0}.q-dialog__inner--right:not(.q-dialog__inner--animating)>div,.q-dialog__inner--top:not(.q-dialog__inner--animating)>div{border-top-right-radius:0}.q-dialog__inner--bottom:not(.q-dialog__inner--animating)>div,.q-dialog__inner--left:not(.q-dialog__inner--animating)>div{border-bottom-left-radius:0}.q-dialog__inner--bottom:not(.q-dialog__inner--animating)>div,.q-dialog__inner--right:not(.q-dialog__inner--animating)>div{border-bottom-right-radius:0}.q-dialog__inner--fullwidth>div{width:100%!important;max-width:100%!important}.q-dialog__inner--fullheight>div{height:100%!important;max-height:100%!important}.q-dialog__backdrop{z-index:-1;pointer-events:all;outline:0;background:rgba(0,0,0,.4)}body.platform-android:not(.native-mobile) .q-dialog__inner--minimized>div,body.platform-ios .q-dialog__inner--minimized>div{max-height:calc(100vh - 108px)}body.q-ios-padding .q-dialog__inner{padding-top:20px!important;padding-top:env(safe-area-inset-top)!important;padding-bottom:env(safe-area-inset-bottom)!important}body.q-ios-padding .q-dialog__inner>div{max-height:calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom))!important}@media (max-width:599.98px){.q-dialog__inner--bottom,.q-dialog__inner--top{padding-left:0;padding-right:0}.q-dialog__inner--bottom>div,.q-dialog__inner--top>div{width:100%!important}}@media (min-width:600px){.q-dialog__inner--minimized>div{max-width:560px}}.q-body--dialog{overflow:hidden}.q-editor{border:1px solid rgba(0,0,0,.12);border-radius:4px;background-color:#fff}.q-editor.disabled{border-style:dashed}.q-editor>div:first-child,.q-editor__toolbars-container,.q-editor__toolbars-container>div:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-editor__content{outline:0;padding:10px;min-height:10em;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;overflow:auto;max-width:100%}.q-editor__content pre{white-space:pre-wrap}.q-editor__content hr{border:0;outline:0;margin:1px;height:1px;background:rgba(0,0,0,.12)}.q-editor__content:empty:not(:focus):before{content:attr(placeholder);opacity:.7}.q-editor__toolbar{border-bottom:1px solid rgba(0,0,0,.12);min-height:32px}.q-editor__toolbars-container{max-width:100%}.q-editor .q-btn{margin:4px}.q-editor__toolbar-group{position:relative;margin:0 4px}.q-editor__toolbar-group+.q-editor__toolbar-group:before{content:"";position:absolute;left:-4px;top:4px;bottom:4px;width:1px;background:rgba(0,0,0,.12)}.q-editor__link-input{color:inherit;text-decoration:none;text-transform:none;border:none;border-radius:0;background:0 0;outline:0}.q-editor--flat,.q-editor--flat .q-editor__toolbar{border:0}.q-editor--dense .q-editor__toolbar-group{display:flex;align-items:center;flex-wrap:nowrap}.q-editor--dark{border-color:rgba(255,255,255,.28)}.q-editor--dark .q-editor__content hr{background:rgba(255,255,255,.28)}.q-editor--dark .q-editor__toolbar{border-color:rgba(255,255,255,.28)}.q-editor--dark .q-editor__toolbar-group+.q-editor__toolbar-group:before{background:rgba(255,255,255,.28)}.q-expansion-item__border{opacity:0}.q-expansion-item__toggle-icon{position:relative;transition:transform .3s}.q-expansion-item__toggle-icon--rotated{transform:rotate(180deg)}.q-expansion-item__toggle-focus{width:1em!important;height:1em!important;position:relative!important}.q-expansion-item__toggle-focus+.q-expansion-item__toggle-icon{margin-top:-1em}.q-expansion-item--standard.q-expansion-item--expanded>div>.q-expansion-item__border{opacity:1}.q-expansion-item--popup{transition:padding .5s}.q-expansion-item--popup>.q-expansion-item__container{border:1px solid rgba(0,0,0,.12)}.q-expansion-item--popup>.q-expansion-item__container>.q-separator{display:none}.q-expansion-item--popup.q-expansion-item--collapsed{padding:0 15px}.q-expansion-item--popup.q-expansion-item--expanded{padding:15px 0}.q-expansion-item--popup.q-expansion-item--expanded+.q-expansion-item--popup.q-expansion-item--expanded{padding-top:0}.q-expansion-item--popup.q-expansion-item--collapsed:not(:first-child)>.q-expansion-item__container{border-top-width:0}.q-expansion-item--popup.q-expansion-item--expanded+.q-expansion-item--popup.q-expansion-item--collapsed>.q-expansion-item__container{border-top-width:1px}.q-expansion-item__content>.q-card{box-shadow:none;border-radius:0}.q-expansion-item:first-child>div>.q-expansion-item__border--top{opacity:0}.q-expansion-item:last-child>div>.q-expansion-item__border--bottom{opacity:0}.q-expansion-item--expanded+.q-expansion-item--expanded>div>.q-expansion-item__border--top{opacity:0}.q-expansion-item--expanded .q-textarea--autogrow textarea{animation:q-expansion-done 0s}@keyframes q-expansion-done{0%{--q-exp-done:1}}.z-fab{z-index:990}.q-fab{position:relative;vertical-align:middle}.q-fab>.q-btn{width:100%}.q-fab--form-rounded{border-radius:28px}.q-fab--form-square{border-radius:4px}.q-fab__active-icon,.q-fab__icon{transition:opacity .4s,transform .4s}.q-fab__icon{opacity:1;transform:rotate(0)}.q-fab__active-icon{opacity:0;transform:rotate(-180deg)}.q-fab__label--external{position:absolute;padding:0 8px;transition:opacity .18s cubic-bezier(.65, .815, .735, .395)}.q-fab__label--external-hidden{opacity:0;pointer-events:none}.q-fab__label--external-left{top:50%;left:-12px;transform:translate(-100%,-50%)}.q-fab__label--external-right{top:50%;right:-12px;transform:translate(100%,-50%)}.q-fab__label--external-bottom{bottom:-12px;left:50%;transform:translate(-50%,100%)}.q-fab__label--external-top{top:-12px;left:50%;transform:translate(-50%,-100%)}.q-fab__label--internal{padding:0;transition:font-size .12s cubic-bezier(.65, .815, .735, .395),max-height .12s cubic-bezier(.65, .815, .735, .395),opacity 70ms cubic-bezier(.65, .815, .735, .395);max-height:30px}.q-fab__label--internal-hidden{font-size:0;opacity:0}.q-fab__label--internal-top{padding-bottom:.12em}.q-fab__label--internal-bottom{padding-top:.12em}.q-fab__label--internal-bottom.q-fab__label--internal-hidden,.q-fab__label--internal-top.q-fab__label--internal-hidden{max-height:0}.q-fab__label--internal-left{padding-left:.285em;padding-right:.571em}.q-fab__label--internal-right{padding-right:.285em;padding-left:.571em}.q-fab__icon-holder{min-width:24px;min-height:24px;position:relative}.q-fab__icon-holder--opened .q-fab__icon{transform:rotate(180deg);opacity:0}.q-fab__icon-holder--opened .q-fab__active-icon{transform:rotate(0);opacity:1}.q-fab__actions{position:absolute;opacity:0;transition:transform .18s ease-in,opacity .18s ease-in;pointer-events:none;align-items:center;justify-content:center;align-self:center;padding:3px}.q-fab__actions .q-btn{margin:5px}.q-fab__actions--right{transform-origin:0 50%;transform:scale(.4) translateX(-62px);height:56px;left:100%;margin-left:9px}.q-fab__actions--left{transform-origin:100% 50%;transform:scale(.4) translateX(62px);height:56px;right:100%;margin-right:9px;flex-direction:row-reverse}.q-fab__actions--up{transform-origin:50% 100%;transform:scale(.4) translateY(62px);width:56px;bottom:100%;margin-bottom:9px;flex-direction:column-reverse}.q-fab__actions--down{transform-origin:50% 0;transform:scale(.4) translateY(-62px);width:56px;top:100%;margin-top:9px;flex-direction:column}.q-fab__actions--down,.q-fab__actions--up{left:50%;margin-left:-28px}.q-fab__actions--opened{opacity:1;transform:scale(1) translate(.1px,0);pointer-events:all}.q-fab--align-left>.q-fab__actions--down,.q-fab--align-left>.q-fab__actions--up{align-items:flex-start;left:28px}.q-fab--align-right>.q-fab__actions--down,.q-fab--align-right>.q-fab__actions--up{align-items:flex-end;left:auto;right:0}.q-field{font-size:14px}.q-field ::-ms-clear,.q-field ::-ms-reveal{display:none}.q-field--with-bottom{padding-bottom:20px}.q-field__marginal{height:56px;color:rgba(0,0,0,.54);font-size:24px}.q-field__marginal>*+*{margin-left:2px}.q-field__marginal .q-avatar{font-size:32px}.q-field__before,.q-field__prepend{padding-right:12px}.q-field__after,.q-field__append{padding-left:12px}.q-field__after:empty,.q-field__append:empty{display:none}.q-field__append+.q-field__append{padding-left:2px}.q-field__inner{text-align:left}.q-field__bottom{font-size:12px;min-height:20px;line-height:1;color:rgba(0,0,0,.54);padding:8px 12px 0;backface-visibility:hidden}.q-field__bottom--animated{transform:translateY(100%);position:absolute;left:0;right:0;bottom:0}.q-field__messages{line-height:1}.q-field__messages>div{word-break:break-word;word-wrap:break-word;overflow-wrap:break-word}.q-field__messages>div+div{margin-top:4px}.q-field__counter{padding-left:8px;line-height:1}.q-field--item-aligned{padding:8px 16px}.q-field--item-aligned .q-field__before{min-width:56px}.q-field__control-container{height:inherit}.q-field__control{color:var(--q-primary);height:56px;max-width:100%;outline:0}.q-field__control:after,.q-field__control:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.q-field__control:before{border-radius:inherit}.q-field__shadow{top:8px;opacity:0;overflow:hidden;white-space:pre-wrap;transition:opacity .36s cubic-bezier(.4, 0, .2, 1)}.q-field__shadow+.q-field__native::placeholder{transition:opacity .36s cubic-bezier(.4, 0, .2, 1)}.q-field__shadow+.q-field__native:focus::placeholder{opacity:0}.q-field__input,.q-field__native,.q-field__prefix,.q-field__suffix{font-weight:400;line-height:28px;letter-spacing:.00937em;text-decoration:inherit;text-transform:inherit;border:none;border-radius:0;background:0 0;color:rgba(0,0,0,.87);outline:0;padding:6px 0}.q-field__input,.q-field__native{width:100%;min-width:0;outline:0!important;user-select:auto}.q-field__input:-webkit-autofill,.q-field__native:-webkit-autofill{-webkit-animation-name:q-autofill;-webkit-animation-fill-mode:both}.q-field__input:invalid,.q-field__native:invalid{box-shadow:none}.q-field__native[type=file]{line-height:1em}.q-field__input{padding:0;height:0;min-height:24px;line-height:24px}.q-field__prefix,.q-field__suffix{transition:opacity .36s cubic-bezier(.4, 0, .2, 1);white-space:nowrap}.q-field__prefix{padding-right:4px}.q-field__suffix{padding-left:4px}.q-field--disabled .q-placeholder,.q-field--readonly .q-placeholder{opacity:1!important}.q-field--readonly.q-field--labeled .q-field__input,.q-field--readonly.q-field--labeled .q-field__native{cursor:default}.q-field--readonly.q-field--float .q-field__input,.q-field--readonly.q-field--float .q-field__native{cursor:text}.q-field--disabled .q-field__inner{cursor:not-allowed}.q-field--disabled .q-field__control{pointer-events:none}.q-field--disabled .q-field__control>div{opacity:.6!important}.q-field--disabled .q-field__control>div,.q-field--disabled .q-field__control>div *{outline:0!important}.q-field__label{left:0;top:18px;max-width:100%;color:rgba(0,0,0,.6);font-size:16px;line-height:1.25;font-weight:400;letter-spacing:.00937em;text-decoration:inherit;text-transform:inherit;transform-origin:left top;transition:transform .36s cubic-bezier(.4, 0, .2, 1),max-width 324ms cubic-bezier(.4, 0, .2, 1);backface-visibility:hidden}.q-field__label:has(+ :is(.q-field__native,.q-field__input):is(:-webkit-autofill,[type=color],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])){transform:translateY(-40%) scale(.75)}.q-field--float .q-field__label{max-width:133%;transform:translateY(-40%) scale(.75);transition:transform .36s cubic-bezier(.4, 0, .2, 1),max-width 396ms cubic-bezier(.4, 0, .2, 1)}.q-field--highlighted .q-field__label{color:currentColor}.q-field--highlighted .q-field__shadow{opacity:.5}.q-field--filled .q-field__control{padding:0 12px;background:rgba(0,0,0,.05);border-radius:4px 4px 0 0}.q-field--filled .q-field__control:before{background:rgba(0,0,0,.05);border-bottom:1px solid rgba(0,0,0,.42);opacity:0;transition:opacity .36s cubic-bezier(.4, 0, .2, 1),background .36s cubic-bezier(.4, 0, .2, 1)}.q-field--filled .q-field__control:hover:before{opacity:1}.q-field--filled .q-field__control:after{height:2px;top:auto;transform-origin:center bottom;transform:scale3d(0,1,1);background:currentColor;transition:transform .36s cubic-bezier(.4, 0, .2, 1)}.q-field--filled.q-field--rounded .q-field__control{border-radius:28px 28px 0 0}.q-field--filled.q-field--highlighted .q-field__control:before{opacity:1;background:rgba(0,0,0,.12)}.q-field--filled.q-field--highlighted .q-field__control:after{transform:scale3d(1,1,1)}.q-field--filled.q-field--dark .q-field__control,.q-field--filled.q-field--dark .q-field__control:before{background:rgba(255,255,255,.07)}.q-field--filled.q-field--dark.q-field--highlighted .q-field__control:before{background:rgba(255,255,255,.1)}.q-field--filled.q-field--readonly .q-field__control:before{opacity:1;background:0 0;border-bottom-style:dashed}.q-field--outlined .q-field__control{border-radius:4px;padding:0 12px}.q-field--outlined .q-field__control:before{border:1px solid rgba(0,0,0,.24);transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--outlined .q-field__control:hover:before{border-color:#000}.q-field--outlined .q-field__control:after{height:inherit;border-radius:inherit;border:2px solid transparent;transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--outlined .q-field__input:-webkit-autofill,.q-field--outlined .q-field__native:-webkit-autofill{margin-top:1px;margin-bottom:1px}.q-field--outlined.q-field--rounded .q-field__control{border-radius:28px}.q-field--outlined.q-field--highlighted .q-field__control:hover:before{border-color:transparent}.q-field--outlined.q-field--highlighted .q-field__control:after{border-color:currentColor;border-width:2px;transform:scale3d(1,1,1)}.q-field--outlined.q-field--readonly .q-field__control:before{border-style:dashed}.q-field--standard .q-field__control:before{border-bottom:1px solid rgba(0,0,0,.24);transition:border-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standard .q-field__control:hover:before{border-color:#000}.q-field--standard .q-field__control:after{height:2px;top:auto;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;transform-origin:center bottom;transform:scale3d(0,1,1);background:currentColor;transition:transform .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standard.q-field--highlighted .q-field__control:after{transform:scale3d(1,1,1)}.q-field--standard.q-field--readonly .q-field__control:before{border-bottom-style:dashed}.q-field--dark .q-field__control:before{border-color:rgba(255,255,255,.6)}.q-field--dark .q-field__control:hover:before{border-color:#fff}.q-field--dark .q-field__input,.q-field--dark .q-field__native,.q-field--dark .q-field__prefix,.q-field--dark .q-field__suffix{color:#fff}.q-field--dark .q-field__bottom,.q-field--dark .q-field__marginal,.q-field--dark:not(.q-field--highlighted) .q-field__label{color:rgba(255,255,255,.7)}.q-field--standout .q-field__control{padding:0 12px;background:rgba(0,0,0,.05);border-radius:4px;transition:box-shadow .36s cubic-bezier(.4, 0, .2, 1),background-color .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standout .q-field__control:before{background:rgba(0,0,0,.07);opacity:0;transition:opacity .36s cubic-bezier(.4, 0, .2, 1),background .36s cubic-bezier(.4, 0, .2, 1)}.q-field--standout .q-field__control:hover:before{opacity:1}.q-field--standout.q-field--rounded .q-field__control{border-radius:28px}.q-field--standout.q-field--highlighted .q-field__control{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);background:#000}.q-field--standout.q-field--highlighted .q-field__append,.q-field--standout.q-field--highlighted .q-field__input,.q-field--standout.q-field--highlighted .q-field__native,.q-field--standout.q-field--highlighted .q-field__prefix,.q-field--standout.q-field--highlighted .q-field__prepend,.q-field--standout.q-field--highlighted .q-field__suffix{color:#fff}.q-field--standout.q-field--readonly .q-field__control:before{opacity:1;background:0 0;border:1px dashed rgba(0,0,0,.24)}.q-field--standout.q-field--dark .q-field__control{background:rgba(255,255,255,.07)}.q-field--standout.q-field--dark .q-field__control:before{background:rgba(255,255,255,.07)}.q-field--standout.q-field--dark.q-field--highlighted .q-field__control{background:#fff}.q-field--standout.q-field--dark.q-field--highlighted .q-field__append,.q-field--standout.q-field--dark.q-field--highlighted .q-field__input,.q-field--standout.q-field--dark.q-field--highlighted .q-field__native,.q-field--standout.q-field--dark.q-field--highlighted .q-field__prefix,.q-field--standout.q-field--dark.q-field--highlighted .q-field__prepend,.q-field--standout.q-field--dark.q-field--highlighted .q-field__suffix{color:#000}.q-field--standout.q-field--dark.q-field--readonly .q-field__control:before{border-color:rgba(255,255,255,.24)}.q-field--labeled .q-field__native,.q-field--labeled .q-field__prefix,.q-field--labeled .q-field__suffix{line-height:24px;padding-top:24px;padding-bottom:8px}.q-field--labeled .q-field__shadow{top:0}.q-field--labeled:not(.q-field--float) .q-field__prefix,.q-field--labeled:not(.q-field--float) .q-field__suffix{opacity:0}.q-field--labeled:not(.q-field--float) .q-field__input::placeholder,.q-field--labeled:not(.q-field--float) .q-field__native::placeholder{color:transparent}.q-field--labeled.q-field--dense .q-field__native,.q-field--labeled.q-field--dense .q-field__prefix,.q-field--labeled.q-field--dense .q-field__suffix{padding-top:14px;padding-bottom:2px}.q-field--dense .q-field--with-bottom{padding-bottom:19px}.q-field--dense .q-field__shadow{top:0}.q-field--dense .q-field__control,.q-field--dense .q-field__marginal{height:40px}.q-field--dense .q-field__bottom{font-size:11px}.q-field--dense .q-field__label{font-size:14px;top:10px}.q-field--dense .q-field__before,.q-field--dense .q-field__prepend{padding-right:6px}.q-field--dense .q-field__after,.q-field--dense .q-field__append{padding-left:6px}.q-field--dense .q-field__append+.q-field__append{padding-left:2px}.q-field--dense .q-field__marginal .q-avatar{font-size:24px}.q-field--dense.q-field--float .q-field__label{transform:translateY(-30%) scale(.75)}.q-field--dense .q-field__label:has(+ :is(.q-field__native,.q-field__input):is(:-webkit-autofill,[type=color],[type=date],[type=datetime-local],[type=month],[type=time],[type=week])){transform:translateY(-30%) scale(.75)}.q-field--borderless .q-field__bottom,.q-field--borderless.q-field--dense .q-field__control,.q-field--standard .q-field__bottom,.q-field--standard.q-field--dense .q-field__control{padding-left:0;padding-right:0}.q-field--error .q-field__label{animation:q-field-label .36s}.q-field--error .q-field__bottom{color:var(--q-negative)}.q-field__focusable-action{opacity:.6;cursor:pointer;outline:0!important;border:0;color:inherit;background:0 0;padding:0}.q-field__focusable-action:focus,.q-field__focusable-action:hover{opacity:1}.q-field--auto-height .q-field__control{height:auto}.q-field--auto-height .q-field__control,.q-field--auto-height .q-field__native{min-height:56px}.q-field--auto-height .q-field__native{align-items:center}.q-field--auto-height .q-field__control-container{padding-top:0}.q-field--auto-height .q-field__native,.q-field--auto-height .q-field__prefix,.q-field--auto-height .q-field__suffix{line-height:18px}.q-field--auto-height.q-field--labeled .q-field__control-container{padding-top:24px}.q-field--auto-height.q-field--labeled .q-field__shadow{top:24px}.q-field--auto-height.q-field--labeled .q-field__native,.q-field--auto-height.q-field--labeled .q-field__prefix,.q-field--auto-height.q-field--labeled .q-field__suffix{padding-top:0}.q-field--auto-height.q-field--labeled .q-field__native{min-height:24px}.q-field--auto-height.q-field--dense .q-field__control,.q-field--auto-height.q-field--dense .q-field__native{min-height:40px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__control-container{padding-top:14px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__shadow{top:14px}.q-field--auto-height.q-field--dense.q-field--labeled .q-field__native{min-height:24px}.q-field--square .q-field__control{border-radius:0!important}.q-transition--field-message-enter-active,.q-transition--field-message-leave-active{transition:transform .6s cubic-bezier(.86, 0, .07, 1),opacity .6s cubic-bezier(.86, 0, .07, 1)}.q-transition--field-message-enter-from,.q-transition--field-message-leave-to{opacity:0;transform:translateY(-10px)}.q-transition--field-message-leave-active,.q-transition--field-message-leave-from{position:absolute}@keyframes q-field-label{40%{margin-left:2px}60%,80%{margin-left:-2px}70%,90%{margin-left:2px}}@keyframes q-autofill{to{background:0 0;color:inherit}}.q-file .q-field__native{word-break:break-all;overflow:hidden}.q-file .q-field__input{opacity:0!important}.q-file .q-field__input::-webkit-file-upload-button{cursor:pointer}.q-file__filler{visibility:hidden;width:100%;border:none;padding:0}.q-file__dnd{outline:1px dashed currentColor;outline-offset:-4px}.q-form{position:relative}.q-img{position:relative;width:100%;display:inline-block;vertical-align:middle;overflow:hidden}.q-img__loading .q-spinner{font-size:50px}.q-img__container{border-radius:inherit;font-size:0}.q-img__image{border-radius:inherit;width:100%;height:100%;opacity:0}.q-img__image--with-transition{transition:opacity .28s ease-in}.q-img__image--loaded{opacity:1}.q-img__content{border-radius:inherit;pointer-events:none}.q-img__content>div{pointer-events:all;position:absolute;padding:16px;color:#fff;background:rgba(0,0,0,.47)}.q-img--no-menu .q-img__image,.q-img--no-menu .q-img__placeholder{pointer-events:none}.q-inner-loading{background:rgba(255,255,255,.6);border-radius:inherit}.q-inner-loading--dark{background:rgba(0,0,0,.4)}.q-inner-loading__label{margin-top:8px}.q-textarea .q-field__control{min-height:56px;height:auto}.q-textarea .q-field__control-container{padding-top:2px;padding-bottom:2px}.q-textarea .q-field__shadow{top:2px;bottom:2px}.q-textarea .q-field__native,.q-textarea .q-field__prefix,.q-textarea .q-field__suffix{line-height:18px}.q-textarea .q-field__native{resize:vertical;padding-top:17px;min-height:52px}.q-textarea.q-field--labeled .q-field__control-container{padding-top:26px}.q-textarea.q-field--labeled .q-field__shadow{top:26px}.q-textarea.q-field--labeled .q-field__native,.q-textarea.q-field--labeled .q-field__prefix,.q-textarea.q-field--labeled .q-field__suffix{padding-top:0}.q-textarea.q-field--labeled .q-field__native{min-height:26px;padding-top:1px}.q-textarea--autogrow .q-field__native{resize:none}.q-textarea.q-field--dense .q-field__control,.q-textarea.q-field--dense .q-field__native{min-height:36px}.q-textarea.q-field--dense .q-field__native{padding-top:9px}.q-textarea.q-field--dense.q-field--labeled .q-field__control-container{padding-top:14px}.q-textarea.q-field--dense.q-field--labeled .q-field__shadow{top:14px}.q-textarea.q-field--dense.q-field--labeled .q-field__native{min-height:24px;padding-top:3px}.q-textarea.q-field--dense.q-field--labeled .q-field__prefix,.q-textarea.q-field--dense.q-field--labeled .q-field__suffix{padding-top:2px}.q-textarea.disabled .q-field__native,body.mobile .q-textarea .q-field__native{resize:none}.q-intersection{position:relative}.q-item{min-height:48px;padding:8px 16px;color:inherit;transition:color .3s,background-color .3s}.q-item__section--side{color:#757575;align-items:flex-start;padding-right:16px;width:auto;min-width:0;max-width:100%}.q-item__section--side>.q-icon{font-size:24px}.q-item__section--side>.q-avatar{font-size:40px}.q-item__section--avatar{color:inherit;min-width:56px}.q-item__section--thumbnail img{width:100px;height:56px}.q-item__section--nowrap{white-space:nowrap}.q-item>.q-focus-helper+.q-item__section--thumbnail,.q-item>.q-item__section--thumbnail:first-child{margin-left:-16px}.q-item>.q-item__section--thumbnail:last-of-type{margin-right:-16px}.q-item__label{line-height:1.2em!important;max-width:100%}.q-item__label--overline{color:rgba(0,0,0,.7)}.q-item__label--caption{color:rgba(0,0,0,.54)}.q-item__label--header{color:#757575;padding:16px;font-size:.875rem;line-height:1.25rem;letter-spacing:.01786em}.q-list--padding .q-item__label--header,.q-separator--spaced+.q-item__label--header{padding-top:8px}.q-item__label+.q-item__label{margin-top:4px}.q-item__section--main{width:auto;min-width:0;max-width:100%;flex:10000 1 0%}.q-item__section--main+.q-item__section--main{margin-left:8px}.q-item__section--main~.q-item__section--side{align-items:flex-end;padding-right:0;padding-left:16px}.q-item__section--main.q-item__section--thumbnail{margin-left:0;margin-right:-16px}.q-list--bordered{border:1px solid rgba(0,0,0,.12)}.q-list--separator>.q-item-type+.q-item-type,.q-list--separator>.q-virtual-scroll__content>.q-item-type+.q-item-type{border-top:1px solid rgba(0,0,0,.12)}.q-list--padding{padding:8px 0}.q-item--dense,.q-list--dense>.q-item{min-height:32px;padding:2px 16px}.q-list--dark.q-list--separator>.q-item-type+.q-item-type,.q-list--dark.q-list--separator>.q-virtual-scroll__content>.q-item-type+.q-item-type{border-top-color:rgba(255,255,255,.28)}.q-item--dark,.q-list--dark{color:#fff;border-color:rgba(255,255,255,.28)}.q-item--dark .q-item__section--side:not(.q-item__section--avatar),.q-list--dark .q-item__section--side:not(.q-item__section--avatar){color:rgba(255,255,255,.7)}.q-item--dark .q-item__label--header,.q-list--dark .q-item__label--header{color:rgba(255,255,255,.64)}.q-item--dark .q-item__label--caption,.q-item--dark .q-item__label--overline,.q-list--dark .q-item__label--caption,.q-list--dark .q-item__label--overline{color:rgba(255,255,255,.8)}.q-item{position:relative}.q-item--active,.q-item.q-router-link--active{color:var(--q-primary)}.q-knob{font-size:48px}.q-knob--editable{cursor:pointer;outline:0}.q-knob--editable:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;box-shadow:none;transition:box-shadow .24s ease-in-out}.q-knob--editable:focus:before{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}body.body--dark .q-knob--editable:focus:before{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-layout{width:100%;outline:0}.q-layout-container{position:relative;width:100%;height:100%}.q-layout-container .q-layout{min-height:100%}.q-layout-container>div{transform:translate3d(0,0,0)}.q-layout-container>div>div{min-height:0;max-height:100%}.q-layout__shadow{width:100%}.q-layout__shadow:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;box-shadow:0 0 10px 2px rgba(0,0,0,.2),0 0 10px rgba(0,0,0,.24)}.q-layout__section--marginal{background-color:var(--q-primary);color:#fff}.q-header--hidden{transform:translateY(-110%)}.q-header--bordered{border-bottom:1px solid rgba(0,0,0,.12)}.q-header .q-layout__shadow{bottom:-10px}.q-header .q-layout__shadow:after{bottom:10px}.q-footer--hidden{transform:translateY(110%)}.q-footer--bordered{border-top:1px solid rgba(0,0,0,.12)}.q-footer .q-layout__shadow{top:-10px}.q-footer .q-layout__shadow:after{top:10px}.q-footer,.q-header{z-index:2000}.q-drawer{position:absolute;top:0;bottom:0;background:#fff;z-index:1000}.q-drawer--on-top{z-index:3000}.q-drawer--left{left:0;transform:translateX(-100%)}.q-drawer--left.q-drawer--bordered{border-right:1px solid rgba(0,0,0,.12)}.q-drawer--left .q-layout__shadow{left:10px;right:-10px}.q-drawer--left .q-layout__shadow:after{right:10px}.q-drawer--right{right:0;transform:translateX(100%)}.q-drawer--right.q-drawer--bordered{border-left:1px solid rgba(0,0,0,.12)}.q-drawer--right .q-layout__shadow{left:-10px}.q-drawer--right .q-layout__shadow:after{left:10px}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini{padding:0!important}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section{text-align:center;justify-content:center;padding-left:0;padding-right:0;min-width:0}.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__label,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section--main,.q-drawer-container:not(.q-drawer--mini-animate) .q-drawer--mini .q-item__section--side~.q-item__section--side{display:none}.q-drawer--mini .q-expansion-item__content,.q-drawer--mini .q-mini-drawer-hide{display:none}.q-drawer--mini-animate .q-drawer__content{overflow-x:hidden!important;white-space:nowrap}.q-drawer--standard .q-mini-drawer-only{display:none}.q-drawer--mobile .q-mini-drawer-hide,.q-drawer--mobile .q-mini-drawer-only{display:none}.q-drawer__backdrop{z-index:2999!important;will-change:background-color}.q-drawer__opener{z-index:2001;height:100%;width:15px;user-select:none}.q-footer,.q-header,.q-layout,.q-page{position:relative}.q-page-sticky--shrink{pointer-events:none}.q-page-sticky--shrink>div{display:inline-block;pointer-events:auto}body.q-ios-padding .q-layout--standard .q-drawer--top-padding .q-drawer__content,body.q-ios-padding .q-layout--standard .q-header>.q-tabs:first-child .q-tabs__content,body.q-ios-padding .q-layout--standard .q-header>.q-toolbar:first-child{padding-top:20px;min-height:70px;padding-top:env(safe-area-inset-top);min-height:calc(env(safe-area-inset-top) + 50px)}body.q-ios-padding .q-layout--standard .q-drawer--top-padding .q-drawer__content,body.q-ios-padding .q-layout--standard .q-footer>.q-tabs:nth-last-child(1of:not(.q-layout__shadow)) .q-tabs__content,body.q-ios-padding .q-layout--standard .q-footer>.q-toolbar:last-child{padding-bottom:env(safe-area-inset-bottom);min-height:calc(env(safe-area-inset-bottom) + 50px)}.q-body--layout-animate .q-drawer__backdrop{transition:background-color .12s!important}.q-body--layout-animate .q-drawer{transition:transform .12s,width .12s,top .12s,bottom .12s!important}.q-body--layout-animate .q-layout__section--marginal{transition:transform .12s,left .12s,right .12s!important}.q-body--layout-animate .q-page-container{transition:padding-top .12s,padding-right .12s,padding-bottom .12s,padding-left .12s!important}.q-body--layout-animate .q-page-sticky{transition:transform .12s,left .12s,right .12s,top .12s,bottom .12s!important}body:not(.q-body--layout-animate) .q-layout--prevent-focus{visibility:hidden}.q-body--drawer-toggle{overflow-x:hidden!important}@media (max-width:599.98px){.q-layout-padding{padding:8px}}@media (min-width:600px) and (max-width:1439.98px){.q-layout-padding{padding:16px}}@media (min-width:1440px){.q-layout-padding{padding:24px}}body.body--dark .q-drawer,body.body--dark .q-footer,body.body--dark .q-header{border-color:rgba(255,255,255,.28)}body.body--dark .q-layout__shadow:after{box-shadow:0 0 10px 2px rgba(255,255,255,.2),0 0 10px rgba(255,255,255,.24)}body.platform-ios .q-layout--containerized{position:unset!important}.q-linear-progress{--q-linear-progress-speed:.3s;position:relative;width:100%;overflow:hidden;font-size:4px;height:1em;color:var(--q-primary);transform:scale3d(1,1,1)}.q-linear-progress__model,.q-linear-progress__track{transform-origin:0 0}.q-linear-progress__model--with-transition,.q-linear-progress__track--with-transition{transition:transform var(--q-linear-progress-speed)}.q-linear-progress--reverse .q-linear-progress__model,.q-linear-progress--reverse .q-linear-progress__track{transform-origin:0 100%}.q-linear-progress__model--determinate{background:currentColor}.q-linear-progress__model--indeterminate,.q-linear-progress__model--query{transition:none}.q-linear-progress__model--indeterminate:after,.q-linear-progress__model--indeterminate:before,.q-linear-progress__model--query:after,.q-linear-progress__model--query:before{background:currentColor;content:"";position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:0 0}.q-linear-progress__model--indeterminate:before,.q-linear-progress__model--query:before{animation:q-linear-progress--indeterminate 2.1s cubic-bezier(.65,.815,.735,.395) infinite}.q-linear-progress__model--indeterminate:after,.q-linear-progress__model--query:after{transform:translate3d(-101%,0,0) scale3d(1,1,1);animation:q-linear-progress--indeterminate-short 2.1s cubic-bezier(.165,.84,.44,1) infinite;animation-delay:1.15s}.q-linear-progress__track{opacity:.4}.q-linear-progress__track--light{background:rgba(0,0,0,.26)}.q-linear-progress__track--dark{background:rgba(255,255,255,.6)}.q-linear-progress__stripe{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,rgba(255,255,255,0) 25%,rgba(255,255,255,0) 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,rgba(255,255,255,0) 75%,rgba(255,255,255,0))!important;background-size:40px 40px!important}.q-linear-progress__stripe--with-transition{transition:width var(--q-linear-progress-speed)}@keyframes q-linear-progress--indeterminate{0%{transform:translate3d(-35%,0,0) scale3d(.35,1,1)}60%{transform:translate3d(100%,0,0) scale3d(.9,1,1)}100%{transform:translate3d(100%,0,0) scale3d(.9,1,1)}}@keyframes q-linear-progress--indeterminate-short{0%{transform:translate3d(-101%,0,0) scale3d(1,1,1)}60%{transform:translate3d(107%,0,0) scale3d(.01,1,1)}100%{transform:translate3d(107%,0,0) scale3d(.01,1,1)}}.q-menu{position:fixed!important;display:inline-block;max-width:95vw;max-height:65vh;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);background:#fff;border-radius:4px;overflow-y:auto;overflow-x:hidden;outline:0;z-index:6000}.q-menu--square{border-radius:0}.q-menu--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-option-group--inline>div{display:inline-block}.q-pagination input{text-align:center;-moz-appearance:textfield}.q-pagination input::-webkit-inner-spin-button,.q-pagination input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.q-pagination__content{--q-pagination-gutter-parent:-2px;--q-pagination-gutter-child:2px;margin-top:var(--q-pagination-gutter-parent);margin-left:var(--q-pagination-gutter-parent)}.q-pagination__content>.q-btn,.q-pagination__content>.q-input,.q-pagination__middle>.q-btn{margin-top:var(--q-pagination-gutter-child);margin-left:var(--q-pagination-gutter-child)}.q-parallax{position:relative;width:100%;overflow:hidden;border-radius:inherit}.q-parallax__media>img,.q-parallax__media>video{position:absolute;left:50%;bottom:0;min-width:100%;min-height:100%;will-change:transform;display:none}.q-popup-edit{padding:8px 16px}.q-popup-edit__buttons{margin-top:8px}.q-popup-edit__buttons .q-btn+.q-btn{margin-left:8px}.q-pull-to-refresh{position:relative}.q-pull-to-refresh__puller{border-radius:50%;width:40px;height:40px;color:var(--q-primary);background:#fff;box-shadow:0 0 4px 0 rgba(0,0,0,.3)}.q-pull-to-refresh__puller--animating{transition:transform .3s,opacity .3s}.q-radio{vertical-align:middle}.q-radio__native{width:1px;height:1px}.q-radio__bg,.q-radio__icon-container{user-select:none}.q-radio__bg{top:25%;left:25%;width:50%;height:50%;-webkit-print-color-adjust:exact}.q-radio__bg path{fill:currentColor}.q-radio__icon{color:currentColor;font-size:.5em}.q-radio__check{transform-origin:50% 50%;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}.q-radio__inner{font-size:40px;width:1em;min-width:1em;height:1em;outline:0;border-radius:50%;color:rgba(0,0,0,.54)}.q-radio__inner--truthy{color:var(--q-primary)}.q-radio__inner--truthy .q-radio__check{transform:scale3d(1,1,1)}.q-radio.disabled{opacity:.75!important}.q-radio--dark .q-radio__inner{color:rgba(255,255,255,.7)}.q-radio--dark .q-radio__inner:before{opacity:.32!important}.q-radio--dark .q-radio__inner--truthy{color:var(--q-primary)}.q-radio--dense .q-radio__inner{width:.5em;min-width:.5em;height:.5em}.q-radio--dense .q-radio__bg{left:0;top:0;width:100%;height:100%}.q-radio--dense .q-radio__label{padding-left:.5em}.q-radio--dense.reverse .q-radio__label{padding-left:0;padding-right:.5em}body.desktop .q-radio:not(.disabled) .q-radio__inner:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1) 0s}body.desktop .q-radio:not(.disabled):focus .q-radio__inner:before,body.desktop .q-radio:not(.disabled):hover .q-radio__inner:before{transform:scale3d(1,1,1)}body.desktop .q-radio--dense:not(.disabled):focus .q-radio__inner:before,body.desktop .q-radio--dense:not(.disabled):hover .q-radio__inner:before{transform:scale3d(1.5,1.5,1)}.q-rating{color:#ffeb3b;vertical-align:middle}.q-rating__icon-container{height:1em;outline:0}.q-rating__icon-container+.q-rating__icon-container{margin-left:2px}[dir=rtl] .q-rating__icon-container+.q-rating__icon-container{margin-left:0;margin-right:2px}.q-rating__icon{color:currentColor;text-shadow:0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);position:relative;opacity:.4;transition:transform .2s ease-in,opacity .2s ease-in,color .2s ease-in}.q-rating__icon--hovered{transform:scale(1.3)}.q-rating__icon--active{opacity:1}.q-rating__icon--exselected{opacity:.7}.q-rating--no-dimming .q-rating__icon{opacity:1}.q-rating--editable .q-rating__icon-container{cursor:pointer}.q-responsive{position:relative;max-width:100%;max-height:100%}.q-responsive__filler{width:inherit;max-width:inherit;height:inherit;max-height:inherit}.q-responsive__content{border-radius:inherit}.q-responsive__content>*{width:100%!important;height:100%!important;max-height:100%!important;max-width:100%!important}.q-scrollarea{position:relative;contain:strict}.q-scrollarea__bar,.q-scrollarea__thumb{opacity:.2;transition:opacity .3s;will-change:opacity;cursor:grab}.q-scrollarea__bar--v,.q-scrollarea__thumb--v{right:0;width:10px}.q-scrollarea__bar--h,.q-scrollarea__thumb--h{bottom:0;height:10px}.q-scrollarea__bar--invisible,.q-scrollarea__thumb--invisible{opacity:0!important;pointer-events:none}.q-scrollarea__thumb{background:#000;border-radius:3px}.q-scrollarea__thumb:hover{opacity:.3}.q-scrollarea__thumb:active{opacity:.5}.q-scrollarea__content{min-height:100%;min-width:100%}.q-scrollarea--dark .q-scrollarea__thumb{background:#fff}.q-select--without-input .q-field__control{cursor:pointer}.q-select--with-input .q-field__control{cursor:text}.q-select .q-field__input{min-width:50px!important;cursor:text}.q-select .q-field__input--padding{padding-left:4px}.q-select__autocomplete-input,.q-select__focus-target{position:absolute;outline:0!important;width:1px;height:1px;padding:0;border:0;opacity:0}.q-select__dropdown-icon{cursor:pointer;transition:transform .28s}.q-select.q-field--readonly .q-field__control,.q-select.q-field--readonly .q-select__dropdown-icon{cursor:default}.q-select__dialog{width:90vw!important;max-width:90vw!important;max-height:calc(100vh - 70px)!important;background:#fff;display:flex;flex-direction:column}.q-select__dialog>.scroll{position:relative;background:inherit}body.mobile:not(.native-mobile) .q-select__dialog{max-height:calc(100vh - 108px)!important}body.platform-android.native-mobile .q-dialog__inner--top .q-select__dialog{max-height:calc(100vh - 24px)!important}body.platform-android:not(.native-mobile) .q-dialog__inner--top .q-select__dialog{max-height:calc(100vh - 80px)!important}body.platform-ios.native-mobile .q-dialog__inner--top>div{border-radius:4px}body.platform-ios.native-mobile .q-dialog__inner--top .q-select__dialog--focused{max-height:47vh!important}body.platform-ios:not(.native-mobile) .q-dialog__inner--top .q-select__dialog--focused{max-height:50vh!important}.q-separator{border:0;background:rgba(0,0,0,.12);margin:0;transition:background .3s,opacity .3s;flex-shrink:0}.q-separator--dark{background:rgba(255,255,255,.28)}.q-separator--horizontal{display:block;height:1px}.q-separator--horizontal-inset{margin-left:16px;margin-right:16px}.q-separator--horizontal-item-inset{margin-left:72px;margin-right:0}.q-separator--horizontal-item-thumbnail-inset{margin-left:116px;margin-right:0}.q-separator--vertical{width:1px;height:auto;align-self:stretch}.q-separator--vertical-inset{margin-top:8px;margin-bottom:8px}.q-skeleton{--q-skeleton-speed:1500ms;background:rgba(0,0,0,.12);border-radius:4px;box-sizing:border-box}.q-skeleton--anim{cursor:wait}.q-skeleton:before{content:" "}.q-skeleton--type-text{transform:scale(1,.5)}.q-skeleton--type-QAvatar,.q-skeleton--type-circle{height:48px;width:48px;border-radius:50%}.q-skeleton--type-QBtn{width:90px;height:36px}.q-skeleton--type-QBadge{width:70px;height:16px}.q-skeleton--type-QChip{width:90px;height:28px;border-radius:16px}.q-skeleton--type-QToolbar{height:50px}.q-skeleton--type-QCheckbox,.q-skeleton--type-QRadio{width:40px;height:40px;border-radius:50%}.q-skeleton--type-QToggle{width:56px;height:40px;border-radius:7px}.q-skeleton--type-QRange,.q-skeleton--type-QSlider{height:40px}.q-skeleton--type-QInput{height:56px}.q-skeleton--bordered{border:1px solid rgba(0,0,0,.05)}.q-skeleton--square{border-radius:0}.q-skeleton--anim-fade{animation:q-skeleton--fade var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--anim-pulse{animation:q-skeleton--pulse var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-pulse-x{animation:q-skeleton--pulse-x var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-pulse-y{animation:q-skeleton--pulse-y var(--q-skeleton-speed) ease-in-out .5s infinite}.q-skeleton--anim-blink,.q-skeleton--anim-pop,.q-skeleton--anim-wave{position:relative;overflow:hidden;z-index:1}.q-skeleton--anim-blink:after,.q-skeleton--anim-pop:after,.q-skeleton--anim-wave:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.q-skeleton--anim-blink:after{background:rgba(255,255,255,.7);animation:q-skeleton--fade var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--anim-wave:after{background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.5),rgba(255,255,255,0));animation:q-skeleton--wave var(--q-skeleton-speed) linear .5s infinite}.q-skeleton--dark{background:rgba(255,255,255,.05)}.q-skeleton--dark.q-skeleton--bordered{border:1px solid rgba(255,255,255,.25)}.q-skeleton--dark.q-skeleton--anim-wave:after{background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.1),rgba(255,255,255,0))}.q-skeleton--dark.q-skeleton--anim-blink:after{background:rgba(255,255,255,.2)}@keyframes q-skeleton--fade{0%{opacity:1}50%{opacity:.4}100%{opacity:1}}@keyframes q-skeleton--pulse{0%{transform:scale(1)}50%{transform:scale(.85)}100%{transform:scale(1)}}@keyframes q-skeleton--pulse-x{0%{transform:scaleX(1)}50%{transform:scaleX(.75)}100%{transform:scaleX(1)}}@keyframes q-skeleton--pulse-y{0%{transform:scaleY(1)}50%{transform:scaleY(.75)}100%{transform:scaleY(1)}}@keyframes q-skeleton--wave{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.q-slide-item{position:relative;background:#fff}.q-slide-item__bottom,.q-slide-item__left,.q-slide-item__right,.q-slide-item__top{visibility:hidden;font-size:14px;color:#fff}.q-slide-item__bottom .q-icon,.q-slide-item__left .q-icon,.q-slide-item__right .q-icon,.q-slide-item__top .q-icon{font-size:1.714em}.q-slide-item__left{background:#4caf50;padding:8px 16px}.q-slide-item__left>div{transform-origin:left center}.q-slide-item__right{background:#ff9800;padding:8px 16px}.q-slide-item__right>div{transform-origin:right center}.q-slide-item__top{background:#2196f3;padding:16px 8px}.q-slide-item__top>div{transform-origin:top center}.q-slide-item__bottom{background:#9c27b0;padding:16px 8px}.q-slide-item__bottom>div{transform-origin:bottom center}.q-slide-item__content{background:inherit;transition:transform .2s ease-in;user-select:none;cursor:pointer}.q-slider{position:relative}.q-slider--h{width:100%}.q-slider--v{height:200px}.q-slider--editable .q-slider__track-container{cursor:grab}.q-slider__track-container{outline:0}.q-slider__track-container--h{width:100%;padding:12px 0}.q-slider__track-container--h .q-slider__selection{will-change:width,left}.q-slider__track-container--v{height:100%;padding:0 12px}.q-slider__track-container--v .q-slider__selection{will-change:height,top}.q-slider__track{color:var(--q-primary);background:rgba(0,0,0,.1);border-radius:4px;width:inherit;height:inherit}.q-slider__inner{background:rgba(0,0,0,.1);border-radius:inherit;width:100%;height:100%}.q-slider__selection{background:currentColor;border-radius:inherit;width:100%;height:100%}.q-slider__markers{color:rgba(0,0,0,.3);border-radius:inherit;width:100%;height:100%}.q-slider__markers:after{content:"";position:absolute;background:currentColor}.q-slider__markers--h{background-image:repeating-linear-gradient(to right,currentColor,currentColor 2px,rgba(255,255,255,0) 0,rgba(255,255,255,0))}.q-slider__markers--h:after{height:100%;width:2px;top:0;right:0}.q-slider__markers--v{background-image:repeating-linear-gradient(to bottom,currentColor,currentColor 2px,rgba(255,255,255,0) 0,rgba(255,255,255,0))}.q-slider__markers--v:after{width:100%;height:2px;left:0;bottom:0}.q-slider__marker-labels-container{position:relative;width:100%;height:100%;min-height:24px;min-width:24px}.q-slider__marker-labels{position:absolute}.q-slider__marker-labels--h-standard{top:0}.q-slider__marker-labels--h-switched{bottom:0}.q-slider__marker-labels--h-ltr{transform:translateX(-50%)}.q-slider__marker-labels--h-rtl{transform:translateX(50%)}.q-slider__marker-labels--v-standard{left:4px}.q-slider__marker-labels--v-switched{right:4px}.q-slider__marker-labels--v-ltr{transform:translateY(-50%)}.q-slider__marker-labels--v-rtl{transform:translateY(50%)}.q-slider__thumb{z-index:1;outline:0;color:var(--q-primary);transition:transform .18s ease-out,fill .18s ease-out,stroke .18s ease-out}.q-slider__thumb.q-slider--focus{opacity:1!important}.q-slider__thumb--h{top:50%;will-change:left}.q-slider__thumb--h-ltr{transform:scale(1) translate(-50%,-50%)}.q-slider__thumb--h-rtl{transform:scale(1) translate(50%,-50%)}.q-slider__thumb--v{left:50%;will-change:top}.q-slider__thumb--v-ltr{transform:scale(1) translate(-50%,-50%)}.q-slider__thumb--v-rtl{transform:scale(1) translate(-50%,50%)}.q-slider__thumb-shape{top:0;left:0;stroke-width:3.5;stroke:currentColor;transition:transform .28s}.q-slider__thumb-shape path{stroke:currentColor;fill:currentColor}.q-slider__focus-ring{border-radius:50%;opacity:0;transition:transform .266s ease-out,opacity .266s ease-out,background-color .266s ease-out;transition-delay:0.14s}.q-slider__pin{opacity:0;white-space:nowrap;transition:opacity .28s ease-out;transition-delay:0.14s}.q-slider__pin:before{content:"";width:0;height:0;position:absolute}.q-slider__pin--h:before{border-left:6px solid transparent;border-right:6px solid transparent;left:50%;transform:translateX(-50%)}.q-slider__pin--h-standard{bottom:100%}.q-slider__pin--h-standard:before{bottom:2px;border-top:6px solid currentColor}.q-slider__pin--h-switched{top:100%}.q-slider__pin--h-switched:before{top:2px;border-bottom:6px solid currentColor}.q-slider__pin--v{top:0}.q-slider__pin--v:before{top:50%;transform:translateY(-50%);border-top:6px solid transparent;border-bottom:6px solid transparent}.q-slider__pin--v-standard{left:100%}.q-slider__pin--v-standard:before{left:2px;border-right:6px solid currentColor}.q-slider__pin--v-switched{right:100%}.q-slider__pin--v-switched:before{right:2px;border-left:6px solid currentColor}.q-slider__label{z-index:1;white-space:nowrap;position:absolute}.q-slider__label--h{left:50%;transform:translateX(-50%)}.q-slider__label--h-standard{bottom:7px}.q-slider__label--h-switched{top:7px}.q-slider__label--v{top:50%;transform:translateY(-50%)}.q-slider__label--v-standard{left:7px}.q-slider__label--v-switched{right:7px}.q-slider__text-container{min-height:25px;padding:2px 8px;border-radius:4px;background:currentColor;position:relative;text-align:center}.q-slider__text{color:#fff;font-size:12px}.q-slider--no-value .q-slider__inner,.q-slider--no-value .q-slider__selection,.q-slider--no-value .q-slider__thumb{opacity:0}.q-slider--focus .q-slider__focus-ring,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__focus-ring{background:currentColor;transform:scale3d(1.55,1.55,1);opacity:.25}.q-slider--focus .q-slider__inner,.q-slider--focus .q-slider__selection,.q-slider--focus .q-slider__thumb,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__inner,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__selection,body.desktop .q-slider.q-slider--editable .q-slider__track-container:hover .q-slider__thumb{opacity:1}.q-slider--inactive .q-slider__thumb--h{transition:left .28s,right .28s}.q-slider--inactive .q-slider__thumb--v{transition:top .28s,bottom .28s}.q-slider--inactive .q-slider__selection{transition:width .28s,left .28s,right .28s,height .28s,top .28s,bottom .28s}.q-slider--inactive .q-slider__text-container{transition:transform .28s}.q-slider--active{cursor:grabbing}.q-slider--active .q-slider__thumb-shape{transform:scale(1.5)}.q-slider--active .q-slider__focus-ring,.q-slider--active.q-slider--label .q-slider__thumb-shape{transform:scale(0)!important}body.desktop .q-slider.q-slider--enabled .q-slider__track-container:hover .q-slider__pin{opacity:1}.q-slider--label .q-slider--focus .q-slider__pin,.q-slider--label.q-slider--active .q-slider__pin,.q-slider--label.q-slider--label-always .q-slider__pin{opacity:1}.q-slider--dark .q-slider__track{background:rgba(255,255,255,.1)}.q-slider--dark .q-slider__inner{background:rgba(255,255,255,.1)}.q-slider--dark .q-slider__markers{color:rgba(255,255,255,.3)}.q-slider--dense .q-slider__track-container--h{padding:6px 0}.q-slider--dense .q-slider__track-container--v{padding:0 6px}.q-space{flex-grow:1!important}.q-spinner{vertical-align:middle}.q-spinner-mat{animation:q-spin 2s linear infinite;transform-origin:center center}.q-spinner-mat .path{stroke-dasharray:1,200;stroke-dashoffset:0;animation:q-mat-dash 1.5s ease-in-out infinite}@keyframes q-spin{0%{transform:rotate3d(0,0,1,0deg)}25%{transform:rotate3d(0,0,1,90deg)}50%{transform:rotate3d(0,0,1,180deg)}75%{transform:rotate3d(0,0,1,270deg)}100%{transform:rotate3d(0,0,1,359deg)}}@keyframes q-mat-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}.q-splitter__panel{position:relative;z-index:0}.q-splitter__panel>.q-splitter{width:100%;height:100%}.q-splitter__separator{background-color:rgba(0,0,0,.12);user-select:none;position:relative;z-index:1}.q-splitter__separator-area>*{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.q-splitter--dark .q-splitter__separator{background-color:rgba(255,255,255,.28)}.q-splitter--vertical>.q-splitter__panel{height:100%}.q-splitter--vertical.q-splitter--active{cursor:col-resize}.q-splitter--vertical>.q-splitter__separator{width:1px}.q-splitter--vertical>.q-splitter__separator>div{left:-6px;right:-6px}.q-splitter--vertical.q-splitter--workable>.q-splitter__separator{cursor:col-resize}.q-splitter--horizontal>.q-splitter__panel{width:100%}.q-splitter--horizontal.q-splitter--active{cursor:row-resize}.q-splitter--horizontal>.q-splitter__separator{height:1px}.q-splitter--horizontal>.q-splitter__separator>div{top:-6px;bottom:-6px}.q-splitter--horizontal.q-splitter--workable>.q-splitter__separator{cursor:row-resize}.q-splitter__after,.q-splitter__before{overflow:auto}.q-stepper{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff}.q-stepper__title{font-size:14px;line-height:1.285714;letter-spacing:.1px}.q-stepper__caption{font-size:12px;line-height:1.16667}.q-stepper__dot{contain:layout;margin-right:8px;font-size:14px;width:24px;min-width:24px;height:24px;border-radius:50%;background:currentColor}.q-stepper__dot span{color:#fff}.q-stepper__tab{padding:8px 24px;font-size:14px;color:#9e9e9e;flex-direction:row}.q-stepper--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-stepper--dark .q-stepper__dot span{color:#000}.q-stepper__tab--navigation{user-select:none;cursor:pointer}.q-stepper__tab--active,.q-stepper__tab--done{color:var(--q-primary)}.q-stepper__tab--active .q-stepper__dot,.q-stepper__tab--active .q-stepper__label,.q-stepper__tab--done .q-stepper__dot,.q-stepper__tab--done .q-stepper__label{text-shadow:0 0 0 currentColor}.q-stepper__tab--disabled .q-stepper__dot{background:rgba(0,0,0,.22)}.q-stepper__tab--disabled .q-stepper__label{color:rgba(0,0,0,.32)}.q-stepper__tab--error{color:var(--q-negative)}.q-stepper__tab--error-with-icon .q-stepper__dot{background:0 0!important}.q-stepper__tab--error-with-icon .q-stepper__dot span{color:currentColor;font-size:24px}.q-stepper__header{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-stepper__header--border{border-bottom:1px solid rgba(0,0,0,.12)}.q-stepper__header--standard-labels .q-stepper__tab{min-height:72px;justify-content:center}.q-stepper__header--standard-labels .q-stepper__tab:first-child{justify-content:flex-start}.q-stepper__header--standard-labels .q-stepper__tab:last-child{justify-content:flex-end}.q-stepper__header--standard-labels .q-stepper__tab:only-child{justify-content:center}.q-stepper__header--standard-labels .q-stepper__dot:after{display:none}.q-stepper__header--alternative-labels .q-stepper__tab{min-height:104px;padding:24px 32px;flex-direction:column;justify-content:flex-start}.q-stepper__header--alternative-labels .q-stepper__dot{margin-right:0}.q-stepper__header--alternative-labels .q-stepper__label{margin-top:8px;text-align:center}.q-stepper__header--alternative-labels .q-stepper__label:after,.q-stepper__header--alternative-labels .q-stepper__label:before{display:none}.q-stepper__header--contracted{min-height:72px}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab{min-height:72px}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab:first-child{align-items:flex-start}.q-stepper__header--contracted.q-stepper__header--alternative-labels .q-stepper__tab:last-child{align-items:flex-end}.q-stepper__header--contracted .q-stepper__tab{padding:24px 0}.q-stepper__header--contracted .q-stepper__tab:first-child .q-stepper__dot{transform:translateX(24px)}.q-stepper__header--contracted .q-stepper__tab:last-child .q-stepper__dot{transform:translateX(-24px)}.q-stepper__header--contracted .q-stepper__tab:not(:last-child) .q-stepper__dot:after{display:block!important}.q-stepper__header--contracted .q-stepper__dot{margin:0}.q-stepper__header--contracted .q-stepper__label{display:none}.q-stepper__nav{padding-top:24px}.q-stepper--flat{box-shadow:none}.q-stepper--bordered{border:1px solid rgba(0,0,0,.12)}.q-stepper--horizontal .q-stepper__step-inner{padding:24px}.q-stepper--horizontal .q-stepper__tab:first-child{border-top-left-radius:inherit}.q-stepper--horizontal .q-stepper__tab:last-child{border-top-right-radius:inherit}.q-stepper--horizontal .q-stepper__tab:first-child .q-stepper__dot:before,.q-stepper--horizontal .q-stepper__tab:last-child .q-stepper__dot:after,.q-stepper--horizontal .q-stepper__tab:last-child .q-stepper__label:after{display:none}.q-stepper--horizontal .q-stepper__tab{overflow:hidden}.q-stepper--horizontal .q-stepper__line{contain:layout}.q-stepper--horizontal .q-stepper__line:after,.q-stepper--horizontal .q-stepper__line:before{position:absolute;top:50%;height:1px;width:100vw;background:rgba(0,0,0,.12)}.q-stepper--horizontal .q-stepper__dot:after,.q-stepper--horizontal .q-stepper__label:after{content:"";left:100%;margin-left:8px}.q-stepper--horizontal .q-stepper__dot:before{content:"";right:100%;margin-right:8px}.q-stepper--horizontal>.q-stepper__nav{padding:0 24px 24px}.q-stepper--vertical{padding:16px 0}.q-stepper--vertical .q-stepper__tab{padding:12px 24px}.q-stepper--vertical .q-stepper__title{line-height:18px}.q-stepper--vertical .q-stepper__step-inner{padding:0 24px 32px 60px}.q-stepper--vertical>.q-stepper__nav{padding:24px 24px 0}.q-stepper--vertical .q-stepper__step{overflow:hidden}.q-stepper--vertical .q-stepper__dot{margin-right:12px}.q-stepper--vertical .q-stepper__dot:after,.q-stepper--vertical .q-stepper__dot:before{content:"";position:absolute;left:50%;width:1px;height:99999px;background:rgba(0,0,0,.12)}.q-stepper--vertical .q-stepper__dot:before{bottom:100%;margin-bottom:8px}.q-stepper--vertical .q-stepper__dot:after{top:100%;margin-top:8px}.q-stepper--vertical .q-stepper__step:first-child .q-stepper__dot:before,.q-stepper--vertical .q-stepper__step:last-child .q-stepper__dot:after{display:none}.q-stepper--vertical .q-stepper__step:last-child .q-stepper__step-inner{padding-bottom:8px}.q-stepper--dark .q-stepper__header--border,.q-stepper--dark.q-stepper--bordered{border-color:rgba(255,255,255,.28)}.q-stepper--dark.q-stepper--horizontal .q-stepper__line:after,.q-stepper--dark.q-stepper--horizontal .q-stepper__line:before{background:rgba(255,255,255,.28)}.q-stepper--dark.q-stepper--vertical .q-stepper__dot:after,.q-stepper--dark.q-stepper--vertical .q-stepper__dot:before{background:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled{color:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled .q-stepper__dot{background:rgba(255,255,255,.28)}.q-stepper--dark .q-stepper__tab--disabled .q-stepper__label{color:rgba(255,255,255,.54)}.q-tab-panels{background:#fff}.q-tab-panel{padding:16px}.q-markup-table{overflow:auto;background:#fff}.q-table{width:100%;max-width:100%;border-collapse:separate;border-spacing:0}.q-table tbody td,.q-table thead tr{height:48px}.q-table th{font-weight:500;font-size:12px;user-select:none}.q-table th.sortable{cursor:pointer}.q-table th.sortable:hover .q-table__sort-icon{opacity:.64}.q-table th.sorted .q-table__sort-icon{opacity:.86!important}.q-table th.sort-desc .q-table__sort-icon{transform:rotate(180deg)}.q-table td,.q-table th{padding:7px 16px;background-color:inherit}.q-table td,.q-table th,.q-table thead{border-style:solid;border-width:0}.q-table tbody td{font-size:13px}.q-table__card{color:#000;background-color:#fff;border-radius:4px;box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.q-table__card .q-table__middle{flex:1 1 auto}.q-table__card .q-table__bottom,.q-table__card .q-table__top{flex:0 0 auto}.q-table__container{position:relative}.q-table__container>div:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.q-table__container>div:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.q-table__container>.q-inner-loading{border-radius:inherit!important}.q-table__top{padding:12px 16px}.q-table__top .q-table__control{flex-wrap:wrap}.q-table__title{font-size:20px;letter-spacing:.005em;font-weight:400}.q-table__separator{min-width:8px!important}.q-table__progress{height:0!important}.q-table__progress th{padding:0!important;border:0!important}.q-table__progress .q-linear-progress{position:absolute;bottom:0}.q-table__middle{max-width:100%}.q-table__bottom{min-height:50px;padding:4px 14px 4px 16px;font-size:12px}.q-table__bottom .q-table__control{min-height:24px}.q-table__bottom-nodata-icon{font-size:200%;margin-right:8px}.q-table__bottom-item{margin-right:16px}.q-table__control{display:flex;align-items:center}.q-table__sort-icon{transition:transform .3s cubic-bezier(.25, .8, .5, 1);opacity:0;font-size:120%}.q-table__sort-icon--center,.q-table__sort-icon--left{margin-left:4px}.q-table__sort-icon--right{margin-right:4px}.q-table--col-auto-width{width:1px}.q-table--dark,.q-table__card--dark{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-table--flat{box-shadow:none}.q-table--bordered{border:1px solid rgba(0,0,0,.12)}.q-table--square{border-radius:0}.q-table__linear-progress{height:2px}.q-table--no-wrap td,.q-table--no-wrap th{white-space:nowrap}.q-table--grid{box-shadow:none;border-radius:4px}.q-table--grid .q-table__top{padding-bottom:4px}.q-table--grid .q-table__middle{min-height:2px;margin-bottom:4px}.q-table--grid .q-table__middle thead,.q-table--grid .q-table__middle thead th{border:0!important}.q-table--grid .q-table__linear-progress{bottom:0}.q-table--grid .q-table__bottom{border-top:0}.q-table--grid .q-table__grid-content{flex:1 1 auto}.q-table--grid.fullscreen{background:inherit}.q-table__grid-item-card{vertical-align:top;padding:12px}.q-table__grid-item-card .q-separator{margin:12px 0}.q-table__grid-item-row+.q-table__grid-item-row{margin-top:8px}.q-table__grid-item-title{opacity:.54;font-weight:500;font-size:12px}.q-table__grid-item-value{font-size:13px}.q-table__grid-item{padding:4px;transition:transform .3s cubic-bezier(.25, .8, .5, 1)}.q-table__grid-item--selected{transform:scale(.95)}.q-table--cell-separator tbody tr:not(:last-child)>td,.q-table--cell-separator thead th,.q-table--horizontal-separator tbody tr:not(:last-child)>td,.q-table--horizontal-separator thead th{border-bottom-width:1px}.q-table--cell-separator td,.q-table--cell-separator th,.q-table--vertical-separator td,.q-table--vertical-separator th{border-left-width:1px}.q-table--cell-separator thead tr:last-child th,.q-table--cell-separator.q-table--loading tr:nth-last-child(2) th,.q-table--vertical-separator thead tr:last-child th,.q-table--vertical-separator.q-table--loading tr:nth-last-child(2) th{border-bottom-width:1px}.q-table--cell-separator td:first-child,.q-table--cell-separator th:first-child,.q-table--vertical-separator td:first-child,.q-table--vertical-separator th:first-child{border-left:0}.q-table--cell-separator .q-table__top,.q-table--vertical-separator .q-table__top{border-bottom:1px solid rgba(0,0,0,.12)}.q-table--dense .q-table__top{padding:6px 16px}.q-table--dense .q-table__bottom{min-height:33px}.q-table--dense .q-table__sort-icon{font-size:110%}.q-table--dense .q-table td,.q-table--dense .q-table th{padding:4px 8px}.q-table--dense .q-table tbody td,.q-table--dense .q-table tbody tr,.q-table--dense .q-table thead tr{height:28px}.q-table--dense .q-table td:first-child,.q-table--dense .q-table th:first-child{padding-left:16px}.q-table--dense .q-table td:last-child,.q-table--dense .q-table th:last-child{padding-right:16px}.q-table--dense .q-table__bottom-item{margin-right:8px}.q-table--dense .q-table__select .q-field__control,.q-table--dense .q-table__select .q-field__native{min-height:24px;padding:0}.q-table--dense .q-table__select .q-field__marginal{height:24px}.q-table__bottom:not(.q-table__bottom--nodata){border-top:1px solid rgba(0,0,0,.12)}.q-table td,.q-table th,.q-table thead,.q-table tr{border-color:rgba(0,0,0,.12)}.q-table tbody td{position:relative}.q-table tbody td:after,.q-table tbody td:before{position:absolute;top:0;left:0;right:0;bottom:0;pointer-events:none}.q-table tbody td:before{background:rgba(0,0,0,.03)}.q-table tbody td:after{background:rgba(0,0,0,.06)}.q-table tbody tr.selected td:after{content:""}body.desktop .q-table>tbody>tr:not(.q-tr--no-hover):hover>td:not(.q-td--no-hover):before{content:""}.q-table--dark,.q-table__card--dark{border-color:rgba(255,255,255,.28)}.q-table--dark .q-table__bottom,.q-table--dark td,.q-table--dark th,.q-table--dark thead,.q-table--dark tr{border-color:rgba(255,255,255,.28)}.q-table--dark tbody td:before{background:rgba(255,255,255,.07)}.q-table--dark tbody td:after{background:rgba(255,255,255,.1)}.q-table--dark.q-table--cell-separator .q-table__top,.q-table--dark.q-table--vertical-separator .q-table__top{border-color:rgba(255,255,255,.28)}.q-tab{padding:0 16px;min-height:48px;transition:color .3s,background-color .3s;text-transform:uppercase;white-space:nowrap;color:inherit;text-decoration:none}.q-tab--full{min-height:72px}.q-tab--no-caps{text-transform:none}.q-tab__content{height:inherit;padding:4px 0;min-width:40px}.q-tab__content--inline .q-tab__icon+.q-tab__label{padding-left:8px}.q-tab__content .q-chip--floating{top:0;right:-16px}.q-tab__icon{width:24px;height:24px;font-size:24px}.q-tab__label{font-size:14px;line-height:1.715em;font-weight:500}.q-tab .q-badge{top:3px;right:-12px}.q-tab__alert,.q-tab__alert-icon{position:absolute}.q-tab__alert{top:7px;right:-9px;height:10px;width:10px;border-radius:50%;background:currentColor}.q-tab__alert-icon{top:2px;right:-12px;font-size:18px}.q-tab__indicator{opacity:0;height:2px;background:currentColor}.q-tab--active .q-tab__indicator{opacity:1;transform-origin:left}.q-tab--inactive{opacity:.85}.q-tabs{position:relative;transition:color .3s,background-color .3s}.q-tabs--scrollable.q-tabs__arrows--outside.q-tabs--horizontal{padding-left:36px;padding-right:36px}.q-tabs--scrollable.q-tabs__arrows--outside.q-tabs--vertical{padding-top:36px;padding-bottom:36px}.q-tabs--scrollable.q-tabs__arrows--outside .q-tabs__arrow--faded{opacity:.3;pointer-events:none}.q-tabs--scrollable.q-tabs__arrows--inside .q-tabs__arrow--faded{display:none}.q-tabs--not-scrollable.q-tabs__arrows--outside,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows.q-tabs__arrows--outside{padding-left:0;padding-right:0}.q-tabs--not-scrollable .q-tabs__arrow,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows .q-tabs__arrow{display:none}.q-tabs--not-scrollable .q-tabs__content,body.mobile .q-tabs--scrollable.q-tabs--mobile-without-arrows .q-tabs__content{border-radius:inherit}.q-tabs__arrow{cursor:pointer;font-size:32px;min-width:36px;text-shadow:0 0 3px #fff,0 0 1px #fff,0 0 1px #000;transition:opacity .3s}.q-tabs__content{overflow:hidden;flex:1 1 auto}.q-tabs__content--align-center{justify-content:center}.q-tabs__content--align-right{justify-content:flex-end}.q-tabs__content--align-justify .q-tab{flex:1 1 auto}.q-tabs__offset{display:none}.q-tabs--horizontal .q-tabs__arrow{height:100%}.q-tabs--horizontal .q-tabs__arrow--left{top:0;left:0;bottom:0}.q-tabs--horizontal .q-tabs__arrow--right{top:0;right:0;bottom:0}.q-tabs--vertical{display:block!important;height:100%}.q-tabs--vertical .q-tabs__content{display:block!important;height:100%}.q-tabs--vertical .q-tabs__arrow{width:100%;height:36px;text-align:center}.q-tabs--vertical .q-tabs__arrow--left{top:0;left:0;right:0}.q-tabs--vertical .q-tabs__arrow--right{left:0;right:0;bottom:0}.q-tabs--vertical .q-tab{padding:0 8px}.q-tabs--vertical .q-tab__indicator{height:unset;width:2px}.q-tabs--vertical.q-tabs--not-scrollable .q-tabs__content{height:100%}.q-tabs--vertical.q-tabs--dense .q-tab__content{min-width:24px}.q-tabs--dense .q-tab{min-height:36px}.q-tabs--dense .q-tab--full{min-height:52px}.q-time{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;background:#fff;outline:0;width:290px;min-width:290px;max-width:100%}.q-time--bordered{border:1px solid rgba(0,0,0,.12)}.q-time__header{border-top-left-radius:inherit;color:#fff;background-color:var(--q-primary);padding:16px;font-weight:300}.q-time__actions{padding:0 16px 16px}.q-time__header-label{font-size:28px;line-height:1;letter-spacing:-.00833em}.q-time__header-label>div+div{margin-left:4px}.q-time__link{opacity:.56;outline:0;transition:opacity .3s ease-out}.q-time__link--active,.q-time__link:focus,.q-time__link:hover{opacity:1}.q-time__header-ampm{font-size:16px;letter-spacing:.1em}.q-time__content{padding:16px}.q-time__content:before{content:"";display:block;padding-bottom:100%}.q-time__container-parent{padding:16px}.q-time__container-child{border-radius:50%;background:rgba(0,0,0,.12)}.q-time__clock{padding:24px;width:100%;height:100%;max-width:100%;max-height:100%;font-size:14px}.q-time__clock-circle{position:relative}.q-time__clock-center{height:6px;width:6px;margin:auto;border-radius:50%;min-height:0;background:currentColor}.q-time__clock-pointer{width:2px;height:50%;transform-origin:0 0;min-height:0;position:absolute;left:50%;right:0;bottom:0;color:var(--q-primary);background:currentColor;transform:translateX(-50%)}.q-time__clock-pointer:after,.q-time__clock-pointer:before{content:"";position:absolute;left:50%;border-radius:50%;background:currentColor;transform:translateX(-50%)}.q-time__clock-pointer:before{bottom:-4px;width:8px;height:8px}.q-time__clock-pointer:after{top:-3px;height:6px;width:6px}.q-time__clock-position{position:absolute;min-height:32px;width:32px;height:32px;font-size:12px;line-height:32px;margin:0;padding:0;transform:translate(-50%,-50%);border-radius:50%}.q-time__clock-position--disable{opacity:.4}.q-time__clock-position--active{background-color:var(--q-primary);color:#fff}.q-time__clock-pos-0{top:0;left:50%}.q-time__clock-pos-1{top:6.7%;left:75%}.q-time__clock-pos-2{top:25%;left:93.3%}.q-time__clock-pos-3{top:50%;left:100%}.q-time__clock-pos-4{top:75%;left:93.3%}.q-time__clock-pos-5{top:93.3%;left:75%}.q-time__clock-pos-6{top:100%;left:50%}.q-time__clock-pos-7{top:93.3%;left:25%}.q-time__clock-pos-8{top:75%;left:6.7%}.q-time__clock-pos-9{top:50%;left:0}.q-time__clock-pos-10{top:25%;left:6.7%}.q-time__clock-pos-11{top:6.7%;left:25%}.q-time__clock-pos-12{top:15%;left:50%}.q-time__clock-pos-13{top:19.69%;left:67.5%}.q-time__clock-pos-14{top:32.5%;left:80.31%}.q-time__clock-pos-15{top:50%;left:85%}.q-time__clock-pos-16{top:67.5%;left:80.31%}.q-time__clock-pos-17{top:80.31%;left:67.5%}.q-time__clock-pos-18{top:85%;left:50%}.q-time__clock-pos-19{top:80.31%;left:32.5%}.q-time__clock-pos-20{top:67.5%;left:19.69%}.q-time__clock-pos-21{top:50%;left:15%}.q-time__clock-pos-22{top:32.5%;left:19.69%}.q-time__clock-pos-23{top:19.69%;left:32.5%}.q-time__now-button{background-color:var(--q-primary);color:#fff;top:12px;right:12px}.q-time--readonly .q-time__content,.q-time--readonly .q-time__header-ampm,.q-time.disabled .q-time__content,.q-time.disabled .q-time__header-ampm{pointer-events:none}.q-time--portrait{display:inline-flex;flex-direction:column}.q-time--portrait .q-time__header{border-top-right-radius:inherit;min-height:86px}.q-time--portrait .q-time__header-ampm{margin-left:12px}.q-time--portrait.q-time--bordered .q-time__content{margin:1px 0}.q-time--landscape{display:inline-flex;align-items:stretch;min-width:420px}.q-time--landscape>div{display:flex;flex-direction:column;justify-content:center}.q-time--landscape .q-time__header{border-bottom-left-radius:inherit;min-width:156px}.q-time--landscape .q-time__header-ampm{margin-top:12px}.q-time--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-timeline{padding:0;width:100%;list-style:none}.q-timeline h6{line-height:inherit}.q-timeline--dark{color:#fff}.q-timeline--dark .q-timeline__subtitle{opacity:.7}.q-timeline__content{padding-bottom:24px}.q-timeline__title{margin-top:0;margin-bottom:16px}.q-timeline__subtitle{font-size:12px;margin-bottom:8px;opacity:.6;text-transform:uppercase;letter-spacing:1px;font-weight:700}.q-timeline__dot{position:absolute;top:0;bottom:0;width:15px}.q-timeline__dot:after,.q-timeline__dot:before{content:"";background:currentColor;display:block;position:absolute}.q-timeline__dot:before{border:3px solid transparent;border-radius:100%;height:15px;width:15px;top:4px;left:0;transition:background .3s ease-in-out,border .3s ease-in-out}.q-timeline__dot:after{width:3px;opacity:.4;top:24px;bottom:0;left:6px}.q-timeline__dot .q-icon{position:absolute;top:0;left:0;right:0;font-size:16px;height:38px;line-height:38px;width:100%;color:#fff}.q-timeline__dot .q-icon>img,.q-timeline__dot .q-icon>svg{width:1em;height:1em}.q-timeline__dot-img{position:absolute;top:4px;left:0;right:0;height:31px;width:31px;background:currentColor;border-radius:50%}.q-timeline__heading{position:relative}.q-timeline__heading:first-child .q-timeline__heading-title{padding-top:0}.q-timeline__heading:last-child .q-timeline__heading-title{padding-bottom:0}.q-timeline__heading-title{padding:32px 0;margin:0}.q-timeline__entry{position:relative;line-height:22px}.q-timeline__entry:last-child{padding-bottom:0!important}.q-timeline__entry:last-child .q-timeline__dot:after{content:none}.q-timeline__entry--icon .q-timeline__dot{width:31px}.q-timeline__entry--icon .q-timeline__dot:before{height:31px;width:31px}.q-timeline__entry--icon .q-timeline__dot:after{top:41px;left:14px}.q-timeline__entry--icon .q-timeline__subtitle{padding-top:8px}.q-timeline--dense--right .q-timeline__entry{padding-left:40px}.q-timeline--dense--right .q-timeline__entry--icon .q-timeline__dot{left:-8px}.q-timeline--dense--right .q-timeline__dot{left:0}.q-timeline--dense--left .q-timeline__heading{text-align:right}.q-timeline--dense--left .q-timeline__entry{padding-right:40px}.q-timeline--dense--left .q-timeline__entry--icon .q-timeline__dot{right:-8px}.q-timeline--dense--left .q-timeline__content,.q-timeline--dense--left .q-timeline__subtitle,.q-timeline--dense--left .q-timeline__title{text-align:right}.q-timeline--dense--left .q-timeline__dot{right:0}.q-timeline--comfortable{display:table}.q-timeline--comfortable .q-timeline__heading{display:table-row;font-size:200%}.q-timeline--comfortable .q-timeline__heading>div{display:table-cell}.q-timeline--comfortable .q-timeline__entry{display:table-row;padding:0}.q-timeline--comfortable .q-timeline__entry--icon .q-timeline__content{padding-top:8px}.q-timeline--comfortable .q-timeline__content,.q-timeline--comfortable .q-timeline__dot,.q-timeline--comfortable .q-timeline__subtitle{display:table-cell;vertical-align:top}.q-timeline--comfortable .q-timeline__subtitle{width:35%}.q-timeline--comfortable .q-timeline__dot{position:relative;min-width:31px}.q-timeline--comfortable--right .q-timeline__heading .q-timeline__heading-title{margin-left:-50px}.q-timeline--comfortable--right .q-timeline__subtitle{text-align:right;padding-right:30px}.q-timeline--comfortable--right .q-timeline__content{padding-left:30px}.q-timeline--comfortable--right .q-timeline__entry--icon .q-timeline__dot{left:-8px}.q-timeline--comfortable--left .q-timeline__heading{text-align:right}.q-timeline--comfortable--left .q-timeline__heading .q-timeline__heading-title{margin-right:-50px}.q-timeline--comfortable--left .q-timeline__subtitle{padding-left:30px}.q-timeline--comfortable--left .q-timeline__content{padding-right:30px}.q-timeline--comfortable--left .q-timeline__content,.q-timeline--comfortable--left .q-timeline__title{text-align:right}.q-timeline--comfortable--left .q-timeline__entry--icon .q-timeline__dot{right:0}.q-timeline--comfortable--left .q-timeline__dot{right:-8px}.q-timeline--loose .q-timeline__heading-title{text-align:center;margin-left:0}.q-timeline--loose .q-timeline__content,.q-timeline--loose .q-timeline__dot,.q-timeline--loose .q-timeline__entry,.q-timeline--loose .q-timeline__subtitle{display:block;margin:0;padding:0}.q-timeline--loose .q-timeline__dot{position:absolute;left:50%;margin-left:-7.15px}.q-timeline--loose .q-timeline__entry{padding-bottom:24px;overflow:hidden}.q-timeline--loose .q-timeline__entry--icon .q-timeline__dot{margin-left:-15px}.q-timeline--loose .q-timeline__entry--icon .q-timeline__subtitle{line-height:38px}.q-timeline--loose .q-timeline__entry--icon .q-timeline__content{padding-top:8px}.q-timeline--loose .q-timeline__entry--left .q-timeline__content,.q-timeline--loose .q-timeline__entry--right .q-timeline__subtitle{float:left;padding-right:30px;text-align:right}.q-timeline--loose .q-timeline__entry--left .q-timeline__subtitle,.q-timeline--loose .q-timeline__entry--right .q-timeline__content{float:right;text-align:left;padding-left:30px}.q-timeline--loose .q-timeline__content,.q-timeline--loose .q-timeline__subtitle{width:50%}.q-toggle{vertical-align:middle}.q-toggle__native{width:1px;height:1px}.q-toggle__track{height:.35em;border-radius:.175em;opacity:.38;background:currentColor}.q-toggle__thumb{top:.25em;left:.25em;width:.5em;height:.5em;transition:left .22s cubic-bezier(.4, 0, .2, 1);user-select:none;z-index:0}.q-toggle__thumb:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:#fff;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.q-toggle__thumb .q-icon{font-size:.3em;min-width:1em;color:#000;opacity:.54;z-index:1}.q-toggle__inner{font-size:40px;width:1.4em;min-width:1.4em;height:1em;padding:.325em .3em;-webkit-print-color-adjust:exact}.q-toggle__inner--indet .q-toggle__thumb{left:.45em}.q-toggle__inner--truthy{color:var(--q-primary)}.q-toggle__inner--truthy .q-toggle__track{opacity:.54}.q-toggle__inner--truthy .q-toggle__thumb{left:.65em}.q-toggle__inner--truthy .q-toggle__thumb:after{background-color:currentColor}.q-toggle__inner--truthy .q-toggle__thumb .q-icon{color:#fff;opacity:1}.q-toggle.disabled{opacity:.75!important}.q-toggle--dark .q-toggle__inner{color:#fff}.q-toggle--dark .q-toggle__inner--truthy{color:var(--q-primary)}.q-toggle--dark .q-toggle__thumb:after{box-shadow:none}.q-toggle--dark .q-toggle__thumb:before{opacity:.32!important}.q-toggle--dense .q-toggle__inner{width:.8em;min-width:.8em;height:.5em;padding:.07625em 0}.q-toggle--dense .q-toggle__thumb{top:0;left:0}.q-toggle--dense .q-toggle__inner--indet .q-toggle__thumb{left:.15em}.q-toggle--dense .q-toggle__inner--truthy .q-toggle__thumb{left:.3em}.q-toggle--dense .q-toggle__label{padding-left:.5em}.q-toggle--dense.reverse .q-toggle__label{padding-left:0;padding-right:.5em}body.desktop .q-toggle:not(.disabled) .q-toggle__thumb:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:currentColor;opacity:.12;transform:scale3d(0,0,1);transition:transform .22s cubic-bezier(0, 0, .2, 1)}body.desktop .q-toggle:not(.disabled):focus .q-toggle__thumb:before,body.desktop .q-toggle:not(.disabled):hover .q-toggle__thumb:before{transform:scale3d(2,2,1)}body.desktop .q-toggle--dense:not(.disabled):focus .q-toggle__thumb:before,body.desktop .q-toggle--dense:not(.disabled):hover .q-toggle__thumb:before{transform:scale3d(1.5,1.5,1)}.q-toolbar{position:relative;padding:0 12px;min-height:50px;width:100%}.q-toolbar--inset{padding-left:58px}.q-toolbar .q-avatar{font-size:38px}.q-toolbar__title{flex:1 1 0%;min-width:1px;max-width:100%;font-size:21px;font-weight:400;letter-spacing:.01em;padding:0 12px}.q-toolbar__title:first-child{padding-left:0}.q-toolbar__title:last-child{padding-right:0}.q-tooltip--style{font-size:10px;color:#fafafa;background:#757575;border-radius:4px;text-transform:none;font-weight:400}.q-tooltip{z-index:9000;position:fixed!important;overflow-y:auto;overflow-x:hidden;padding:6px 10px;max-width:95vw;max-height:65vh}@media (max-width:599.98px){.q-tooltip{font-size:14px;padding:8px 16px}}.q-tree{position:relative;color:#9e9e9e}.q-tree__node{padding:0 0 3px 22px}.q-tree__node:after{content:"";position:absolute;top:-3px;bottom:0;width:2px;right:auto;left:-13px;border-left:1px solid currentColor}.q-tree__node:last-child:after{display:none}.q-tree__node--disabled{pointer-events:none}.q-tree__node--disabled .disabled{opacity:1!important}.q-tree__node--disabled>.disabled,.q-tree__node--disabled>div,.q-tree__node--disabled>i{opacity:.6!important}.q-tree__node--disabled>.disabled .q-tree__node--disabled>.disabled,.q-tree__node--disabled>.disabled .q-tree__node--disabled>div,.q-tree__node--disabled>.disabled .q-tree__node--disabled>i,.q-tree__node--disabled>div .q-tree__node--disabled>.disabled,.q-tree__node--disabled>div .q-tree__node--disabled>div,.q-tree__node--disabled>div .q-tree__node--disabled>i,.q-tree__node--disabled>i .q-tree__node--disabled>.disabled,.q-tree__node--disabled>i .q-tree__node--disabled>div,.q-tree__node--disabled>i .q-tree__node--disabled>i{opacity:1!important}.q-tree__node-header:before{content:"";position:absolute;top:-3px;bottom:50%;width:31px;left:-35px;border-left:1px solid currentColor;border-bottom:1px solid currentColor}.q-tree__children{padding-left:25px}.q-tree__node-body{padding:5px 0 8px 5px}.q-tree__node--parent{padding-left:2px}.q-tree__node--parent>.q-tree__node-header:before{width:15px;left:-15px}.q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body{padding:5px 0 8px 27px}.q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body:after{content:"";position:absolute;top:0;width:2px;height:100%;right:auto;left:12px;border-left:1px solid currentColor;bottom:50px}.q-tree__node--link{cursor:pointer}.q-tree__node-header{padding:4px;margin-top:3px;border-radius:4px;outline:0}.q-tree__node-header-content{color:#000;transition:color .3s}.q-tree__node--selected .q-tree__node-header-content{color:#9e9e9e}.q-tree__icon,.q-tree__node-header-content .q-icon{font-size:21px}.q-tree__img{height:42px;border-radius:2px}.q-tree__avatar,.q-tree__node-header-content .q-avatar{font-size:28px;border-radius:50%;width:28px;height:28px}.q-tree__arrow,.q-tree__spinner{font-size:16px;margin-right:4px}.q-tree__arrow{transition:transform .3s}.q-tree__arrow--rotate{transform:rotate3d(0,0,1,90deg)}.q-tree__tickbox{margin-right:4px}.q-tree>.q-tree__node{padding:0}.q-tree>.q-tree__node:after,.q-tree>.q-tree__node>.q-tree__node-header:before{display:none}.q-tree>.q-tree__node--child>.q-tree__node-header{padding-left:24px}.q-tree--dark .q-tree__node-header-content{color:#fff}.q-tree--no-connectors .q-tree__node-body:after,.q-tree--no-connectors .q-tree__node-header:before,.q-tree--no-connectors .q-tree__node:after{display:none!important}.q-tree--dense>.q-tree__node--child>.q-tree__node-header{padding-left:1px}.q-tree--dense .q-tree__arrow,.q-tree--dense .q-tree__spinner{margin-right:1px}.q-tree--dense .q-tree__img{height:32px}.q-tree--dense .q-tree__tickbox{margin-right:3px}.q-tree--dense .q-tree__node{padding:0}.q-tree--dense .q-tree__node:after{top:0;left:-8px}.q-tree--dense .q-tree__node-header{margin-top:0;padding:1px}.q-tree--dense .q-tree__node-header:before{top:0;left:-8px;width:8px}.q-tree--dense .q-tree__node--child{padding-left:17px}.q-tree--dense .q-tree__node--child>.q-tree__node-header:before{left:-25px;width:21px}.q-tree--dense .q-tree__node-body{padding:0 0 2px}.q-tree--dense .q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body{padding:0 0 2px 20px}.q-tree--dense .q-tree__node--parent>.q-tree__node-collapsible>.q-tree__node-body:after{left:8px}.q-tree--dense .q-tree__children{padding-left:16px}[dir=rtl] .q-tree__arrow{transform:rotate3d(0,0,1,180deg)}[dir=rtl] .q-tree__arrow--rotate{transform:rotate3d(0,0,1,90deg)}.q-uploader{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;vertical-align:top;background:#fff;position:relative;width:320px;max-height:320px}.q-uploader--bordered{border:1px solid rgba(0,0,0,.12)}.q-uploader__input{opacity:0;width:100%;height:100%;cursor:pointer!important;z-index:1}.q-uploader__input::-webkit-file-upload-button{cursor:pointer}.q-uploader__file:before{content:"";border-top-left-radius:inherit;border-top-right-radius:inherit;position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;background:currentColor;opacity:.04}.q-uploader__header{position:relative;border-top-left-radius:inherit;border-top-right-radius:inherit;background-color:var(--q-primary);color:#fff;width:100%}.q-uploader__spinner{font-size:24px;margin-right:4px}.q-uploader__header-content{padding:8px}.q-uploader__dnd{outline:1px dashed currentColor;outline-offset:-4px;background:rgba(255,255,255,.6)}.q-uploader__overlay{font-size:36px;color:#000;background-color:rgba(255,255,255,.6)}.q-uploader__list{position:relative;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;padding:8px;min-height:60px;flex:1 1 auto}.q-uploader__file{border-radius:4px 4px 0 0;border:1px solid rgba(0,0,0,.12)}.q-uploader__file .q-circular-progress{font-size:24px}.q-uploader__file--img{color:#fff;height:200px;min-width:200px;background-position:50% 50%;background-repeat:no-repeat}.q-uploader__file--img:before{content:none}.q-uploader__file--img .q-circular-progress{color:#fff}.q-uploader__file--img .q-uploader__file-header{padding-bottom:24px;background:linear-gradient(to bottom,rgba(0,0,0,.7) 20%,rgba(255,255,255,0))}.q-uploader__file+.q-uploader__file{margin-top:8px}.q-uploader__file-header{position:relative;padding:4px 8px;border-top-left-radius:inherit;border-top-right-radius:inherit}.q-uploader__file-header-content{padding-right:8px}.q-uploader__file-status{font-size:24px;margin-right:4px}.q-uploader__title{font-size:14px;font-weight:700;line-height:1.285714;word-break:break-word}.q-uploader__subtitle{font-size:12px;line-height:1.5}.q-uploader--disable .q-uploader__header,.q-uploader--disable .q-uploader__list{pointer-events:none}.q-uploader--dark{border-color:rgba(255,255,255,.28);box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}.q-uploader--dark .q-uploader__file{border-color:rgba(255,255,255,.28)}.q-uploader--dark .q-uploader__dnd,.q-uploader--dark .q-uploader__overlay{background:rgba(255,255,255,.3)}.q-uploader--dark .q-uploader__overlay{color:#fff}img.responsive{max-width:100%;height:auto}.q-video{position:relative;overflow:hidden;border-radius:inherit}.q-video embed,.q-video iframe,.q-video object{width:100%;height:100%}.q-video--responsive{height:0}.q-video--responsive embed,.q-video--responsive iframe,.q-video--responsive object{position:absolute;top:0;left:0}.q-virtual-scroll:focus{outline:0}.q-virtual-scroll__content{outline:0;contain:content}.q-virtual-scroll__content>*{overflow-anchor:none}.q-virtual-scroll__content>[data-q-vs-anchor]{overflow-anchor:auto}.q-virtual-scroll__padding{background:linear-gradient(rgba(255,255,255,0),rgba(255,255,255,0) 20%,rgba(128,128,128,.03) 20%,rgba(128,128,128,.08) 50%,rgba(128,128,128,.03) 80%,rgba(255,255,255,0) 80%,rgba(255,255,255,0));background-size:var(--q-virtual-scroll-item-width,100%) var(--q-virtual-scroll-item-height,50px)}.q-table .q-virtual-scroll__padding tr{height:0!important}.q-table .q-virtual-scroll__padding td{padding:0!important}.q-virtual-scroll--horizontal{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:stretch}.q-virtual-scroll--horizontal .q-virtual-scroll__content{display:flex;flex-direction:row;flex-wrap:nowrap}.q-virtual-scroll--horizontal .q-virtual-scroll__content,.q-virtual-scroll--horizontal .q-virtual-scroll__content>*,.q-virtual-scroll--horizontal .q-virtual-scroll__padding{flex:0 0 auto}.q-virtual-scroll--horizontal .q-virtual-scroll__padding{background:linear-gradient(to left,rgba(255,255,255,0),rgba(255,255,255,0) 20%,rgba(128,128,128,.03) 20%,rgba(128,128,128,.08) 50%,rgba(128,128,128,.03) 80%,rgba(255,255,255,0) 80%,rgba(255,255,255,0));background-size:var(--q-virtual-scroll-item-width,50px) var(--q-virtual-scroll-item-height,100%)}.q-ripple{position:absolute;top:0;left:0;width:100%;height:100%;color:inherit;border-radius:inherit;z-index:0;pointer-events:none;overflow:hidden;contain:strict}.q-ripple__inner{position:absolute;top:0;left:0;opacity:0;color:inherit;border-radius:50%;background:currentColor;pointer-events:none;will-change:transform,opacity}.q-ripple__inner--enter{transition:transform 225ms cubic-bezier(.4, 0, .2, 1),opacity .1s cubic-bezier(.4, 0, .2, 1)}.q-ripple__inner--leave{transition:opacity .25s cubic-bezier(.4, 0, .2, 1)}.q-morph--internal,.q-morph--invisible{opacity:0!important;pointer-events:none!important;position:fixed!important;right:200vw!important;bottom:200vh!important}.q-bottom-sheet{padding-bottom:8px}.q-bottom-sheet__avatar{border-radius:50%}.q-bottom-sheet--list{width:400px}.q-bottom-sheet--list .q-icon,.q-bottom-sheet--list img{font-size:24px;width:24px;height:24px}.q-bottom-sheet--grid{width:700px}.q-bottom-sheet--grid .q-bottom-sheet__item{padding:8px;text-align:center;min-width:100px}.q-bottom-sheet--grid .q-bottom-sheet__empty-icon,.q-bottom-sheet--grid .q-icon,.q-bottom-sheet--grid img{font-size:48px;width:48px;height:48px;margin-bottom:8px}.q-bottom-sheet--grid .q-separator{margin:12px 0}.q-bottom-sheet__item{flex:0 0 33.3333%}@media (min-width:600px){.q-bottom-sheet__item{flex:0 0 25%}}.q-dialog-plugin{width:400px}.q-dialog-plugin__form{max-height:50vh}.q-dialog-plugin .q-card__section+.q-card__section{padding-top:0}.q-dialog-plugin--progress{text-align:center}.q-loading{color:#000;position:fixed!important}.q-loading__backdrop{position:fixed;top:0;right:0;bottom:0;left:0;opacity:.5;z-index:-1;background-color:#000;transition:background-color .28s}.q-loading__box{border-radius:4px;padding:18px;color:#fff;max-width:450px}.q-loading__message{margin:40px 20px 0;text-align:center}.q-notifications__list{z-index:9500;pointer-events:none;left:0;right:0;margin-bottom:10px;position:relative}.q-notifications__list--center{top:0;bottom:0}.q-notifications__list--top{top:0}.q-notifications__list--bottom{bottom:0}body.q-ios-padding .q-notifications__list--center,body.q-ios-padding .q-notifications__list--top{top:20px;top:env(safe-area-inset-top)}body.q-ios-padding .q-notifications__list--bottom,body.q-ios-padding .q-notifications__list--center{bottom:env(safe-area-inset-bottom)}.q-notification{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12);border-radius:4px;pointer-events:all;display:inline-flex;margin:10px 10px 0;transition:transform 1s,opacity 1s;z-index:9500;flex-shrink:0;max-width:95vw;background:#323232;color:#fff;font-size:14px}.q-notification__icon{font-size:24px;flex:0 0 1em}.q-notification__icon--additional{margin-right:16px}.q-notification__avatar{font-size:32px}.q-notification__avatar--additional{margin-right:8px}.q-notification__spinner{font-size:32px}.q-notification__spinner--additional{margin-right:8px}.q-notification__message{padding:8px 0}.q-notification__caption{font-size:.9em;opacity:.7}.q-notification__actions{color:var(--q-primary)}.q-notification__badge{animation:q-notif-badge .42s;padding:4px 8px;position:absolute;box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12);background-color:var(--q-negative);color:#fff;border-radius:4px;font-size:12px;line-height:12px}.q-notification__badge--top-left,.q-notification__badge--top-right{top:-6px}.q-notification__badge--bottom-left,.q-notification__badge--bottom-right{bottom:-6px}.q-notification__badge--bottom-left,.q-notification__badge--top-left{left:-22px}.q-notification__badge--bottom-right,.q-notification__badge--top-right{right:-22px}.q-notification__progress{z-index:-1;position:absolute;height:3px;bottom:0;left:-10px;right:-10px;animation:q-notif-progress linear;background:currentColor;opacity:.3;border-radius:4px 4px 0 0;transform-origin:0 50%;transform:scaleX(0)}.q-notification--standard{padding:0 16px;min-height:48px}.q-notification--standard .q-notification__actions{padding:6px 0 6px 8px;margin-right:-8px}.q-notification--multi-line{min-height:68px;padding:8px 16px}.q-notification--multi-line .q-notification__badge--top-left,.q-notification--multi-line .q-notification__badge--top-right{top:-15px}.q-notification--multi-line .q-notification__badge--bottom-left,.q-notification--multi-line .q-notification__badge--bottom-right{bottom:-15px}.q-notification--multi-line .q-notification__progress{bottom:-8px}.q-notification--multi-line .q-notification__actions{padding:0}.q-notification--multi-line .q-notification__actions--with-media{padding-left:25px}.q-notification--top-enter-from,.q-notification--top-leave-to,.q-notification--top-left-enter-from,.q-notification--top-left-leave-to,.q-notification--top-right-enter-from,.q-notification--top-right-leave-to{opacity:0;transform:translateY(-50px);z-index:9499}.q-notification--center-enter-from,.q-notification--center-leave-to,.q-notification--left-enter-from,.q-notification--left-leave-to,.q-notification--right-enter-from,.q-notification--right-leave-to{opacity:0;transform:rotateX(90deg);z-index:9499}.q-notification--bottom-enter-from,.q-notification--bottom-leave-to,.q-notification--bottom-left-enter-from,.q-notification--bottom-left-leave-to,.q-notification--bottom-right-enter-from,.q-notification--bottom-right-leave-to{opacity:0;transform:translateY(50px);z-index:9499}.q-notification--bottom-leave-active,.q-notification--bottom-left-leave-active,.q-notification--bottom-right-leave-active,.q-notification--center-leave-active,.q-notification--left-leave-active,.q-notification--right-leave-active,.q-notification--top-leave-active,.q-notification--top-left-leave-active,.q-notification--top-right-leave-active{position:absolute;z-index:9499;margin-left:0;margin-right:0}.q-notification--center-leave-active,.q-notification--top-leave-active{top:0}.q-notification--bottom-leave-active,.q-notification--bottom-left-leave-active,.q-notification--bottom-right-leave-active{bottom:0}@media (min-width:600px){.q-notification{max-width:65vw}}@keyframes q-notif-badge{15%{transform:translate3d(-25%,0,0) rotate3d(0,0,1,-5deg)}30%{transform:translate3d(20%,0,0) rotate3d(0,0,1,3deg)}45%{transform:translate3d(-15%,0,0) rotate3d(0,0,1,-3deg)}60%{transform:translate3d(10%,0,0) rotate3d(0,0,1,2deg)}75%{transform:translate3d(-5%,0,0) rotate3d(0,0,1,-1deg)}}@keyframes q-notif-progress{0%{transform:scaleX(1)}100%{transform:scaleX(0)}}:root{--animate-duration:0.3s;--animate-delay:0.3s;--animate-repeat:1}.animated{animation-duration:var(--animate-duration);animation-fill-mode:both}.animated.infinite{animation-iteration-count:infinite}.animated.hinge{animation-duration:2s}.animated.repeat-1{animation-iteration-count:var(--animate-repeat)}.animated.repeat-2{animation-iteration-count:calc(var(--animate-repeat) * 2)}.animated.repeat-3{animation-iteration-count:calc(var(--animate-repeat) * 3)}.animated.delay-1s{animation-delay:var(--animate-delay)}.animated.delay-2s{animation-delay:calc(var(--animate-delay) * 2)}.animated.delay-3s{animation-delay:calc(var(--animate-delay) * 3)}.animated.delay-4s{animation-delay:calc(var(--animate-delay) * 4)}.animated.delay-5s{animation-delay:calc(var(--animate-delay) * 5)}.animated.faster{animation-duration:calc(var(--animate-duration) / 2)}.animated.fast{animation-duration:calc(var(--animate-duration) * .8)}.animated.slow{animation-duration:calc(var(--animate-duration) * 2)}.animated.slower{animation-duration:calc(var(--animate-duration) * 3)}@media print,(prefers-reduced-motion:reduce){.animated{animation-duration:1ms!important;transition-duration:1ms!important;animation-iteration-count:1!important}.animated[class*=Out]{opacity:0}}.q-animate--scale{animation:q-scale .15s;animation-timing-function:cubic-bezier(0.25,0.8,0.25,1)}@keyframes q-scale{0%{transform:scale(1)}50%{transform:scale(1.04)}100%{transform:scale(1)}}.q-animate--fade{animation:q-fade .2s}@keyframes q-fade{0%{opacity:0}100%{opacity:1}}:root{--q-primary:#1976D2;--q-secondary:#26A69A;--q-accent:#9C27B0;--q-positive:#21BA45;--q-negative:#C10015;--q-info:#31CCEC;--q-warning:#F2C037;--q-dark:#1d1d1d;--q-dark-page:#121212}.text-dark{color:var(--q-dark)!important}.bg-dark{background:var(--q-dark)!important}.text-primary{color:var(--q-primary)!important}.bg-primary{background:var(--q-primary)!important}.text-secondary{color:var(--q-secondary)!important}.bg-secondary{background:var(--q-secondary)!important}.text-accent{color:var(--q-accent)!important}.bg-accent{background:var(--q-accent)!important}.text-positive{color:var(--q-positive)!important}.bg-positive{background:var(--q-positive)!important}.text-negative{color:var(--q-negative)!important}.bg-negative{background:var(--q-negative)!important}.text-info{color:var(--q-info)!important}.bg-info{background:var(--q-info)!important}.text-warning{color:var(--q-warning)!important}.bg-warning{background:var(--q-warning)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.text-transparent{color:transparent!important}.bg-transparent{background:0 0!important}.text-separator{color:rgba(0,0,0,.12)!important}.bg-separator{background:rgba(0,0,0,.12)!important}.text-dark-separator{color:rgba(255,255,255,.28)!important}.bg-dark-separator{background:rgba(255,255,255,.28)!important}.text-red{color:#f44336!important}.text-red-1{color:#ffebee!important}.text-red-2{color:#ffcdd2!important}.text-red-3{color:#ef9a9a!important}.text-red-4{color:#e57373!important}.text-red-5{color:#ef5350!important}.text-red-6{color:#f44336!important}.text-red-7{color:#e53935!important}.text-red-8{color:#d32f2f!important}.text-red-9{color:#c62828!important}.text-red-10{color:#b71c1c!important}.text-red-11{color:#ff8a80!important}.text-red-12{color:#ff5252!important}.text-red-13{color:#ff1744!important}.text-red-14{color:#d50000!important}.text-pink{color:#e91e63!important}.text-pink-1{color:#fce4ec!important}.text-pink-2{color:#f8bbd0!important}.text-pink-3{color:#f48fb1!important}.text-pink-4{color:#f06292!important}.text-pink-5{color:#ec407a!important}.text-pink-6{color:#e91e63!important}.text-pink-7{color:#d81b60!important}.text-pink-8{color:#c2185b!important}.text-pink-9{color:#ad1457!important}.text-pink-10{color:#880e4f!important}.text-pink-11{color:#ff80ab!important}.text-pink-12{color:#ff4081!important}.text-pink-13{color:#f50057!important}.text-pink-14{color:#c51162!important}.text-purple{color:#9c27b0!important}.text-purple-1{color:#f3e5f5!important}.text-purple-2{color:#e1bee7!important}.text-purple-3{color:#ce93d8!important}.text-purple-4{color:#ba68c8!important}.text-purple-5{color:#ab47bc!important}.text-purple-6{color:#9c27b0!important}.text-purple-7{color:#8e24aa!important}.text-purple-8{color:#7b1fa2!important}.text-purple-9{color:#6a1b9a!important}.text-purple-10{color:#4a148c!important}.text-purple-11{color:#ea80fc!important}.text-purple-12{color:#e040fb!important}.text-purple-13{color:#d500f9!important}.text-purple-14{color:#a0f!important}.text-deep-purple{color:#673ab7!important}.text-deep-purple-1{color:#ede7f6!important}.text-deep-purple-2{color:#d1c4e9!important}.text-deep-purple-3{color:#b39ddb!important}.text-deep-purple-4{color:#9575cd!important}.text-deep-purple-5{color:#7e57c2!important}.text-deep-purple-6{color:#673ab7!important}.text-deep-purple-7{color:#5e35b1!important}.text-deep-purple-8{color:#512da8!important}.text-deep-purple-9{color:#4527a0!important}.text-deep-purple-10{color:#311b92!important}.text-deep-purple-11{color:#b388ff!important}.text-deep-purple-12{color:#7c4dff!important}.text-deep-purple-13{color:#651fff!important}.text-deep-purple-14{color:#6200ea!important}.text-indigo{color:#3f51b5!important}.text-indigo-1{color:#e8eaf6!important}.text-indigo-2{color:#c5cae9!important}.text-indigo-3{color:#9fa8da!important}.text-indigo-4{color:#7986cb!important}.text-indigo-5{color:#5c6bc0!important}.text-indigo-6{color:#3f51b5!important}.text-indigo-7{color:#3949ab!important}.text-indigo-8{color:#303f9f!important}.text-indigo-9{color:#283593!important}.text-indigo-10{color:#1a237e!important}.text-indigo-11{color:#8c9eff!important}.text-indigo-12{color:#536dfe!important}.text-indigo-13{color:#3d5afe!important}.text-indigo-14{color:#304ffe!important}.text-blue{color:#2196f3!important}.text-blue-1{color:#e3f2fd!important}.text-blue-2{color:#bbdefb!important}.text-blue-3{color:#90caf9!important}.text-blue-4{color:#64b5f6!important}.text-blue-5{color:#42a5f5!important}.text-blue-6{color:#2196f3!important}.text-blue-7{color:#1e88e5!important}.text-blue-8{color:#1976d2!important}.text-blue-9{color:#1565c0!important}.text-blue-10{color:#0d47a1!important}.text-blue-11{color:#82b1ff!important}.text-blue-12{color:#448aff!important}.text-blue-13{color:#2979ff!important}.text-blue-14{color:#2962ff!important}.text-light-blue{color:#03a9f4!important}.text-light-blue-1{color:#e1f5fe!important}.text-light-blue-2{color:#b3e5fc!important}.text-light-blue-3{color:#81d4fa!important}.text-light-blue-4{color:#4fc3f7!important}.text-light-blue-5{color:#29b6f6!important}.text-light-blue-6{color:#03a9f4!important}.text-light-blue-7{color:#039be5!important}.text-light-blue-8{color:#0288d1!important}.text-light-blue-9{color:#0277bd!important}.text-light-blue-10{color:#01579b!important}.text-light-blue-11{color:#80d8ff!important}.text-light-blue-12{color:#40c4ff!important}.text-light-blue-13{color:#00b0ff!important}.text-light-blue-14{color:#0091ea!important}.text-cyan{color:#00bcd4!important}.text-cyan-1{color:#e0f7fa!important}.text-cyan-2{color:#b2ebf2!important}.text-cyan-3{color:#80deea!important}.text-cyan-4{color:#4dd0e1!important}.text-cyan-5{color:#26c6da!important}.text-cyan-6{color:#00bcd4!important}.text-cyan-7{color:#00acc1!important}.text-cyan-8{color:#0097a7!important}.text-cyan-9{color:#00838f!important}.text-cyan-10{color:#006064!important}.text-cyan-11{color:#84ffff!important}.text-cyan-12{color:#18ffff!important}.text-cyan-13{color:#00e5ff!important}.text-cyan-14{color:#00b8d4!important}.text-teal{color:#009688!important}.text-teal-1{color:#e0f2f1!important}.text-teal-2{color:#b2dfdb!important}.text-teal-3{color:#80cbc4!important}.text-teal-4{color:#4db6ac!important}.text-teal-5{color:#26a69a!important}.text-teal-6{color:#009688!important}.text-teal-7{color:#00897b!important}.text-teal-8{color:#00796b!important}.text-teal-9{color:#00695c!important}.text-teal-10{color:#004d40!important}.text-teal-11{color:#a7ffeb!important}.text-teal-12{color:#64ffda!important}.text-teal-13{color:#1de9b6!important}.text-teal-14{color:#00bfa5!important}.text-green{color:#4caf50!important}.text-green-1{color:#e8f5e9!important}.text-green-2{color:#c8e6c9!important}.text-green-3{color:#a5d6a7!important}.text-green-4{color:#81c784!important}.text-green-5{color:#66bb6a!important}.text-green-6{color:#4caf50!important}.text-green-7{color:#43a047!important}.text-green-8{color:#388e3c!important}.text-green-9{color:#2e7d32!important}.text-green-10{color:#1b5e20!important}.text-green-11{color:#b9f6ca!important}.text-green-12{color:#69f0ae!important}.text-green-13{color:#00e676!important}.text-green-14{color:#00c853!important}.text-light-green{color:#8bc34a!important}.text-light-green-1{color:#f1f8e9!important}.text-light-green-2{color:#dcedc8!important}.text-light-green-3{color:#c5e1a5!important}.text-light-green-4{color:#aed581!important}.text-light-green-5{color:#9ccc65!important}.text-light-green-6{color:#8bc34a!important}.text-light-green-7{color:#7cb342!important}.text-light-green-8{color:#689f38!important}.text-light-green-9{color:#558b2f!important}.text-light-green-10{color:#33691e!important}.text-light-green-11{color:#ccff90!important}.text-light-green-12{color:#b2ff59!important}.text-light-green-13{color:#76ff03!important}.text-light-green-14{color:#64dd17!important}.text-lime{color:#cddc39!important}.text-lime-1{color:#f9fbe7!important}.text-lime-2{color:#f0f4c3!important}.text-lime-3{color:#e6ee9c!important}.text-lime-4{color:#dce775!important}.text-lime-5{color:#d4e157!important}.text-lime-6{color:#cddc39!important}.text-lime-7{color:#c0ca33!important}.text-lime-8{color:#afb42b!important}.text-lime-9{color:#9e9d24!important}.text-lime-10{color:#827717!important}.text-lime-11{color:#f4ff81!important}.text-lime-12{color:#eeff41!important}.text-lime-13{color:#c6ff00!important}.text-lime-14{color:#aeea00!important}.text-yellow{color:#ffeb3b!important}.text-yellow-1{color:#fffde7!important}.text-yellow-2{color:#fff9c4!important}.text-yellow-3{color:#fff59d!important}.text-yellow-4{color:#fff176!important}.text-yellow-5{color:#ffee58!important}.text-yellow-6{color:#ffeb3b!important}.text-yellow-7{color:#fdd835!important}.text-yellow-8{color:#fbc02d!important}.text-yellow-9{color:#f9a825!important}.text-yellow-10{color:#f57f17!important}.text-yellow-11{color:#ffff8d!important}.text-yellow-12{color:#ff0!important}.text-yellow-13{color:#ffea00!important}.text-yellow-14{color:#ffd600!important}.text-amber{color:#ffc107!important}.text-amber-1{color:#fff8e1!important}.text-amber-2{color:#ffecb3!important}.text-amber-3{color:#ffe082!important}.text-amber-4{color:#ffd54f!important}.text-amber-5{color:#ffca28!important}.text-amber-6{color:#ffc107!important}.text-amber-7{color:#ffb300!important}.text-amber-8{color:#ffa000!important}.text-amber-9{color:#ff8f00!important}.text-amber-10{color:#ff6f00!important}.text-amber-11{color:#ffe57f!important}.text-amber-12{color:#ffd740!important}.text-amber-13{color:#ffc400!important}.text-amber-14{color:#ffab00!important}.text-orange{color:#ff9800!important}.text-orange-1{color:#fff3e0!important}.text-orange-2{color:#ffe0b2!important}.text-orange-3{color:#ffcc80!important}.text-orange-4{color:#ffb74d!important}.text-orange-5{color:#ffa726!important}.text-orange-6{color:#ff9800!important}.text-orange-7{color:#fb8c00!important}.text-orange-8{color:#f57c00!important}.text-orange-9{color:#ef6c00!important}.text-orange-10{color:#e65100!important}.text-orange-11{color:#ffd180!important}.text-orange-12{color:#ffab40!important}.text-orange-13{color:#ff9100!important}.text-orange-14{color:#ff6d00!important}.text-deep-orange{color:#ff5722!important}.text-deep-orange-1{color:#fbe9e7!important}.text-deep-orange-2{color:#ffccbc!important}.text-deep-orange-3{color:#ffab91!important}.text-deep-orange-4{color:#ff8a65!important}.text-deep-orange-5{color:#ff7043!important}.text-deep-orange-6{color:#ff5722!important}.text-deep-orange-7{color:#f4511e!important}.text-deep-orange-8{color:#e64a19!important}.text-deep-orange-9{color:#d84315!important}.text-deep-orange-10{color:#bf360c!important}.text-deep-orange-11{color:#ff9e80!important}.text-deep-orange-12{color:#ff6e40!important}.text-deep-orange-13{color:#ff3d00!important}.text-deep-orange-14{color:#dd2c00!important}.text-brown{color:#795548!important}.text-brown-1{color:#efebe9!important}.text-brown-2{color:#d7ccc8!important}.text-brown-3{color:#bcaaa4!important}.text-brown-4{color:#a1887f!important}.text-brown-5{color:#8d6e63!important}.text-brown-6{color:#795548!important}.text-brown-7{color:#6d4c41!important}.text-brown-8{color:#5d4037!important}.text-brown-9{color:#4e342e!important}.text-brown-10{color:#3e2723!important}.text-brown-11{color:#d7ccc8!important}.text-brown-12{color:#bcaaa4!important}.text-brown-13{color:#8d6e63!important}.text-brown-14{color:#5d4037!important}.text-grey{color:#9e9e9e!important}.text-grey-1{color:#fafafa!important}.text-grey-2{color:#f5f5f5!important}.text-grey-3{color:#eee!important}.text-grey-4{color:#e0e0e0!important}.text-grey-5{color:#bdbdbd!important}.text-grey-6{color:#9e9e9e!important}.text-grey-7{color:#757575!important}.text-grey-8{color:#616161!important}.text-grey-9{color:#424242!important}.text-grey-10{color:#212121!important}.text-grey-11{color:#f5f5f5!important}.text-grey-12{color:#eee!important}.text-grey-13{color:#bdbdbd!important}.text-grey-14{color:#616161!important}.text-blue-grey{color:#607d8b!important}.text-blue-grey-1{color:#eceff1!important}.text-blue-grey-2{color:#cfd8dc!important}.text-blue-grey-3{color:#b0bec5!important}.text-blue-grey-4{color:#90a4ae!important}.text-blue-grey-5{color:#78909c!important}.text-blue-grey-6{color:#607d8b!important}.text-blue-grey-7{color:#546e7a!important}.text-blue-grey-8{color:#455a64!important}.text-blue-grey-9{color:#37474f!important}.text-blue-grey-10{color:#263238!important}.text-blue-grey-11{color:#cfd8dc!important}.text-blue-grey-12{color:#b0bec5!important}.text-blue-grey-13{color:#78909c!important}.text-blue-grey-14{color:#455a64!important}.bg-red{background:#f44336!important}.bg-red-1{background:#ffebee!important}.bg-red-2{background:#ffcdd2!important}.bg-red-3{background:#ef9a9a!important}.bg-red-4{background:#e57373!important}.bg-red-5{background:#ef5350!important}.bg-red-6{background:#f44336!important}.bg-red-7{background:#e53935!important}.bg-red-8{background:#d32f2f!important}.bg-red-9{background:#c62828!important}.bg-red-10{background:#b71c1c!important}.bg-red-11{background:#ff8a80!important}.bg-red-12{background:#ff5252!important}.bg-red-13{background:#ff1744!important}.bg-red-14{background:#d50000!important}.bg-pink{background:#e91e63!important}.bg-pink-1{background:#fce4ec!important}.bg-pink-2{background:#f8bbd0!important}.bg-pink-3{background:#f48fb1!important}.bg-pink-4{background:#f06292!important}.bg-pink-5{background:#ec407a!important}.bg-pink-6{background:#e91e63!important}.bg-pink-7{background:#d81b60!important}.bg-pink-8{background:#c2185b!important}.bg-pink-9{background:#ad1457!important}.bg-pink-10{background:#880e4f!important}.bg-pink-11{background:#ff80ab!important}.bg-pink-12{background:#ff4081!important}.bg-pink-13{background:#f50057!important}.bg-pink-14{background:#c51162!important}.bg-purple{background:#9c27b0!important}.bg-purple-1{background:#f3e5f5!important}.bg-purple-2{background:#e1bee7!important}.bg-purple-3{background:#ce93d8!important}.bg-purple-4{background:#ba68c8!important}.bg-purple-5{background:#ab47bc!important}.bg-purple-6{background:#9c27b0!important}.bg-purple-7{background:#8e24aa!important}.bg-purple-8{background:#7b1fa2!important}.bg-purple-9{background:#6a1b9a!important}.bg-purple-10{background:#4a148c!important}.bg-purple-11{background:#ea80fc!important}.bg-purple-12{background:#e040fb!important}.bg-purple-13{background:#d500f9!important}.bg-purple-14{background:#a0f!important}.bg-deep-purple{background:#673ab7!important}.bg-deep-purple-1{background:#ede7f6!important}.bg-deep-purple-2{background:#d1c4e9!important}.bg-deep-purple-3{background:#b39ddb!important}.bg-deep-purple-4{background:#9575cd!important}.bg-deep-purple-5{background:#7e57c2!important}.bg-deep-purple-6{background:#673ab7!important}.bg-deep-purple-7{background:#5e35b1!important}.bg-deep-purple-8{background:#512da8!important}.bg-deep-purple-9{background:#4527a0!important}.bg-deep-purple-10{background:#311b92!important}.bg-deep-purple-11{background:#b388ff!important}.bg-deep-purple-12{background:#7c4dff!important}.bg-deep-purple-13{background:#651fff!important}.bg-deep-purple-14{background:#6200ea!important}.bg-indigo{background:#3f51b5!important}.bg-indigo-1{background:#e8eaf6!important}.bg-indigo-2{background:#c5cae9!important}.bg-indigo-3{background:#9fa8da!important}.bg-indigo-4{background:#7986cb!important}.bg-indigo-5{background:#5c6bc0!important}.bg-indigo-6{background:#3f51b5!important}.bg-indigo-7{background:#3949ab!important}.bg-indigo-8{background:#303f9f!important}.bg-indigo-9{background:#283593!important}.bg-indigo-10{background:#1a237e!important}.bg-indigo-11{background:#8c9eff!important}.bg-indigo-12{background:#536dfe!important}.bg-indigo-13{background:#3d5afe!important}.bg-indigo-14{background:#304ffe!important}.bg-blue{background:#2196f3!important}.bg-blue-1{background:#e3f2fd!important}.bg-blue-2{background:#bbdefb!important}.bg-blue-3{background:#90caf9!important}.bg-blue-4{background:#64b5f6!important}.bg-blue-5{background:#42a5f5!important}.bg-blue-6{background:#2196f3!important}.bg-blue-7{background:#1e88e5!important}.bg-blue-8{background:#1976d2!important}.bg-blue-9{background:#1565c0!important}.bg-blue-10{background:#0d47a1!important}.bg-blue-11{background:#82b1ff!important}.bg-blue-12{background:#448aff!important}.bg-blue-13{background:#2979ff!important}.bg-blue-14{background:#2962ff!important}.bg-light-blue{background:#03a9f4!important}.bg-light-blue-1{background:#e1f5fe!important}.bg-light-blue-2{background:#b3e5fc!important}.bg-light-blue-3{background:#81d4fa!important}.bg-light-blue-4{background:#4fc3f7!important}.bg-light-blue-5{background:#29b6f6!important}.bg-light-blue-6{background:#03a9f4!important}.bg-light-blue-7{background:#039be5!important}.bg-light-blue-8{background:#0288d1!important}.bg-light-blue-9{background:#0277bd!important}.bg-light-blue-10{background:#01579b!important}.bg-light-blue-11{background:#80d8ff!important}.bg-light-blue-12{background:#40c4ff!important}.bg-light-blue-13{background:#00b0ff!important}.bg-light-blue-14{background:#0091ea!important}.bg-cyan{background:#00bcd4!important}.bg-cyan-1{background:#e0f7fa!important}.bg-cyan-2{background:#b2ebf2!important}.bg-cyan-3{background:#80deea!important}.bg-cyan-4{background:#4dd0e1!important}.bg-cyan-5{background:#26c6da!important}.bg-cyan-6{background:#00bcd4!important}.bg-cyan-7{background:#00acc1!important}.bg-cyan-8{background:#0097a7!important}.bg-cyan-9{background:#00838f!important}.bg-cyan-10{background:#006064!important}.bg-cyan-11{background:#84ffff!important}.bg-cyan-12{background:#18ffff!important}.bg-cyan-13{background:#00e5ff!important}.bg-cyan-14{background:#00b8d4!important}.bg-teal{background:#009688!important}.bg-teal-1{background:#e0f2f1!important}.bg-teal-2{background:#b2dfdb!important}.bg-teal-3{background:#80cbc4!important}.bg-teal-4{background:#4db6ac!important}.bg-teal-5{background:#26a69a!important}.bg-teal-6{background:#009688!important}.bg-teal-7{background:#00897b!important}.bg-teal-8{background:#00796b!important}.bg-teal-9{background:#00695c!important}.bg-teal-10{background:#004d40!important}.bg-teal-11{background:#a7ffeb!important}.bg-teal-12{background:#64ffda!important}.bg-teal-13{background:#1de9b6!important}.bg-teal-14{background:#00bfa5!important}.bg-green{background:#4caf50!important}.bg-green-1{background:#e8f5e9!important}.bg-green-2{background:#c8e6c9!important}.bg-green-3{background:#a5d6a7!important}.bg-green-4{background:#81c784!important}.bg-green-5{background:#66bb6a!important}.bg-green-6{background:#4caf50!important}.bg-green-7{background:#43a047!important}.bg-green-8{background:#388e3c!important}.bg-green-9{background:#2e7d32!important}.bg-green-10{background:#1b5e20!important}.bg-green-11{background:#b9f6ca!important}.bg-green-12{background:#69f0ae!important}.bg-green-13{background:#00e676!important}.bg-green-14{background:#00c853!important}.bg-light-green{background:#8bc34a!important}.bg-light-green-1{background:#f1f8e9!important}.bg-light-green-2{background:#dcedc8!important}.bg-light-green-3{background:#c5e1a5!important}.bg-light-green-4{background:#aed581!important}.bg-light-green-5{background:#9ccc65!important}.bg-light-green-6{background:#8bc34a!important}.bg-light-green-7{background:#7cb342!important}.bg-light-green-8{background:#689f38!important}.bg-light-green-9{background:#558b2f!important}.bg-light-green-10{background:#33691e!important}.bg-light-green-11{background:#ccff90!important}.bg-light-green-12{background:#b2ff59!important}.bg-light-green-13{background:#76ff03!important}.bg-light-green-14{background:#64dd17!important}.bg-lime{background:#cddc39!important}.bg-lime-1{background:#f9fbe7!important}.bg-lime-2{background:#f0f4c3!important}.bg-lime-3{background:#e6ee9c!important}.bg-lime-4{background:#dce775!important}.bg-lime-5{background:#d4e157!important}.bg-lime-6{background:#cddc39!important}.bg-lime-7{background:#c0ca33!important}.bg-lime-8{background:#afb42b!important}.bg-lime-9{background:#9e9d24!important}.bg-lime-10{background:#827717!important}.bg-lime-11{background:#f4ff81!important}.bg-lime-12{background:#eeff41!important}.bg-lime-13{background:#c6ff00!important}.bg-lime-14{background:#aeea00!important}.bg-yellow{background:#ffeb3b!important}.bg-yellow-1{background:#fffde7!important}.bg-yellow-2{background:#fff9c4!important}.bg-yellow-3{background:#fff59d!important}.bg-yellow-4{background:#fff176!important}.bg-yellow-5{background:#ffee58!important}.bg-yellow-6{background:#ffeb3b!important}.bg-yellow-7{background:#fdd835!important}.bg-yellow-8{background:#fbc02d!important}.bg-yellow-9{background:#f9a825!important}.bg-yellow-10{background:#f57f17!important}.bg-yellow-11{background:#ffff8d!important}.bg-yellow-12{background:#ff0!important}.bg-yellow-13{background:#ffea00!important}.bg-yellow-14{background:#ffd600!important}.bg-amber{background:#ffc107!important}.bg-amber-1{background:#fff8e1!important}.bg-amber-2{background:#ffecb3!important}.bg-amber-3{background:#ffe082!important}.bg-amber-4{background:#ffd54f!important}.bg-amber-5{background:#ffca28!important}.bg-amber-6{background:#ffc107!important}.bg-amber-7{background:#ffb300!important}.bg-amber-8{background:#ffa000!important}.bg-amber-9{background:#ff8f00!important}.bg-amber-10{background:#ff6f00!important}.bg-amber-11{background:#ffe57f!important}.bg-amber-12{background:#ffd740!important}.bg-amber-13{background:#ffc400!important}.bg-amber-14{background:#ffab00!important}.bg-orange{background:#ff9800!important}.bg-orange-1{background:#fff3e0!important}.bg-orange-2{background:#ffe0b2!important}.bg-orange-3{background:#ffcc80!important}.bg-orange-4{background:#ffb74d!important}.bg-orange-5{background:#ffa726!important}.bg-orange-6{background:#ff9800!important}.bg-orange-7{background:#fb8c00!important}.bg-orange-8{background:#f57c00!important}.bg-orange-9{background:#ef6c00!important}.bg-orange-10{background:#e65100!important}.bg-orange-11{background:#ffd180!important}.bg-orange-12{background:#ffab40!important}.bg-orange-13{background:#ff9100!important}.bg-orange-14{background:#ff6d00!important}.bg-deep-orange{background:#ff5722!important}.bg-deep-orange-1{background:#fbe9e7!important}.bg-deep-orange-2{background:#ffccbc!important}.bg-deep-orange-3{background:#ffab91!important}.bg-deep-orange-4{background:#ff8a65!important}.bg-deep-orange-5{background:#ff7043!important}.bg-deep-orange-6{background:#ff5722!important}.bg-deep-orange-7{background:#f4511e!important}.bg-deep-orange-8{background:#e64a19!important}.bg-deep-orange-9{background:#d84315!important}.bg-deep-orange-10{background:#bf360c!important}.bg-deep-orange-11{background:#ff9e80!important}.bg-deep-orange-12{background:#ff6e40!important}.bg-deep-orange-13{background:#ff3d00!important}.bg-deep-orange-14{background:#dd2c00!important}.bg-brown{background:#795548!important}.bg-brown-1{background:#efebe9!important}.bg-brown-2{background:#d7ccc8!important}.bg-brown-3{background:#bcaaa4!important}.bg-brown-4{background:#a1887f!important}.bg-brown-5{background:#8d6e63!important}.bg-brown-6{background:#795548!important}.bg-brown-7{background:#6d4c41!important}.bg-brown-8{background:#5d4037!important}.bg-brown-9{background:#4e342e!important}.bg-brown-10{background:#3e2723!important}.bg-brown-11{background:#d7ccc8!important}.bg-brown-12{background:#bcaaa4!important}.bg-brown-13{background:#8d6e63!important}.bg-brown-14{background:#5d4037!important}.bg-grey{background:#9e9e9e!important}.bg-grey-1{background:#fafafa!important}.bg-grey-2{background:#f5f5f5!important}.bg-grey-3{background:#eee!important}.bg-grey-4{background:#e0e0e0!important}.bg-grey-5{background:#bdbdbd!important}.bg-grey-6{background:#9e9e9e!important}.bg-grey-7{background:#757575!important}.bg-grey-8{background:#616161!important}.bg-grey-9{background:#424242!important}.bg-grey-10{background:#212121!important}.bg-grey-11{background:#f5f5f5!important}.bg-grey-12{background:#eee!important}.bg-grey-13{background:#bdbdbd!important}.bg-grey-14{background:#616161!important}.bg-blue-grey{background:#607d8b!important}.bg-blue-grey-1{background:#eceff1!important}.bg-blue-grey-2{background:#cfd8dc!important}.bg-blue-grey-3{background:#b0bec5!important}.bg-blue-grey-4{background:#90a4ae!important}.bg-blue-grey-5{background:#78909c!important}.bg-blue-grey-6{background:#607d8b!important}.bg-blue-grey-7{background:#546e7a!important}.bg-blue-grey-8{background:#455a64!important}.bg-blue-grey-9{background:#37474f!important}.bg-blue-grey-10{background:#263238!important}.bg-blue-grey-11{background:#cfd8dc!important}.bg-blue-grey-12{background:#b0bec5!important}.bg-blue-grey-13{background:#78909c!important}.bg-blue-grey-14{background:#455a64!important}.shadow-transition{transition:box-shadow .28s cubic-bezier(.4, 0, .2, 1)!important}.shadow-1{box-shadow:0 1px 3px rgba(0,0,0,.2),0 1px 1px rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12)}.shadow-up-1{box-shadow:0 -1px 3px rgba(0,0,0,.2),0 -1px 1px rgba(0,0,0,.14),0 -2px 1px -1px rgba(0,0,0,.12)}.shadow-2{box-shadow:0 1px 5px rgba(0,0,0,.2),0 2px 2px rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.12)}.shadow-up-2{box-shadow:0 -1px 5px rgba(0,0,0,.2),0 -2px 2px rgba(0,0,0,.14),0 -3px 1px -2px rgba(0,0,0,.12)}.shadow-3{box-shadow:0 1px 8px rgba(0,0,0,.2),0 3px 4px rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.12)}.shadow-up-3{box-shadow:0 -1px 8px rgba(0,0,0,.2),0 -3px 4px rgba(0,0,0,.14),0 -3px 3px -2px rgba(0,0,0,.12)}.shadow-4{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px rgba(0,0,0,.14),0 1px 10px rgba(0,0,0,.12)}.shadow-up-4{box-shadow:0 -2px 4px -1px rgba(0,0,0,.2),0 -4px 5px rgba(0,0,0,.14),0 -1px 10px rgba(0,0,0,.12)}.shadow-5{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px rgba(0,0,0,.14),0 1px 14px rgba(0,0,0,.12)}.shadow-up-5{box-shadow:0 -3px 5px -1px rgba(0,0,0,.2),0 -5px 8px rgba(0,0,0,.14),0 -1px 14px rgba(0,0,0,.12)}.shadow-6{box-shadow:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px rgba(0,0,0,.14),0 1px 18px rgba(0,0,0,.12)}.shadow-up-6{box-shadow:0 -3px 5px -1px rgba(0,0,0,.2),0 -6px 10px rgba(0,0,0,.14),0 -1px 18px rgba(0,0,0,.12)}.shadow-7{box-shadow:0 4px 5px -2px rgba(0,0,0,.2),0 7px 10px 1px rgba(0,0,0,.14),0 2px 16px 1px rgba(0,0,0,.12)}.shadow-up-7{box-shadow:0 -4px 5px -2px rgba(0,0,0,.2),0 -7px 10px 1px rgba(0,0,0,.14),0 -2px 16px 1px rgba(0,0,0,.12)}.shadow-8{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.shadow-up-8{box-shadow:0 -5px 5px -3px rgba(0,0,0,.2),0 -8px 10px 1px rgba(0,0,0,.14),0 -3px 14px 2px rgba(0,0,0,.12)}.shadow-9{box-shadow:0 5px 6px -3px rgba(0,0,0,.2),0 9px 12px 1px rgba(0,0,0,.14),0 3px 16px 2px rgba(0,0,0,.12)}.shadow-up-9{box-shadow:0 -5px 6px -3px rgba(0,0,0,.2),0 -9px 12px 1px rgba(0,0,0,.14),0 -3px 16px 2px rgba(0,0,0,.12)}.shadow-10{box-shadow:0 6px 6px -3px rgba(0,0,0,.2),0 10px 14px 1px rgba(0,0,0,.14),0 4px 18px 3px rgba(0,0,0,.12)}.shadow-up-10{box-shadow:0 -6px 6px -3px rgba(0,0,0,.2),0 -10px 14px 1px rgba(0,0,0,.14),0 -4px 18px 3px rgba(0,0,0,.12)}.shadow-11{box-shadow:0 6px 7px -4px rgba(0,0,0,.2),0 11px 15px 1px rgba(0,0,0,.14),0 4px 20px 3px rgba(0,0,0,.12)}.shadow-up-11{box-shadow:0 -6px 7px -4px rgba(0,0,0,.2),0 -11px 15px 1px rgba(0,0,0,.14),0 -4px 20px 3px rgba(0,0,0,.12)}.shadow-12{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 12px 17px 2px rgba(0,0,0,.14),0 5px 22px 4px rgba(0,0,0,.12)}.shadow-up-12{box-shadow:0 -7px 8px -4px rgba(0,0,0,.2),0 -12px 17px 2px rgba(0,0,0,.14),0 -5px 22px 4px rgba(0,0,0,.12)}.shadow-13{box-shadow:0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12)}.shadow-up-13{box-shadow:0 -7px 8px -4px rgba(0,0,0,.2),0 -13px 19px 2px rgba(0,0,0,.14),0 -5px 24px 4px rgba(0,0,0,.12)}.shadow-14{box-shadow:0 7px 9px -4px rgba(0,0,0,.2),0 14px 21px 2px rgba(0,0,0,.14),0 5px 26px 4px rgba(0,0,0,.12)}.shadow-up-14{box-shadow:0 -7px 9px -4px rgba(0,0,0,.2),0 -14px 21px 2px rgba(0,0,0,.14),0 -5px 26px 4px rgba(0,0,0,.12)}.shadow-15{box-shadow:0 8px 9px -5px rgba(0,0,0,.2),0 15px 22px 2px rgba(0,0,0,.14),0 6px 28px 5px rgba(0,0,0,.12)}.shadow-up-15{box-shadow:0 -8px 9px -5px rgba(0,0,0,.2),0 -15px 22px 2px rgba(0,0,0,.14),0 -6px 28px 5px rgba(0,0,0,.12)}.shadow-16{box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.shadow-up-16{box-shadow:0 -8px 10px -5px rgba(0,0,0,.2),0 -16px 24px 2px rgba(0,0,0,.14),0 -6px 30px 5px rgba(0,0,0,.12)}.shadow-17{box-shadow:0 8px 11px -5px rgba(0,0,0,.2),0 17px 26px 2px rgba(0,0,0,.14),0 6px 32px 5px rgba(0,0,0,.12)}.shadow-up-17{box-shadow:0 -8px 11px -5px rgba(0,0,0,.2),0 -17px 26px 2px rgba(0,0,0,.14),0 -6px 32px 5px rgba(0,0,0,.12)}.shadow-18{box-shadow:0 9px 11px -5px rgba(0,0,0,.2),0 18px 28px 2px rgba(0,0,0,.14),0 7px 34px 6px rgba(0,0,0,.12)}.shadow-up-18{box-shadow:0 -9px 11px -5px rgba(0,0,0,.2),0 -18px 28px 2px rgba(0,0,0,.14),0 -7px 34px 6px rgba(0,0,0,.12)}.shadow-19{box-shadow:0 9px 12px -6px rgba(0,0,0,.2),0 19px 29px 2px rgba(0,0,0,.14),0 7px 36px 6px rgba(0,0,0,.12)}.shadow-up-19{box-shadow:0 -9px 12px -6px rgba(0,0,0,.2),0 -19px 29px 2px rgba(0,0,0,.14),0 -7px 36px 6px rgba(0,0,0,.12)}.shadow-20{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 20px 31px 3px rgba(0,0,0,.14),0 8px 38px 7px rgba(0,0,0,.12)}.shadow-up-20{box-shadow:0 -10px 13px -6px rgba(0,0,0,.2),0 -20px 31px 3px rgba(0,0,0,.14),0 -8px 38px 7px rgba(0,0,0,.12)}.shadow-21{box-shadow:0 10px 13px -6px rgba(0,0,0,.2),0 21px 33px 3px rgba(0,0,0,.14),0 8px 40px 7px rgba(0,0,0,.12)}.shadow-up-21{box-shadow:0 -10px 13px -6px rgba(0,0,0,.2),0 -21px 33px 3px rgba(0,0,0,.14),0 -8px 40px 7px rgba(0,0,0,.12)}.shadow-22{box-shadow:0 10px 14px -6px rgba(0,0,0,.2),0 22px 35px 3px rgba(0,0,0,.14),0 8px 42px 7px rgba(0,0,0,.12)}.shadow-up-22{box-shadow:0 -10px 14px -6px rgba(0,0,0,.2),0 -22px 35px 3px rgba(0,0,0,.14),0 -8px 42px 7px rgba(0,0,0,.12)}.shadow-23{box-shadow:0 11px 14px -7px rgba(0,0,0,.2),0 23px 36px 3px rgba(0,0,0,.14),0 9px 44px 8px rgba(0,0,0,.12)}.shadow-up-23{box-shadow:0 -11px 14px -7px rgba(0,0,0,.2),0 -23px 36px 3px rgba(0,0,0,.14),0 -9px 44px 8px rgba(0,0,0,.12)}.shadow-24{box-shadow:0 11px 15px -7px rgba(0,0,0,.2),0 24px 38px 3px rgba(0,0,0,.14),0 9px 46px 8px rgba(0,0,0,.12)}.shadow-up-24{box-shadow:0 -11px 15px -7px rgba(0,0,0,.2),0 -24px 38px 3px rgba(0,0,0,.14),0 -9px 46px 8px rgba(0,0,0,.12)}.inset-shadow{box-shadow:0 7px 9px -7px rgba(0,0,0,.7) inset}.inset-shadow-down{box-shadow:0 -7px 9px -7px rgba(0,0,0,.7) inset}body.body--dark .shadow-1{box-shadow:0 1px 3px rgba(255,255,255,.2),0 1px 1px rgba(255,255,255,.14),0 2px 1px -1px rgba(255,255,255,.12)}body.body--dark .shadow-up-1{box-shadow:0 -1px 3px rgba(255,255,255,.2),0 -1px 1px rgba(255,255,255,.14),0 -2px 1px -1px rgba(255,255,255,.12)}body.body--dark .shadow-2{box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}body.body--dark .shadow-up-2{box-shadow:0 -1px 5px rgba(255,255,255,.2),0 -2px 2px rgba(255,255,255,.14),0 -3px 1px -2px rgba(255,255,255,.12)}body.body--dark .shadow-3{box-shadow:0 1px 8px rgba(255,255,255,.2),0 3px 4px rgba(255,255,255,.14),0 3px 3px -2px rgba(255,255,255,.12)}body.body--dark .shadow-up-3{box-shadow:0 -1px 8px rgba(255,255,255,.2),0 -3px 4px rgba(255,255,255,.14),0 -3px 3px -2px rgba(255,255,255,.12)}body.body--dark .shadow-4{box-shadow:0 2px 4px -1px rgba(255,255,255,.2),0 4px 5px rgba(255,255,255,.14),0 1px 10px rgba(255,255,255,.12)}body.body--dark .shadow-up-4{box-shadow:0 -2px 4px -1px rgba(255,255,255,.2),0 -4px 5px rgba(255,255,255,.14),0 -1px 10px rgba(255,255,255,.12)}body.body--dark .shadow-5{box-shadow:0 3px 5px -1px rgba(255,255,255,.2),0 5px 8px rgba(255,255,255,.14),0 1px 14px rgba(255,255,255,.12)}body.body--dark .shadow-up-5{box-shadow:0 -3px 5px -1px rgba(255,255,255,.2),0 -5px 8px rgba(255,255,255,.14),0 -1px 14px rgba(255,255,255,.12)}body.body--dark .shadow-6{box-shadow:0 3px 5px -1px rgba(255,255,255,.2),0 6px 10px rgba(255,255,255,.14),0 1px 18px rgba(255,255,255,.12)}body.body--dark .shadow-up-6{box-shadow:0 -3px 5px -1px rgba(255,255,255,.2),0 -6px 10px rgba(255,255,255,.14),0 -1px 18px rgba(255,255,255,.12)}body.body--dark .shadow-7{box-shadow:0 4px 5px -2px rgba(255,255,255,.2),0 7px 10px 1px rgba(255,255,255,.14),0 2px 16px 1px rgba(255,255,255,.12)}body.body--dark .shadow-up-7{box-shadow:0 -4px 5px -2px rgba(255,255,255,.2),0 -7px 10px 1px rgba(255,255,255,.14),0 -2px 16px 1px rgba(255,255,255,.12)}body.body--dark .shadow-8{box-shadow:0 5px 5px -3px rgba(255,255,255,.2),0 8px 10px 1px rgba(255,255,255,.14),0 3px 14px 2px rgba(255,255,255,.12)}body.body--dark .shadow-up-8{box-shadow:0 -5px 5px -3px rgba(255,255,255,.2),0 -8px 10px 1px rgba(255,255,255,.14),0 -3px 14px 2px rgba(255,255,255,.12)}body.body--dark .shadow-9{box-shadow:0 5px 6px -3px rgba(255,255,255,.2),0 9px 12px 1px rgba(255,255,255,.14),0 3px 16px 2px rgba(255,255,255,.12)}body.body--dark .shadow-up-9{box-shadow:0 -5px 6px -3px rgba(255,255,255,.2),0 -9px 12px 1px rgba(255,255,255,.14),0 -3px 16px 2px rgba(255,255,255,.12)}body.body--dark .shadow-10{box-shadow:0 6px 6px -3px rgba(255,255,255,.2),0 10px 14px 1px rgba(255,255,255,.14),0 4px 18px 3px rgba(255,255,255,.12)}body.body--dark .shadow-up-10{box-shadow:0 -6px 6px -3px rgba(255,255,255,.2),0 -10px 14px 1px rgba(255,255,255,.14),0 -4px 18px 3px rgba(255,255,255,.12)}body.body--dark .shadow-11{box-shadow:0 6px 7px -4px rgba(255,255,255,.2),0 11px 15px 1px rgba(255,255,255,.14),0 4px 20px 3px rgba(255,255,255,.12)}body.body--dark .shadow-up-11{box-shadow:0 -6px 7px -4px rgba(255,255,255,.2),0 -11px 15px 1px rgba(255,255,255,.14),0 -4px 20px 3px rgba(255,255,255,.12)}body.body--dark .shadow-12{box-shadow:0 7px 8px -4px rgba(255,255,255,.2),0 12px 17px 2px rgba(255,255,255,.14),0 5px 22px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-12{box-shadow:0 -7px 8px -4px rgba(255,255,255,.2),0 -12px 17px 2px rgba(255,255,255,.14),0 -5px 22px 4px rgba(255,255,255,.12)}body.body--dark .shadow-13{box-shadow:0 7px 8px -4px rgba(255,255,255,.2),0 13px 19px 2px rgba(255,255,255,.14),0 5px 24px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-13{box-shadow:0 -7px 8px -4px rgba(255,255,255,.2),0 -13px 19px 2px rgba(255,255,255,.14),0 -5px 24px 4px rgba(255,255,255,.12)}body.body--dark .shadow-14{box-shadow:0 7px 9px -4px rgba(255,255,255,.2),0 14px 21px 2px rgba(255,255,255,.14),0 5px 26px 4px rgba(255,255,255,.12)}body.body--dark .shadow-up-14{box-shadow:0 -7px 9px -4px rgba(255,255,255,.2),0 -14px 21px 2px rgba(255,255,255,.14),0 -5px 26px 4px rgba(255,255,255,.12)}body.body--dark .shadow-15{box-shadow:0 8px 9px -5px rgba(255,255,255,.2),0 15px 22px 2px rgba(255,255,255,.14),0 6px 28px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-15{box-shadow:0 -8px 9px -5px rgba(255,255,255,.2),0 -15px 22px 2px rgba(255,255,255,.14),0 -6px 28px 5px rgba(255,255,255,.12)}body.body--dark .shadow-16{box-shadow:0 8px 10px -5px rgba(255,255,255,.2),0 16px 24px 2px rgba(255,255,255,.14),0 6px 30px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-16{box-shadow:0 -8px 10px -5px rgba(255,255,255,.2),0 -16px 24px 2px rgba(255,255,255,.14),0 -6px 30px 5px rgba(255,255,255,.12)}body.body--dark .shadow-17{box-shadow:0 8px 11px -5px rgba(255,255,255,.2),0 17px 26px 2px rgba(255,255,255,.14),0 6px 32px 5px rgba(255,255,255,.12)}body.body--dark .shadow-up-17{box-shadow:0 -8px 11px -5px rgba(255,255,255,.2),0 -17px 26px 2px rgba(255,255,255,.14),0 -6px 32px 5px rgba(255,255,255,.12)}body.body--dark .shadow-18{box-shadow:0 9px 11px -5px rgba(255,255,255,.2),0 18px 28px 2px rgba(255,255,255,.14),0 7px 34px 6px rgba(255,255,255,.12)}body.body--dark .shadow-up-18{box-shadow:0 -9px 11px -5px rgba(255,255,255,.2),0 -18px 28px 2px rgba(255,255,255,.14),0 -7px 34px 6px rgba(255,255,255,.12)}body.body--dark .shadow-19{box-shadow:0 9px 12px -6px rgba(255,255,255,.2),0 19px 29px 2px rgba(255,255,255,.14),0 7px 36px 6px rgba(255,255,255,.12)}body.body--dark .shadow-up-19{box-shadow:0 -9px 12px -6px rgba(255,255,255,.2),0 -19px 29px 2px rgba(255,255,255,.14),0 -7px 36px 6px rgba(255,255,255,.12)}body.body--dark .shadow-20{box-shadow:0 10px 13px -6px rgba(255,255,255,.2),0 20px 31px 3px rgba(255,255,255,.14),0 8px 38px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-20{box-shadow:0 -10px 13px -6px rgba(255,255,255,.2),0 -20px 31px 3px rgba(255,255,255,.14),0 -8px 38px 7px rgba(255,255,255,.12)}body.body--dark .shadow-21{box-shadow:0 10px 13px -6px rgba(255,255,255,.2),0 21px 33px 3px rgba(255,255,255,.14),0 8px 40px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-21{box-shadow:0 -10px 13px -6px rgba(255,255,255,.2),0 -21px 33px 3px rgba(255,255,255,.14),0 -8px 40px 7px rgba(255,255,255,.12)}body.body--dark .shadow-22{box-shadow:0 10px 14px -6px rgba(255,255,255,.2),0 22px 35px 3px rgba(255,255,255,.14),0 8px 42px 7px rgba(255,255,255,.12)}body.body--dark .shadow-up-22{box-shadow:0 -10px 14px -6px rgba(255,255,255,.2),0 -22px 35px 3px rgba(255,255,255,.14),0 -8px 42px 7px rgba(255,255,255,.12)}body.body--dark .shadow-23{box-shadow:0 11px 14px -7px rgba(255,255,255,.2),0 23px 36px 3px rgba(255,255,255,.14),0 9px 44px 8px rgba(255,255,255,.12)}body.body--dark .shadow-up-23{box-shadow:0 -11px 14px -7px rgba(255,255,255,.2),0 -23px 36px 3px rgba(255,255,255,.14),0 -9px 44px 8px rgba(255,255,255,.12)}body.body--dark .shadow-24{box-shadow:0 11px 15px -7px rgba(255,255,255,.2),0 24px 38px 3px rgba(255,255,255,.14),0 9px 46px 8px rgba(255,255,255,.12)}body.body--dark .shadow-up-24{box-shadow:0 -11px 15px -7px rgba(255,255,255,.2),0 -24px 38px 3px rgba(255,255,255,.14),0 -9px 46px 8px rgba(255,255,255,.12)}body.body--dark .inset-shadow{box-shadow:0 7px 9px -7px rgba(255,255,255,.7) inset}body.body--dark .inset-shadow-down{box-shadow:0 -7px 9px -7px rgba(255,255,255,.7) inset}.no-shadow,.shadow-0{box-shadow:none!important}.z-marginals{z-index:2000}.z-notify{z-index:9500}.z-fullscreen{z-index:6000}.z-inherit{z-index:inherit!important}.column,.flex,.row{display:flex;flex-wrap:wrap}.column.inline,.flex.inline,.row.inline{display:inline-flex}.row.reverse{flex-direction:row-reverse}.column{flex-direction:column}.column.reverse{flex-direction:column-reverse}.wrap{flex-wrap:wrap}.no-wrap{flex-wrap:nowrap}.reverse-wrap{flex-wrap:wrap-reverse}.order-first{order:-10000}.order-last{order:10000}.order-none{order:0}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.flex-center,.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.flex-center,.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-center{align-content:center}.content-stretch{align-content:stretch}.content-between{align-content:space-between}.content-around{align-content:space-around}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-baseline{align-self:baseline}.self-stretch{align-self:stretch}.q-gutter-none,.q-gutter-x-none{margin-left:0}.q-gutter-none>*,.q-gutter-x-none>*{margin-left:0}.q-gutter-none,.q-gutter-y-none{margin-top:0}.q-gutter-none>*,.q-gutter-y-none>*{margin-top:0}.q-col-gutter-none,.q-col-gutter-x-none{margin-left:0}.q-col-gutter-none>*,.q-col-gutter-x-none>*{padding-left:0}.q-col-gutter-none,.q-col-gutter-y-none{margin-top:0}.q-col-gutter-none>*,.q-col-gutter-y-none>*{padding-top:0}.q-gutter-x-xs,.q-gutter-xs{margin-left:-4px}.q-gutter-x-xs>*,.q-gutter-xs>*{margin-left:4px}.q-gutter-xs,.q-gutter-y-xs{margin-top:-4px}.q-gutter-xs>*,.q-gutter-y-xs>*{margin-top:4px}.q-col-gutter-x-xs,.q-col-gutter-xs{margin-left:-4px}.q-col-gutter-x-xs>*,.q-col-gutter-xs>*{padding-left:4px}.q-col-gutter-xs,.q-col-gutter-y-xs{margin-top:-4px}.q-col-gutter-xs>*,.q-col-gutter-y-xs>*{padding-top:4px}.q-gutter-sm,.q-gutter-x-sm{margin-left:-8px}.q-gutter-sm>*,.q-gutter-x-sm>*{margin-left:8px}.q-gutter-sm,.q-gutter-y-sm{margin-top:-8px}.q-gutter-sm>*,.q-gutter-y-sm>*{margin-top:8px}.q-col-gutter-sm,.q-col-gutter-x-sm{margin-left:-8px}.q-col-gutter-sm>*,.q-col-gutter-x-sm>*{padding-left:8px}.q-col-gutter-sm,.q-col-gutter-y-sm{margin-top:-8px}.q-col-gutter-sm>*,.q-col-gutter-y-sm>*{padding-top:8px}.q-gutter-md,.q-gutter-x-md{margin-left:-16px}.q-gutter-md>*,.q-gutter-x-md>*{margin-left:16px}.q-gutter-md,.q-gutter-y-md{margin-top:-16px}.q-gutter-md>*,.q-gutter-y-md>*{margin-top:16px}.q-col-gutter-md,.q-col-gutter-x-md{margin-left:-16px}.q-col-gutter-md>*,.q-col-gutter-x-md>*{padding-left:16px}.q-col-gutter-md,.q-col-gutter-y-md{margin-top:-16px}.q-col-gutter-md>*,.q-col-gutter-y-md>*{padding-top:16px}.q-gutter-lg,.q-gutter-x-lg{margin-left:-24px}.q-gutter-lg>*,.q-gutter-x-lg>*{margin-left:24px}.q-gutter-lg,.q-gutter-y-lg{margin-top:-24px}.q-gutter-lg>*,.q-gutter-y-lg>*{margin-top:24px}.q-col-gutter-lg,.q-col-gutter-x-lg{margin-left:-24px}.q-col-gutter-lg>*,.q-col-gutter-x-lg>*{padding-left:24px}.q-col-gutter-lg,.q-col-gutter-y-lg{margin-top:-24px}.q-col-gutter-lg>*,.q-col-gutter-y-lg>*{padding-top:24px}.q-gutter-x-xl,.q-gutter-xl{margin-left:-48px}.q-gutter-x-xl>*,.q-gutter-xl>*{margin-left:48px}.q-gutter-xl,.q-gutter-y-xl{margin-top:-48px}.q-gutter-xl>*,.q-gutter-y-xl>*{margin-top:48px}.q-col-gutter-x-xl,.q-col-gutter-xl{margin-left:-48px}.q-col-gutter-x-xl>*,.q-col-gutter-xl>*{padding-left:48px}.q-col-gutter-xl,.q-col-gutter-y-xl{margin-top:-48px}.q-col-gutter-xl>*,.q-col-gutter-y-xl>*{padding-top:48px}@media (min-width:0){.flex>.col,.flex>.col-0,.flex>.col-1,.flex>.col-10,.flex>.col-11,.flex>.col-12,.flex>.col-2,.flex>.col-3,.flex>.col-4,.flex>.col-5,.flex>.col-6,.flex>.col-7,.flex>.col-8,.flex>.col-9,.flex>.col-auto,.flex>.col-grow,.flex>.col-shrink,.flex>.col-xs,.flex>.col-xs-0,.flex>.col-xs-1,.flex>.col-xs-10,.flex>.col-xs-11,.flex>.col-xs-12,.flex>.col-xs-2,.flex>.col-xs-3,.flex>.col-xs-4,.flex>.col-xs-5,.flex>.col-xs-6,.flex>.col-xs-7,.flex>.col-xs-8,.flex>.col-xs-9,.flex>.col-xs-auto,.flex>.col-xs-grow,.flex>.col-xs-shrink,.row>.col,.row>.col-0,.row>.col-1,.row>.col-10,.row>.col-11,.row>.col-12,.row>.col-2,.row>.col-3,.row>.col-4,.row>.col-5,.row>.col-6,.row>.col-7,.row>.col-8,.row>.col-9,.row>.col-auto,.row>.col-grow,.row>.col-shrink,.row>.col-xs,.row>.col-xs-0,.row>.col-xs-1,.row>.col-xs-10,.row>.col-xs-11,.row>.col-xs-12,.row>.col-xs-2,.row>.col-xs-3,.row>.col-xs-4,.row>.col-xs-5,.row>.col-xs-6,.row>.col-xs-7,.row>.col-xs-8,.row>.col-xs-9,.row>.col-xs-auto,.row>.col-xs-grow,.row>.col-xs-shrink{width:auto;min-width:0;max-width:100%}.column>.col,.column>.col-0,.column>.col-1,.column>.col-10,.column>.col-11,.column>.col-12,.column>.col-2,.column>.col-3,.column>.col-4,.column>.col-5,.column>.col-6,.column>.col-7,.column>.col-8,.column>.col-9,.column>.col-auto,.column>.col-grow,.column>.col-shrink,.column>.col-xs,.column>.col-xs-0,.column>.col-xs-1,.column>.col-xs-10,.column>.col-xs-11,.column>.col-xs-12,.column>.col-xs-2,.column>.col-xs-3,.column>.col-xs-4,.column>.col-xs-5,.column>.col-xs-6,.column>.col-xs-7,.column>.col-xs-8,.column>.col-xs-9,.column>.col-xs-auto,.column>.col-xs-grow,.column>.col-xs-shrink,.flex>.col,.flex>.col-0,.flex>.col-1,.flex>.col-10,.flex>.col-11,.flex>.col-12,.flex>.col-2,.flex>.col-3,.flex>.col-4,.flex>.col-5,.flex>.col-6,.flex>.col-7,.flex>.col-8,.flex>.col-9,.flex>.col-auto,.flex>.col-grow,.flex>.col-shrink,.flex>.col-xs,.flex>.col-xs-0,.flex>.col-xs-1,.flex>.col-xs-10,.flex>.col-xs-11,.flex>.col-xs-12,.flex>.col-xs-2,.flex>.col-xs-3,.flex>.col-xs-4,.flex>.col-xs-5,.flex>.col-xs-6,.flex>.col-xs-7,.flex>.col-xs-8,.flex>.col-xs-9,.flex>.col-xs-auto,.flex>.col-xs-grow,.flex>.col-xs-shrink{height:auto;min-height:0;max-height:100%}.col,.col-xs{flex:10000 1 0%}.col-0,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-xs-0,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-auto{flex:0 0 auto}.col-grow,.col-xs-grow{flex:1 0 auto}.col-shrink,.col-xs-shrink{flex:0 1 auto}.row>.col-0,.row>.col-xs-0{height:auto;width:0%}.row>.offset-0,.row>.offset-xs-0{margin-left:0}.column>.col-0,.column>.col-xs-0{height:0%;width:auto}.row>.col-1,.row>.col-xs-1{height:auto;width:8.3333%}.row>.offset-1,.row>.offset-xs-1{margin-left:8.3333%}.column>.col-1,.column>.col-xs-1{height:8.3333%;width:auto}.row>.col-2,.row>.col-xs-2{height:auto;width:16.6667%}.row>.offset-2,.row>.offset-xs-2{margin-left:16.6667%}.column>.col-2,.column>.col-xs-2{height:16.6667%;width:auto}.row>.col-3,.row>.col-xs-3{height:auto;width:25%}.row>.offset-3,.row>.offset-xs-3{margin-left:25%}.column>.col-3,.column>.col-xs-3{height:25%;width:auto}.row>.col-4,.row>.col-xs-4{height:auto;width:33.3333%}.row>.offset-4,.row>.offset-xs-4{margin-left:33.3333%}.column>.col-4,.column>.col-xs-4{height:33.3333%;width:auto}.row>.col-5,.row>.col-xs-5{height:auto;width:41.6667%}.row>.offset-5,.row>.offset-xs-5{margin-left:41.6667%}.column>.col-5,.column>.col-xs-5{height:41.6667%;width:auto}.row>.col-6,.row>.col-xs-6{height:auto;width:50%}.row>.offset-6,.row>.offset-xs-6{margin-left:50%}.column>.col-6,.column>.col-xs-6{height:50%;width:auto}.row>.col-7,.row>.col-xs-7{height:auto;width:58.3333%}.row>.offset-7,.row>.offset-xs-7{margin-left:58.3333%}.column>.col-7,.column>.col-xs-7{height:58.3333%;width:auto}.row>.col-8,.row>.col-xs-8{height:auto;width:66.6667%}.row>.offset-8,.row>.offset-xs-8{margin-left:66.6667%}.column>.col-8,.column>.col-xs-8{height:66.6667%;width:auto}.row>.col-9,.row>.col-xs-9{height:auto;width:75%}.row>.offset-9,.row>.offset-xs-9{margin-left:75%}.column>.col-9,.column>.col-xs-9{height:75%;width:auto}.row>.col-10,.row>.col-xs-10{height:auto;width:83.3333%}.row>.offset-10,.row>.offset-xs-10{margin-left:83.3333%}.column>.col-10,.column>.col-xs-10{height:83.3333%;width:auto}.row>.col-11,.row>.col-xs-11{height:auto;width:91.6667%}.row>.offset-11,.row>.offset-xs-11{margin-left:91.6667%}.column>.col-11,.column>.col-xs-11{height:91.6667%;width:auto}.row>.col-12,.row>.col-xs-12{height:auto;width:100%}.row>.offset-12,.row>.offset-xs-12{margin-left:100%}.column>.col-12,.column>.col-xs-12{height:100%;width:auto}.row>.col-all{height:auto;flex:0 0 100%}}@media (min-width:600px){.flex>.col-sm,.flex>.col-sm-0,.flex>.col-sm-1,.flex>.col-sm-10,.flex>.col-sm-11,.flex>.col-sm-12,.flex>.col-sm-2,.flex>.col-sm-3,.flex>.col-sm-4,.flex>.col-sm-5,.flex>.col-sm-6,.flex>.col-sm-7,.flex>.col-sm-8,.flex>.col-sm-9,.flex>.col-sm-auto,.flex>.col-sm-grow,.flex>.col-sm-shrink,.row>.col-sm,.row>.col-sm-0,.row>.col-sm-1,.row>.col-sm-10,.row>.col-sm-11,.row>.col-sm-12,.row>.col-sm-2,.row>.col-sm-3,.row>.col-sm-4,.row>.col-sm-5,.row>.col-sm-6,.row>.col-sm-7,.row>.col-sm-8,.row>.col-sm-9,.row>.col-sm-auto,.row>.col-sm-grow,.row>.col-sm-shrink{width:auto;min-width:0;max-width:100%}.column>.col-sm,.column>.col-sm-0,.column>.col-sm-1,.column>.col-sm-10,.column>.col-sm-11,.column>.col-sm-12,.column>.col-sm-2,.column>.col-sm-3,.column>.col-sm-4,.column>.col-sm-5,.column>.col-sm-6,.column>.col-sm-7,.column>.col-sm-8,.column>.col-sm-9,.column>.col-sm-auto,.column>.col-sm-grow,.column>.col-sm-shrink,.flex>.col-sm,.flex>.col-sm-0,.flex>.col-sm-1,.flex>.col-sm-10,.flex>.col-sm-11,.flex>.col-sm-12,.flex>.col-sm-2,.flex>.col-sm-3,.flex>.col-sm-4,.flex>.col-sm-5,.flex>.col-sm-6,.flex>.col-sm-7,.flex>.col-sm-8,.flex>.col-sm-9,.flex>.col-sm-auto,.flex>.col-sm-grow,.flex>.col-sm-shrink{height:auto;min-height:0;max-height:100%}.col-sm{flex:10000 1 0%}.col-sm-0,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto{flex:0 0 auto}.col-sm-grow{flex:1 0 auto}.col-sm-shrink{flex:0 1 auto}.row>.col-sm-0{height:auto;width:0%}.row>.offset-sm-0{margin-left:0}.column>.col-sm-0{height:0%;width:auto}.row>.col-sm-1{height:auto;width:8.3333%}.row>.offset-sm-1{margin-left:8.3333%}.column>.col-sm-1{height:8.3333%;width:auto}.row>.col-sm-2{height:auto;width:16.6667%}.row>.offset-sm-2{margin-left:16.6667%}.column>.col-sm-2{height:16.6667%;width:auto}.row>.col-sm-3{height:auto;width:25%}.row>.offset-sm-3{margin-left:25%}.column>.col-sm-3{height:25%;width:auto}.row>.col-sm-4{height:auto;width:33.3333%}.row>.offset-sm-4{margin-left:33.3333%}.column>.col-sm-4{height:33.3333%;width:auto}.row>.col-sm-5{height:auto;width:41.6667%}.row>.offset-sm-5{margin-left:41.6667%}.column>.col-sm-5{height:41.6667%;width:auto}.row>.col-sm-6{height:auto;width:50%}.row>.offset-sm-6{margin-left:50%}.column>.col-sm-6{height:50%;width:auto}.row>.col-sm-7{height:auto;width:58.3333%}.row>.offset-sm-7{margin-left:58.3333%}.column>.col-sm-7{height:58.3333%;width:auto}.row>.col-sm-8{height:auto;width:66.6667%}.row>.offset-sm-8{margin-left:66.6667%}.column>.col-sm-8{height:66.6667%;width:auto}.row>.col-sm-9{height:auto;width:75%}.row>.offset-sm-9{margin-left:75%}.column>.col-sm-9{height:75%;width:auto}.row>.col-sm-10{height:auto;width:83.3333%}.row>.offset-sm-10{margin-left:83.3333%}.column>.col-sm-10{height:83.3333%;width:auto}.row>.col-sm-11{height:auto;width:91.6667%}.row>.offset-sm-11{margin-left:91.6667%}.column>.col-sm-11{height:91.6667%;width:auto}.row>.col-sm-12{height:auto;width:100%}.row>.offset-sm-12{margin-left:100%}.column>.col-sm-12{height:100%;width:auto}}@media (min-width:1024px){.flex>.col-md,.flex>.col-md-0,.flex>.col-md-1,.flex>.col-md-10,.flex>.col-md-11,.flex>.col-md-12,.flex>.col-md-2,.flex>.col-md-3,.flex>.col-md-4,.flex>.col-md-5,.flex>.col-md-6,.flex>.col-md-7,.flex>.col-md-8,.flex>.col-md-9,.flex>.col-md-auto,.flex>.col-md-grow,.flex>.col-md-shrink,.row>.col-md,.row>.col-md-0,.row>.col-md-1,.row>.col-md-10,.row>.col-md-11,.row>.col-md-12,.row>.col-md-2,.row>.col-md-3,.row>.col-md-4,.row>.col-md-5,.row>.col-md-6,.row>.col-md-7,.row>.col-md-8,.row>.col-md-9,.row>.col-md-auto,.row>.col-md-grow,.row>.col-md-shrink{width:auto;min-width:0;max-width:100%}.column>.col-md,.column>.col-md-0,.column>.col-md-1,.column>.col-md-10,.column>.col-md-11,.column>.col-md-12,.column>.col-md-2,.column>.col-md-3,.column>.col-md-4,.column>.col-md-5,.column>.col-md-6,.column>.col-md-7,.column>.col-md-8,.column>.col-md-9,.column>.col-md-auto,.column>.col-md-grow,.column>.col-md-shrink,.flex>.col-md,.flex>.col-md-0,.flex>.col-md-1,.flex>.col-md-10,.flex>.col-md-11,.flex>.col-md-12,.flex>.col-md-2,.flex>.col-md-3,.flex>.col-md-4,.flex>.col-md-5,.flex>.col-md-6,.flex>.col-md-7,.flex>.col-md-8,.flex>.col-md-9,.flex>.col-md-auto,.flex>.col-md-grow,.flex>.col-md-shrink{height:auto;min-height:0;max-height:100%}.col-md{flex:10000 1 0%}.col-md-0,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto{flex:0 0 auto}.col-md-grow{flex:1 0 auto}.col-md-shrink{flex:0 1 auto}.row>.col-md-0{height:auto;width:0%}.row>.offset-md-0{margin-left:0}.column>.col-md-0{height:0%;width:auto}.row>.col-md-1{height:auto;width:8.3333%}.row>.offset-md-1{margin-left:8.3333%}.column>.col-md-1{height:8.3333%;width:auto}.row>.col-md-2{height:auto;width:16.6667%}.row>.offset-md-2{margin-left:16.6667%}.column>.col-md-2{height:16.6667%;width:auto}.row>.col-md-3{height:auto;width:25%}.row>.offset-md-3{margin-left:25%}.column>.col-md-3{height:25%;width:auto}.row>.col-md-4{height:auto;width:33.3333%}.row>.offset-md-4{margin-left:33.3333%}.column>.col-md-4{height:33.3333%;width:auto}.row>.col-md-5{height:auto;width:41.6667%}.row>.offset-md-5{margin-left:41.6667%}.column>.col-md-5{height:41.6667%;width:auto}.row>.col-md-6{height:auto;width:50%}.row>.offset-md-6{margin-left:50%}.column>.col-md-6{height:50%;width:auto}.row>.col-md-7{height:auto;width:58.3333%}.row>.offset-md-7{margin-left:58.3333%}.column>.col-md-7{height:58.3333%;width:auto}.row>.col-md-8{height:auto;width:66.6667%}.row>.offset-md-8{margin-left:66.6667%}.column>.col-md-8{height:66.6667%;width:auto}.row>.col-md-9{height:auto;width:75%}.row>.offset-md-9{margin-left:75%}.column>.col-md-9{height:75%;width:auto}.row>.col-md-10{height:auto;width:83.3333%}.row>.offset-md-10{margin-left:83.3333%}.column>.col-md-10{height:83.3333%;width:auto}.row>.col-md-11{height:auto;width:91.6667%}.row>.offset-md-11{margin-left:91.6667%}.column>.col-md-11{height:91.6667%;width:auto}.row>.col-md-12{height:auto;width:100%}.row>.offset-md-12{margin-left:100%}.column>.col-md-12{height:100%;width:auto}}@media (min-width:1440px){.flex>.col-lg,.flex>.col-lg-0,.flex>.col-lg-1,.flex>.col-lg-10,.flex>.col-lg-11,.flex>.col-lg-12,.flex>.col-lg-2,.flex>.col-lg-3,.flex>.col-lg-4,.flex>.col-lg-5,.flex>.col-lg-6,.flex>.col-lg-7,.flex>.col-lg-8,.flex>.col-lg-9,.flex>.col-lg-auto,.flex>.col-lg-grow,.flex>.col-lg-shrink,.row>.col-lg,.row>.col-lg-0,.row>.col-lg-1,.row>.col-lg-10,.row>.col-lg-11,.row>.col-lg-12,.row>.col-lg-2,.row>.col-lg-3,.row>.col-lg-4,.row>.col-lg-5,.row>.col-lg-6,.row>.col-lg-7,.row>.col-lg-8,.row>.col-lg-9,.row>.col-lg-auto,.row>.col-lg-grow,.row>.col-lg-shrink{width:auto;min-width:0;max-width:100%}.column>.col-lg,.column>.col-lg-0,.column>.col-lg-1,.column>.col-lg-10,.column>.col-lg-11,.column>.col-lg-12,.column>.col-lg-2,.column>.col-lg-3,.column>.col-lg-4,.column>.col-lg-5,.column>.col-lg-6,.column>.col-lg-7,.column>.col-lg-8,.column>.col-lg-9,.column>.col-lg-auto,.column>.col-lg-grow,.column>.col-lg-shrink,.flex>.col-lg,.flex>.col-lg-0,.flex>.col-lg-1,.flex>.col-lg-10,.flex>.col-lg-11,.flex>.col-lg-12,.flex>.col-lg-2,.flex>.col-lg-3,.flex>.col-lg-4,.flex>.col-lg-5,.flex>.col-lg-6,.flex>.col-lg-7,.flex>.col-lg-8,.flex>.col-lg-9,.flex>.col-lg-auto,.flex>.col-lg-grow,.flex>.col-lg-shrink{height:auto;min-height:0;max-height:100%}.col-lg{flex:10000 1 0%}.col-lg-0,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto{flex:0 0 auto}.col-lg-grow{flex:1 0 auto}.col-lg-shrink{flex:0 1 auto}.row>.col-lg-0{height:auto;width:0%}.row>.offset-lg-0{margin-left:0}.column>.col-lg-0{height:0%;width:auto}.row>.col-lg-1{height:auto;width:8.3333%}.row>.offset-lg-1{margin-left:8.3333%}.column>.col-lg-1{height:8.3333%;width:auto}.row>.col-lg-2{height:auto;width:16.6667%}.row>.offset-lg-2{margin-left:16.6667%}.column>.col-lg-2{height:16.6667%;width:auto}.row>.col-lg-3{height:auto;width:25%}.row>.offset-lg-3{margin-left:25%}.column>.col-lg-3{height:25%;width:auto}.row>.col-lg-4{height:auto;width:33.3333%}.row>.offset-lg-4{margin-left:33.3333%}.column>.col-lg-4{height:33.3333%;width:auto}.row>.col-lg-5{height:auto;width:41.6667%}.row>.offset-lg-5{margin-left:41.6667%}.column>.col-lg-5{height:41.6667%;width:auto}.row>.col-lg-6{height:auto;width:50%}.row>.offset-lg-6{margin-left:50%}.column>.col-lg-6{height:50%;width:auto}.row>.col-lg-7{height:auto;width:58.3333%}.row>.offset-lg-7{margin-left:58.3333%}.column>.col-lg-7{height:58.3333%;width:auto}.row>.col-lg-8{height:auto;width:66.6667%}.row>.offset-lg-8{margin-left:66.6667%}.column>.col-lg-8{height:66.6667%;width:auto}.row>.col-lg-9{height:auto;width:75%}.row>.offset-lg-9{margin-left:75%}.column>.col-lg-9{height:75%;width:auto}.row>.col-lg-10{height:auto;width:83.3333%}.row>.offset-lg-10{margin-left:83.3333%}.column>.col-lg-10{height:83.3333%;width:auto}.row>.col-lg-11{height:auto;width:91.6667%}.row>.offset-lg-11{margin-left:91.6667%}.column>.col-lg-11{height:91.6667%;width:auto}.row>.col-lg-12{height:auto;width:100%}.row>.offset-lg-12{margin-left:100%}.column>.col-lg-12{height:100%;width:auto}}@media (min-width:1920px){.flex>.col-xl,.flex>.col-xl-0,.flex>.col-xl-1,.flex>.col-xl-10,.flex>.col-xl-11,.flex>.col-xl-12,.flex>.col-xl-2,.flex>.col-xl-3,.flex>.col-xl-4,.flex>.col-xl-5,.flex>.col-xl-6,.flex>.col-xl-7,.flex>.col-xl-8,.flex>.col-xl-9,.flex>.col-xl-auto,.flex>.col-xl-grow,.flex>.col-xl-shrink,.row>.col-xl,.row>.col-xl-0,.row>.col-xl-1,.row>.col-xl-10,.row>.col-xl-11,.row>.col-xl-12,.row>.col-xl-2,.row>.col-xl-3,.row>.col-xl-4,.row>.col-xl-5,.row>.col-xl-6,.row>.col-xl-7,.row>.col-xl-8,.row>.col-xl-9,.row>.col-xl-auto,.row>.col-xl-grow,.row>.col-xl-shrink{width:auto;min-width:0;max-width:100%}.column>.col-xl,.column>.col-xl-0,.column>.col-xl-1,.column>.col-xl-10,.column>.col-xl-11,.column>.col-xl-12,.column>.col-xl-2,.column>.col-xl-3,.column>.col-xl-4,.column>.col-xl-5,.column>.col-xl-6,.column>.col-xl-7,.column>.col-xl-8,.column>.col-xl-9,.column>.col-xl-auto,.column>.col-xl-grow,.column>.col-xl-shrink,.flex>.col-xl,.flex>.col-xl-0,.flex>.col-xl-1,.flex>.col-xl-10,.flex>.col-xl-11,.flex>.col-xl-12,.flex>.col-xl-2,.flex>.col-xl-3,.flex>.col-xl-4,.flex>.col-xl-5,.flex>.col-xl-6,.flex>.col-xl-7,.flex>.col-xl-8,.flex>.col-xl-9,.flex>.col-xl-auto,.flex>.col-xl-grow,.flex>.col-xl-shrink{height:auto;min-height:0;max-height:100%}.col-xl{flex:10000 1 0%}.col-xl-0,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{flex:0 0 auto}.col-xl-grow{flex:1 0 auto}.col-xl-shrink{flex:0 1 auto}.row>.col-xl-0{height:auto;width:0%}.row>.offset-xl-0{margin-left:0}.column>.col-xl-0{height:0%;width:auto}.row>.col-xl-1{height:auto;width:8.3333%}.row>.offset-xl-1{margin-left:8.3333%}.column>.col-xl-1{height:8.3333%;width:auto}.row>.col-xl-2{height:auto;width:16.6667%}.row>.offset-xl-2{margin-left:16.6667%}.column>.col-xl-2{height:16.6667%;width:auto}.row>.col-xl-3{height:auto;width:25%}.row>.offset-xl-3{margin-left:25%}.column>.col-xl-3{height:25%;width:auto}.row>.col-xl-4{height:auto;width:33.3333%}.row>.offset-xl-4{margin-left:33.3333%}.column>.col-xl-4{height:33.3333%;width:auto}.row>.col-xl-5{height:auto;width:41.6667%}.row>.offset-xl-5{margin-left:41.6667%}.column>.col-xl-5{height:41.6667%;width:auto}.row>.col-xl-6{height:auto;width:50%}.row>.offset-xl-6{margin-left:50%}.column>.col-xl-6{height:50%;width:auto}.row>.col-xl-7{height:auto;width:58.3333%}.row>.offset-xl-7{margin-left:58.3333%}.column>.col-xl-7{height:58.3333%;width:auto}.row>.col-xl-8{height:auto;width:66.6667%}.row>.offset-xl-8{margin-left:66.6667%}.column>.col-xl-8{height:66.6667%;width:auto}.row>.col-xl-9{height:auto;width:75%}.row>.offset-xl-9{margin-left:75%}.column>.col-xl-9{height:75%;width:auto}.row>.col-xl-10{height:auto;width:83.3333%}.row>.offset-xl-10{margin-left:83.3333%}.column>.col-xl-10{height:83.3333%;width:auto}.row>.col-xl-11{height:auto;width:91.6667%}.row>.offset-xl-11{margin-left:91.6667%}.column>.col-xl-11{height:91.6667%;width:auto}.row>.col-xl-12{height:auto;width:100%}.row>.offset-xl-12{margin-left:100%}.column>.col-xl-12{height:100%;width:auto}}.rounded-borders{border-radius:4px}.border-radius-inherit{border-radius:inherit}.no-transition{transition:none!important}.transition-0{transition:0s!important}.glossy{background-image:linear-gradient(to bottom,rgba(255,255,255,.3),rgba(255,255,255,0) 50%,rgba(0,0,0,.12) 51%,rgba(0,0,0,.04))!important}.q-placeholder::placeholder{color:inherit;opacity:.7}.q-document--prevent-scroll{overscroll-behavior:none!important}.q-document--prevent-scroll body{position:fixed!important}.q-body--fullscreen-mixin{position:fixed!important}.q-body--force-scrollbar-x{overflow-x:scroll}.q-body--force-scrollbar-y{overflow-y:scroll}.q-no-input-spinner{-moz-appearance:textfield!important}.q-no-input-spinner::-webkit-inner-spin-button,.q-no-input-spinner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.q-link{outline:0;text-decoration:none}.q-link--focusable:focus-visible{text-decoration:underline dashed currentColor 1px}body.electron .q-electron-drag{-webkit-user-select:none;-webkit-app-region:drag}body.electron .q-electron-drag .q-btn-item,body.electron .q-electron-drag--exception{-webkit-app-region:no-drag}img.responsive{max-width:100%;height:auto}.non-selectable{user-select:none!important}.scroll,body.mobile .scroll--mobile{overflow:auto}.scroll,.scroll-x,.scroll-y{-webkit-overflow-scrolling:touch;will-change:scroll-position}.scroll-x{overflow-x:auto}.scroll-y{overflow-y:auto}.no-scroll{overflow:hidden!important}.no-pointer-events,.no-pointer-events--children,.no-pointer-events--children *{pointer-events:none!important}.all-pointer-events{pointer-events:all!important}.cursor-pointer{cursor:pointer!important}.cursor-not-allowed{cursor:not-allowed!important}.cursor-inherit{cursor:inherit!important}.cursor-none{cursor:none!important}[aria-busy=true]{cursor:progress}[aria-controls]{cursor:pointer}[aria-disabled=true]{cursor:default}.rotate-45{transform:rotate(45deg)}.rotate-90{transform:rotate(90deg)}.rotate-135{transform:rotate(135deg)}.rotate-180{transform:rotate(180deg)}.rotate-225{transform:rotate(225deg)}.rotate-270{transform:rotate(270deg)}.rotate-315{transform:rotate(315deg)}.flip-horizontal{transform:scaleX(-1)}.flip-vertical{transform:scaleY(-1)}.float-left{float:left}.float-right{float:right}.relative-position{position:relative}.fixed,.fixed-bottom,.fixed-bottom-left,.fixed-bottom-right,.fixed-center,.fixed-full,.fixed-left,.fixed-right,.fixed-top,.fixed-top-left,.fixed-top-right,.fullscreen{position:fixed}.absolute,.absolute-bottom,.absolute-bottom-left,.absolute-bottom-right,.absolute-center,.absolute-full,.absolute-left,.absolute-right,.absolute-top,.absolute-top-left,.absolute-top-right{position:absolute}.absolute-top,.fixed-top{top:0;left:0;right:0}.absolute-right,.fixed-right{top:0;right:0;bottom:0}.absolute-bottom,.fixed-bottom{right:0;bottom:0;left:0}.absolute-left,.fixed-left{top:0;bottom:0;left:0}.absolute-top-left,.fixed-top-left{top:0;left:0}.absolute-top-right,.fixed-top-right{top:0;right:0}.absolute-bottom-left,.fixed-bottom-left{bottom:0;left:0}.absolute-bottom-right,.fixed-bottom-right{bottom:0;right:0}.fullscreen{z-index:6000;border-radius:0!important;max-width:100vw;max-height:100vh}body.q-ios-padding .fullscreen{padding-top:20px!important;padding-top:env(safe-area-inset-top)!important;padding-bottom:env(safe-area-inset-bottom)!important}.absolute-full,.fixed-full,.fullscreen{top:0;right:0;bottom:0;left:0}.absolute-center,.fixed-center{top:50%;left:50%;transform:translate(-50%,-50%)}.vertical-top{vertical-align:top!important}.vertical-middle{vertical-align:middle!important}.vertical-bottom{vertical-align:bottom!important}.on-left{margin-right:12px}.on-right{margin-left:12px}.q-position-engine{margin-top:var(--q-pe-top,0)!important;margin-left:var(--q-pe-left,0)!important;will-change:auto;visibility:collapse}:root{--q-size-xs:0;--q-size-sm:600px;--q-size-md:1024px;--q-size-lg:1440px;--q-size-xl:1920px}.fit{width:100%!important;height:100%!important}.full-height{height:100%!important}.full-width{width:100%!important;margin-left:0!important;margin-right:0!important}.window-height{margin-top:0!important;margin-bottom:0!important;height:100vh!important}.window-width{margin-left:0!important;margin-right:0!important;width:100vw!important}.block{display:block!important}.inline-block{display:inline-block!important}.q-pa-none{padding:0 0}.q-pl-none{padding-left:0}.q-pr-none{padding-right:0}.q-pt-none{padding-top:0}.q-pb-none{padding-bottom:0}.q-px-none{padding-left:0;padding-right:0}.q-py-none{padding-top:0;padding-bottom:0}.q-ma-none{margin:0 0}.q-ml-none{margin-left:0}.q-mr-none{margin-right:0}.q-mt-none{margin-top:0}.q-mb-none{margin-bottom:0}.q-mx-none{margin-left:0;margin-right:0}.q-my-none{margin-top:0;margin-bottom:0}.q-pa-xs{padding:4px 4px}.q-pl-xs{padding-left:4px}.q-pr-xs{padding-right:4px}.q-pt-xs{padding-top:4px}.q-pb-xs{padding-bottom:4px}.q-px-xs{padding-left:4px;padding-right:4px}.q-py-xs{padding-top:4px;padding-bottom:4px}.q-ma-xs{margin:4px 4px}.q-ml-xs{margin-left:4px}.q-mr-xs{margin-right:4px}.q-mt-xs{margin-top:4px}.q-mb-xs{margin-bottom:4px}.q-mx-xs{margin-left:4px;margin-right:4px}.q-my-xs{margin-top:4px;margin-bottom:4px}.q-pa-sm{padding:8px 8px}.q-pl-sm{padding-left:8px}.q-pr-sm{padding-right:8px}.q-pt-sm{padding-top:8px}.q-pb-sm{padding-bottom:8px}.q-px-sm{padding-left:8px;padding-right:8px}.q-py-sm{padding-top:8px;padding-bottom:8px}.q-ma-sm{margin:8px 8px}.q-ml-sm{margin-left:8px}.q-mr-sm{margin-right:8px}.q-mt-sm{margin-top:8px}.q-mb-sm{margin-bottom:8px}.q-mx-sm{margin-left:8px;margin-right:8px}.q-my-sm{margin-top:8px;margin-bottom:8px}.q-pa-md{padding:16px 16px}.q-pl-md{padding-left:16px}.q-pr-md{padding-right:16px}.q-pt-md{padding-top:16px}.q-pb-md{padding-bottom:16px}.q-px-md{padding-left:16px;padding-right:16px}.q-py-md{padding-top:16px;padding-bottom:16px}.q-ma-md{margin:16px 16px}.q-ml-md{margin-left:16px}.q-mr-md{margin-right:16px}.q-mt-md{margin-top:16px}.q-mb-md{margin-bottom:16px}.q-mx-md{margin-left:16px;margin-right:16px}.q-my-md{margin-top:16px;margin-bottom:16px}.q-pa-lg{padding:24px 24px}.q-pl-lg{padding-left:24px}.q-pr-lg{padding-right:24px}.q-pt-lg{padding-top:24px}.q-pb-lg{padding-bottom:24px}.q-px-lg{padding-left:24px;padding-right:24px}.q-py-lg{padding-top:24px;padding-bottom:24px}.q-ma-lg{margin:24px 24px}.q-ml-lg{margin-left:24px}.q-mr-lg{margin-right:24px}.q-mt-lg{margin-top:24px}.q-mb-lg{margin-bottom:24px}.q-mx-lg{margin-left:24px;margin-right:24px}.q-my-lg{margin-top:24px;margin-bottom:24px}.q-pa-xl{padding:48px 48px}.q-pl-xl{padding-left:48px}.q-pr-xl{padding-right:48px}.q-pt-xl{padding-top:48px}.q-pb-xl{padding-bottom:48px}.q-px-xl{padding-left:48px;padding-right:48px}.q-py-xl{padding-top:48px;padding-bottom:48px}.q-ma-xl{margin:48px 48px}.q-ml-xl{margin-left:48px}.q-mr-xl{margin-right:48px}.q-mt-xl{margin-top:48px}.q-mb-xl{margin-bottom:48px}.q-mx-xl{margin-left:48px;margin-right:48px}.q-my-xl{margin-top:48px;margin-bottom:48px}.q-mt-auto,.q-my-auto{margin-top:auto}.q-ml-auto{margin-left:auto}.q-mb-auto,.q-my-auto{margin-bottom:auto}.q-mr-auto{margin-right:auto}.q-mx-auto{margin-left:auto;margin-right:auto}.q-touch{user-select:none;user-drag:none;-khtml-user-drag:none;-webkit-user-drag:none}.q-touch-x{touch-action:pan-x}.q-touch-y{touch-action:pan-y}:root{--q-transition-duration:.3s}.q-transition--fade-enter-active,.q-transition--fade-leave-active,.q-transition--flip-enter-active,.q-transition--flip-leave-active,.q-transition--jump-down-enter-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-enter-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-enter-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-enter-active,.q-transition--jump-up-leave-active,.q-transition--rotate-enter-active,.q-transition--rotate-leave-active,.q-transition--scale-enter-active,.q-transition--scale-leave-active,.q-transition--slide-down-enter-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-enter-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-enter-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-enter-active,.q-transition--slide-up-leave-active{--q-transition-duration:.3s;--q-transition-easing:cubic-bezier(0.215,0.61,0.355,1)}.q-transition--fade-leave-active,.q-transition--flip-leave-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-leave-active,.q-transition--rotate-leave-active,.q-transition--scale-leave-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-leave-active{position:absolute}.q-transition--slide-down-enter-active,.q-transition--slide-down-leave-active,.q-transition--slide-left-enter-active,.q-transition--slide-left-leave-active,.q-transition--slide-right-enter-active,.q-transition--slide-right-leave-active,.q-transition--slide-up-enter-active,.q-transition--slide-up-leave-active{transition:transform var(--q-transition-duration) var(--q-transition-easing)}.q-transition--slide-right-enter-from{transform:translate3d(-100%,0,0)}.q-transition--slide-right-leave-to{transform:translate3d(100%,0,0)}.q-transition--slide-left-enter-from{transform:translate3d(100%,0,0)}.q-transition--slide-left-leave-to{transform:translate3d(-100%,0,0)}.q-transition--slide-up-enter-from{transform:translate3d(0,100%,0)}.q-transition--slide-up-leave-to{transform:translate3d(0,-100%,0)}.q-transition--slide-down-enter-from{transform:translate3d(0,-100%,0)}.q-transition--slide-down-leave-to{transform:translate3d(0,100%,0)}.q-transition--jump-down-enter-active,.q-transition--jump-down-leave-active,.q-transition--jump-left-enter-active,.q-transition--jump-left-leave-active,.q-transition--jump-right-enter-active,.q-transition--jump-right-leave-active,.q-transition--jump-up-enter-active,.q-transition--jump-up-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration)}.q-transition--jump-down-enter-from,.q-transition--jump-down-leave-to,.q-transition--jump-left-enter-from,.q-transition--jump-left-leave-to,.q-transition--jump-right-enter-from,.q-transition--jump-right-leave-to,.q-transition--jump-up-enter-from,.q-transition--jump-up-leave-to{opacity:0}.q-transition--jump-right-enter-from{transform:translate3d(-15px,0,0)}.q-transition--jump-right-leave-to{transform:translate3d(15px,0,0)}.q-transition--jump-left-enter-from{transform:translate3d(15px,0,0)}.q-transition--jump-left-leave-to{transform:translateX(-15px)}.q-transition--jump-up-enter-from{transform:translate3d(0,15px,0)}.q-transition--jump-up-leave-to{transform:translate3d(0,-15px,0)}.q-transition--jump-down-enter-from{transform:translate3d(0,-15px,0)}.q-transition--jump-down-leave-to{transform:translate3d(0,15px,0)}.q-transition--fade-enter-active,.q-transition--fade-leave-active{transition:opacity var(--q-transition-duration) ease-out}.q-transition--fade-enter-from,.q-transition--fade-leave-to{opacity:0}.q-transition--scale-enter-active,.q-transition--scale-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration) var(--q-transition-easing)}.q-transition--scale-enter-from,.q-transition--scale-leave-to{opacity:0;transform:scale3d(0,0,1)}.q-transition--rotate-enter-active,.q-transition--rotate-leave-active{transition:opacity var(--q-transition-duration),transform var(--q-transition-duration) var(--q-transition-easing);transform-style:preserve-3d}.q-transition--rotate-enter-from,.q-transition--rotate-leave-to{opacity:0;transform:scale3d(0,0,1) rotate3d(0,0,1,90deg)}.q-transition--flip-down-enter-active,.q-transition--flip-down-leave-active,.q-transition--flip-left-enter-active,.q-transition--flip-left-leave-active,.q-transition--flip-right-enter-active,.q-transition--flip-right-leave-active,.q-transition--flip-up-enter-active,.q-transition--flip-up-leave-active{transition:transform var(--q-transition-duration);backface-visibility:hidden}.q-transition--flip-down-enter-to,.q-transition--flip-down-leave-from,.q-transition--flip-left-enter-to,.q-transition--flip-left-leave-from,.q-transition--flip-right-enter-to,.q-transition--flip-right-leave-from,.q-transition--flip-up-enter-to,.q-transition--flip-up-leave-from{transform:perspective(400px) rotate3d(1,1,0,0deg)}.q-transition--flip-right-enter-from{transform:perspective(400px) rotate3d(0,1,0,-180deg)}.q-transition--flip-right-leave-to{transform:perspective(400px) rotate3d(0,1,0,180deg)}.q-transition--flip-left-enter-from{transform:perspective(400px) rotate3d(0,1,0,180deg)}.q-transition--flip-left-leave-to{transform:perspective(400px) rotate3d(0,1,0,-180deg)}.q-transition--flip-up-enter-from{transform:perspective(400px) rotate3d(1,0,0,-180deg)}.q-transition--flip-up-leave-to{transform:perspective(400px) rotate3d(1,0,0,180deg)}.q-transition--flip-down-enter-from{transform:perspective(400px) rotate3d(1,0,0,180deg)}.q-transition--flip-down-leave-to{transform:perspective(400px) rotate3d(1,0,0,-180deg)}body{min-width:100px;min-height:100%;font-family:Roboto,"-apple-system","Helvetica Neue",Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased;line-height:1.5;font-size:14px}h1{font-size:6rem;font-weight:300;line-height:6rem;letter-spacing:-.01562em}h2{font-size:3.75rem;font-weight:300;line-height:3.75rem;letter-spacing:-.00833em}h3{font-size:3rem;font-weight:400;line-height:3.125rem;letter-spacing:normal}h4{font-size:2.125rem;font-weight:400;line-height:2.5rem;letter-spacing:.00735em}h5{font-size:1.5rem;font-weight:400;line-height:2rem;letter-spacing:normal}h6{font-size:1.25rem;font-weight:500;line-height:2rem;letter-spacing:.0125em}p{margin:0 0 16px}.text-h1{font-size:6rem;font-weight:300;line-height:6rem;letter-spacing:-.01562em}.text-h2{font-size:3.75rem;font-weight:300;line-height:3.75rem;letter-spacing:-.00833em}.text-h3{font-size:3rem;font-weight:400;line-height:3.125rem;letter-spacing:normal}.text-h4{font-size:2.125rem;font-weight:400;line-height:2.5rem;letter-spacing:.00735em}.text-h5{font-size:1.5rem;font-weight:400;line-height:2rem;letter-spacing:normal}.text-h6{font-size:1.25rem;font-weight:500;line-height:2rem;letter-spacing:.0125em}.text-subtitle1{font-size:1rem;font-weight:400;line-height:1.75rem;letter-spacing:.00937em}.text-subtitle2{font-size:.875rem;font-weight:500;line-height:1.375rem;letter-spacing:.00714em}.text-body1{font-size:1rem;font-weight:400;line-height:1.5rem;letter-spacing:.03125em}.text-body2{font-size:.875rem;font-weight:400;line-height:1.25rem;letter-spacing:.01786em}.text-overline{font-size:.75rem;font-weight:500;line-height:2rem;letter-spacing:.16667em}.text-caption{font-size:.75rem;font-weight:400;line-height:1.25rem;letter-spacing:.03333em}.text-uppercase{text-transform:uppercase}.text-lowercase{text-transform:lowercase}.text-capitalize{text-transform:capitalize}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.text-justify{text-align:justify;hyphens:auto}.text-italic{font-style:italic}.text-bold{font-weight:700}.text-no-wrap{white-space:nowrap}.text-strike{text-decoration:line-through}.text-weight-thin{font-weight:100}.text-weight-light{font-weight:300}.text-weight-regular{font-weight:400}.text-weight-medium{font-weight:500}.text-weight-bold{font-weight:700}.text-weight-bolder{font-weight:900}small{font-size:80%}big{font-size:170%}sub{bottom:-.25em}sup{top:-.5em}.no-margin{margin:0!important}.no-padding{padding:0!important}.no-border{border:0!important}.no-border-radius{border-radius:0!important}.no-box-shadow{box-shadow:none!important}.no-outline{outline:0!important}.ellipsis{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ellipsis-2-lines,.ellipsis-3-lines{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical}.ellipsis-2-lines{-webkit-line-clamp:2}.ellipsis-3-lines{-webkit-line-clamp:3}.readonly{cursor:default!important}.disabled,.disabled *,[disabled],[disabled] *{outline:0!important;cursor:not-allowed!important}.disabled,[disabled]{opacity:.6!important}.hidden{display:none!important}.invisible,.invisible *{visibility:hidden!important;transition:none!important;animation:none!important}.transparent{background:0 0!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-hidden-y{overflow-y:hidden!important}.hide-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.hide-scrollbar::-webkit-scrollbar{width:0;height:0;display:none}.dimmed:after,.light-dimmed:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0}.dimmed:after{background:rgba(0,0,0,.4)!important}.light-dimmed:after{background:rgba(255,255,255,.6)!important}.z-top{z-index:7000!important}.z-max{z-index:9998!important}body.desktop .desktop-hide,body:not(.desktop) .desktop-only{display:none!important}body.mobile .mobile-hide,body:not(.mobile) .mobile-only{display:none!important}body.native-mobile .native-mobile-hide,body:not(.native-mobile) .native-mobile-only{display:none!important}body.cordova .cordova-hide,body:not(.cordova) .cordova-only{display:none!important}body.capacitor .capacitor-hide,body:not(.capacitor) .capacitor-only{display:none!important}body.electron .electron-hide,body:not(.electron) .electron-only{display:none!important}body.touch .touch-hide,body:not(.touch) .touch-only{display:none!important}body.within-iframe .within-iframe-hide,body:not(.within-iframe) .within-iframe-only{display:none!important}body.platform-ios .platform-ios-hide,body:not(.platform-ios) .platform-ios-only{display:none!important}body.platform-android .platform-android-hide,body:not(.platform-android) .platform-android-only{display:none!important}@media all and (orientation:portrait){.orientation-landscape{display:none!important}}@media all and (orientation:landscape){.orientation-portrait{display:none!important}}@media screen{.print-only{display:none!important}}@media print{.print-hide{display:none!important}}@media (max-width:599.98px){.gt-lg,.gt-md,.gt-sm,.gt-xs,.lg,.md,.sm,.xl,.xs-hide{display:none!important}}@media (min-width:600px) and (max-width:1023.98px){.gt-lg,.gt-md,.gt-sm,.lg,.lt-sm,.md,.sm-hide,.xl,.xs{display:none!important}}@media (min-width:1024px) and (max-width:1439.98px){.gt-lg,.gt-md,.lg,.lt-md,.lt-sm,.md-hide,.sm,.xl,.xs{display:none!important}}@media (min-width:1440px) and (max-width:1919.98px){.gt-lg,.lg-hide,.lt-lg,.lt-md,.lt-sm,.md,.sm,.xl,.xs{display:none!important}}@media (min-width:1920px){.lg,.lt-lg,.lt-md,.lt-sm,.lt-xl,.md,.sm,.xl-hide,.xs{display:none!important}}.q-focus-helper,.q-focusable,.q-hoverable,.q-manual-focusable{outline:0}body.desktop .q-focus-helper{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;border-radius:inherit;opacity:0;transition:background-color .3s cubic-bezier(.25, .8, .5, 1),opacity .4s cubic-bezier(.25, .8, .5, 1)}body.desktop .q-focus-helper:after,body.desktop .q-focus-helper:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;border-radius:inherit;transition:background-color .3s cubic-bezier(.25, .8, .5, 1),opacity .6s cubic-bezier(.25, .8, .5, 1)}body.desktop .q-focus-helper:before{background:#000}body.desktop .q-focus-helper:after{background:#fff}body.desktop .q-focus-helper--rounded{border-radius:4px}body.desktop .q-focus-helper--round{border-radius:50%}body.desktop .q-focusable:focus>.q-focus-helper,body.desktop .q-hoverable:hover>.q-focus-helper,body.desktop .q-manual-focusable--focused>.q-focus-helper{background:currentColor;opacity:.15}body.desktop .q-focusable:focus>.q-focus-helper:before,body.desktop .q-hoverable:hover>.q-focus-helper:before,body.desktop .q-manual-focusable--focused>.q-focus-helper:before{opacity:.1}body.desktop .q-focusable:focus>.q-focus-helper:after,body.desktop .q-hoverable:hover>.q-focus-helper:after,body.desktop .q-manual-focusable--focused>.q-focus-helper:after{opacity:.4}body.desktop .q-focusable:focus>.q-focus-helper,body.desktop .q-manual-focusable--focused>.q-focus-helper{opacity:.22}body.body--dark{color:#fff;background:var(--q-dark-page)}.q-dark{color:#fff;background:var(--q-dark)}body[data-theme=classic].neon-border .q-card,body[data-theme=classic].neon-border .q-card.q-card--dark,body[data-theme=classic].neon-border .q-date,body[data-theme=classic].neon-border .q-date--dark{border:2px solid #673ab7;box-shadow:none}body[data-theme=bitcoin].neon-border .q-card,body[data-theme=bitcoin].neon-border .q-card.q-card--dark,body[data-theme=bitcoin].neon-border .q-date,body[data-theme=bitcoin].neon-border .q-date--dark{border:2px solid #ea611d;box-shadow:none}body[data-theme=freedom].neon-border .q-card,body[data-theme=freedom].neon-border .q-card.q-card--dark,body[data-theme=freedom].neon-border .q-date,body[data-theme=freedom].neon-border .q-date--dark{border:2px solid #e22156;box-shadow:none}body[data-theme=cyber].neon-border .q-card,body[data-theme=cyber].neon-border .q-card.q-card--dark,body[data-theme=cyber].neon-border .q-date,body[data-theme=cyber].neon-border .q-date--dark{border:2px solid #7cb342;box-shadow:none}body[data-theme=mint].neon-border .q-card,body[data-theme=mint].neon-border .q-card.q-card--dark,body[data-theme=mint].neon-border .q-date,body[data-theme=mint].neon-border .q-date--dark{border:2px solid #3ab77d;box-shadow:none}body[data-theme=autumn].neon-border .q-card,body[data-theme=autumn].neon-border .q-card.q-card--dark,body[data-theme=autumn].neon-border .q-date,body[data-theme=autumn].neon-border .q-date--dark{border:2px solid #b7763a;box-shadow:none}body[data-theme=flamingo].neon-border .q-card,body[data-theme=flamingo].neon-border .q-card.q-card--dark,body[data-theme=flamingo].neon-border .q-date,body[data-theme=flamingo].neon-border .q-date--dark{border:2px solid #f0f;box-shadow:none}body[data-theme=monochrome].neon-border .q-card,body[data-theme=monochrome].neon-border .q-card.q-card--dark,body[data-theme=monochrome].neon-border .q-date,body[data-theme=monochrome].neon-border .q-date--dark{border:2px solid #494949;box-shadow:none}body[data-theme=salvador].neon-border .q-card,body[data-theme=salvador].neon-border .q-card.q-card--dark,body[data-theme=salvador].neon-border .q-date,body[data-theme=salvador].neon-border .q-date--dark{border:2px solid #1976d2;box-shadow:none}body.hard-border .q-card,body.hard-border .q-card.q-card--dark,body.hard-border .q-date,body.hard-border .q-date--dark{box-shadow:0 0 0 1px rgba(0,0,0,.12),0 0 0 1px rgba(255,255,255,.2784313725);border:none}body.retro-border .q-card,body.retro-border .q-card.q-card--dark,body.retro-border .q-date,body.retro-border .q-date--dark{border:none;box-shadow:0 1px 5px rgba(255,255,255,.2),0 2px 2px rgba(255,255,255,.14),0 3px 1px -2px rgba(255,255,255,.12)}body.no-border .q-card,body.no-border .q-card.q-card--dark,body.no-border .q-date,body.no-border .q-date--dark{border:none;box-shadow:none}body[data-theme=classic]{--q-primary:#673ab7;--q-secondary:#9c27b0;--q-dark-page:#1f2234}body[data-theme=classic] [data-theme=classic] .q-card--dark,body[data-theme=classic] [data-theme=classic] .q-stepper--dark{background:#333646!important}body[data-theme=bitcoin]{--q-primary:#ea611d;--q-secondary:#e56f35;--q-dark-page:#2d293b}body[data-theme=bitcoin] [data-theme=bitcoin] .q-card--dark,body[data-theme=bitcoin] [data-theme=bitcoin] .q-stepper--dark{background:#333646!important}body[data-theme=freedom]{--q-primary:#e22156;--q-secondary:#b91a45;--q-dark-page:#462f36}body[data-theme=freedom] [data-theme=freedom] .q-card--dark,body[data-theme=freedom] [data-theme=freedom] .q-stepper--dark{background:#47393d!important}body[data-theme=cyber]{--q-primary:#7cb342;--q-secondary:#558b2f;--q-dark-page:#000}body[data-theme=cyber] [data-theme=cyber] .q-card--dark,body[data-theme=cyber] [data-theme=cyber] .q-stepper--dark{background:#1f2915!important}body[data-theme=mint]{--q-primary:#3ab77d;--q-secondary:#27b065;--q-dark-page:#1f342b}body[data-theme=mint] [data-theme=mint] .q-card--dark,body[data-theme=mint] [data-theme=mint] .q-stepper--dark{background:#334642!important}body[data-theme=autumn]{--q-primary:#b7763a;--q-secondary:#b07927;--q-dark-page:#34291f}body[data-theme=autumn] [data-theme=autumn] .q-card--dark,body[data-theme=autumn] [data-theme=autumn] .q-stepper--dark{background:#463f33!important}body[data-theme=flamingo]{--q-primary:#ff00ff;--q-secondary:#fda3fd;--q-dark-page:#2f032f}body[data-theme=flamingo] [data-theme=flamingo] .q-card--dark,body[data-theme=flamingo] [data-theme=flamingo] .q-stepper--dark{background:#bc23bc!important}body[data-theme=monochrome]{--q-primary:#494949;--q-secondary:#6b6b6b;--q-dark-page:#000}body[data-theme=monochrome] [data-theme=monochrome] .q-card--dark,body[data-theme=monochrome] [data-theme=monochrome] .q-stepper--dark{background:#272727!important}body[data-theme=salvador]{--q-primary:#1976d2;--q-secondary:#26a69a;--q-dark-page:#253647}body[data-theme=salvador] [data-theme=salvador] .q-card--dark,body[data-theme=salvador] [data-theme=salvador] .q-stepper--dark{background:#343d47!important}body.gradient-bg{background-image:linear-gradient(to bottom right,#fff,var(--q-primary));background-attachment:fixed}body.gradient-bg.body--dark{background-image:linear-gradient(to bottom right,var(--q-dark-page),#0a0a0a);background-attachment:fixed}body.bg-image::before{content:"";position:fixed;z-index:-1;top:0;left:0;width:100%;height:100%;filter:blur(8px);background-image:var(--background);background-size:cover;background-position:center;background-repeat:no-repeat}body.bg-image .q-page-container{backdrop-filter:none}body.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){--q-dark:rgba(29, 29, 29, 0.3);background-color:var(--q-dark)}body.body--dark .q-drawer,body.body--dark .q-header{--q-dark:rgba(29, 29, 29, 0.3);background-color:var(--q-dark);backdrop-filter:brightness(0.8)}body.rounded-ui .q-btn,body.rounded-ui .q-card{border-radius:10px}body[data-theme=classic].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(103,58,183,.08),rgba(156,39,176,.06))}body[data-theme=classic].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(103,58,183,.06),rgba(156,39,176,.04))}body[data-theme=classic].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(38.6192771084,42.356626506,64.7807228916),rgba(103,58,183,.07))}body[data-theme=classic].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(36.7144578313,40.2674698795,61.5855421687),rgba(103,58,183,.05))}body[data-theme=bitcoin].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(234,97,29,.08),rgba(229,111,53,.06))}body[data-theme=bitcoin].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(234,97,29,.06),rgba(229,111,53,.04))}body[data-theme=bitcoin].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(54.18,49.364,71.036),rgba(234,97,29,.07))}body[data-theme=bitcoin].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(51.885,47.273,68.027),rgba(234,97,29,.05))}body[data-theme=freedom].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(226,33,86,.08),rgba(185,26,69,.06))}body[data-theme=freedom].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(226,33,86,.06),rgba(185,26,69,.04))}body[data-theme=freedom].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(82.2051282051,55.1948717949,63.4153846154),rgba(226,33,86,.07))}body[data-theme=freedom].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(79.1538461538,53.1461538462,61.0615384615),rgba(226,33,86,.05))}body[data-theme=cyber].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(124,179,66,.08),rgba(85,139,47,.06))}body[data-theme=cyber].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(124,179,66,.06),rgba(85,139,47,.04))}body[data-theme=cyber].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(10.2,10.2,10.2),rgba(124,179,66,.07))}body[data-theme=cyber].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(7.65,7.65,7.65),rgba(124,179,66,.05))}body[data-theme=mint].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(58,183,125,.08),rgba(39,176,101,.06))}body[data-theme=mint].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(58,183,125,.06),rgba(39,176,101,.04))}body[data-theme=mint].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(38.6192771084,64.7807228916,53.5686746988),rgba(58,183,125,.07))}body[data-theme=mint].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(36.7144578313,61.5855421687,50.9265060241),rgba(58,183,125,.05))}body[data-theme=autumn].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(183,118,58,.08),rgba(176,121,39,.06))}body[data-theme=autumn].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(183,118,58,.06),rgba(176,121,39,.04))}body[data-theme=autumn].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(64.7807228916,51.0771084337,38.6192771084),rgba(183,118,58,.07))}body[data-theme=autumn].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(61.5855421687,48.5578313253,36.7144578313),rgba(183,118,58,.05))}body[data-theme=flamingo].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(255,0,255,.08),rgba(253,163,253,.06))}body[data-theme=flamingo].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(255,0,255,.06),rgba(253,163,253,.04))}body[data-theme=flamingo].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(66.176,4.224,66.176),rgba(255,0,255,.07))}body[data-theme=flamingo].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(61.382,3.918,61.382),rgba(255,0,255,.05))}body[data-theme=monochrome].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(73,73,73,.08),rgba(107,107,107,.06))}body[data-theme=monochrome].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(73,73,73,.06),rgba(107,107,107,.04))}body[data-theme=monochrome].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(10.2,10.2,10.2),rgba(73,73,73,.07))}body[data-theme=monochrome].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(7.65,7.65,7.65),rgba(73,73,73,.05))}body[data-theme=salvador].card-gradient .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgba(25,118,210,.08),rgba(38,166,154,.06))}body[data-theme=salvador].card-gradient .q-drawer{background-image:linear-gradient(165deg,rgba(25,118,210,.06),rgba(38,166,154,.04))}body[data-theme=salvador].card-gradient.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){background-image:linear-gradient(135deg,rgb(43.9888888889,64.2,84.4111111111),rgba(25,118,210,.07))}body[data-theme=salvador].card-gradient.body--dark .q-drawer{background-image:linear-gradient(165deg,rgb(42.2416666667,61.65,81.0583333333),rgba(25,118,210,.05))}body.card-shadow .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){box-shadow:0 10px 24px rgba(0,0,0,.18)}body.card-shadow.body--dark .q-card:not(.q-dialog .q-card,.lnbits__dialog-card,.q-dialog-plugin--dark){box-shadow:0 12px 28px rgba(0,0,0,.45)}body.no-burger-background .q-drawer{background-color:transparent!important;background-image:none!important;backdrop-filter:none!important;box-shadow:none!important}:root{--size:100px;--gap:25px}.home .wrapper{display:flex;flex-direction:column;gap:var(--gap);margin:auto;max-width:100%}.home .marquee{display:flex;overflow:hidden;user-select:none;gap:var(--gap);height:max-content;mask-image:linear-gradient(to right,hsla(0,0%,0%,0),hsl(0,0%,0%) 20%,hsl(0,0%,0%) 80%,hsla(0,0%,0%,0))}.home .marquee__group{flex-shrink:0;display:flex;align-items:center;justify-content:space-around;gap:var(--gap);min-width:100%;animation:scroll-x 60s linear infinite}.home .marquee:hover .marquee__group{animation-play-state:paused}.home .marquee__group div{width:var(--size)}@keyframes scroll-x{from{transform:translateX(0)}to{transform:translateX(calc(-100% - var(--gap)))}}[v-cloak]{display:none}body.body--dark .q-table--dark{background:0 0}body.body--dark .q-field--error .q-field__messages,body.body--dark .q-field--error .text-negative{color:#ff0!important}.lnbits-drawer__q-list .q-item{padding-top:5px!important;padding-bottom:5px!important;border-top-right-radius:3px;border-bottom-right-radius:3px}.lnbits-drawer__q-list .q-item.q-item--active{color:inherit;font-weight:700}.lnbits__dialog-card{width:500px}.blur-and-disable{filter:blur(4px);pointer-events:none;user-select:none;opacity:.6}.lnbits__table-bordered td,.lnbits__table-bordered th{border:1px solid #000;border-collapse:collapse}.q-table--dense .q-table__bottom,.q-table--dense td:first-child,.q-table--dense th:first-child{padding-left:6px!important}.q-table--dense .q-table__bottom,.q-table--dense td:last-child,.q-table--dense th:last-child{padding-right:6px!important}a.inherit{color:inherit;text-decoration:none}video{border-radius:3px}.material-icons{font-family:"Material Icons";font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;-moz-font-feature-settings:"liga";-moz-osx-font-smoothing:grayscale}.q-rating__icon{font-size:1em}.text-wrap{word-break:break-word}.q-card code{overflow-wrap:break-word}.qrcode__wrapper{position:relative;display:flex;align-items:center;justify-content:center;margin:0 auto}.qrcode__wrapper canvas{width:100%!important;height:100%!important;max-width:320px}.qrcode__image{position:absolute;max-width:52px;width:15%;overflow:hidden;background:#fff;overflow:hidden;padding:.2rem;border-radius:.2rem}.whitespace-pre-line{white-space:pre-line}.q-carousel__slide{background-size:contain;background-repeat:no-repeat}.q-dialog__inner--minimized{padding:12px}.first-install{display:flex;flex-direction:column;justify-content:center;align-items:center;height:100%}.first-install .grid{display:block}.first-install .hero-wrapper{display:none}.first-install .hero{display:block;height:100%;max-width:250px;background-image:url(/static/images/logos/lnbits.svg);background-position:center;background-size:contain;background-repeat:no-repeat}@media (min-width:992px){.first-install .grid{display:grid;grid-template-columns:1fr 1fr;grid-gap:1rem}.first-install .hero-wrapper{display:block;position:relative;height:100%;padding:1rem}}.wallet-list-card{margin-top:1px;margin-right:1rem}.wallet-list-card:first-child{margin-left:1px}@media (max-width:1024px){.wallet-card{background:0 0!important;box-shadow:none!important;border:none!important}.mobile-simple .wallet-wrapper{position:fixed!important;top:50%!important;left:50%!important;transform:translate(-50%,-50%)!important}.mobile-simple .wallet-card{width:90%!important}}.error-code{font-size:clamp(15vh, 20vw, 30vh)}.error-message{font-size:clamp(1.5rem, 3vw, 3.75rem);font-weight:300;opacity:.4} \ No newline at end of file diff --git a/lnbits/static/bundle.min.js b/lnbits/static/bundle.min.js index a8279ec72..3f33d32d0 100644 --- a/lnbits/static/bundle.min.js +++ b/lnbits/static/bundle.min.js @@ -3,46 +3,46 @@ //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var e,t;function n(){return e.apply(null,arguments)}function a(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function i(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function r(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var t;for(t in e)if(o(e,t))return!1;return!0}function s(e){return void 0===e}function l(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function u(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function c(e,t){var n,a=[],i=e.length;for(n=0;n>>0;for(t=0;t0)for(n=0;n=0?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+a}var M=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,L=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,R={},z={};function N(e,t,n,a){var i=a;"string"==typeof a&&(i=function(){return this[a]()}),e&&(z[e]=i),t&&(z[t[0]]=function(){return A(i.apply(this,arguments),t[1],t[2])}),n&&(z[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function O(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function I(e,t){return e.isValid()?(t=q(t,e.localeData()),R[t]=R[t]||function(e){var t,n,a=e.match(M);for(t=0,n=a.length;t=0&&L.test(e);)e=e.replace(L,a),L.lastIndex=0,n-=1;return e}var D={D:"date",dates:"date",date:"date",d:"day",days:"day",day:"day",e:"weekday",weekdays:"weekday",weekday:"weekday",E:"isoWeekday",isoweekdays:"isoWeekday",isoweekday:"isoWeekday",DDD:"dayOfYear",dayofyears:"dayOfYear",dayofyear:"dayOfYear",h:"hour",hours:"hour",hour:"hour",ms:"millisecond",milliseconds:"millisecond",millisecond:"millisecond",m:"minute",minutes:"minute",minute:"minute",M:"month",months:"month",month:"month",Q:"quarter",quarters:"quarter",quarter:"quarter",s:"second",seconds:"second",second:"second",gg:"weekYear",weekyears:"weekYear",weekyear:"weekYear",GG:"isoWeekYear",isoweekyears:"isoWeekYear",isoweekyear:"isoWeekYear",w:"week",weeks:"week",week:"week",W:"isoWeek",isoweeks:"isoWeek",isoweek:"isoWeek",y:"year",years:"year",year:"year"};function j(e){return"string"==typeof e?D[e]||D[e.toLowerCase()]:void 0}function B(e){var t,n,a={};for(n in e)o(e,n)&&(t=j(n))&&(a[t]=e[n]);return a}var F={date:9,day:11,weekday:11,isoWeekday:11,dayOfYear:4,hour:13,millisecond:16,minute:14,month:8,quarter:7,second:15,weekYear:1,isoWeekYear:1,week:5,isoWeek:5,year:1};var $,V=/\d/,U=/\d\d/,H=/\d{3}/,W=/\d{4}/,G=/[+-]?\d{6}/,K=/\d\d?/,Y=/\d\d\d\d?/,Q=/\d\d\d\d\d\d?/,Z=/\d{1,3}/,J=/\d{1,4}/,X=/[+-]?\d{1,6}/,ee=/\d+/,te=/[+-]?\d+/,ne=/Z|[+-]\d\d:?\d\d/gi,ae=/Z|[+-]\d\d(?::?\d\d)?/gi,ie=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,oe=/^[1-9]\d?/,re=/^([1-9]\d|\d)/;function se(e,t,n){$[e]=T(t)?t:function(e,a){return e&&n?n:t}}function le(e,t){return o($,e)?$[e](t._strict,t._locale):new RegExp(ue(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(e,t,n,a,i){return t||n||a||i})))}function ue(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ce(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function de(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=ce(t)),n}$={};var he={};function pe(e,t){var n,a,i=t;for("string"==typeof e&&(e=[e]),l(t)&&(i=function(e,n){n[t]=de(e)}),a=e.length,n=0;n68?1900:2e3)};var Pe,Ee=Ae("FullYear",!0);function Ae(e,t){return function(a){return null!=a?(Le(this,e,a),n.updateOffset(this,t),this):Me(this,e)}}function Me(e,t){if(!e.isValid())return NaN;var n=e._d,a=e._isUTC;switch(t){case"Milliseconds":return a?n.getUTCMilliseconds():n.getMilliseconds();case"Seconds":return a?n.getUTCSeconds():n.getSeconds();case"Minutes":return a?n.getUTCMinutes():n.getMinutes();case"Hours":return a?n.getUTCHours():n.getHours();case"Date":return a?n.getUTCDate():n.getDate();case"Day":return a?n.getUTCDay():n.getDay();case"Month":return a?n.getUTCMonth():n.getMonth();case"FullYear":return a?n.getUTCFullYear():n.getFullYear();default:return NaN}}function Le(e,t,n){var a,i,o,r,s;if(e.isValid()&&!isNaN(n)){switch(a=e._d,i=e._isUTC,t){case"Milliseconds":return void(i?a.setUTCMilliseconds(n):a.setMilliseconds(n));case"Seconds":return void(i?a.setUTCSeconds(n):a.setSeconds(n));case"Minutes":return void(i?a.setUTCMinutes(n):a.setMinutes(n));case"Hours":return void(i?a.setUTCHours(n):a.setHours(n));case"Date":return void(i?a.setUTCDate(n):a.setDate(n));case"FullYear":break;default:return}o=n,r=e.month(),s=29!==(s=e.date())||1!==r||ge(o)?s:28,i?a.setUTCFullYear(o,r,s):a.setFullYear(o,r,s)}}function Re(e,t){if(isNaN(e)||isNaN(t))return NaN;var n,a=(t%(n=12)+n)%n;return e+=(t-a)/12,1===a?ge(e)?29:28:31-a%7%2}Pe=Array.prototype.indexOf?Array.prototype.indexOf:function(e){var t;for(t=0;t=0?(s=new Date(e+400,t,n,a,i,o,r),isFinite(s.getFullYear())&&s.setFullYear(e)):s=new Date(e,t,n,a,i,o,r),s}function Ve(e){var t,n;return e<100&&e>=0?((n=Array.prototype.slice.call(arguments))[0]=e+400,t=new Date(Date.UTC.apply(null,n)),isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e)):t=new Date(Date.UTC.apply(null,arguments)),t}function Ue(e,t,n){var a=7+t-n;return-((7+Ve(e,0,a).getUTCDay()-t)%7)+a-1}function He(e,t,n,a,i){var o,r,s=1+7*(t-1)+(7+n-a)%7+Ue(e,a,i);return s<=0?r=Te(o=e-1)+s:s>Te(e)?(o=e+1,r=s-Te(e)):(o=e,r=s),{year:o,dayOfYear:r}}function We(e,t,n){var a,i,o=Ue(e.year(),t,n),r=Math.floor((e.dayOfYear()-o-1)/7)+1;return r<1?a=r+Ge(i=e.year()-1,t,n):r>Ge(e.year(),t,n)?(a=r-Ge(e.year(),t,n),i=e.year()+1):(i=e.year(),a=r),{week:a,year:i}}function Ge(e,t,n){var a=Ue(e,t,n),i=Ue(e+1,t,n);return(Te(e)-a+i)/7}N("w",["ww",2],"wo","week"),N("W",["WW",2],"Wo","isoWeek"),se("w",K,oe),se("ww",K,U),se("W",K,oe),se("WW",K,U),fe(["w","ww","W","WW"],function(e,t,n,a){t[a.substr(0,1)]=de(e)});function Ke(e,t){return e.slice(t,7).concat(e.slice(0,t))}N("d",0,"do","day"),N("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),N("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),N("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),N("e",0,0,"weekday"),N("E",0,0,"isoWeekday"),se("d",K),se("e",K),se("E",K),se("dd",function(e,t){return t.weekdaysMinRegex(e)}),se("ddd",function(e,t){return t.weekdaysShortRegex(e)}),se("dddd",function(e,t){return t.weekdaysRegex(e)}),fe(["dd","ddd","dddd"],function(e,t,n,a){var i=n._locale.weekdaysParse(e,a,n._strict);null!=i?t.d=i:p(n).invalidWeekday=e}),fe(["d","e","E"],function(e,t,n,a){t[a]=de(e)});var Ye="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Qe="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ze="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Je=ie,Xe=ie,et=ie;function tt(e,t,n){var a,i,o,r=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],a=0;a<7;++a)o=h([2e3,1]).day(a),this._minWeekdaysParse[a]=this.weekdaysMin(o,"").toLocaleLowerCase(),this._shortWeekdaysParse[a]=this.weekdaysShort(o,"").toLocaleLowerCase(),this._weekdaysParse[a]=this.weekdays(o,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(i=Pe.call(this._weekdaysParse,r))?i:null:"ddd"===t?-1!==(i=Pe.call(this._shortWeekdaysParse,r))?i:null:-1!==(i=Pe.call(this._minWeekdaysParse,r))?i:null:"dddd"===t?-1!==(i=Pe.call(this._weekdaysParse,r))||-1!==(i=Pe.call(this._shortWeekdaysParse,r))||-1!==(i=Pe.call(this._minWeekdaysParse,r))?i:null:"ddd"===t?-1!==(i=Pe.call(this._shortWeekdaysParse,r))||-1!==(i=Pe.call(this._weekdaysParse,r))||-1!==(i=Pe.call(this._minWeekdaysParse,r))?i:null:-1!==(i=Pe.call(this._minWeekdaysParse,r))||-1!==(i=Pe.call(this._weekdaysParse,r))||-1!==(i=Pe.call(this._shortWeekdaysParse,r))?i:null}function nt(){function e(e,t){return t.length-e.length}var t,n,a,i,o,r=[],s=[],l=[],u=[];for(t=0;t<7;t++)n=h([2e3,1]).day(t),a=ue(this.weekdaysMin(n,"")),i=ue(this.weekdaysShort(n,"")),o=ue(this.weekdays(n,"")),r.push(a),s.push(i),l.push(o),u.push(a),u.push(i),u.push(o);r.sort(e),s.sort(e),l.sort(e),u.sort(e),this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+r.join("|")+")","i")}function at(){return this.hours()%12||12}function it(e,t){N(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function ot(e,t){return t._meridiemParse}N("H",["HH",2],0,"hour"),N("h",["hh",2],0,at),N("k",["kk",2],0,function(){return this.hours()||24}),N("hmm",0,0,function(){return""+at.apply(this)+A(this.minutes(),2)}),N("hmmss",0,0,function(){return""+at.apply(this)+A(this.minutes(),2)+A(this.seconds(),2)}),N("Hmm",0,0,function(){return""+this.hours()+A(this.minutes(),2)}),N("Hmmss",0,0,function(){return""+this.hours()+A(this.minutes(),2)+A(this.seconds(),2)}),it("a",!0),it("A",!1),se("a",ot),se("A",ot),se("H",K,re),se("h",K,oe),se("k",K,oe),se("HH",K,U),se("hh",K,U),se("kk",K,U),se("hmm",Y),se("hmmss",Q),se("Hmm",Y),se("Hmmss",Q),pe(["H","HH"],ye),pe(["k","kk"],function(e,t,n){var a=de(e);t[ye]=24===a?0:a}),pe(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),pe(["h","hh"],function(e,t,n){t[ye]=de(e),p(n).bigHour=!0}),pe("hmm",function(e,t,n){var a=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a)),p(n).bigHour=!0}),pe("hmmss",function(e,t,n){var a=e.length-4,i=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a,2)),t[ke]=de(e.substr(i)),p(n).bigHour=!0}),pe("Hmm",function(e,t,n){var a=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a))}),pe("Hmmss",function(e,t,n){var a=e.length-4,i=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a,2)),t[ke]=de(e.substr(i))});var rt=Ae("Hours",!0);var st,lt={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:ze,monthsShort:Ne,week:{dow:0,doy:6},weekdays:Ye,weekdaysMin:Ze,weekdaysShort:Qe,meridiemParse:/[ap]\.?m?\.?/i},ut={},ct={};function dt(e,t){var n,a=Math.min(e.length,t.length);for(n=0;n0;){if(a=pt(i.slice(0,t).join("-")))return a;if(n&&n.length>=t&&dt(i,n)>=t-1)break;t--}o++}return st}(e)}function _t(e){var t,n=e._a;return n&&-2===p(e).overflow&&(t=n[ve]<0||n[ve]>11?ve:n[be]<1||n[be]>Re(n[_e],n[ve])?be:n[ye]<0||n[ye]>24||24===n[ye]&&(0!==n[we]||0!==n[ke]||0!==n[xe])?ye:n[we]<0||n[we]>59?we:n[ke]<0||n[ke]>59?ke:n[xe]<0||n[xe]>999?xe:-1,p(e)._overflowDayOfYear&&(t<_e||t>be)&&(t=be),p(e)._overflowWeeks&&-1===t&&(t=Se),p(e)._overflowWeekday&&-1===t&&(t=Ce),p(e).overflow=t),e}var vt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,bt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,yt=/Z|[+-]\d\d(?::?\d\d)?/,wt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],kt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],xt=/^\/?Date\((-?\d+)/i,St=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Ct={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Tt(e){var t,n,a,i,o,r,s=e._i,l=vt.exec(s)||bt.exec(s),u=wt.length,c=kt.length;if(l){for(p(e).iso=!0,t=0,n=u;t7)&&(l=!0)):(o=e._locale._week.dow,r=e._locale._week.doy,u=We(Nt(),o,r),n=At(t.gg,e._a[_e],u.year),a=At(t.w,u.week),null!=t.d?((i=t.d)<0||i>6)&&(l=!0):null!=t.e?(i=t.e+o,(t.e<0||t.e>6)&&(l=!0)):i=o);a<1||a>Ge(n,o,r)?p(e)._overflowWeeks=!0:null!=l?p(e)._overflowWeekday=!0:(s=He(n,a,i,o,r),e._a[_e]=s.year,e._dayOfYear=s.dayOfYear)}(e),null!=e._dayOfYear&&(r=At(e._a[_e],i[_e]),(e._dayOfYear>Te(r)||0===e._dayOfYear)&&(p(e)._overflowDayOfYear=!0),a=Ve(r,0,e._dayOfYear),e._a[ve]=a.getUTCMonth(),e._a[be]=a.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=s[t]=i[t];for(;t<7;t++)e._a[t]=s[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[ye]&&0===e._a[we]&&0===e._a[ke]&&0===e._a[xe]&&(e._nextDay=!0,e._a[ye]=0),e._d=(e._useUTC?Ve:$e).apply(null,s),o=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[ye]=24),e._w&&void 0!==e._w.d&&e._w.d!==o&&(p(e).weekdayMismatch=!0)}}function Lt(e){if(e._f!==n.ISO_8601)if(e._f!==n.RFC_2822){e._a=[],p(e).empty=!0;var t,a,i,o,r,s,l,u=""+e._i,c=u.length,d=0;for(l=(i=q(e._f,e._locale).match(M)||[]).length,t=0;t0&&p(e).unusedInput.push(r),u=u.slice(u.indexOf(a)+a.length),d+=a.length),z[o]?(a?p(e).empty=!1:p(e).unusedTokens.push(o),me(o,a,e)):e._strict&&!a&&p(e).unusedTokens.push(o);p(e).charsLeftOver=c-d,u.length>0&&p(e).unusedInput.push(u),e._a[ye]<=12&&!0===p(e).bigHour&&e._a[ye]>0&&(p(e).bigHour=void 0),p(e).parsedDateParts=e._a.slice(0),p(e).meridiem=e._meridiem,e._a[ye]=function(e,t,n){var a;if(null==n)return t;return null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?((a=e.isPM(n))&&t<12&&(t+=12),a||12!==t||(t=0),t):t}(e._locale,e._a[ye],e._meridiem),null!==(s=p(e).era)&&(e._a[_e]=e._locale.erasConvertYear(s,e._a[_e])),Mt(e),_t(e)}else Et(e);else Tt(e)}function Rt(e){var t=e._i,o=e._f;return e._locale=e._locale||gt(e._l),null===t||void 0===o&&""===t?m({nullInput:!0}):("string"==typeof t&&(e._i=t=e._locale.preparse(t)),y(t)?new b(_t(t)):(u(t)?e._d=t:a(o)?function(e){var t,n,a,i,o,r,s=!1,l=e._f.length;if(0===l)return p(e).invalidFormat=!0,void(e._d=new Date(NaN));for(i=0;ithis?this:e:m()});function qt(e,t){var n,i;if(1===t.length&&a(t[0])&&(t=t[0]),!t.length)return Nt();for(n=t[0],i=1;i=0?new Date(e+400,t,n)-pn:new Date(e,t,n).valueOf()}function gn(e,t,n){return e<100&&e>=0?Date.UTC(e+400,t,n)-pn:Date.UTC(e,t,n)}function _n(e,t){return t.erasAbbrRegex(e)}function vn(){var e,t,n,a,i,o=[],r=[],s=[],l=[],u=this.eras();for(e=0,t=u.length;e(o=Ge(e,a,i))&&(t=o),wn.call(this,e,t,n,a,i))}function wn(e,t,n,a,i){var o=He(e,t,n,a,i),r=Ve(o.year,0,o.dayOfYear);return this.year(r.getUTCFullYear()),this.month(r.getUTCMonth()),this.date(r.getUTCDate()),this}N("N",0,0,"eraAbbr"),N("NN",0,0,"eraAbbr"),N("NNN",0,0,"eraAbbr"),N("NNNN",0,0,"eraName"),N("NNNNN",0,0,"eraNarrow"),N("y",["y",1],"yo","eraYear"),N("y",["yy",2],0,"eraYear"),N("y",["yyy",3],0,"eraYear"),N("y",["yyyy",4],0,"eraYear"),se("N",_n),se("NN",_n),se("NNN",_n),se("NNNN",function(e,t){return t.erasNameRegex(e)}),se("NNNNN",function(e,t){return t.erasNarrowRegex(e)}),pe(["N","NN","NNN","NNNN","NNNNN"],function(e,t,n,a){var i=n._locale.erasParse(e,a,n._strict);i?p(n).era=i:p(n).invalidEra=e}),se("y",ee),se("yy",ee),se("yyy",ee),se("yyyy",ee),se("yo",function(e,t){return t._eraYearOrdinalRegex||ee}),pe(["y","yy","yyy","yyyy"],_e),pe(["yo"],function(e,t,n,a){var i;n._locale._eraYearOrdinalRegex&&(i=e.match(n._locale._eraYearOrdinalRegex)),n._locale.eraYearOrdinalParse?t[_e]=n._locale.eraYearOrdinalParse(e,i):t[_e]=parseInt(e,10)}),N(0,["gg",2],0,function(){return this.weekYear()%100}),N(0,["GG",2],0,function(){return this.isoWeekYear()%100}),bn("gggg","weekYear"),bn("ggggg","weekYear"),bn("GGGG","isoWeekYear"),bn("GGGGG","isoWeekYear"),se("G",te),se("g",te),se("GG",K,U),se("gg",K,U),se("GGGG",J,W),se("gggg",J,W),se("GGGGG",X,G),se("ggggg",X,G),fe(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,a){t[a.substr(0,2)]=de(e)}),fe(["gg","GG"],function(e,t,a,i){t[i]=n.parseTwoDigitYear(e)}),N("Q",0,"Qo","quarter"),se("Q",V),pe("Q",function(e,t){t[ve]=3*(de(e)-1)}),N("D",["DD",2],"Do","date"),se("D",K,oe),se("DD",K,U),se("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),pe(["D","DD"],be),pe("Do",function(e,t){t[be]=de(e.match(K)[0])});var kn=Ae("Date",!0);N("DDD",["DDDD",3],"DDDo","dayOfYear"),se("DDD",Z),se("DDDD",H),pe(["DDD","DDDD"],function(e,t,n){n._dayOfYear=de(e)}),N("m",["mm",2],0,"minute"),se("m",K,re),se("mm",K,U),pe(["m","mm"],we);var xn=Ae("Minutes",!1);N("s",["ss",2],0,"second"),se("s",K,re),se("ss",K,U),pe(["s","ss"],ke);var Sn,Cn,Tn=Ae("Seconds",!1);for(N("S",0,0,function(){return~~(this.millisecond()/100)}),N(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),N(0,["SSS",3],0,"millisecond"),N(0,["SSSS",4],0,function(){return 10*this.millisecond()}),N(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),N(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),N(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),N(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),N(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),se("S",Z,V),se("SS",Z,U),se("SSS",Z,H),Sn="SSSS";Sn.length<=9;Sn+="S")se(Sn,ee);function Pn(e,t){t[xe]=de(1e3*("0."+e))}for(Sn="S";Sn.length<=9;Sn+="S")pe(Sn,Pn);Cn=Ae("Milliseconds",!1),N("z",0,0,"zoneAbbr"),N("zz",0,0,"zoneName");var En=b.prototype;function An(e){return e}En.add=tn,En.calendar=function(e,t){1===arguments.length&&(arguments[0]?on(arguments[0])?(e=arguments[0],t=void 0):function(e){var t,n=i(e)&&!r(e),a=!1,s=["sameDay","nextDay","lastDay","nextWeek","lastWeek","sameElse"];for(t=0;tn.valueOf():n.valueOf()9999?I(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):T(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",I(n,"Z")):I(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},En.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,t,n,a="moment",i="";return this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",i="Z"),e="["+a+'("]',t=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",n=i+'[")]',this.format(e+t+"-MM-DD[T]HH:mm:ss.SSS"+n)},"undefined"!=typeof Symbol&&null!=Symbol.for&&(En[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),En.toJSON=function(){return this.isValid()?this.toISOString():null},En.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},En.unix=function(){return Math.floor(this.valueOf()/1e3)},En.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},En.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},En.eraName=function(){var e,t,n,a=this.localeData().eras();for(e=0,t=a.length;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},En.isLocal=function(){return!!this.isValid()&&!this._isUTC},En.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},En.isUtc=Gt,En.isUTC=Gt,En.zoneAbbr=function(){return this._isUTC?"UTC":""},En.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},En.dates=k("dates accessor is deprecated. Use date instead.",kn),En.months=k("months accessor is deprecated. Use month instead",Be),En.years=k("years accessor is deprecated. Use year instead",Ee),En.zone=k("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),En.isDSTShifted=k("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!s(this._isDSTShifted))return this._isDSTShifted;var e,t={};return v(t,this),(t=Rt(t))._a?(e=t._isUTC?h(t._a):Nt(t._a),this._isDSTShifted=this.isValid()&&function(e,t,n){var a,i=Math.min(e.length,t.length),o=Math.abs(e.length-t.length),r=0;for(a=0;a0):this._isDSTShifted=!1,this._isDSTShifted});var Mn=E.prototype;function Ln(e,t,n,a){var i=gt(),o=h().set(a,t);return i[n](o,e)}function Rn(e,t,n){if(l(e)&&(t=e,e=void 0),e=e||"",null!=t)return Ln(e,t,n,"month");var a,i=[];for(a=0;a<12;a++)i[a]=Ln(e,a,n,"month");return i}function zn(e,t,n,a){"boolean"==typeof e?(l(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,l(t)&&(n=t,t=void 0),t=t||"");var i,o=gt(),r=e?o._week.dow:0,s=[];if(null!=n)return Ln(t,(n+r)%7,a,"day");for(i=0;i<7;i++)s[i]=Ln(t,(i+r)%7,a,"day");return s}Mn.calendar=function(e,t,n){var a=this._calendar[e]||this._calendar.sameElse;return T(a)?a.call(t,n):a},Mn.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.match(M).map(function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e}).join(""),this._longDateFormat[e])},Mn.invalidDate=function(){return this._invalidDate},Mn.ordinal=function(e){return this._ordinal.replace("%d",e)},Mn.preparse=An,Mn.postformat=An,Mn.relativeTime=function(e,t,n,a){var i=this._relativeTime[n];return T(i)?i(e,t,n,a):i.replace(/%d/i,e)},Mn.pastFuture=function(e,t){var n=this._relativeTime[e>0?"future":"past"];return T(n)?n(t):n.replace(/%s/i,t)},Mn.set=function(e){var t,n;for(n in e)o(e,n)&&(T(t=e[n])?this[n]=t:this["_"+n]=t);this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Mn.eras=function(e,t){var a,i,o,r=this._eras||gt("en")._eras;for(a=0,i=r.length;a=0)return l[a]},Mn.erasConvertYear=function(e,t){var a=e.since<=e.until?1:-1;return void 0===t?n(e.since).year():n(e.since).year()+(t-e.offset)*a},Mn.erasAbbrRegex=function(e){return o(this,"_erasAbbrRegex")||vn.call(this),e?this._erasAbbrRegex:this._erasRegex},Mn.erasNameRegex=function(e){return o(this,"_erasNameRegex")||vn.call(this),e?this._erasNameRegex:this._erasRegex},Mn.erasNarrowRegex=function(e){return o(this,"_erasNarrowRegex")||vn.call(this),e?this._erasNarrowRegex:this._erasRegex},Mn.months=function(e,t){return e?a(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Oe).test(t)?"format":"standalone"][e.month()]:a(this._months)?this._months:this._months.standalone},Mn.monthsShort=function(e,t){return e?a(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Oe.test(t)?"format":"standalone"][e.month()]:a(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Mn.monthsParse=function(e,t,n){var a,i,o;if(this._monthsParseExact)return De.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),a=0;a<12;a++){if(i=h([2e3,a]),n&&!this._longMonthsParse[a]&&(this._longMonthsParse[a]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[a]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[a]||(o="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[a]=new RegExp(o.replace(".",""),"i")),n&&"MMMM"===t&&this._longMonthsParse[a].test(e))return a;if(n&&"MMM"===t&&this._shortMonthsParse[a].test(e))return a;if(!n&&this._monthsParse[a].test(e))return a}},Mn.monthsRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||Fe.call(this),e?this._monthsStrictRegex:this._monthsRegex):(o(this,"_monthsRegex")||(this._monthsRegex=qe),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},Mn.monthsShortRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||Fe.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(o(this,"_monthsShortRegex")||(this._monthsShortRegex=Ie),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},Mn.week=function(e){return We(e,this._week.dow,this._week.doy).week},Mn.firstDayOfYear=function(){return this._week.doy},Mn.firstDayOfWeek=function(){return this._week.dow},Mn.weekdays=function(e,t){var n=a(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(t)?"format":"standalone"];return!0===e?Ke(n,this._week.dow):e?n[e.day()]:n},Mn.weekdaysMin=function(e){return!0===e?Ke(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin},Mn.weekdaysShort=function(e){return!0===e?Ke(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort},Mn.weekdaysParse=function(e,t,n){var a,i,o;if(this._weekdaysParseExact)return tt.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),a=0;a<7;a++){if(i=h([2e3,1]).day(a),n&&!this._fullWeekdaysParse[a]&&(this._fullWeekdaysParse[a]=new RegExp("^"+this.weekdays(i,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[a]=new RegExp("^"+this.weekdaysShort(i,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[a]=new RegExp("^"+this.weekdaysMin(i,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[a]||(o="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[a]=new RegExp(o.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[a].test(e))return a;if(n&&"ddd"===t&&this._shortWeekdaysParse[a].test(e))return a;if(n&&"dd"===t&&this._minWeekdaysParse[a].test(e))return a;if(!n&&this._weekdaysParse[a].test(e))return a}},Mn.weekdaysRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(o(this,"_weekdaysRegex")||(this._weekdaysRegex=Je),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},Mn.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(o(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Xe),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Mn.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(o(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=et),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Mn.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},Mn.meridiem=function(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"},ft("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===de(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),n.lang=k("moment.lang is deprecated. Use moment.locale instead.",ft),n.langData=k("moment.langData is deprecated. Use moment.localeData instead.",gt);var Nn=Math.abs;function On(e,t,n,a){var i=Qt(t,n);return e._milliseconds+=a*i._milliseconds,e._days+=a*i._days,e._months+=a*i._months,e._bubble()}function In(e){return e<0?Math.floor(e):Math.ceil(e)}function qn(e){return 4800*e/146097}function Dn(e){return 146097*e/4800}function jn(e){return function(){return this.as(e)}}var Bn=jn("ms"),Fn=jn("s"),$n=jn("m"),Vn=jn("h"),Un=jn("d"),Hn=jn("w"),Wn=jn("M"),Gn=jn("Q"),Kn=jn("y"),Yn=Bn;function Qn(e){return function(){return this.isValid()?this._data[e]:NaN}}var Zn=Qn("milliseconds"),Jn=Qn("seconds"),Xn=Qn("minutes"),ea=Qn("hours"),ta=Qn("days"),na=Qn("months"),aa=Qn("years");var ia=Math.round,oa={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function ra(e,t,n,a,i){return i.relativeTime(t||1,!!n,e,a)}var sa=Math.abs;function la(e){return(e>0)-(e<0)||+e}function ua(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,a,i,o,r,s,l=sa(this._milliseconds)/1e3,u=sa(this._days),c=sa(this._months),d=this.asSeconds();return d?(e=ce(l/60),t=ce(e/60),l%=60,e%=60,n=ce(c/12),c%=12,a=l?l.toFixed(3).replace(/\.?0+$/,""):"",i=d<0?"-":"",o=la(this._months)!==la(d)?"-":"",r=la(this._days)!==la(d)?"-":"",s=la(this._milliseconds)!==la(d)?"-":"",i+"P"+(n?o+n+"Y":"")+(c?o+c+"M":"")+(u?r+u+"D":"")+(t||e||l?"T":"")+(t?s+t+"H":"")+(e?s+e+"M":"")+(l?s+a+"S":"")):"P0D"}var ca=jt.prototype;return ca.isValid=function(){return this._isValid},ca.abs=function(){var e=this._data;return this._milliseconds=Nn(this._milliseconds),this._days=Nn(this._days),this._months=Nn(this._months),e.milliseconds=Nn(e.milliseconds),e.seconds=Nn(e.seconds),e.minutes=Nn(e.minutes),e.hours=Nn(e.hours),e.months=Nn(e.months),e.years=Nn(e.years),this},ca.add=function(e,t){return On(this,e,t,1)},ca.subtract=function(e,t){return On(this,e,t,-1)},ca.as=function(e){if(!this.isValid())return NaN;var t,n,a=this._milliseconds;if("month"===(e=j(e))||"quarter"===e||"year"===e)switch(t=this._days+a/864e5,n=this._months+qn(t),e){case"month":return n;case"quarter":return n/3;case"year":return n/12}else switch(t=this._days+Math.round(Dn(this._months)),e){case"week":return t/7+a/6048e5;case"day":return t+a/864e5;case"hour":return 24*t+a/36e5;case"minute":return 1440*t+a/6e4;case"second":return 86400*t+a/1e3;case"millisecond":return Math.floor(864e5*t)+a;default:throw new Error("Unknown unit "+e)}},ca.asMilliseconds=Bn,ca.asSeconds=Fn,ca.asMinutes=$n,ca.asHours=Vn,ca.asDays=Un,ca.asWeeks=Hn,ca.asMonths=Wn,ca.asQuarters=Gn,ca.asYears=Kn,ca.valueOf=Yn,ca._bubble=function(){var e,t,n,a,i,o=this._milliseconds,r=this._days,s=this._months,l=this._data;return o>=0&&r>=0&&s>=0||o<=0&&r<=0&&s<=0||(o+=864e5*In(Dn(s)+r),r=0,s=0),l.milliseconds=o%1e3,e=ce(o/1e3),l.seconds=e%60,t=ce(e/60),l.minutes=t%60,n=ce(t/60),l.hours=n%24,r+=ce(n/24),s+=i=ce(qn(r)),r-=In(Dn(i)),a=ce(s/12),s%=12,l.days=r,l.months=s,l.years=a,this},ca.clone=function(){return Qt(this)},ca.get=function(e){return e=j(e),this.isValid()?this[e+"s"]():NaN},ca.milliseconds=Zn,ca.seconds=Jn,ca.minutes=Xn,ca.hours=ea,ca.days=ta,ca.weeks=function(){return ce(this.days()/7)},ca.months=na,ca.years=aa,ca.humanize=function(e,t){if(!this.isValid())return this.localeData().invalidDate();var n,a,i=!1,o=oa;return"object"==typeof e&&(t=e,e=!1),"boolean"==typeof e&&(i=e),"object"==typeof t&&(o=Object.assign({},oa,t),null!=t.s&&null==t.ss&&(o.ss=t.s-1)),a=function(e,t,n,a){var i=Qt(e).abs(),o=ia(i.as("s")),r=ia(i.as("m")),s=ia(i.as("h")),l=ia(i.as("d")),u=ia(i.as("M")),c=ia(i.as("w")),d=ia(i.as("y")),h=o<=n.ss&&["s",o]||o0,h[4]=a,ra.apply(null,h)}(this,!i,o,n=this.localeData()),i&&(a=n.pastFuture(+this,a)),n.postformat(a)},ca.toISOString=ua,ca.toString=ua,ca.toJSON=ua,ca.locale=sn,ca.localeData=un,ca.toIsoString=k("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ua),ca.lang=ln,N("X",0,0,"unix"),N("x",0,0,"valueOf"),se("x",te),se("X",/[+-]?\d+(\.\d{1,3})?/),pe("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e))}),pe("x",function(e,t,n){n._d=new Date(de(e))}), +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.moment=t()}(this,function(){"use strict";var e,t;function n(){return e.apply(null,arguments)}function a(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function i(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function r(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function o(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var t;for(t in e)if(r(e,t))return!1;return!0}function s(e){return void 0===e}function l(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function u(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function c(e,t){var n,a=[],i=e.length;for(n=0;n>>0;for(t=0;t0)for(n=0;n=0?n?"+":"":"-")+Math.pow(10,Math.max(0,i)).toString().substr(1)+a}var L=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,M=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,R={},z={};function I(e,t,n,a){var i=a;"string"==typeof a&&(i=function(){return this[a]()}),e&&(z[e]=i),t&&(z[t[0]]=function(){return A(i.apply(this,arguments),t[1],t[2])}),n&&(z[n]=function(){return this.localeData().ordinal(i.apply(this,arguments),e)})}function N(e){return e.match(/\[[\s\S]/)?e.replace(/^\[|\]$/g,""):e.replace(/\\/g,"")}function O(e,t){return e.isValid()?(t=j(t,e.localeData()),R[t]=R[t]||function(e){var t,n,a=e.match(L);for(t=0,n=a.length;t=0&&M.test(e);)e=e.replace(M,a),M.lastIndex=0,n-=1;return e}var D={D:"date",dates:"date",date:"date",d:"day",days:"day",day:"day",e:"weekday",weekdays:"weekday",weekday:"weekday",E:"isoWeekday",isoweekdays:"isoWeekday",isoweekday:"isoWeekday",DDD:"dayOfYear",dayofyears:"dayOfYear",dayofyear:"dayOfYear",h:"hour",hours:"hour",hour:"hour",ms:"millisecond",milliseconds:"millisecond",millisecond:"millisecond",m:"minute",minutes:"minute",minute:"minute",M:"month",months:"month",month:"month",Q:"quarter",quarters:"quarter",quarter:"quarter",s:"second",seconds:"second",second:"second",gg:"weekYear",weekyears:"weekYear",weekyear:"weekYear",GG:"isoWeekYear",isoweekyears:"isoWeekYear",isoweekyear:"isoWeekYear",w:"week",weeks:"week",week:"week",W:"isoWeek",isoweeks:"isoWeek",isoweek:"isoWeek",y:"year",years:"year",year:"year"};function q(e){return"string"==typeof e?D[e]||D[e.toLowerCase()]:void 0}function B(e){var t,n,a={};for(n in e)r(e,n)&&(t=q(n))&&(a[t]=e[n]);return a}var F={date:9,day:11,weekday:11,isoWeekday:11,dayOfYear:4,hour:13,millisecond:16,minute:14,month:8,quarter:7,second:15,weekYear:1,isoWeekYear:1,week:5,isoWeek:5,year:1};var V,U=/\d/,$=/\d\d/,H=/\d{3}/,W=/\d{4}/,G=/[+-]?\d{6}/,K=/\d\d?/,Y=/\d\d\d\d?/,Q=/\d\d\d\d\d\d?/,Z=/\d{1,3}/,J=/\d{1,4}/,X=/[+-]?\d{1,6}/,ee=/\d+/,te=/[+-]?\d+/,ne=/Z|[+-]\d\d:?\d\d/gi,ae=/Z|[+-]\d\d(?::?\d\d)?/gi,ie=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,re=/^[1-9]\d?/,oe=/^([1-9]\d|\d)/;function se(e,t,n){V[e]=T(t)?t:function(e,a){return e&&n?n:t}}function le(e,t){return r(V,e)?V[e](t._strict,t._locale):new RegExp(ue(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(e,t,n,a,i){return t||n||a||i})))}function ue(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function ce(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function de(e){var t=+e,n=0;return 0!==t&&isFinite(t)&&(n=ce(t)),n}V={};var he={};function pe(e,t){var n,a,i=t;for("string"==typeof e&&(e=[e]),l(t)&&(i=function(e,n){n[t]=de(e)}),a=e.length,n=0;n68?1900:2e3)};var Pe,Ee=Ae("FullYear",!0);function Ae(e,t){return function(a){return null!=a?(Me(this,e,a),n.updateOffset(this,t),this):Le(this,e)}}function Le(e,t){if(!e.isValid())return NaN;var n=e._d,a=e._isUTC;switch(t){case"Milliseconds":return a?n.getUTCMilliseconds():n.getMilliseconds();case"Seconds":return a?n.getUTCSeconds():n.getSeconds();case"Minutes":return a?n.getUTCMinutes():n.getMinutes();case"Hours":return a?n.getUTCHours():n.getHours();case"Date":return a?n.getUTCDate():n.getDate();case"Day":return a?n.getUTCDay():n.getDay();case"Month":return a?n.getUTCMonth():n.getMonth();case"FullYear":return a?n.getUTCFullYear():n.getFullYear();default:return NaN}}function Me(e,t,n){var a,i,r,o,s;if(e.isValid()&&!isNaN(n)){switch(a=e._d,i=e._isUTC,t){case"Milliseconds":return void(i?a.setUTCMilliseconds(n):a.setMilliseconds(n));case"Seconds":return void(i?a.setUTCSeconds(n):a.setSeconds(n));case"Minutes":return void(i?a.setUTCMinutes(n):a.setMinutes(n));case"Hours":return void(i?a.setUTCHours(n):a.setHours(n));case"Date":return void(i?a.setUTCDate(n):a.setDate(n));case"FullYear":break;default:return}r=n,o=e.month(),s=29!==(s=e.date())||1!==o||_e(r)?s:28,i?a.setUTCFullYear(r,o,s):a.setFullYear(r,o,s)}}function Re(e,t){if(isNaN(e)||isNaN(t))return NaN;var n,a=(t%(n=12)+n)%n;return e+=(t-a)/12,1===a?_e(e)?29:28:31-a%7%2}Pe=Array.prototype.indexOf?Array.prototype.indexOf:function(e){var t;for(t=0;t=0?(s=new Date(e+400,t,n,a,i,r,o),isFinite(s.getFullYear())&&s.setFullYear(e)):s=new Date(e,t,n,a,i,r,o),s}function Ue(e){var t,n;return e<100&&e>=0?((n=Array.prototype.slice.call(arguments))[0]=e+400,t=new Date(Date.UTC.apply(null,n)),isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e)):t=new Date(Date.UTC.apply(null,arguments)),t}function $e(e,t,n){var a=7+t-n;return-((7+Ue(e,0,a).getUTCDay()-t)%7)+a-1}function He(e,t,n,a,i){var r,o,s=1+7*(t-1)+(7+n-a)%7+$e(e,a,i);return s<=0?o=Te(r=e-1)+s:s>Te(e)?(r=e+1,o=s-Te(e)):(r=e,o=s),{year:r,dayOfYear:o}}function We(e,t,n){var a,i,r=$e(e.year(),t,n),o=Math.floor((e.dayOfYear()-r-1)/7)+1;return o<1?a=o+Ge(i=e.year()-1,t,n):o>Ge(e.year(),t,n)?(a=o-Ge(e.year(),t,n),i=e.year()+1):(i=e.year(),a=o),{week:a,year:i}}function Ge(e,t,n){var a=$e(e,t,n),i=$e(e+1,t,n);return(Te(e)-a+i)/7}I("w",["ww",2],"wo","week"),I("W",["WW",2],"Wo","isoWeek"),se("w",K,re),se("ww",K,$),se("W",K,re),se("WW",K,$),fe(["w","ww","W","WW"],function(e,t,n,a){t[a.substr(0,1)]=de(e)});function Ke(e,t){return e.slice(t,7).concat(e.slice(0,t))}I("d",0,"do","day"),I("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),I("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),I("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),I("e",0,0,"weekday"),I("E",0,0,"isoWeekday"),se("d",K),se("e",K),se("E",K),se("dd",function(e,t){return t.weekdaysMinRegex(e)}),se("ddd",function(e,t){return t.weekdaysShortRegex(e)}),se("dddd",function(e,t){return t.weekdaysRegex(e)}),fe(["dd","ddd","dddd"],function(e,t,n,a){var i=n._locale.weekdaysParse(e,a,n._strict);null!=i?t.d=i:p(n).invalidWeekday=e}),fe(["d","e","E"],function(e,t,n,a){t[a]=de(e)});var Ye="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Qe="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ze="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Je=ie,Xe=ie,et=ie;function tt(e,t,n){var a,i,r,o=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],a=0;a<7;++a)r=h([2e3,1]).day(a),this._minWeekdaysParse[a]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[a]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[a]=this.weekdays(r,"").toLocaleLowerCase();return n?"dddd"===t?-1!==(i=Pe.call(this._weekdaysParse,o))?i:null:"ddd"===t?-1!==(i=Pe.call(this._shortWeekdaysParse,o))?i:null:-1!==(i=Pe.call(this._minWeekdaysParse,o))?i:null:"dddd"===t?-1!==(i=Pe.call(this._weekdaysParse,o))||-1!==(i=Pe.call(this._shortWeekdaysParse,o))||-1!==(i=Pe.call(this._minWeekdaysParse,o))?i:null:"ddd"===t?-1!==(i=Pe.call(this._shortWeekdaysParse,o))||-1!==(i=Pe.call(this._weekdaysParse,o))||-1!==(i=Pe.call(this._minWeekdaysParse,o))?i:null:-1!==(i=Pe.call(this._minWeekdaysParse,o))||-1!==(i=Pe.call(this._weekdaysParse,o))||-1!==(i=Pe.call(this._shortWeekdaysParse,o))?i:null}function nt(){function e(e,t){return t.length-e.length}var t,n,a,i,r,o=[],s=[],l=[],u=[];for(t=0;t<7;t++)n=h([2e3,1]).day(t),a=ue(this.weekdaysMin(n,"")),i=ue(this.weekdaysShort(n,"")),r=ue(this.weekdays(n,"")),o.push(a),s.push(i),l.push(r),u.push(a),u.push(i),u.push(r);o.sort(e),s.sort(e),l.sort(e),u.sort(e),this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function at(){return this.hours()%12||12}function it(e,t){I(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function rt(e,t){return t._meridiemParse}I("H",["HH",2],0,"hour"),I("h",["hh",2],0,at),I("k",["kk",2],0,function(){return this.hours()||24}),I("hmm",0,0,function(){return""+at.apply(this)+A(this.minutes(),2)}),I("hmmss",0,0,function(){return""+at.apply(this)+A(this.minutes(),2)+A(this.seconds(),2)}),I("Hmm",0,0,function(){return""+this.hours()+A(this.minutes(),2)}),I("Hmmss",0,0,function(){return""+this.hours()+A(this.minutes(),2)+A(this.seconds(),2)}),it("a",!0),it("A",!1),se("a",rt),se("A",rt),se("H",K,oe),se("h",K,re),se("k",K,re),se("HH",K,$),se("hh",K,$),se("kk",K,$),se("hmm",Y),se("hmmss",Q),se("Hmm",Y),se("Hmmss",Q),pe(["H","HH"],ye),pe(["k","kk"],function(e,t,n){var a=de(e);t[ye]=24===a?0:a}),pe(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e),n._meridiem=e}),pe(["h","hh"],function(e,t,n){t[ye]=de(e),p(n).bigHour=!0}),pe("hmm",function(e,t,n){var a=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a)),p(n).bigHour=!0}),pe("hmmss",function(e,t,n){var a=e.length-4,i=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a,2)),t[ke]=de(e.substr(i)),p(n).bigHour=!0}),pe("Hmm",function(e,t,n){var a=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a))}),pe("Hmmss",function(e,t,n){var a=e.length-4,i=e.length-2;t[ye]=de(e.substr(0,a)),t[we]=de(e.substr(a,2)),t[ke]=de(e.substr(i))});var ot=Ae("Hours",!0);var st,lt={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:ze,monthsShort:Ie,week:{dow:0,doy:6},weekdays:Ye,weekdaysMin:Ze,weekdaysShort:Qe,meridiemParse:/[ap]\.?m?\.?/i},ut={},ct={};function dt(e,t){var n,a=Math.min(e.length,t.length);for(n=0;n0;){if(a=pt(i.slice(0,t).join("-")))return a;if(n&&n.length>=t&&dt(i,n)>=t-1)break;t--}r++}return st}(e)}function gt(e){var t,n=e._a;return n&&-2===p(e).overflow&&(t=n[ve]<0||n[ve]>11?ve:n[be]<1||n[be]>Re(n[ge],n[ve])?be:n[ye]<0||n[ye]>24||24===n[ye]&&(0!==n[we]||0!==n[ke]||0!==n[xe])?ye:n[we]<0||n[we]>59?we:n[ke]<0||n[ke]>59?ke:n[xe]<0||n[xe]>999?xe:-1,p(e)._overflowDayOfYear&&(tbe)&&(t=be),p(e)._overflowWeeks&&-1===t&&(t=Se),p(e)._overflowWeekday&&-1===t&&(t=Ce),p(e).overflow=t),e}var vt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,bt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,yt=/Z|[+-]\d\d(?::?\d\d)?/,wt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],kt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],xt=/^\/?Date\((-?\d+)/i,St=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Ct={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Tt(e){var t,n,a,i,r,o,s=e._i,l=vt.exec(s)||bt.exec(s),u=wt.length,c=kt.length;if(l){for(p(e).iso=!0,t=0,n=u;t7)&&(l=!0)):(r=e._locale._week.dow,o=e._locale._week.doy,u=We(It(),r,o),n=At(t.gg,e._a[ge],u.year),a=At(t.w,u.week),null!=t.d?((i=t.d)<0||i>6)&&(l=!0):null!=t.e?(i=t.e+r,(t.e<0||t.e>6)&&(l=!0)):i=r);a<1||a>Ge(n,r,o)?p(e)._overflowWeeks=!0:null!=l?p(e)._overflowWeekday=!0:(s=He(n,a,i,r,o),e._a[ge]=s.year,e._dayOfYear=s.dayOfYear)}(e),null!=e._dayOfYear&&(o=At(e._a[ge],i[ge]),(e._dayOfYear>Te(o)||0===e._dayOfYear)&&(p(e)._overflowDayOfYear=!0),a=Ue(o,0,e._dayOfYear),e._a[ve]=a.getUTCMonth(),e._a[be]=a.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=s[t]=i[t];for(;t<7;t++)e._a[t]=s[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[ye]&&0===e._a[we]&&0===e._a[ke]&&0===e._a[xe]&&(e._nextDay=!0,e._a[ye]=0),e._d=(e._useUTC?Ue:Ve).apply(null,s),r=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[ye]=24),e._w&&void 0!==e._w.d&&e._w.d!==r&&(p(e).weekdayMismatch=!0)}}function Mt(e){if(e._f!==n.ISO_8601)if(e._f!==n.RFC_2822){e._a=[],p(e).empty=!0;var t,a,i,r,o,s,l,u=""+e._i,c=u.length,d=0;for(l=(i=j(e._f,e._locale).match(L)||[]).length,t=0;t0&&p(e).unusedInput.push(o),u=u.slice(u.indexOf(a)+a.length),d+=a.length),z[r]?(a?p(e).empty=!1:p(e).unusedTokens.push(r),me(r,a,e)):e._strict&&!a&&p(e).unusedTokens.push(r);p(e).charsLeftOver=c-d,u.length>0&&p(e).unusedInput.push(u),e._a[ye]<=12&&!0===p(e).bigHour&&e._a[ye]>0&&(p(e).bigHour=void 0),p(e).parsedDateParts=e._a.slice(0),p(e).meridiem=e._meridiem,e._a[ye]=function(e,t,n){var a;if(null==n)return t;return null!=e.meridiemHour?e.meridiemHour(t,n):null!=e.isPM?((a=e.isPM(n))&&t<12&&(t+=12),a||12!==t||(t=0),t):t}(e._locale,e._a[ye],e._meridiem),null!==(s=p(e).era)&&(e._a[ge]=e._locale.erasConvertYear(s,e._a[ge])),Lt(e),gt(e)}else Et(e);else Tt(e)}function Rt(e){var t=e._i,r=e._f;return e._locale=e._locale||_t(e._l),null===t||void 0===r&&""===t?m({nullInput:!0}):("string"==typeof t&&(e._i=t=e._locale.preparse(t)),y(t)?new b(gt(t)):(u(t)?e._d=t:a(r)?function(e){var t,n,a,i,r,o,s=!1,l=e._f.length;if(0===l)return p(e).invalidFormat=!0,void(e._d=new Date(NaN));for(i=0;ithis?this:e:m()});function jt(e,t){var n,i;if(1===t.length&&a(t[0])&&(t=t[0]),!t.length)return It();for(n=t[0],i=1;i=0?new Date(e+400,t,n)-pn:new Date(e,t,n).valueOf()}function _n(e,t,n){return e<100&&e>=0?Date.UTC(e+400,t,n)-pn:Date.UTC(e,t,n)}function gn(e,t){return t.erasAbbrRegex(e)}function vn(){var e,t,n,a,i,r=[],o=[],s=[],l=[],u=this.eras();for(e=0,t=u.length;e(r=Ge(e,a,i))&&(t=r),wn.call(this,e,t,n,a,i))}function wn(e,t,n,a,i){var r=He(e,t,n,a,i),o=Ue(r.year,0,r.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}I("N",0,0,"eraAbbr"),I("NN",0,0,"eraAbbr"),I("NNN",0,0,"eraAbbr"),I("NNNN",0,0,"eraName"),I("NNNNN",0,0,"eraNarrow"),I("y",["y",1],"yo","eraYear"),I("y",["yy",2],0,"eraYear"),I("y",["yyy",3],0,"eraYear"),I("y",["yyyy",4],0,"eraYear"),se("N",gn),se("NN",gn),se("NNN",gn),se("NNNN",function(e,t){return t.erasNameRegex(e)}),se("NNNNN",function(e,t){return t.erasNarrowRegex(e)}),pe(["N","NN","NNN","NNNN","NNNNN"],function(e,t,n,a){var i=n._locale.erasParse(e,a,n._strict);i?p(n).era=i:p(n).invalidEra=e}),se("y",ee),se("yy",ee),se("yyy",ee),se("yyyy",ee),se("yo",function(e,t){return t._eraYearOrdinalRegex||ee}),pe(["y","yy","yyy","yyyy"],ge),pe(["yo"],function(e,t,n,a){var i;n._locale._eraYearOrdinalRegex&&(i=e.match(n._locale._eraYearOrdinalRegex)),n._locale.eraYearOrdinalParse?t[ge]=n._locale.eraYearOrdinalParse(e,i):t[ge]=parseInt(e,10)}),I(0,["gg",2],0,function(){return this.weekYear()%100}),I(0,["GG",2],0,function(){return this.isoWeekYear()%100}),bn("gggg","weekYear"),bn("ggggg","weekYear"),bn("GGGG","isoWeekYear"),bn("GGGGG","isoWeekYear"),se("G",te),se("g",te),se("GG",K,$),se("gg",K,$),se("GGGG",J,W),se("gggg",J,W),se("GGGGG",X,G),se("ggggg",X,G),fe(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,a){t[a.substr(0,2)]=de(e)}),fe(["gg","GG"],function(e,t,a,i){t[i]=n.parseTwoDigitYear(e)}),I("Q",0,"Qo","quarter"),se("Q",U),pe("Q",function(e,t){t[ve]=3*(de(e)-1)}),I("D",["DD",2],"Do","date"),se("D",K,re),se("DD",K,$),se("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),pe(["D","DD"],be),pe("Do",function(e,t){t[be]=de(e.match(K)[0])});var kn=Ae("Date",!0);I("DDD",["DDDD",3],"DDDo","dayOfYear"),se("DDD",Z),se("DDDD",H),pe(["DDD","DDDD"],function(e,t,n){n._dayOfYear=de(e)}),I("m",["mm",2],0,"minute"),se("m",K,oe),se("mm",K,$),pe(["m","mm"],we);var xn=Ae("Minutes",!1);I("s",["ss",2],0,"second"),se("s",K,oe),se("ss",K,$),pe(["s","ss"],ke);var Sn,Cn,Tn=Ae("Seconds",!1);for(I("S",0,0,function(){return~~(this.millisecond()/100)}),I(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),I(0,["SSS",3],0,"millisecond"),I(0,["SSSS",4],0,function(){return 10*this.millisecond()}),I(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),I(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),I(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),I(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),I(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),se("S",Z,U),se("SS",Z,$),se("SSS",Z,H),Sn="SSSS";Sn.length<=9;Sn+="S")se(Sn,ee);function Pn(e,t){t[xe]=de(1e3*("0."+e))}for(Sn="S";Sn.length<=9;Sn+="S")pe(Sn,Pn);Cn=Ae("Milliseconds",!1),I("z",0,0,"zoneAbbr"),I("zz",0,0,"zoneName");var En=b.prototype;function An(e){return e}En.add=tn,En.calendar=function(e,t){1===arguments.length&&(arguments[0]?rn(arguments[0])?(e=arguments[0],t=void 0):function(e){var t,n=i(e)&&!o(e),a=!1,s=["sameDay","nextDay","lastDay","nextWeek","lastWeek","sameElse"];for(t=0;tn.valueOf():n.valueOf()9999?O(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):T(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",O(n,"Z")):O(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},En.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,t,n,a="moment",i="";return this.isLocal()||(a=0===this.utcOffset()?"moment.utc":"moment.parseZone",i="Z"),e="["+a+'("]',t=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",n=i+'[")]',this.format(e+t+"-MM-DD[T]HH:mm:ss.SSS"+n)},"undefined"!=typeof Symbol&&null!=Symbol.for&&(En[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),En.toJSON=function(){return this.isValid()?this.toISOString():null},En.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},En.unix=function(){return Math.floor(this.valueOf()/1e3)},En.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},En.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},En.eraName=function(){var e,t,n,a=this.localeData().eras();for(e=0,t=a.length;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},En.isLocal=function(){return!!this.isValid()&&!this._isUTC},En.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},En.isUtc=Gt,En.isUTC=Gt,En.zoneAbbr=function(){return this._isUTC?"UTC":""},En.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},En.dates=k("dates accessor is deprecated. Use date instead.",kn),En.months=k("months accessor is deprecated. Use month instead",Be),En.years=k("years accessor is deprecated. Use year instead",Ee),En.zone=k("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()}),En.isDSTShifted=k("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function(){if(!s(this._isDSTShifted))return this._isDSTShifted;var e,t={};return v(t,this),(t=Rt(t))._a?(e=t._isUTC?h(t._a):It(t._a),this._isDSTShifted=this.isValid()&&function(e,t,n){var a,i=Math.min(e.length,t.length),r=Math.abs(e.length-t.length),o=0;for(a=0;a0):this._isDSTShifted=!1,this._isDSTShifted});var Ln=E.prototype;function Mn(e,t,n,a){var i=_t(),r=h().set(a,t);return i[n](r,e)}function Rn(e,t,n){if(l(e)&&(t=e,e=void 0),e=e||"",null!=t)return Mn(e,t,n,"month");var a,i=[];for(a=0;a<12;a++)i[a]=Mn(e,a,n,"month");return i}function zn(e,t,n,a){"boolean"==typeof e?(l(t)&&(n=t,t=void 0),t=t||""):(n=t=e,e=!1,l(t)&&(n=t,t=void 0),t=t||"");var i,r=_t(),o=e?r._week.dow:0,s=[];if(null!=n)return Mn(t,(n+o)%7,a,"day");for(i=0;i<7;i++)s[i]=Mn(t,(i+o)%7,a,"day");return s}Ln.calendar=function(e,t,n){var a=this._calendar[e]||this._calendar.sameElse;return T(a)?a.call(t,n):a},Ln.longDateFormat=function(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];return t||!n?t:(this._longDateFormat[e]=n.match(L).map(function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e}).join(""),this._longDateFormat[e])},Ln.invalidDate=function(){return this._invalidDate},Ln.ordinal=function(e){return this._ordinal.replace("%d",e)},Ln.preparse=An,Ln.postformat=An,Ln.relativeTime=function(e,t,n,a){var i=this._relativeTime[n];return T(i)?i(e,t,n,a):i.replace(/%d/i,e)},Ln.pastFuture=function(e,t){var n=this._relativeTime[e>0?"future":"past"];return T(n)?n(t):n.replace(/%s/i,t)},Ln.set=function(e){var t,n;for(n in e)r(e,n)&&(T(t=e[n])?this[n]=t:this["_"+n]=t);this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Ln.eras=function(e,t){var a,i,r,o=this._eras||_t("en")._eras;for(a=0,i=o.length;a=0)return l[a]},Ln.erasConvertYear=function(e,t){var a=e.since<=e.until?1:-1;return void 0===t?n(e.since).year():n(e.since).year()+(t-e.offset)*a},Ln.erasAbbrRegex=function(e){return r(this,"_erasAbbrRegex")||vn.call(this),e?this._erasAbbrRegex:this._erasRegex},Ln.erasNameRegex=function(e){return r(this,"_erasNameRegex")||vn.call(this),e?this._erasNameRegex:this._erasRegex},Ln.erasNarrowRegex=function(e){return r(this,"_erasNarrowRegex")||vn.call(this),e?this._erasNarrowRegex:this._erasRegex},Ln.months=function(e,t){return e?a(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Ne).test(t)?"format":"standalone"][e.month()]:a(this._months)?this._months:this._months.standalone},Ln.monthsShort=function(e,t){return e?a(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Ne.test(t)?"format":"standalone"][e.month()]:a(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Ln.monthsParse=function(e,t,n){var a,i,r;if(this._monthsParseExact)return De.call(this,e,t,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),a=0;a<12;a++){if(i=h([2e3,a]),n&&!this._longMonthsParse[a]&&(this._longMonthsParse[a]=new RegExp("^"+this.months(i,"").replace(".","")+"$","i"),this._shortMonthsParse[a]=new RegExp("^"+this.monthsShort(i,"").replace(".","")+"$","i")),n||this._monthsParse[a]||(r="^"+this.months(i,"")+"|^"+this.monthsShort(i,""),this._monthsParse[a]=new RegExp(r.replace(".",""),"i")),n&&"MMMM"===t&&this._longMonthsParse[a].test(e))return a;if(n&&"MMM"===t&&this._shortMonthsParse[a].test(e))return a;if(!n&&this._monthsParse[a].test(e))return a}},Ln.monthsRegex=function(e){return this._monthsParseExact?(r(this,"_monthsRegex")||Fe.call(this),e?this._monthsStrictRegex:this._monthsRegex):(r(this,"_monthsRegex")||(this._monthsRegex=je),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},Ln.monthsShortRegex=function(e){return this._monthsParseExact?(r(this,"_monthsRegex")||Fe.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(r(this,"_monthsShortRegex")||(this._monthsShortRegex=Oe),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},Ln.week=function(e){return We(e,this._week.dow,this._week.doy).week},Ln.firstDayOfYear=function(){return this._week.doy},Ln.firstDayOfWeek=function(){return this._week.dow},Ln.weekdays=function(e,t){var n=a(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(t)?"format":"standalone"];return!0===e?Ke(n,this._week.dow):e?n[e.day()]:n},Ln.weekdaysMin=function(e){return!0===e?Ke(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin},Ln.weekdaysShort=function(e){return!0===e?Ke(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort},Ln.weekdaysParse=function(e,t,n){var a,i,r;if(this._weekdaysParseExact)return tt.call(this,e,t,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),a=0;a<7;a++){if(i=h([2e3,1]).day(a),n&&!this._fullWeekdaysParse[a]&&(this._fullWeekdaysParse[a]=new RegExp("^"+this.weekdays(i,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[a]=new RegExp("^"+this.weekdaysShort(i,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[a]=new RegExp("^"+this.weekdaysMin(i,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[a]||(r="^"+this.weekdays(i,"")+"|^"+this.weekdaysShort(i,"")+"|^"+this.weekdaysMin(i,""),this._weekdaysParse[a]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===t&&this._fullWeekdaysParse[a].test(e))return a;if(n&&"ddd"===t&&this._shortWeekdaysParse[a].test(e))return a;if(n&&"dd"===t&&this._minWeekdaysParse[a].test(e))return a;if(!n&&this._weekdaysParse[a].test(e))return a}},Ln.weekdaysRegex=function(e){return this._weekdaysParseExact?(r(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(r(this,"_weekdaysRegex")||(this._weekdaysRegex=Je),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},Ln.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(r(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(r(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Xe),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Ln.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(r(this,"_weekdaysRegex")||nt.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(r(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=et),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Ln.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},Ln.meridiem=function(e,t,n){return e>11?n?"pm":"PM":n?"am":"AM"},ft("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===de(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),n.lang=k("moment.lang is deprecated. Use moment.locale instead.",ft),n.langData=k("moment.langData is deprecated. Use moment.localeData instead.",_t);var In=Math.abs;function Nn(e,t,n,a){var i=Qt(t,n);return e._milliseconds+=a*i._milliseconds,e._days+=a*i._days,e._months+=a*i._months,e._bubble()}function On(e){return e<0?Math.floor(e):Math.ceil(e)}function jn(e){return 4800*e/146097}function Dn(e){return 146097*e/4800}function qn(e){return function(){return this.as(e)}}var Bn=qn("ms"),Fn=qn("s"),Vn=qn("m"),Un=qn("h"),$n=qn("d"),Hn=qn("w"),Wn=qn("M"),Gn=qn("Q"),Kn=qn("y"),Yn=Bn;function Qn(e){return function(){return this.isValid()?this._data[e]:NaN}}var Zn=Qn("milliseconds"),Jn=Qn("seconds"),Xn=Qn("minutes"),ea=Qn("hours"),ta=Qn("days"),na=Qn("months"),aa=Qn("years");var ia=Math.round,ra={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function oa(e,t,n,a,i){return i.relativeTime(t||1,!!n,e,a)}var sa=Math.abs;function la(e){return(e>0)-(e<0)||+e}function ua(){if(!this.isValid())return this.localeData().invalidDate();var e,t,n,a,i,r,o,s,l=sa(this._milliseconds)/1e3,u=sa(this._days),c=sa(this._months),d=this.asSeconds();return d?(e=ce(l/60),t=ce(e/60),l%=60,e%=60,n=ce(c/12),c%=12,a=l?l.toFixed(3).replace(/\.?0+$/,""):"",i=d<0?"-":"",r=la(this._months)!==la(d)?"-":"",o=la(this._days)!==la(d)?"-":"",s=la(this._milliseconds)!==la(d)?"-":"",i+"P"+(n?r+n+"Y":"")+(c?r+c+"M":"")+(u?o+u+"D":"")+(t||e||l?"T":"")+(t?s+t+"H":"")+(e?s+e+"M":"")+(l?s+a+"S":"")):"P0D"}var ca=qt.prototype;return ca.isValid=function(){return this._isValid},ca.abs=function(){var e=this._data;return this._milliseconds=In(this._milliseconds),this._days=In(this._days),this._months=In(this._months),e.milliseconds=In(e.milliseconds),e.seconds=In(e.seconds),e.minutes=In(e.minutes),e.hours=In(e.hours),e.months=In(e.months),e.years=In(e.years),this},ca.add=function(e,t){return Nn(this,e,t,1)},ca.subtract=function(e,t){return Nn(this,e,t,-1)},ca.as=function(e){if(!this.isValid())return NaN;var t,n,a=this._milliseconds;if("month"===(e=q(e))||"quarter"===e||"year"===e)switch(t=this._days+a/864e5,n=this._months+jn(t),e){case"month":return n;case"quarter":return n/3;case"year":return n/12}else switch(t=this._days+Math.round(Dn(this._months)),e){case"week":return t/7+a/6048e5;case"day":return t+a/864e5;case"hour":return 24*t+a/36e5;case"minute":return 1440*t+a/6e4;case"second":return 86400*t+a/1e3;case"millisecond":return Math.floor(864e5*t)+a;default:throw new Error("Unknown unit "+e)}},ca.asMilliseconds=Bn,ca.asSeconds=Fn,ca.asMinutes=Vn,ca.asHours=Un,ca.asDays=$n,ca.asWeeks=Hn,ca.asMonths=Wn,ca.asQuarters=Gn,ca.asYears=Kn,ca.valueOf=Yn,ca._bubble=function(){var e,t,n,a,i,r=this._milliseconds,o=this._days,s=this._months,l=this._data;return r>=0&&o>=0&&s>=0||r<=0&&o<=0&&s<=0||(r+=864e5*On(Dn(s)+o),o=0,s=0),l.milliseconds=r%1e3,e=ce(r/1e3),l.seconds=e%60,t=ce(e/60),l.minutes=t%60,n=ce(t/60),l.hours=n%24,o+=ce(n/24),s+=i=ce(jn(o)),o-=On(Dn(i)),a=ce(s/12),s%=12,l.days=o,l.months=s,l.years=a,this},ca.clone=function(){return Qt(this)},ca.get=function(e){return e=q(e),this.isValid()?this[e+"s"]():NaN},ca.milliseconds=Zn,ca.seconds=Jn,ca.minutes=Xn,ca.hours=ea,ca.days=ta,ca.weeks=function(){return ce(this.days()/7)},ca.months=na,ca.years=aa,ca.humanize=function(e,t){if(!this.isValid())return this.localeData().invalidDate();var n,a,i=!1,r=ra;return"object"==typeof e&&(t=e,e=!1),"boolean"==typeof e&&(i=e),"object"==typeof t&&(r=Object.assign({},ra,t),null!=t.s&&null==t.ss&&(r.ss=t.s-1)),a=function(e,t,n,a){var i=Qt(e).abs(),r=ia(i.as("s")),o=ia(i.as("m")),s=ia(i.as("h")),l=ia(i.as("d")),u=ia(i.as("M")),c=ia(i.as("w")),d=ia(i.as("y")),h=r<=n.ss&&["s",r]||r0,h[4]=a,oa.apply(null,h)}(this,!i,r,n=this.localeData()),i&&(a=n.pastFuture(+this,a)),n.postformat(a)},ca.toISOString=ua,ca.toString=ua,ca.toJSON=ua,ca.locale=sn,ca.localeData=un,ca.toIsoString=k("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ua),ca.lang=ln,I("X",0,0,"unix"),I("x",0,0,"valueOf"),se("x",te),se("X",/[+-]?\d+(\.\d{1,3})?/),pe("X",function(e,t,n){n._d=new Date(1e3*parseFloat(e))}),pe("x",function(e,t,n){n._d=new Date(de(e))}), //! moment.js -n.version="2.30.1",e=Nt,n.fn=En,n.min=function(){return qt("isBefore",[].slice.call(arguments,0))},n.max=function(){return qt("isAfter",[].slice.call(arguments,0))},n.now=function(){return Date.now?Date.now():+new Date},n.utc=h,n.unix=function(e){return Nt(1e3*e)},n.months=function(e,t){return Rn(e,t,"months")},n.isDate=u,n.locale=ft,n.invalid=m,n.duration=Qt,n.isMoment=y,n.weekdays=function(e,t,n){return zn(e,t,n,"weekdays")},n.parseZone=function(){return Nt.apply(null,arguments).parseZone()},n.localeData=gt,n.isDuration=Bt,n.monthsShort=function(e,t){return Rn(e,t,"monthsShort")},n.weekdaysMin=function(e,t,n){return zn(e,t,n,"weekdaysMin")},n.defineLocale=mt,n.updateLocale=function(e,t){if(null!=t){var n,a,i=lt;null!=ut[e]&&null!=ut[e].parentLocale?ut[e].set(P(ut[e]._config,t)):(null!=(a=pt(e))&&(i=a._config),t=P(i,t),null==a&&(t.abbr=e),(n=new E(t)).parentLocale=ut[e],ut[e]=n),ft(e)}else null!=ut[e]&&(null!=ut[e].parentLocale?(ut[e]=ut[e].parentLocale,e===ft()&&ft(e)):null!=ut[e]&&delete ut[e]);return ut[e]},n.locales=function(){return x(ut)},n.weekdaysShort=function(e,t,n){return zn(e,t,n,"weekdaysShort")},n.normalizeUnits=j,n.relativeTimeRounding=function(e){return void 0===e?ia:"function"==typeof e&&(ia=e,!0)},n.relativeTimeThreshold=function(e,t){return void 0!==oa[e]&&(void 0===t?oa[e]:(oa[e]=t,"s"===e&&(oa.ss=t-1),!0))},n.calendarFormat=function(e,t){var n=e.diff(t,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"},n.prototype=En,n.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},n}),function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("underscore",t):(e="undefined"!=typeof globalThis?globalThis:e||self,function(){var n=e._,a=e._=t();a.noConflict=function(){return e._=n,a}}())}(this,function(){var e="1.13.8",t="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},n=Array.prototype,a=Object.prototype,i="undefined"!=typeof Symbol?Symbol.prototype:null,o=n.push,r=n.slice,s=a.toString,l=a.hasOwnProperty,u="undefined"!=typeof ArrayBuffer,c="undefined"!=typeof DataView,d=Array.isArray,h=Object.keys,p=Object.create,f=u&&ArrayBuffer.isView,m=isNaN,g=isFinite,_=!{toString:null}.propertyIsEnumerable("toString"),v=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],b=Math.pow(2,53)-1;function y(e,t){return t=null==t?e.length-1:+t,function(){for(var n=Math.max(arguments.length-t,0),a=Array(n),i=0;i=0&&n<=b}}function G(e){return function(t){return null==t?void 0:t[e]}}var K=G("byteLength"),Y=W(K),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var Z=u?function(e){return f?f(e)&&!j(e):Y(e)&&Q.test(s.call(e))}:H(!1),J=G("length");function X(e,t){t=function(e){for(var t={},n=e.length,a=0;a":">",'"':""","'":"'","`":"`"},Fe=je(Be),$e=je(ve(Be)),Ve=ne.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Ue=/(.)^/,He={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},We=/\\|'|\r|\n|\u2028|\u2029/g;function Ge(e){return"\\"+He[e]}var Ke=/^\s*(\w|\$)+\s*$/;var Ye=0;function Qe(e,t,n,a,i){if(!(a instanceof t))return e.apply(n,i);var o=Se(e.prototype),r=e.apply(o,i);return w(r)?r:o}var Ze=y(function(e,t){var n=Ze.placeholder,a=function(){for(var i=0,o=t.length,r=Array(o),s=0;s=r){if(!s.length)break;var l=s.pop();o=l.i,e=l.v,r=J(e)}else{var u=e[o++];s.length>=t?a[i++]=u:Xe(u)&&(B(u)||V(u))?(s.push({i:o,v:e}),o=0,r=J(e=u)):n||(a[i++]=u)}return a}var tt=y(function(e,t){var n=(t=et(t,!1,!1)).length;if(n<1)throw new Error("bindAll must be passed function names");for(;n--;){var a=t[n];e[a]=Je(e[a],e)}return e});var nt=y(function(e,t,n){return setTimeout(function(){return e.apply(null,n)},t)}),at=Ze(nt,ne,1);function it(e){return function(){return!e.apply(this,arguments)}}function ot(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}}var rt=Ze(ot,2);function st(e,t,n){t=Oe(t,n);for(var a,i=ee(e),o=0,r=i.length;o0?0:i-1;o>=0&&o0?s=o>=0?o:Math.max(o+l,s):l=o>=0?Math.min(o+1,l):o+l+1;else if(n&&o&&l)return a[o=n(a,i)]===i?o:-1;if(i!=i)return(o=t(r.call(a,s,l),U))>=0?o+s:-1;for(o=e>0?s:l-1;o>=0&&o=3;return function(t,n,a,i){var o=!Xe(t)&&ee(t),r=(o||t).length,s=e>0?0:r-1;for(i||(a=t[o?o[s]:s],s+=e);s>=0&&s=0}var Ct=y(function(e,t,n){var a,i;return N(t)?i=t:(t=Te(t),a=t.slice(0,-1),t=t[t.length-1]),_t(e,function(e){var o=i;if(!o){if(a&&a.length&&(e=Pe(e,a)),null==e)return;o=e[t]}return null==o?o:o.apply(e,n)})});function Tt(e,t){return _t(e,Le(t))}function Pt(e,t,n){var a,i,o=-1/0,r=-1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,l=(e=Xe(e)?e:_e(e)).length;so&&(o=a);else t=Oe(t,n),gt(e,function(e,n,a){((i=t(e,n,a))>r||i===-1/0&&o===-1/0)&&(o=e,r=i)});return o}var Et=/[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;function At(e){return e?B(e)?r.call(e):C(e)?e.match(Et):Xe(e)?_t(e,Ae):_e(e):[]}function Mt(e,t,n){if(null==t||n)return Xe(e)||(e=_e(e)),e[qe(e.length-1)];var a=At(e),i=J(a);t=Math.max(Math.min(t,i),0);for(var o=i-1,r=0;r1&&(a=Re(a,t[1])),t=oe(e)):(a=It,t=et(t,!1,!1),e=Object(e));for(var i=0,o=t.length;i1&&(n=t[1])):(t=_t(et(t,!1,!1),String),a=function(e,n){return!St(t,n)}),qt(e,a,n)});function jt(e,t,n){return r.call(e,0,Math.max(0,e.length-(null==t||n?1:t)))}function Bt(e,t,n){return null==e||e.length<1?null==t||n?void 0:[]:null==t||n?e[0]:jt(e,e.length-t)}function Ft(e,t,n){return r.call(e,null==t||n?1:t)}var $t=y(function(e,t){return t=et(t,!0,!0),wt(e,function(e){return!St(t,e)})}),Vt=y(function(e,t){return $t(e,t)});function Ut(e,t,n,a){x(t)||(a=n,n=t,t=!1),null!=n&&(n=Oe(n,a));for(var i=[],o=[],r=0,s=J(e);r=0))if(a.push(e),o.push(t),n.push(!0),c){if((p=e.length)!==t.length)return!1;for(;p--;)n.push({a:e[p],b:t[p]})}else{var f,m=ee(e);if(p=m.length,ee(t).length!==p)return!1;for(;p--;){if(!F(t,f=m[p]))return!1;n.push({a:e[f],b:t[f]})}}}else a.pop(),o.pop()}return!0},isMap:pe,isWeakMap:fe,isSet:me,isWeakSet:ge,keys:ee,allKeys:oe,values:_e,pairs:function(e){for(var t=ee(e),n=t.length,a=Array(n),i=0;it?(a&&(clearTimeout(a),a=null),s=u,r=e.apply(i,o),a||(i=o=null)):a||!1===n.trailing||(a=setTimeout(l,c)),r};return u.cancel=function(){clearTimeout(a),s=0,a=i=o=null},u},debounce:function(e,t,n){var a,i,o,r,s,l=function(){var u=De()-i;t>u?a=setTimeout(l,t-u):(a=null,n||(r=e.apply(s,o)),a||(o=s=null))},u=y(function(u){return s=this,o=u,i=De(),a||(a=setTimeout(l,t),n&&(r=e.apply(s,o))),r});return u.cancel=function(){clearTimeout(a),a=o=s=null},u},wrap:function(e,t){return Ze(t,e)},negate:it,compose:function(){var e=arguments,t=e.length-1;return function(){for(var n=t,a=e[t].apply(this,arguments);n--;)a=e[n].call(this,a);return a}},after:function(e,t){return function(){if(--e<1)return t.apply(this,arguments)}},before:ot,once:rt,findKey:st,findIndex:ut,findLastIndex:ct,sortedIndex:dt,indexOf:pt,lastIndexOf:ft,find:mt,detect:mt,findWhere:function(e,t){return mt(e,Me(t))},each:gt,forEach:gt,map:_t,collect:_t,reduce:bt,foldl:bt,inject:bt,reduceRight:yt,foldr:yt,filter:wt,select:wt,reject:function(e,t,n){return wt(e,it(Oe(t)),n)},every:kt,all:kt,some:xt,any:xt,contains:St,includes:St,include:St,invoke:Ct,pluck:Tt,where:function(e,t){return wt(e,Me(t))},max:Pt,min:function(e,t,n){var a,i,o=1/0,r=1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,l=(e=Xe(e)?e:_e(e)).length;sa||void 0===n)return 1;if(ne.length)&&(t=e.length);for(var n=0,a=Array(t);n=0&&n<=b}}function G(e){return function(t){return null==t?void 0:t[e]}}var K=G("byteLength"),Y=W(K),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var Z=u?function(e){return f?f(e)&&!q(e):Y(e)&&Q.test(s.call(e))}:H(!1),J=G("length");function X(e,t){t=function(e){for(var t={},n=e.length,a=0;a":">",'"':""","'":"'","`":"`"},Fe=qe(Be),Ve=qe(ve(Be)),Ue=ne.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},$e=/(.)^/,He={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},We=/\\|'|\r|\n|\u2028|\u2029/g;function Ge(e){return"\\"+He[e]}var Ke=/^\s*(\w|\$)+\s*$/;var Ye=0;function Qe(e,t,n,a,i){if(!(a instanceof t))return e.apply(n,i);var r=Se(e.prototype),o=e.apply(r,i);return w(o)?o:r}var Ze=y(function(e,t){var n=Ze.placeholder,a=function(){for(var i=0,r=t.length,o=Array(r),s=0;s=o){if(!s.length)break;var l=s.pop();r=l.i,e=l.v,o=J(e)}else{var u=e[r++];s.length>=t?a[i++]=u:Xe(u)&&(B(u)||U(u))?(s.push({i:r,v:e}),r=0,o=J(e=u)):n||(a[i++]=u)}return a}var tt=y(function(e,t){var n=(t=et(t,!1,!1)).length;if(n<1)throw new Error("bindAll must be passed function names");for(;n--;){var a=t[n];e[a]=Je(e[a],e)}return e});var nt=y(function(e,t,n){return setTimeout(function(){return e.apply(null,n)},t)}),at=Ze(nt,ne,1);function it(e){return function(){return!e.apply(this,arguments)}}function rt(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}}var ot=Ze(rt,2);function st(e,t,n){t=Ne(t,n);for(var a,i=ee(e),r=0,o=i.length;r0?0:i-1;r>=0&&r0?s=r>=0?r:Math.max(r+l,s):l=r>=0?Math.min(r+1,l):r+l+1;else if(n&&r&&l)return a[r=n(a,i)]===i?r:-1;if(i!=i)return(r=t(o.call(a,s,l),$))>=0?r+s:-1;for(r=e>0?s:l-1;r>=0&&r=3;return function(t,n,a,i){var r=!Xe(t)&&ee(t),o=(r||t).length,s=e>0?0:o-1;for(i||(a=t[r?r[s]:s],s+=e);s>=0&&s=0}var Ct=y(function(e,t,n){var a,i;return I(t)?i=t:(t=Te(t),a=t.slice(0,-1),t=t[t.length-1]),gt(e,function(e){var r=i;if(!r){if(a&&a.length&&(e=Pe(e,a)),null==e)return;r=e[t]}return null==r?r:r.apply(e,n)})});function Tt(e,t){return gt(e,Me(t))}function Pt(e,t,n){var a,i,r=-1/0,o=-1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,l=(e=Xe(e)?e:ge(e)).length;sr&&(r=a);else t=Ne(t,n),_t(e,function(e,n,a){((i=t(e,n,a))>o||i===-1/0&&r===-1/0)&&(r=e,o=i)});return r}var Et=/[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;function At(e){return e?B(e)?o.call(e):C(e)?e.match(Et):Xe(e)?gt(e,Ae):ge(e):[]}function Lt(e,t,n){if(null==t||n)return Xe(e)||(e=ge(e)),e[je(e.length-1)];var a=At(e),i=J(a);t=Math.max(Math.min(t,i),0);for(var r=i-1,o=0;o1&&(a=Re(a,t[1])),t=re(e)):(a=Ot,t=et(t,!1,!1),e=Object(e));for(var i=0,r=t.length;i1&&(n=t[1])):(t=gt(et(t,!1,!1),String),a=function(e,n){return!St(t,n)}),jt(e,a,n)});function qt(e,t,n){return o.call(e,0,Math.max(0,e.length-(null==t||n?1:t)))}function Bt(e,t,n){return null==e||e.length<1?null==t||n?void 0:[]:null==t||n?e[0]:qt(e,e.length-t)}function Ft(e,t,n){return o.call(e,null==t||n?1:t)}var Vt=y(function(e,t){return t=et(t,!0,!0),wt(e,function(e){return!St(t,e)})}),Ut=y(function(e,t){return Vt(e,t)});function $t(e,t,n,a){x(t)||(a=n,n=t,t=!1),null!=n&&(n=Ne(n,a));for(var i=[],r=[],o=0,s=J(e);o=0))if(a.push(e),r.push(t),n.push(!0),c){if((p=e.length)!==t.length)return!1;for(;p--;)n.push({a:e[p],b:t[p]})}else{var f,m=ee(e);if(p=m.length,ee(t).length!==p)return!1;for(;p--;){if(!F(t,f=m[p]))return!1;n.push({a:e[f],b:t[f]})}}}else a.pop(),r.pop()}return!0},isMap:pe,isWeakMap:fe,isSet:me,isWeakSet:_e,keys:ee,allKeys:re,values:ge,pairs:function(e){for(var t=ee(e),n=t.length,a=Array(n),i=0;it?(a&&(clearTimeout(a),a=null),s=u,o=e.apply(i,r),a||(i=r=null)):a||!1===n.trailing||(a=setTimeout(l,c)),o};return u.cancel=function(){clearTimeout(a),s=0,a=i=r=null},u},debounce:function(e,t,n){var a,i,r,o,s,l=function(){var u=De()-i;t>u?a=setTimeout(l,t-u):(a=null,n||(o=e.apply(s,r)),a||(r=s=null))},u=y(function(u){return s=this,r=u,i=De(),a||(a=setTimeout(l,t),n&&(o=e.apply(s,r))),o});return u.cancel=function(){clearTimeout(a),a=r=s=null},u},wrap:function(e,t){return Ze(t,e)},negate:it,compose:function(){var e=arguments,t=e.length-1;return function(){for(var n=t,a=e[t].apply(this,arguments);n--;)a=e[n].call(this,a);return a}},after:function(e,t){return function(){if(--e<1)return t.apply(this,arguments)}},before:rt,once:ot,findKey:st,findIndex:ut,findLastIndex:ct,sortedIndex:dt,indexOf:pt,lastIndexOf:ft,find:mt,detect:mt,findWhere:function(e,t){return mt(e,Le(t))},each:_t,forEach:_t,map:gt,collect:gt,reduce:bt,foldl:bt,inject:bt,reduceRight:yt,foldr:yt,filter:wt,select:wt,reject:function(e,t,n){return wt(e,it(Ne(t)),n)},every:kt,all:kt,some:xt,any:xt,contains:St,includes:St,include:St,invoke:Ct,pluck:Tt,where:function(e,t){return wt(e,Le(t))},max:Pt,min:function(e,t,n){var a,i,r=1/0,o=1/0;if(null==t||"number"==typeof t&&"object"!=typeof e[0]&&null!=e)for(var s=0,l=(e=Xe(e)?e:ge(e)).length;sa||void 0===n)return 1;if(ne.length)&&(t=e.length);for(var n=0,a=Array(t);n3?(i=f===a)&&(l=o[(s=o[4])?5:(s=3,3)],o[4]=o[5]=e):o[0]<=p&&((i=n<2&&pa||a>f)&&(o[4]=n,o[5]=a,h.n=f,s=0))}if(i||n>1)return r;throw d=!0,a}return function(i,c,f){if(u>1)throw TypeError("Generator is already running");for(d&&1===c&&p(c,f),s=c,l=f;(t=s<2?e:l)||!d;){o||(s?s<3?(s>1&&(h.n=-1),p(s,l)):h.n=l:h.v=l);try{if(u=2,o){if(s||(i="next"),t=o[i]){if(!(t=t.call(o,l)))throw TypeError("iterator result is not an object");if(!t.done)return t;l=t.value,s<2&&(s=0)}else 1===s&&(t=o.return)&&t.call(o),s<2&&(l=TypeError("The iterator does not provide a '"+i+"' method"),s=1);o=e}else if((t=(d=h.n<0)?l:n.call(a,h))!==r)break}catch(t){o=e,s=1,l=t}finally{u=1}}return{value:t,done:d}}}(n,i,o),!0),u}var r={};function s(){}function l(){}function u(){}t=Object.getPrototypeOf;var c=[][a]?t(t([][a]())):(b(t={},a,function(){return this}),t),d=u.prototype=s.prototype=Object.create(c);function h(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,u):(e.__proto__=u,b(e,i,"GeneratorFunction")),e.prototype=Object.create(d),e}return l.prototype=u,b(d,"constructor",u),b(u,"constructor",l),l.displayName="GeneratorFunction",b(u,i,"GeneratorFunction"),b(d),b(d,i,"Generator"),b(d,a,function(){return this}),b(d,"toString",function(){return"[object Generator]"}),(v=function(){return{w:o,m:h}})()}function b(e,t,n,a){var i=Object.defineProperty;try{i({},"",{})}catch(e){i=0}b=function(e,t,n,a){function o(t,n){b(e,t,function(e){return this._invoke(t,n,e)})}t?i?i(e,t,{value:n,enumerable:!a,configurable:!a,writable:!a}):e[t]=n:(o("next",0),o("throw",1),o("return",2))},b(e,t,n,a)}function y(e){if(null!=e){var t=e["function"==typeof Symbol&&Symbol.iterator||"@@iterator"],n=0;if(t)return t.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length))return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}throw new TypeError(typeof e+" is not iterable")}function w(e,t){return w=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},w(e,t)}function k(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var a,i,o,r,s=[],l=!0,u=!1;try{if(o=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;l=!1}else for(;!(l=(a=o.call(n)).done)&&(s.push(a.value),s.length!==t);l=!0);}catch(e){u=!0,i=e}finally{try{if(!l&&null!=n.return&&(r=n.return(),Object(r)!==r))return}finally{if(u)throw i}}return s}}(e,t)||T(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function x(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||T(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function S(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t||"default");if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}function C(e){return C="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},C(e)}function T(e,n){if(e){if("string"==typeof e)return t(e,n);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,n):void 0}}function P(e){return function(){return new E(e.apply(this,arguments))}}function E(t){var n,a;function i(n,a){try{var r=t[n](a),s=r.value,l=s instanceof e;Promise.resolve(l?s.v:s).then(function(e){if(l){var a="return"===n?"return":"next";if(!s.k||e.done)return i(a,e);e=t[a](e).value}o(r.done?"return":"normal",e)},function(e){i("throw",e)})}catch(e){o("throw",e)}}function o(e,t){switch(e){case"return":n.resolve({value:t,done:!0});break;case"throw":n.reject(t);break;default:n.resolve({value:t,done:!1})}(n=n.next)?i(n.key,n.arg):a=null}this._invoke=function(e,t){return new Promise(function(o,r){var s={key:e,arg:t,resolve:o,reject:r,next:null};a?a=a.next=s:(n=a=s,i(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}function A(e){var t="function"==typeof Map?new Map:void 0;return A=function(e){if(null===e||!function(e){try{return-1!==Function.toString.call(e).indexOf("[native code]")}catch(t){return"function"==typeof e}}(e))return e;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return function(e,t,n){if(m())return Reflect.construct.apply(null,arguments);var a=[null];a.push.apply(a,t);var i=new(e.bind.apply(e,a));return n&&w(i,n.prototype),i}(e,arguments,p(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),w(n,e)},A(e)}function M(e,t){return function(){return e.apply(t,arguments)}}E.prototype["function"==typeof Symbol&&Symbol.asyncIterator||"@@asyncIterator"]=function(){return this},E.prototype.next=function(e){return this._invoke("next",e)},E.prototype.throw=function(e){return this._invoke("throw",e)},E.prototype.return=function(e){return this._invoke("return",e)};var L,R=Object.prototype.toString,z=Object.getPrototypeOf,N=Symbol.iterator,O=Symbol.toStringTag,I=(L=Object.create(null),function(e){var t=R.call(e);return L[t]||(L[t]=t.slice(8,-1).toLowerCase())}),q=function(e){return e=e.toLowerCase(),function(t){return I(t)===e}},D=function(e){return function(t){return C(t)===e}},j=Array.isArray,B=D("undefined");function F(e){return null!==e&&!B(e)&&null!==e.constructor&&!B(e.constructor)&&U(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}var $=q("ArrayBuffer");var V=D("string"),U=D("function"),H=D("number"),W=function(e){return null!==e&&"object"===C(e)},G=function(e){if("object"!==I(e))return!1;var t=z(e);return!(null!==t&&t!==Object.prototype&&null!==Object.getPrototypeOf(t)||O in e||N in e)},K=q("Date"),Y=q("File"),Q=q("Blob"),Z=q("FileList"),J=q("URLSearchParams"),X=k(["ReadableStream","Request","Response","Headers"].map(q),4),ee=X[0],te=X[1],ne=X[2],ae=X[3];function ie(e,t){var n,a,i=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).allOwnKeys,o=void 0!==i&&i;if(null!=e)if("object"!==C(e)&&(e=[e]),j(e))for(n=0,a=e.length;n0;)if(t===(n=a[i]).toLowerCase())return n;return null}var re="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:global,se=function(e){return!B(e)&&e!==re};var le,ue=(le="undefined"!=typeof Uint8Array&&z(Uint8Array),function(e){return le&&e instanceof le}),ce=q("HTMLFormElement"),de=function(){var e=Object.prototype.hasOwnProperty;return function(t,n){return e.call(t,n)}}(),he=q("RegExp"),pe=function(e,t){var n=Object.getOwnPropertyDescriptors(e),a={};ie(n,function(n,i){var o;!1!==(o=t(n,i,e))&&(a[i]=o||n)}),Object.defineProperties(e,a)};var fe,me,ge,_e,ve=q("AsyncFunction"),be=(fe="function"==typeof setImmediate,me=U(re.postMessage),fe?setImmediate:me?(ge="axios@".concat(Math.random()),_e=[],re.addEventListener("message",function(e){var t=e.source,n=e.data;t===re&&n===ge&&_e.length&&_e.shift()()},!1),function(e){_e.push(e),re.postMessage(ge,"*")}):function(e){return setTimeout(e)}),ye="undefined"!=typeof queueMicrotask?queueMicrotask.bind(re):"undefined"!=typeof process&&process.nextTick||be,we={isArray:j,isArrayBuffer:$,isBuffer:F,isFormData:function(e){var t;return e&&("function"==typeof FormData&&e instanceof FormData||U(e.append)&&("formdata"===(t=I(e))||"object"===t&&U(e.toString)&&"[object FormData]"===e.toString()))},isArrayBufferView:function(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&$(e.buffer)},isString:V,isNumber:H,isBoolean:function(e){return!0===e||!1===e},isObject:W,isPlainObject:G,isEmptyObject:function(e){if(!W(e)||F(e))return!1;try{return 0===Object.keys(e).length&&Object.getPrototypeOf(e)===Object.prototype}catch(e){return!1}},isReadableStream:ee,isRequest:te,isResponse:ne,isHeaders:ae,isUndefined:B,isDate:K,isFile:Y,isBlob:Q,isRegExp:he,isFunction:U,isStream:function(e){return W(e)&&U(e.pipe)},isURLSearchParams:J,isTypedArray:ue,isFileList:Z,forEach:ie,merge:function e(){for(var t=se(this)&&this||{},n=t.caseless,a=t.skipUndefined,i={},o=function(t,o){if("__proto__"!==o&&"constructor"!==o&&"prototype"!==o){var r=n&&oe(i,o)||o;G(i[r])&&G(t)?i[r]=e(i[r],t):G(t)?i[r]=e({},t):j(t)?i[r]=t.slice():a&&B(t)||(i[r]=t)}},r=0,s=arguments.length;r3&&void 0!==arguments[3]?arguments[3]:{}).allOwnKeys}),e},trim:function(e){return e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},stripBOM:function(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e},inherits:function(e,t,n,a){e.prototype=Object.create(t.prototype,a),Object.defineProperty(e.prototype,"constructor",{value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{value:t.prototype}),n&&Object.assign(e.prototype,n)},toFlatObject:function(e,t,n,a){var i,o,r,s={};if(t=t||{},null==e)return t;do{for(o=(i=Object.getOwnPropertyNames(e)).length;o-- >0;)r=i[o],a&&!a(r,e,t)||s[r]||(t[r]=e[r],s[r]=!0);e=!1!==n&&z(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:I,kindOfTest:q,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var a=e.indexOf(t,n);return-1!==a&&a===n},toArray:function(e){if(!e)return null;if(j(e))return e;var t=e.length;if(!H(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},forEachEntry:function(e,t){for(var n,a=(e&&e[N]).call(e);(n=a.next())&&!n.done;){var i=n.value;t.call(e,i[0],i[1])}},matchAll:function(e,t){for(var n,a=[];null!==(n=e.exec(t));)a.push(n);return a},isHTMLForm:ce,hasOwnProperty:de,hasOwnProp:de,reduceDescriptors:pe,freezeMethods:function(e){pe(e,function(t,n){if(U(e)&&-1!==["arguments","caller","callee"].indexOf(n))return!1;var a=e[n];U(a)&&(t.enumerable=!1,"writable"in t?t.writable=!1:t.set||(t.set=function(){throw Error("Can not rewrite read-only method '"+n+"'")}))})},toObjectSet:function(e,t){var n={},a=function(e){e.forEach(function(e){n[e]=!0})};return j(e)?a(e):a(String(e).split(t)),n},toCamelCase:function(e){return e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(e,t,n){return t.toUpperCase()+n})},noop:function(){},toFiniteNumber:function(e,t){return null!=e&&Number.isFinite(e=+e)?e:t},findKey:oe,global:re,isContextDefined:se,isSpecCompliantForm:function(e){return!!(e&&U(e.append)&&"FormData"===e[O]&&e[N])},toJSONObject:function(e){var t=new Array(10),n=function(e,a){if(W(e)){if(t.indexOf(e)>=0)return;if(F(e))return e;if(!("toJSON"in e)){t[a]=e;var i=j(e)?[]:{};return ie(e,function(e,t){var o=n(e,a+1);!B(o)&&(i[t]=o)}),t[a]=void 0,i}}return e};return n(e,0)},isAsyncFn:ve,isThenable:function(e){return e&&(W(e)||U(e))&&U(e.then)&&U(e.catch)},setImmediate:be,asap:ye,isIterable:function(e){return null!=e&&U(e[N])}},ke=function(e){function t(e,n,a,i,o){var r;return u(this,t),(r=l(this,t,[e])).name="AxiosError",r.isAxiosError=!0,n&&(r.code=n),a&&(r.config=a),i&&(r.request=i),o&&(r.response=o,r.status=o.status),r}return f(t,e),d(t,[{key:"toJSON",value:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:we.toJSONObject(this.config),code:this.code,status:this.status}}}],[{key:"from",value:function(e,n,a,i,o,r){var s=new t(e.message,n||e.code,a,i,o);return s.cause=e,s.name=e.name,r&&Object.assign(s,r),s}}])}(A(Error));ke.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE",ke.ERR_BAD_OPTION="ERR_BAD_OPTION",ke.ECONNABORTED="ECONNABORTED",ke.ETIMEDOUT="ETIMEDOUT",ke.ERR_NETWORK="ERR_NETWORK",ke.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS",ke.ERR_DEPRECATED="ERR_DEPRECATED",ke.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE",ke.ERR_BAD_REQUEST="ERR_BAD_REQUEST",ke.ERR_CANCELED="ERR_CANCELED",ke.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT",ke.ERR_INVALID_URL="ERR_INVALID_URL";var xe=ke;function Se(e){return we.isPlainObject(e)||we.isArray(e)}function Ce(e){return we.endsWith(e,"[]")?e.slice(0,-2):e}function Te(e,t,n){return e?e.concat(t).map(function(e,t){return e=Ce(e),!n&&t?"["+e+"]":e}).join(n?".":""):t}var Pe=we.toFlatObject(we,{},null,function(e){return/^is[A-Z]/.test(e)});function Ee(e,t,n){if(!we.isObject(e))throw new TypeError("target must be an object");t=t||new FormData;var a=(n=we.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(e,t){return!we.isUndefined(t[e])})).metaTokens,i=n.visitor||u,o=n.dots,r=n.indexes,s=(n.Blob||"undefined"!=typeof Blob&&Blob)&&we.isSpecCompliantForm(t);if(!we.isFunction(i))throw new TypeError("visitor must be a function");function l(e){if(null===e)return"";if(we.isDate(e))return e.toISOString();if(we.isBoolean(e))return e.toString();if(!s&&we.isBlob(e))throw new xe("Blob is not supported. Use a Buffer instead.");return we.isArrayBuffer(e)||we.isTypedArray(e)?s&&"function"==typeof Blob?new Blob([e]):Buffer.from(e):e}function u(e,n,i){var s=e;if(e&&!i&&"object"===C(e))if(we.endsWith(n,"{}"))n=a?n:n.slice(0,-2),e=JSON.stringify(e);else if(we.isArray(e)&&function(e){return we.isArray(e)&&!e.some(Se)}(e)||(we.isFileList(e)||we.endsWith(n,"[]"))&&(s=we.toArray(e)))return n=Ce(n),s.forEach(function(e,a){!we.isUndefined(e)&&null!==e&&t.append(!0===r?Te([n],a,o):null===r?n:n+"[]",l(e))}),!1;return!!Se(e)||(t.append(Te(i,n,o),l(e)),!1)}var c=[],d=Object.assign(Pe,{defaultVisitor:u,convertValue:l,isVisitable:Se});if(!we.isObject(e))throw new TypeError("data must be an object");return function e(n,a){if(!we.isUndefined(n)){if(-1!==c.indexOf(n))throw Error("Circular reference detected in "+a.join("."));c.push(n),we.forEach(n,function(n,o){!0===(!(we.isUndefined(n)||null===n)&&i.call(t,n,we.isString(o)?o.trim():o,a,d))&&e(n,a?a.concat(o):[o])}),c.pop()}}(e),t}function Ae(e){var t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"};return encodeURIComponent(e).replace(/[!'()~]|%20|%00/g,function(e){return t[e]})}function Me(e,t){this._pairs=[],e&&Ee(e,this,t)}var Le=Me.prototype;function Re(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function ze(e,t,n){if(!t)return e;var a,i=n&&n.encode||Re,o=we.isFunction(n)?{serialize:n}:n,r=o&&o.serialize;if(a=r?r(t,o):we.isURLSearchParams(t)?t.toString():new Me(t,o).toString(i)){var s=e.indexOf("#");-1!==s&&(e=e.slice(0,s)),e+=(-1===e.indexOf("?")?"?":"&")+a}return e}Le.append=function(e,t){this._pairs.push([e,t])},Le.toString=function(e){var t=e?function(t){return e.call(this,t,Ae)}:Ae;return this._pairs.map(function(e){return t(e[0])+"="+t(e[1])},"").join("&")};var Ne=function(){return d(function e(){u(this,e),this.handlers=[]},[{key:"use",value:function(e,t,n){return this.handlers.push({fulfilled:e,rejected:t,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1}},{key:"eject",value:function(e){this.handlers[e]&&(this.handlers[e]=null)}},{key:"clear",value:function(){this.handlers&&(this.handlers=[])}},{key:"forEach",value:function(e){we.forEach(this.handlers,function(t){null!==t&&e(t)})}}])}(),Oe={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0},Ie={isBrowser:!0,classes:{URLSearchParams:"undefined"!=typeof URLSearchParams?URLSearchParams:Me,FormData:"undefined"!=typeof FormData?FormData:null,Blob:"undefined"!=typeof Blob?Blob:null},protocols:["http","https","file","blob","url","data"]},qe="undefined"!=typeof window&&"undefined"!=typeof document,De="object"===("undefined"==typeof navigator?"undefined":C(navigator))&&navigator||void 0,je=qe&&(!De||["ReactNative","NativeScript","NS"].indexOf(De.product)<0),Be="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&"function"==typeof self.importScripts,Fe=qe&&window.location.href||"http://localhost",$e=_(_({},Object.freeze({__proto__:null,hasBrowserEnv:qe,hasStandardBrowserWebWorkerEnv:Be,hasStandardBrowserEnv:je,navigator:De,origin:Fe})),Ie);function Ve(e){function t(e,n,a,i){var o=e[i++];if("__proto__"===o)return!0;var r=Number.isFinite(+o),s=i>=e.length;return o=!o&&we.isArray(a)?a.length:o,s?(we.hasOwnProp(a,o)?a[o]=[a[o],n]:a[o]=n,!r):(a[o]&&we.isObject(a[o])||(a[o]=[]),t(e,n,a[o],i)&&we.isArray(a[o])&&(a[o]=function(e){var t,n,a={},i=Object.keys(e),o=i.length;for(t=0;t-1,o=we.isObject(e);if(o&&we.isHTMLForm(e)&&(e=new FormData(e)),we.isFormData(e))return i?JSON.stringify(Ve(e)):e;if(we.isArrayBuffer(e)||we.isBuffer(e)||we.isStream(e)||we.isFile(e)||we.isBlob(e)||we.isReadableStream(e))return e;if(we.isArrayBufferView(e))return e.buffer;if(we.isURLSearchParams(e))return t.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),e.toString();if(o){if(a.indexOf("application/x-www-form-urlencoded")>-1)return function(e,t){return Ee(e,new $e.classes.URLSearchParams,_({visitor:function(e,t,n,a){return $e.isNode&&we.isBuffer(e)?(this.append(t,e.toString("base64")),!1):a.defaultVisitor.apply(this,arguments)}},t))}(e,this.formSerializer).toString();if((n=we.isFileList(e))||a.indexOf("multipart/form-data")>-1){var r=this.env&&this.env.FormData;return Ee(n?{"files[]":e}:e,r&&new r,this.formSerializer)}}return o||i?(t.setContentType("application/json",!1),function(e,t,n){if(we.isString(e))try{return(t||JSON.parse)(e),we.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(n||JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var t=this.transitional||Ue.transitional,n=t&&t.forcedJSONParsing,a="json"===this.responseType;if(we.isResponse(e)||we.isReadableStream(e))return e;if(e&&we.isString(e)&&(n&&!this.responseType||a)){var i=!(t&&t.silentJSONParsing)&&a;try{return JSON.parse(e,this.parseReviver)}catch(e){if(i){if("SyntaxError"===e.name)throw xe.from(e,xe.ERR_BAD_RESPONSE,this,null,this.response);throw e}}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:$e.classes.FormData,Blob:$e.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};we.forEach(["delete","get","head","post","put","patch"],function(e){Ue.headers[e]={}});var He=Ue,We=we.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]),Ge=Symbol("internals");function Ke(e){return e&&String(e).trim().toLowerCase()}function Ye(e){return!1===e||null==e?e:we.isArray(e)?e.map(Ye):String(e)}function Qe(e,t,n,a,i){return we.isFunction(a)?a.call(this,t,n):(i&&(t=n),we.isString(t)?we.isString(a)?-1!==t.indexOf(a):we.isRegExp(a)?a.test(t):void 0:void 0)}var Ze=function(){return d(function e(t){u(this,e),t&&this.set(t)},[{key:"set",value:function(e,t,n){var a=this;function i(e,t,n){var i=Ke(t);if(!i)throw new Error("header name must be a non-empty string");var o=we.findKey(a,i);(!o||void 0===a[o]||!0===n||void 0===n&&!1!==a[o])&&(a[o||t]=Ye(e))}var o=function(e,t){return we.forEach(e,function(e,n){return i(e,n,t)})};if(we.isPlainObject(e)||e instanceof this.constructor)o(e,t);else if(we.isString(e)&&(e=e.trim())&&!/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim()))o(function(e){var t,n,a,i={};return e&&e.split("\n").forEach(function(e){a=e.indexOf(":"),t=e.substring(0,a).trim().toLowerCase(),n=e.substring(a+1).trim(),!t||i[t]&&We[t]||("set-cookie"===t?i[t]?i[t].push(n):i[t]=[n]:i[t]=i[t]?i[t]+", "+n:n)}),i}(e),t);else if(we.isObject(e)&&we.isIterable(e)){var r,s,l,u={},c=function(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=T(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var a=0,i=function(){};return{s:i,n:function(){return a>=e.length?{done:!0}:{done:!1,value:e[a++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,r=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return r=e.done,e},e:function(e){s=!0,o=e},f:function(){try{r||null==n.return||n.return()}finally{if(s)throw o}}}}(e);try{for(c.s();!(l=c.n()).done;){var d=l.value;if(!we.isArray(d))throw TypeError("Object iterator must return a key-value pair");u[s=d[0]]=(r=u[s])?we.isArray(r)?[].concat(x(r),[d[1]]):[r,d[1]]:d[1]}}catch(e){c.e(e)}finally{c.f()}o(u,t)}else null!=e&&i(t,e,n);return this}},{key:"get",value:function(e,t){if(e=Ke(e)){var n=we.findKey(this,e);if(n){var a=this[n];if(!t)return a;if(!0===t)return function(e){for(var t,n=Object.create(null),a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;t=a.exec(e);)n[t[1]]=t[2];return n}(a);if(we.isFunction(t))return t.call(this,a,n);if(we.isRegExp(t))return t.exec(a);throw new TypeError("parser must be boolean|regexp|function")}}}},{key:"has",value:function(e,t){if(e=Ke(e)){var n=we.findKey(this,e);return!(!n||void 0===this[n]||t&&!Qe(0,this[n],n,t))}return!1}},{key:"delete",value:function(e,t){var n=this,a=!1;function i(e){if(e=Ke(e)){var i=we.findKey(n,e);!i||t&&!Qe(0,n[i],i,t)||(delete n[i],a=!0)}}return we.isArray(e)?e.forEach(i):i(e),a}},{key:"clear",value:function(e){for(var t=Object.keys(this),n=t.length,a=!1;n--;){var i=t[n];e&&!Qe(0,this[i],i,e,!0)||(delete this[i],a=!0)}return a}},{key:"normalize",value:function(e){var t=this,n={};return we.forEach(this,function(a,i){var o=we.findKey(n,i);if(o)return t[o]=Ye(a),void delete t[i];var r=e?function(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,function(e,t,n){return t.toUpperCase()+n})}(i):String(i).trim();r!==i&&delete t[i],t[r]=Ye(a),n[r]=!0}),this}},{key:"concat",value:function(){for(var e,t=arguments.length,n=new Array(t),a=0;a1?n-1:0),i=1;i2&&void 0!==arguments[2]?arguments[2]:3,a=0,i=function(e,t){e=e||10;var n,a=new Array(e),i=new Array(e),o=0,r=0;return t=void 0!==t?t:1e3,function(s){var l=Date.now(),u=i[r];n||(n=l),a[o]=s,i[o]=l;for(var c=r,d=0;c!==o;)d+=a[c++],c%=e;if((o=(o+1)%e)===r&&(r=(r+1)%e),!(l-n1&&void 0!==arguments[1]?arguments[1]:Date.now();i=o,n=null,a&&(clearTimeout(a),a=null),e.apply(void 0,x(t))};return[function(){for(var e=Date.now(),t=e-i,s=arguments.length,l=new Array(s),u=0;u=o?r(l,e):(n=l,a||(a=setTimeout(function(){a=null,r(n)},o-t)))},function(){return n&&r(n)}]}(function(n){var o=n.loaded,r=n.lengthComputable?n.total:void 0,s=o-a,l=i(s);a=o;var u=h({loaded:o,total:r,progress:r?o/r:void 0,bytes:s,rate:l||void 0,estimated:l&&r&&o<=r?(r-o)/l:void 0,event:n,lengthComputable:null!=r},t?"download":"upload",!0);e(u)},n)},it=function(e,t){var n=null!=e;return[function(a){return t[0]({lengthComputable:n,total:e,loaded:a})},t[1]]},ot=function(e){return function(){for(var t=arguments.length,n=new Array(t),a=0;a1?t-1:0),a=1;a1?"since :\n"+l.map(At).join("\n"):" "+At(l[0]):"as no adapter specified";throw new xe("There is no suitable adapter to dispatch the request "+u,"ERR_NOT_SUPPORT")}return a},adapters:Et};function Rt(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new tt(null,e)}function zt(e){return Rt(e),e.headers=Je.from(e.headers),e.data=Xe.call(e,e.transformRequest),-1!==["post","put","patch"].indexOf(e.method)&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Lt.getAdapter(e.adapter||He.adapter,e)(e).then(function(t){return Rt(e),t.data=Xe.call(e,e.transformResponse,t),t.headers=Je.from(t.headers),t},function(t){return et(t)||(Rt(e),t&&t.response&&(t.response.data=Xe.call(e,e.transformResponse,t.response),t.response.headers=Je.from(t.response.headers))),Promise.reject(t)})}var Nt="1.13.5",Ot={};["object","boolean","number","function","string","symbol"].forEach(function(e,t){Ot[e]=function(n){return C(n)===e||"a"+(t<1?"n ":" ")+e}});var It={};Ot.transitional=function(e,t,n){function a(e,t){return"[Axios v"+Nt+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,i,o){if(!1===e)throw new xe(a(i," has been removed"+(t?" in "+t:"")),xe.ERR_DEPRECATED);return t&&!It[i]&&(It[i]=!0,console.warn(a(i," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,i,o)}},Ot.spelling=function(e){return function(t,n){return console.warn("".concat(n," is likely a misspelling of ").concat(e)),!0}};var qt={assertOptions:function(e,t,n){if("object"!==C(e))throw new xe("options must be an object",xe.ERR_BAD_OPTION_VALUE);for(var a=Object.keys(e),i=a.length;i-- >0;){var o=a[i],r=t[o];if(r){var s=e[o],l=void 0===s||r(s,o,e);if(!0!==l)throw new xe("option "+o+" must be "+l,xe.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new xe("Unknown option "+o,xe.ERR_BAD_OPTION)}},validators:Ot},Dt=qt.validators,jt=function(){return d(function e(t){u(this,e),this.defaults=t||{},this.interceptors={request:new Ne,response:new Ne}},[{key:"request",value:(e=r(v().m(function e(t,n){var a,i,o;return v().w(function(e){for(;;)switch(e.p=e.n){case 0:return e.p=0,e.n=1,this._request(t,n);case 1:return e.a(2,e.v);case 2:if(e.p=2,(o=e.v)instanceof Error){a={},Error.captureStackTrace?Error.captureStackTrace(a):a=new Error,i=a.stack?a.stack.replace(/^.+\n/,""):"";try{o.stack?i&&!String(o.stack).endsWith(i.replace(/^.+\n.+\n/,""))&&(o.stack+="\n"+i):o.stack=i}catch(e){}}throw o;case 3:return e.a(2)}},e,this,[[0,2]])})),function(t,n){return e.apply(this,arguments)})},{key:"_request",value:function(e,t){"string"==typeof e?(t=t||{}).url=e:t=e||{};var n=t=ct(this.defaults,t),a=n.transitional,i=n.paramsSerializer,o=n.headers;void 0!==a&&qt.assertOptions(a,{silentJSONParsing:Dt.transitional(Dt.boolean),forcedJSONParsing:Dt.transitional(Dt.boolean),clarifyTimeoutError:Dt.transitional(Dt.boolean),legacyInterceptorReqResOrdering:Dt.transitional(Dt.boolean)},!1),null!=i&&(we.isFunction(i)?t.paramsSerializer={serialize:i}:qt.assertOptions(i,{encode:Dt.function,serialize:Dt.function},!0)),void 0!==t.allowAbsoluteUrls||(void 0!==this.defaults.allowAbsoluteUrls?t.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:t.allowAbsoluteUrls=!0),qt.assertOptions(t,{baseUrl:Dt.spelling("baseURL"),withXsrfToken:Dt.spelling("withXSRFToken")},!0),t.method=(t.method||this.defaults.method||"get").toLowerCase();var r=o&&we.merge(o.common,o[t.method]);o&&we.forEach(["delete","get","head","post","put","patch","common"],function(e){delete o[e]}),t.headers=Je.concat(r,o);var s=[],l=!0;this.interceptors.request.forEach(function(e){if("function"!=typeof e.runWhen||!1!==e.runWhen(t)){l=l&&e.synchronous;var n=t.transitional||Oe;n&&n.legacyInterceptorReqResOrdering?s.unshift(e.fulfilled,e.rejected):s.push(e.fulfilled,e.rejected)}});var u,c=[];this.interceptors.response.forEach(function(e){c.push(e.fulfilled,e.rejected)});var d,h=0;if(!l){var p=[zt.bind(this),void 0];for(p.unshift.apply(p,s),p.push.apply(p,c),d=p.length,u=Promise.resolve(t);h0;)a._listeners[t](e);a._listeners=null}}),this.promise.then=function(e){var t,n=new Promise(function(e){a.subscribe(e),t=e}).then(e);return n.cancel=function(){a.unsubscribe(t)},n},t(function(e,t,i){a.reason||(a.reason=new tt(e,t,i),n(a.reason))})}return d(e,[{key:"throwIfRequested",value:function(){if(this.reason)throw this.reason}},{key:"subscribe",value:function(e){this.reason?e(this.reason):this._listeners?this._listeners.push(e):this._listeners=[e]}},{key:"unsubscribe",value:function(e){if(this._listeners){var t=this._listeners.indexOf(e);-1!==t&&this._listeners.splice(t,1)}}},{key:"toAbortSignal",value:function(){var e=this,t=new AbortController,n=function(e){t.abort(e)};return this.subscribe(n),t.signal.unsubscribe=function(){return e.unsubscribe(n)},t.signal}}],[{key:"source",value:function(){var t;return{token:new e(function(e){t=e}),cancel:t}}}])}(),$t=Ft;var Vt={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Vt).forEach(function(e){var t=k(e,2),n=t[0],a=t[1];Vt[a]=n});var Ut=Vt;var Ht=function e(t){var n=new Bt(t),a=M(Bt.prototype.request,n);return we.extend(a,Bt.prototype,n,{allOwnKeys:!0}),we.extend(a,n,null,{allOwnKeys:!0}),a.create=function(n){return e(ct(t,n))},a}(He);return Ht.Axios=Bt,Ht.CanceledError=tt,Ht.CancelToken=$t,Ht.isCancel=et,Ht.VERSION=Nt,Ht.toFormData=Ee,Ht.AxiosError=xe,Ht.Cancel=Ht.CanceledError,Ht.all=function(e){return Promise.all(e)},Ht.spread=function(e){return function(t){return e.apply(null,t)}},Ht.isAxiosError=function(e){return we.isObject(e)&&!0===e.isAxiosError},Ht.mergeConfig=ct,Ht.AxiosHeaders=Je,Ht.formToJSON=function(e){return Ve(we.isHTMLForm(e)?new FormData(e):e)},Ht.getAdapter=Lt.getAdapter,Ht.HttpStatusCode=Ut,Ht.default=Ht,Ht}); +var e,t,n="function"==typeof Symbol?Symbol:{},a=n.iterator||"@@iterator",i=n.toStringTag||"@@toStringTag";function r(n,a,i,r){var l=a&&a.prototype instanceof s?a:s,u=Object.create(l.prototype);return b(u,"_invoke",function(n,a,i){var r,s,l,u=0,c=i||[],d=!1,h={p:0,n:0,v:e,a:p,f:p.bind(e,4),d:function(t,n){return r=t,s=0,l=e,h.n=n,o}};function p(n,a){for(s=n,l=a,t=0;!d&&u&&!i&&t3?(i=f===a)&&(l=r[(s=r[4])?5:(s=3,3)],r[4]=r[5]=e):r[0]<=p&&((i=n<2&&pa||a>f)&&(r[4]=n,r[5]=a,h.n=f,s=0))}if(i||n>1)return o;throw d=!0,a}return function(i,c,f){if(u>1)throw TypeError("Generator is already running");for(d&&1===c&&p(c,f),s=c,l=f;(t=s<2?e:l)||!d;){r||(s?s<3?(s>1&&(h.n=-1),p(s,l)):h.n=l:h.v=l);try{if(u=2,r){if(s||(i="next"),t=r[i]){if(!(t=t.call(r,l)))throw TypeError("iterator result is not an object");if(!t.done)return t;l=t.value,s<2&&(s=0)}else 1===s&&(t=r.return)&&t.call(r),s<2&&(l=TypeError("The iterator does not provide a '"+i+"' method"),s=1);r=e}else if((t=(d=h.n<0)?l:n.call(a,h))!==o)break}catch(t){r=e,s=1,l=t}finally{u=1}}return{value:t,done:d}}}(n,i,r),!0),u}var o={};function s(){}function l(){}function u(){}t=Object.getPrototypeOf;var c=[][a]?t(t([][a]())):(b(t={},a,function(){return this}),t),d=u.prototype=s.prototype=Object.create(c);function h(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,u):(e.__proto__=u,b(e,i,"GeneratorFunction")),e.prototype=Object.create(d),e}return l.prototype=u,b(d,"constructor",u),b(u,"constructor",l),l.displayName="GeneratorFunction",b(u,i,"GeneratorFunction"),b(d),b(d,i,"Generator"),b(d,a,function(){return this}),b(d,"toString",function(){return"[object Generator]"}),(v=function(){return{w:r,m:h}})()}function b(e,t,n,a){var i=Object.defineProperty;try{i({},"",{})}catch(e){i=0}b=function(e,t,n,a){function r(t,n){b(e,t,function(e){return this._invoke(t,n,e)})}t?i?i(e,t,{value:n,enumerable:!a,configurable:!a,writable:!a}):e[t]=n:(r("next",0),r("throw",1),r("return",2))},b(e,t,n,a)}function y(e){if(null!=e){var t=e["function"==typeof Symbol&&Symbol.iterator||"@@iterator"],n=0;if(t)return t.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length))return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}throw new TypeError(typeof e+" is not iterable")}function w(e,t){return w=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},w(e,t)}function k(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var a,i,r,o,s=[],l=!0,u=!1;try{if(r=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;l=!1}else for(;!(l=(a=r.call(n)).done)&&(s.push(a.value),s.length!==t);l=!0);}catch(e){u=!0,i=e}finally{try{if(!l&&null!=n.return&&(o=n.return(),Object(o)!==o))return}finally{if(u)throw i}}return s}}(e,t)||T(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function x(e){return function(e){if(Array.isArray(e))return t(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||T(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function S(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t);if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}function C(e){return C="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},C(e)}function T(e,n){if(e){if("string"==typeof e)return t(e,n);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?t(e,n):void 0}}function P(e){return function(){return new E(e.apply(this,arguments))}}function E(t){var n,a;function i(n,a){try{var o=t[n](a),s=o.value,l=s instanceof e;Promise.resolve(l?s.v:s).then(function(e){if(l){var a="return"===n&&s.k?n:"next";if(!s.k||e.done)return i(a,e);e=t[a](e).value}r(!!o.done,e)},function(e){i("throw",e)})}catch(e){r(2,e)}}function r(e,t){2===e?n.reject(t):n.resolve({value:t,done:e}),(n=n.next)?i(n.key,n.arg):a=null}this._invoke=function(e,t){return new Promise(function(r,o){var s={key:e,arg:t,resolve:r,reject:o,next:null};a?a=a.next=s:(n=a=s,i(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}function A(e){var t="function"==typeof Map?new Map:void 0;return A=function(e){if(null===e||!function(e){try{return-1!==Function.toString.call(e).indexOf("[native code]")}catch(t){return"function"==typeof e}}(e))return e;if("function"!=typeof e)throw new TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return function(e,t,n){if(m())return Reflect.construct.apply(null,arguments);var a=[null];a.push.apply(a,t);var i=new(e.bind.apply(e,a));return n&&w(i,n.prototype),i}(e,arguments,p(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),w(n,e)},A(e)}function L(e,t){return function(){return e.apply(t,arguments)}}E.prototype["function"==typeof Symbol&&Symbol.asyncIterator||"@@asyncIterator"]=function(){return this},E.prototype.next=function(e){return this._invoke("next",e)},E.prototype.throw=function(e){return this._invoke("throw",e)},E.prototype.return=function(e){return this._invoke("return",e)};var M,R=Object.prototype.toString,z=Object.getPrototypeOf,I=Symbol.iterator,N=Symbol.toStringTag,O=function(){var e=Object.prototype.hasOwnProperty;return function(t,n){return e.call(t,n)}}(),j=function(e,t){for(var n=e,a=[];null!=n&&n!==Object.prototype;){if(-1!==a.indexOf(n))return!1;if(a.push(n),O(n,t))return!0;n=z(n)}return!1},D=(M=Object.create(null),function(e){var t=R.call(e);return M[t]||(M[t]=t.slice(8,-1).toLowerCase())}),q=function(e){return e=e.toLowerCase(),function(t){return D(t)===e}},B=function(e){return function(t){return C(t)===e}},F=Array.isArray,V=B("undefined");function U(e){return null!==e&&!V(e)&&null!==e.constructor&&!V(e.constructor)&&W(e.constructor.isBuffer)&&e.constructor.isBuffer(e)}var $=q("ArrayBuffer");var H=B("string"),W=B("function"),G=B("number"),K=function(e){return null!==e&&"object"===C(e)},Y=function(e){if(!K(e))return!1;var t=z(e);return!(null!==t&&t!==Object.prototype&&null!==z(t)||j(e,N)||j(e,I))},Q=q("Date"),Z=q("File"),J=q("Blob"),X=q("FileList");var ee="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{},te=void 0!==ee.FormData?ee.FormData:void 0,ne=q("URLSearchParams"),ae=k(["ReadableStream","Request","Response","Headers"].map(q),4),ie=ae[0],re=ae[1],oe=ae[2],se=ae[3];function le(e,t){var n,a,i=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).allOwnKeys,r=void 0!==i&&i;if(null!=e)if("object"!==C(e)&&(e=[e]),F(e))for(n=0,a=e.length;n0;)if(t===(n=a[i]).toLowerCase())return n;return null}var ce="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:global,de=function(e){return!V(e)&&e!==ce};var he,pe=(he="undefined"!=typeof Uint8Array&&z(Uint8Array),function(e){return he&&e instanceof he}),fe=q("HTMLFormElement"),me=Object.prototype.propertyIsEnumerable,_e=q("RegExp"),ge=function(e,t){var n=Object.getOwnPropertyDescriptors(e),a={};le(n,function(n,i){var r;!1!==(r=t(n,i,e))&&(a[i]=r||n)}),Object.defineProperties(e,a)};var ve,be,ye,we,ke=q("AsyncFunction"),xe=(ve="function"==typeof setImmediate,be=W(ce.postMessage),ve?setImmediate:be?(ye="axios@".concat(Math.random()),we=[],ce.addEventListener("message",function(e){var t=e.source,n=e.data;t===ce&&n===ye&&we.length&&we.shift()()},!1),function(e){we.push(e),ce.postMessage(ye,"*")}):function(e){return setTimeout(e)}),Se="undefined"!=typeof queueMicrotask?queueMicrotask.bind(ce):"undefined"!=typeof process&&process.nextTick||xe,Ce=function(e){return null!=e&&W(e[I])},Te={isArray:F,isArrayBuffer:$,isBuffer:U,isFormData:function(e){if(!e)return!1;if(te&&e instanceof te)return!0;var t=z(e);if(!t||t===Object.prototype)return!1;if(!W(e.append))return!1;var n=D(e);return"formdata"===n||"object"===n&&W(e.toString)&&"[object FormData]"===e.toString()},isArrayBufferView:function(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&$(e.buffer)},isString:H,isNumber:G,isBoolean:function(e){return!0===e||!1===e},isObject:K,isPlainObject:Y,isEmptyObject:function(e){if(!K(e)||U(e))return!1;try{return 0===Object.keys(e).length&&Object.getPrototypeOf(e)===Object.prototype}catch(e){return!1}},isReadableStream:ie,isRequest:re,isResponse:oe,isHeaders:se,isUndefined:V,isDate:Q,isFile:Z,isReactNativeBlob:function(e){return!(!e||void 0===e.uri)},isReactNative:function(e){return e&&void 0!==e.getParts},isBlob:J,isRegExp:_e,isFunction:W,isStream:function(e){return K(e)&&W(e.pipe)},isURLSearchParams:ne,isTypedArray:pe,isFileList:X,forEach:le,merge:function e(){for(var t=de(this)&&this||{},n=t.caseless,a=t.skipUndefined,i={},r=function(t,r){if("__proto__"!==r&&"constructor"!==r&&"prototype"!==r){var o=n&&"string"==typeof r&&ue(i,r)||r,s=O(i,o)?i[o]:void 0;Y(s)&&Y(t)?i[o]=e(s,t):Y(t)?i[o]=e({},t):F(t)?i[o]=t.slice():a&&V(t)||(i[o]=t)}},o=0,s=arguments.length;o3&&void 0!==arguments[3]?arguments[3]:{}).allOwnKeys}),e},trim:function(e){return e.trim?e.trim():e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")},stripBOM:function(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e},inherits:function(e,t,n,a){e.prototype=Object.create(t.prototype,a),Object.defineProperty(e.prototype,"constructor",{__proto__:null,value:e,writable:!0,enumerable:!1,configurable:!0}),Object.defineProperty(e,"super",{__proto__:null,value:t.prototype}),n&&Object.assign(e.prototype,n)},toFlatObject:function(e,t,n,a){var i,r,o,s={};if(t=t||{},null==e)return t;do{for(r=(i=Object.getOwnPropertyNames(e)).length;r-- >0;)o=i[r],a&&!a(o,e,t)||s[o]||(t[o]=e[o],s[o]=!0);e=!1!==n&&z(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:D,kindOfTest:q,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var a=e.indexOf(t,n);return-1!==a&&a===n},toArray:function(e){if(!e)return null;if(F(e))return e;var t=e.length;if(!G(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},forEachEntry:function(e,t){for(var n,a=(e&&e[I]).call(e);(n=a.next())&&!n.done;){var i=n.value;t.call(e,i[0],i[1])}},matchAll:function(e,t){for(var n,a=[];null!==(n=e.exec(t));)a.push(n);return a},isHTMLForm:fe,hasOwnProperty:O,hasOwnProp:O,hasOwnInPrototypeChain:j,getSafeProp:function(e,t){return null!=e&&j(e,t)?e[t]:void 0},reduceDescriptors:ge,freezeMethods:function(e){ge(e,function(t,n){if(W(e)&&["arguments","caller","callee"].includes(n))return!1;var a=e[n];W(a)&&(t.enumerable=!1,"writable"in t?t.writable=!1:t.set||(t.set=function(){throw Error("Can not rewrite read-only method '"+n+"'")}))})},toObjectSet:function(e,t){var n={},a=function(e){e.forEach(function(e){n[e]=!0})};return F(e)?a(e):a(String(e).split(t)),n},toCamelCase:function(e){return e.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,function(e,t,n){return t.toUpperCase()+n})},noop:function(){},toFiniteNumber:function(e,t){return null!=e&&Number.isFinite(e=+e)?e:t},findKey:ue,global:ce,isContextDefined:de,isSpecCompliantForm:function(e){return!!(e&&W(e.append)&&"FormData"===e[N]&&e[I])},toJSONObject:function(e){var t=new WeakSet,n=function(e){if(K(e)){if(t.has(e))return;if(U(e))return e;if(!("toJSON"in e)){t.add(e);var a=F(e)?[]:{};return le(e,function(e,t){var i=n(e);!V(i)&&(a[t]=i)}),t.delete(e),a}}return e};return n(e)},isAsyncFn:ke,isThenable:function(e){return e&&(K(e)||W(e))&&W(e.then)&&W(e.catch)},setImmediate:xe,asap:Se,isIterable:Ce,isSafeIterable:function(e){return null!=e&&j(e,I)&&Ce(e)}},Pe=Te.toObjectSet(["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"]);var Ee=new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+","g"),Ae=new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+","g");function Le(e,t){return Te.isArray(e)?e.map(function(e){return Le(e,t)}):function(e){for(var t=0,n=e.length;tt;){var i=e.charCodeAt(n-1);if(9!==i&&32!==i)break;n-=1}return 0===t&&n===e.length?e:e.slice(t,n)}(String(e).replace(t,""))}function Me(e){var t=Object.create(null);return Te.forEach(e.toJSON(),function(e,n){t[n]=function(e){return Le(e,Ae)}(e)}),t}var Re=Symbol("internals");function ze(e){return e&&String(e).trim().toLowerCase()}function Ie(e){return!1===e||null==e?e:Te.isArray(e)?e.map(Ie):function(e){return Le(e,Ee)}(String(e))}function Ne(e,t,n,a,i){return Te.isFunction(a)?a.call(this,t,n):(i&&(t=n),Te.isString(t)?Te.isString(a)?-1!==t.indexOf(a):Te.isRegExp(a)?a.test(t):void 0:void 0)}var Oe=function(){return d(function e(t){u(this,e),t&&this.set(t)},[{key:"set",value:function(e,t,n){var a=this;function i(e,t,n){var i=ze(t);if(i){var r=Te.findKey(a,i);(!r||void 0===a[r]||!0===n||void 0===n&&!1!==a[r])&&(a[r||t]=Ie(e))}}var r=function(e,t){return Te.forEach(e,function(e,n){return i(e,n,t)})};if(Te.isPlainObject(e)||e instanceof this.constructor)r(e,t);else if(Te.isString(e)&&(e=e.trim())&&!/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(e.trim()))r(function(e){var t,n,a,i={};return e&&e.split("\n").forEach(function(e){a=e.indexOf(":"),t=e.substring(0,a).trim().toLowerCase(),n=e.substring(a+1).trim(),!t||i[t]&&Pe[t]||("set-cookie"===t?i[t]?i[t].push(n):i[t]=[n]:i[t]=i[t]?i[t]+", "+n:n)}),i}(e),t);else if(Te.isObject(e)&&Te.isSafeIterable(e)){var o,s,l,u=Object.create(null),c=function(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=T(e))||t){n&&(e=n);var a=0,i=function(){};return{s:i,n:function(){return a>=e.length?{done:!0}:{done:!1,value:e[a++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return o=e.done,e},e:function(e){s=!0,r=e},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw r}}}}(e);try{for(c.s();!(l=c.n()).done;){var d=l.value;if(!Te.isArray(d))throw new TypeError("Object iterator must return a key-value pair");s=d[0],Te.hasOwnProp(u,s)?(o=u[s],u[s]=Te.isArray(o)?[].concat(x(o),[d[1]]):[o,d[1]]):u[s]=d[1]}}catch(e){c.e(e)}finally{c.f()}r(u,t)}else null!=e&&i(t,e,n);return this}},{key:"get",value:function(e,t){if(e=ze(e)){var n=Te.findKey(this,e);if(n){var a=this[n];if(!t)return a;if(!0===t)return function(e){for(var t,n=Object.create(null),a=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;t=a.exec(e);)n[t[1]]=t[2];return n}(a);if(Te.isFunction(t))return t.call(this,a,n);if(Te.isRegExp(t))return t.exec(a);throw new TypeError("parser must be boolean|regexp|function")}}}},{key:"has",value:function(e,t){if(e=ze(e)){var n=Te.findKey(this,e);return!(!n||void 0===this[n]||t&&!Ne(0,this[n],n,t))}return!1}},{key:"delete",value:function(e,t){var n=this,a=!1;function i(e){if(e=ze(e)){var i=Te.findKey(n,e);!i||t&&!Ne(0,n[i],i,t)||(delete n[i],a=!0)}}return Te.isArray(e)?e.forEach(i):i(e),a}},{key:"clear",value:function(e){for(var t=Object.keys(this),n=t.length,a=!1;n--;){var i=t[n];e&&!Ne(0,this[i],i,e,!0)||(delete this[i],a=!0)}return a}},{key:"normalize",value:function(e){var t=this,n={};return Te.forEach(this,function(a,i){var r=Te.findKey(n,i);if(r)return t[r]=Ie(a),void delete t[i];var o=e?function(e){return e.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,function(e,t,n){return t.toUpperCase()+n})}(i):String(i).trim();o!==i&&delete t[i],t[o]=Ie(a),n[o]=!0}),this}},{key:"concat",value:function(){for(var e,t=arguments.length,n=new Array(t),a=0;a1?n-1:0),i=1;i0?je(e,t):Te.toJSONObject(e);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:n,code:this.code,status:this.status}}}],[{key:"from",value:function(e,n,a,i,r,o){var s=new t(e.message,n||e.code,a,i,r);return s.cause=e,s.name=e.name,null!=e.status&&null==s.status&&(s.status=e.status),o&&Object.assign(s,o),s}}])}(A(Error));De.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE",De.ERR_BAD_OPTION="ERR_BAD_OPTION",De.ECONNABORTED="ECONNABORTED",De.ETIMEDOUT="ETIMEDOUT",De.ECONNREFUSED="ECONNREFUSED",De.ERR_NETWORK="ERR_NETWORK",De.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS",De.ERR_DEPRECATED="ERR_DEPRECATED",De.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE",De.ERR_BAD_REQUEST="ERR_BAD_REQUEST",De.ERR_CANCELED="ERR_CANCELED",De.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT",De.ERR_INVALID_URL="ERR_INVALID_URL",De.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";function qe(e){return Te.isPlainObject(e)||Te.isArray(e)}function Be(e){return Te.endsWith(e,"[]")?e.slice(0,-2):e}function Fe(e,t,n){return e?e.concat(t).map(function(e,t){return e=Be(e),!n&&t?"["+e+"]":e}).join(n?".":""):t}var Ve=Te.toFlatObject(Te,{},null,function(e){return/^is[A-Z]/.test(e)});function Ue(e,t,n){if(!Te.isObject(e))throw new TypeError("target must be an object");t=t||new FormData;var a=(n=Te.toFlatObject(n,{metaTokens:!0,dots:!1,indexes:!1},!1,function(e,t){return!Te.isUndefined(t[e])})).metaTokens,i=n.visitor||p,r=n.dots,o=n.indexes,s=n.Blob||"undefined"!=typeof Blob&&Blob,l=void 0===n.maxDepth?100:n.maxDepth,u=s&&Te.isSpecCompliantForm(t),c=[];if(!Te.isFunction(i))throw new TypeError("visitor must be a function");function d(e){if(null===e)return"";if(Te.isDate(e))return e.toISOString();if(Te.isBoolean(e))return e.toString();if(!u&&Te.isBlob(e))throw new De("Blob is not supported. Use a Buffer instead.");return Te.isArrayBuffer(e)||Te.isTypedArray(e)?u&&"function"==typeof Blob?new Blob([e]):Buffer.from(e):e}function h(e){if(e>l)throw new De("Object is too deeply nested ("+e+" levels). Max depth: "+l,De.ERR_FORM_DATA_DEPTH_EXCEEDED)}function p(e,n,i){var s=e;if(Te.isReactNative(t)&&Te.isReactNativeBlob(e))return t.append(Fe(i,n,r),d(e)),!1;if(e&&!i&&"object"===C(e))if(Te.endsWith(n,"{}"))n=a?n:n.slice(0,-2),e=function(e,t){if(l===1/0)return JSON.stringify(e);var n=[];return JSON.stringify(e,function(e,a){if(!Te.isObject(a))return a;for(;n.length&&n[n.length-1]!==this;)n.pop();return n.push(a),h(t+n.length-1),a})}(e,1);else if(Te.isArray(e)&&function(e){return Te.isArray(e)&&!e.some(qe)}(e)||(Te.isFileList(e)||Te.endsWith(n,"[]"))&&(s=Te.toArray(e)))return n=Be(n),s.forEach(function(e,a){!Te.isUndefined(e)&&null!==e&&t.append(!0===o?Fe([n],a,r):null===o?n:n+"[]",d(e))}),!1;return!!qe(e)||(t.append(Fe(i,n,r),d(e)),!1)}var f=Object.assign(Ve,{defaultVisitor:p,convertValue:d,isVisitable:qe});if(!Te.isObject(e))throw new TypeError("data must be an object");return function e(n,a){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;if(!Te.isUndefined(n)){if(h(r),-1!==c.indexOf(n))throw new Error("Circular reference detected in "+a.join("."));c.push(n),Te.forEach(n,function(n,o){!0===(!(Te.isUndefined(n)||null===n)&&i.call(t,n,Te.isString(o)?o.trim():o,a,f))&&e(n,a?a.concat(o):[o],r+1)}),c.pop()}}(e),t}function $e(e){var t={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(e).replace(/[!'()~]|%20/g,function(e){return t[e]})}function He(e,t){this._pairs=[],e&&Ue(e,this,t)}var We=He.prototype;function Ge(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+")}function Ke(e,t,n){if(!t)return e;var a,i=Te.isFunction(n)?{serialize:n}:n,r=Te.getSafeProp(i,"encode")||Ge,o=Te.getSafeProp(i,"serialize");if(a=o?o(t,i):Te.isURLSearchParams(t)?t.toString():new He(t,i).toString(r)){var s=e.indexOf("#");-1!==s&&(e=e.slice(0,s)),e+=(-1===e.indexOf("?")?"?":"&")+a}return e}We.append=function(e,t){this._pairs.push([e,t])},We.toString=function(e){var t=e?function(t){return e.call(this,t,$e)}:$e;return this._pairs.map(function(e){return t(e[0])+"="+t(e[1])},"").join("&")};var Ye=function(){return d(function e(){u(this,e),this.handlers=[]},[{key:"use",value:function(e,t,n){return this.handlers.push({fulfilled:e,rejected:t,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1}},{key:"eject",value:function(e){this.handlers[e]&&(this.handlers[e]=null)}},{key:"clear",value:function(){this.handlers&&(this.handlers=[])}},{key:"forEach",value:function(e){Te.forEach(this.handlers,function(t){null!==t&&e(t)})}}])}(),Qe={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1,legacyInterceptorReqResOrdering:!0,advertiseZstdAcceptEncoding:!1,validateStatusUndefinedResolves:!0},Ze={isBrowser:!0,classes:{URLSearchParams:"undefined"!=typeof URLSearchParams?URLSearchParams:He,FormData:"undefined"!=typeof FormData?FormData:null,Blob:"undefined"!=typeof Blob?Blob:null},protocols:["http","https","file","blob","url","data"]},Je="undefined"!=typeof window&&"undefined"!=typeof document,Xe="object"===("undefined"==typeof navigator?"undefined":C(navigator))&&navigator||void 0,et=Je&&(!Xe||["ReactNative","NativeScript","NS"].indexOf(Xe.product)<0),tt="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&"function"==typeof self.importScripts,nt=Je&&window.location.href||"http://localhost",at=g(g({},Object.freeze({__proto__:null,hasBrowserEnv:Je,hasStandardBrowserEnv:et,hasStandardBrowserWebWorkerEnv:tt,navigator:Xe,origin:nt})),Ze);function it(e){if(e>100)throw new De("FormData field is too deeply nested ("+e+" levels). Max depth: 100",De.ERR_FORM_DATA_DEPTH_EXCEEDED)}function rt(e){function t(e,n,a,i){it(i);var r=e[i++];if("__proto__"===r)return!0;var o=Number.isFinite(+r),s=i>=e.length;return r=!r&&Te.isArray(a)?a.length:r,s?(Te.hasOwnProp(a,r)?a[r]=Te.isArray(a[r])?a[r].concat(n):[a[r],n]:a[r]=n,!o):(Te.hasOwnProp(a,r)&&Te.isObject(a[r])||(a[r]=[]),t(e,n,a[r],i)&&Te.isArray(a[r])&&(a[r]=function(e){var t,n,a={},i=Object.keys(e),r=i.length;for(t=0;t-1,r=Te.isObject(e);if(r&&Te.isHTMLForm(e)&&(e=new FormData(e)),Te.isFormData(e))return i?JSON.stringify(rt(e)):e;if(Te.isArrayBuffer(e)||Te.isBuffer(e)||Te.isStream(e)||Te.isFile(e)||Te.isBlob(e)||Te.isReadableStream(e))return e;if(Te.isArrayBufferView(e))return e.buffer;if(Te.isURLSearchParams(e))return t.setContentType("application/x-www-form-urlencoded;charset=utf-8",!1),e.toString();if(r){var o=ot(this,"formSerializer");if(a.indexOf("application/x-www-form-urlencoded")>-1)return function(e,t){return Ue(e,new at.classes.URLSearchParams,g({visitor:function(e,t,n,a){return at.isNode&&Te.isBuffer(e)?(this.append(t,e.toString("base64")),!1):a.defaultVisitor.apply(this,arguments)}},t))}(e,o).toString();if((n=Te.isFileList(e))||a.indexOf("multipart/form-data")>-1){var s=ot(this,"env"),l=s&&s.FormData;return Ue(n?{"files[]":e}:e,l&&new l,o)}}return r||i?(t.setContentType("application/json",!1),function(e,t,n){if(Te.isString(e))try{return(t||JSON.parse)(e),Te.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(n||JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var t=ot(this,"transitional")||st.transitional,n=t&&t.forcedJSONParsing,a=ot(this,"responseType"),i="json"===a;if(Te.isResponse(e)||Te.isReadableStream(e))return e;if(e&&Te.isString(e)&&(n&&!a||i)){var r=!(t&&t.silentJSONParsing)&&i;try{return JSON.parse(e,ot(this,"parseReviver"))}catch(e){if(r){if("SyntaxError"===e.name)throw De.from(e,De.ERR_BAD_RESPONSE,this,null,ot(this,"response"));throw e}}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:at.classes.FormData,Blob:at.classes.Blob},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*","Content-Type":void 0}}};function lt(e,t){var n=this||st,a=t||n,i=Oe.from(a.headers),r=a.data;return Te.forEach(e,function(e){r=e.call(n,r,i.normalize(),t?t.status:void 0)}),i.normalize(),r}function ut(e){return!(!e||!e.__CANCEL__)}Te.forEach(["delete","get","head","post","put","patch","query"],function(e){st.headers[e]={}});var ct=function(e){function t(e,n,a){var i;return u(this,t),(i=l(this,t,[null==e?"canceled":e,De.ERR_CANCELED,n,a])).name="CanceledError",i.__CANCEL__=!0,i}return f(t,e),d(t)}(De);function dt(e,t,n){var a=n.config.validateStatus;n.status&&a&&!a(n.status)?t(new De("Request failed with status code "+n.status,n.status>=400&&n.status<500?De.ERR_BAD_REQUEST:De.ERR_BAD_RESPONSE,n.config,n.request,n)):e(n)}var ht=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:3,a=0,i=function(e,t){e=e||10;var n,a=new Array(e),i=new Array(e),r=0,o=0;return t=void 0!==t?t:1e3,function(s){var l=Date.now(),u=i[o];n||(n=l),a[r]=s,i[r]=l;for(var c=o,d=0;c!==r;)d+=a[c++],c%=e;if((r=(r+1)%e)===o&&(o=(o+1)%e),!(l-n1&&void 0!==arguments[1]?arguments[1]:Date.now();i=r,n=null,a&&(clearTimeout(a),a=null),e.apply(void 0,x(t))};return[function(){for(var e=Date.now(),t=e-i,s=arguments.length,l=new Array(s),u=0;u=r?o(l,e):(n=l,a||(a=setTimeout(function(){a=null,o(n)},r-t)))},function(){return n&&o(n)}]}(function(n){if(n&&"number"==typeof n.loaded){var r=n.loaded,o=n.lengthComputable?n.total:void 0,s=null!=o?Math.min(r,o):r,l=Math.max(0,s-a),u=i(l);a=Math.max(a,s);var c=h({loaded:s,total:o,progress:o?s/o:void 0,bytes:l,rate:u||void 0,estimated:u&&o?(o-s)/u:void 0,event:n,lengthComputable:null!=o},t?"download":"upload",!0);e(c)}},n)},pt=function(e,t){var n=null!=e;return[function(a){return t[0]({lengthComputable:n,total:e,loaded:a})},t[1]]},ft=function(e){return function(){for(var t=arguments.length,n=new Array(t),a=0;a=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102},Rt=function(e,t,n){return t+2=2&&37===a.charCodeAt(e-2)&&51===a.charCodeAt(e-1)&&(68===a.charCodeAt(e)||100===a.charCodeAt(e))};c>=0&&(61===a.charCodeAt(c)?(u++,c--):d(c)&&(u++,c-=3)),1===u&&c>=0&&(61===a.charCodeAt(c)||d(c))&&u++;var h=3*Math.floor(i/4)-(u||0);return h>0?h:0}for(var p=0,f=0,m=a.length;f=55296&&_<=56319&&f+1=56320&&g<=57343?(p+=4,f++):p+=3}else p+=3}return p}var It="1.18.0",Nt=Te.isFunction,Ot=function(e){return encodeURIComponent(e).replace(/%([0-9A-F]{2})/gi,function(e,t){return String.fromCharCode(parseInt(t,16))})},jt=function(e){if(!Te.isString(e))return e;try{return decodeURIComponent(e)}catch(t){return e}},Dt=function(e){try{for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a-1,z=Te.isNumber(M)&&M>-1,I=function(e){return Te.hasOwnProp(t,e)?t[e]:void 0},N=r||fetch,C=C?(C+"").toLowerCase():"text",O=Tt([d,h&&h.toAbortSignal()],f),j=null,D=O&&O.unsubscribe&&function(){O.unsubscribe()},B=null,F=function(){return new De("Request body larger than maxBodyLength limit",De.ERR_BAD_REQUEST,t,j)},e.p=1,V=void 0,(U=I("auth"))&&($=Te.getSafeProp(U,"username")||"",H=Te.getSafeProp(U,"password")||"",V={username:$,password:H}),qt(i)&&(W=new URL(i,at.origin),V||!W.username&&!W.password||(G=jt(W.username),K=jt(W.password),V={username:G,password:K}),(W.username||W.password)&&(W.username="",W.password="",i=W.href)),V&&(T.delete("authorization"),T.set("Authorization","Basic "+btoa(Ot((V.username||"")+":"+(V.password||""))))),!R||"string"!=typeof i||!i.startsWith("data:")){e.n=2;break}if(!(zt(i)>L)){e.n=2;break}throw new De("maxContentLength size of "+L+" exceeded",De.ERR_BAD_RESPONSE,t,j);case 2:if(!z||"get"===o||"head"===o){e.n=4;break}return e.n=3,y(u);case 3:if("number"!=typeof(Y=e.v)||!isFinite(Y)){e.n=4;break}if(q=Y,!(Y>M)){e.n=4;break}throw F();case 4:if(Q=z&&(Te.isReadableStream(u)||Te.isStream(u)),Z=function(e,t,n){return Lt(e,65536,function(e){if(z&&e>M)throw B=F();t&&t(e)},n)},!m||"get"===o||"head"===o||!S&&!Q){e.n=8;break}if(null!=q){e.n=6;break}return e.n=5,w(T,u);case 5:we=e.v,e.n=7;break;case 6:we=q;case 7:(0!==(q=we)||Q)&&(J=new s(i,{method:"POST",body:u,duplex:"half"}),Te.isFormData(u)&&(X=J.headers.get("content-type"))&&T.setContentType(X),J.body&&(ee=S&&pt(q,ht(ft(S)))||[],te=k(ee,2),ne=te[0],ae=te[1],u=Z(J.body,ne,ae))),e.n=10;break;case 8:if(!Q||c||!p||"get"===o||"head"===o){e.n=9;break}u=Z(u),e.n=10;break;case 9:if(!Q||!c||m||"get"===o||"head"===o){e.n=10;break}throw new De("Stream request bodies are not supported by the current fetch implementation",De.ERR_NOT_SUPPORT,t,j);case 10:return Te.isString(E)||(E=E?"include":"omit"),ie=c&&"credentials"in s.prototype,Te.isFormData(u)&&(re=T.getContentType())&&/^multipart\/form-data/i.test(re)&&!/boundary=/i.test(re)&&T.delete("content-type"),T.set("User-Agent","axios/"+It,!1),oe=g(g({},A),{},{signal:O,method:o.toUpperCase(),headers:Me(T.normalize()),body:u,duplex:"half",credentials:ie?E:void 0}),j=c&&new s(i,oe),e.n=11,c?N(j,A):N(i,oe);case 11:if(se=e.v,le=Oe.from(se.headers),!R){e.n=12;break}if(!(null!=(ue=Te.toFiniteNumber(le.getContentLength()))&&ue>L)){e.n=12;break}throw new De("maxContentLength size of "+L+" exceeded",De.ERR_BAD_RESPONSE,t,j);case 12:return ce=_&&("stream"===C||"response"===C),_&&se.body&&(x||R||ce&&D)&&(de={},["status","statusText","headers"].forEach(function(e){de[e]=se[e]}),he=Te.toFiniteNumber(le.getContentLength()),pe=x&&pt(he,ht(ft(x),!0))||[],fe=k(pe,2),me=fe[0],_e=fe[1],ge=function(e){if(R&&e>L)throw new De("maxContentLength size of "+L+" exceeded",De.ERR_BAD_RESPONSE,t,j);me&&me(e)},se=new l(Lt(se.body,65536,ge,function(){_e&&_e(),D&&D()}),de)),C=C||"text",e.n=13,b[Te.findKey(b,C)||"text"](se,t);case 13:if(ve=e.v,!R||_||ce){e.n=14;break}if(null!=ve&&("number"==typeof ve.byteLength?be=ve.byteLength:"number"==typeof ve.size?be=ve.size:"string"==typeof ve&&(be="function"==typeof a?(new a).encode(ve).byteLength:ve.length)),!("number"==typeof be&&be>L)){e.n=14;break}throw new De("maxContentLength size of "+L+" exceeded",De.ERR_BAD_RESPONSE,t,j);case 14:return!ce&&D&&D(),e.n=15,new Promise(function(e,n){dt(e,n,{data:ve,headers:Oe.from(se.headers),status:se.status,statusText:se.statusText,config:t,request:j})});case 15:return e.a(2,e.v);case 16:if(e.p=16,ke=e.v,D&&D(),!(O&&O.aborted&&O.reason instanceof De)){e.n=17;break}throw(ye=O.reason).config=t,j&&(ye.request=j),ke!==ye&&(ye.cause=ke),ye;case 17:if(!B){e.n=18;break}throw j&&!B.request&&(B.request=j),B;case 18:if(!(ke instanceof De)){e.n=19;break}throw j&&!ke.request&&(ke.request=j),ke;case 19:if(!ke||"TypeError"!==ke.name||!/Load failed|fetch/i.test(ke.message)){e.n=20;break}throw Object.assign(new De("Network Error",De.ERR_NETWORK,t,j,ke&&ke.response),{cause:ke.cause||ke});case 20:throw De.from(ke,ke&&ke.code,t,j,ke&&ke.response);case 21:return e.a(2)}},e,null,[[1,16]])}));return function(t){return e.apply(this,arguments)}}()},Ft=new Map,Vt=function(e){for(var t,n,a=e&&e.env||{},i=a.fetch,r=[a.Request,a.Response,i],o=r.length,s=Ft;o--;)t=r[o],void 0===(n=s.get(t))&&s.set(t,n=o?new Map:Bt(a)),s=n;return n};Vt();var Ut={http:null,xhr:Ct,fetch:{get:Vt}};Te.forEach(Ut,function(e,t){if(e){try{Object.defineProperty(e,"name",{__proto__:null,value:t})}catch(e){}Object.defineProperty(e,"adapterName",{__proto__:null,value:t})}});var $t=function(e){return"- ".concat(e)},Ht=function(e){return Te.isFunction(e)||null===e||!1===e};var Wt={getAdapter:function(e,t){for(var n,a,i=(e=Te.isArray(e)?e:[e]).length,r={},o=0;o1?"since :\n"+l.map($t).join("\n"):" "+$t(l[0]):"as no adapter specified";throw new De("There is no suitable adapter to dispatch the request "+u,"ERR_NOT_SUPPORT")}return a},adapters:Ut};function Gt(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new ct(null,e)}function Kt(e){return Gt(e),e.headers=Oe.from(e.headers),e.data=lt.call(e,e.transformRequest),-1!==["post","put","patch"].indexOf(e.method)&&e.headers.setContentType("application/x-www-form-urlencoded",!1),Wt.getAdapter(e.adapter||st.adapter,e)(e).then(function(t){Gt(e),e.response=t;try{t.data=lt.call(e,e.transformResponse,t)}finally{delete e.response}return t.headers=Oe.from(t.headers),t},function(t){if(!ut(t)&&(Gt(e),t&&t.response)){e.response=t.response;try{t.response.data=lt.call(e,e.transformResponse,t.response)}finally{delete e.response}t.response.headers=Oe.from(t.response.headers)}return Promise.reject(t)})}var Yt={};["object","boolean","number","function","string","symbol"].forEach(function(e,t){Yt[e]=function(n){return C(n)===e||"a"+(t<1?"n ":" ")+e}});var Qt={};Yt.transitional=function(e,t,n){function a(e,t){return"[Axios v"+It+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,i,r){if(!1===e)throw new De(a(i," has been removed"+(t?" in "+t:"")),De.ERR_DEPRECATED);return t&&!Qt[i]&&(Qt[i]=!0,console.warn(a(i," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,i,r)}},Yt.spelling=function(e){return function(t,n){return console.warn("".concat(n," is likely a misspelling of ").concat(e)),!0}};var Zt={assertOptions:function(e,t,n){if("object"!==C(e))throw new De("options must be an object",De.ERR_BAD_OPTION_VALUE);for(var a=Object.keys(e),i=a.length;i-- >0;){var r=a[i],o=Object.prototype.hasOwnProperty.call(t,r)?t[r]:void 0;if(o){var s=e[r],l=void 0===s||o(s,r,e);if(!0!==l)throw new De("option "+r+" must be "+l,De.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new De("Unknown option "+r,De.ERR_BAD_OPTION)}},validators:Yt},Jt=Zt.validators,Xt=function(){return d(function e(t){u(this,e),this.defaults=t||{},this.interceptors={request:new Ye,response:new Ye}},[{key:"request",value:(e=o(v().m(function e(t,n){var a,i,r,o,s,l;return v().w(function(e){for(;;)switch(e.p=e.n){case 0:return e.p=0,e.n=1,this._request(t,n);case 1:return e.a(2,e.v);case 2:if(e.p=2,(l=e.v)instanceof Error){a={},Error.captureStackTrace?Error.captureStackTrace(a):a=new Error,i=function(){if(!a.stack)return"";var e=a.stack.indexOf("\n");return-1===e?"":a.stack.slice(e+1)}();try{l.stack?i&&(r=i.indexOf("\n"),o=-1===r?-1:i.indexOf("\n",r+1),s=-1===o?"":i.slice(o+1),String(l.stack).endsWith(s)||(l.stack+="\n"+i)):l.stack=i}catch(e){}}throw l;case 3:return e.a(2)}},e,this,[[0,2]])})),function(t,n){return e.apply(this,arguments)})},{key:"_request",value:function(e,t){"string"==typeof e?(t=t||{}).url=e:t=e||{};var n=t=kt(this.defaults,t),a=n.transitional,i=n.paramsSerializer,r=n.headers;void 0!==a&&Zt.assertOptions(a,{silentJSONParsing:Jt.transitional(Jt.boolean),forcedJSONParsing:Jt.transitional(Jt.boolean),clarifyTimeoutError:Jt.transitional(Jt.boolean),legacyInterceptorReqResOrdering:Jt.transitional(Jt.boolean),advertiseZstdAcceptEncoding:Jt.transitional(Jt.boolean),validateStatusUndefinedResolves:Jt.transitional(Jt.boolean)},!1),null!=i&&(Te.isFunction(i)?t.paramsSerializer={serialize:i}:Zt.assertOptions(i,{encode:Jt.function,serialize:Jt.function},!0)),void 0!==t.allowAbsoluteUrls||(void 0!==this.defaults.allowAbsoluteUrls?t.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:t.allowAbsoluteUrls=!0),Zt.assertOptions(t,{baseUrl:Jt.spelling("baseURL"),withXsrfToken:Jt.spelling("withXSRFToken")},!0),t.method=(t.method||this.defaults.method||"get").toLowerCase();var o=r&&Te.merge(r.common,r[t.method]);r&&Te.forEach(["delete","get","head","post","put","patch","query","common"],function(e){delete r[e]}),t.headers=Oe.concat(o,r);var s=[],l=!0;this.interceptors.request.forEach(function(e){if("function"!=typeof e.runWhen||!1!==e.runWhen(t)){l=l&&e.synchronous;var n=t.transitional||Qe;n&&n.legacyInterceptorReqResOrdering?s.unshift(e.fulfilled,e.rejected):s.push(e.fulfilled,e.rejected)}});var u,c=[];this.interceptors.response.forEach(function(e){c.push(e.fulfilled,e.rejected)});var d,h=0;if(!l){var p=[Kt.bind(this),void 0];for(p.unshift.apply(p,s),p.push.apply(p,c),d=p.length,u=Promise.resolve(t);h0;)a._listeners[t](e);a._listeners=null}}),this.promise.then=function(e){var t,n=new Promise(function(e){a.subscribe(e),t=e}).then(e);return n.cancel=function(){a.unsubscribe(t)},n},t(function(e,t,i){a.reason||(a.reason=new ct(e,t,i),n(a.reason))})}return d(e,[{key:"throwIfRequested",value:function(){if(this.reason)throw this.reason}},{key:"subscribe",value:function(e){this.reason?e(this.reason):this._listeners?this._listeners.push(e):this._listeners=[e]}},{key:"unsubscribe",value:function(e){if(this._listeners){var t=this._listeners.indexOf(e);-1!==t&&this._listeners.splice(t,1)}}},{key:"toAbortSignal",value:function(){var e=this,t=new AbortController,n=function(e){t.abort(e)};return this.subscribe(n),t.signal.unsubscribe=function(){return e.unsubscribe(n)},t.signal}}],[{key:"source",value:function(){var t;return{token:new e(function(e){t=e}),cancel:t}}}])}();var tn={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(tn).forEach(function(e){var t=k(e,2),n=t[0],a=t[1];tn[a]=n});var nn=function e(t){var n=new Xt(t),a=L(Xt.prototype.request,n);return Te.extend(a,Xt.prototype,n,{allOwnKeys:!0}),Te.extend(a,n,null,{allOwnKeys:!0}),a.create=function(n){return e(kt(t,n))},a}(st);return nn.Axios=Xt,nn.CanceledError=ct,nn.CancelToken=en,nn.isCancel=ut,nn.VERSION=It,nn.toFormData=Ue,nn.AxiosError=De,nn.Cancel=nn.CanceledError,nn.all=function(e){return Promise.all(e)},nn.spread=function(e){return function(t){return e.apply(null,t)}},nn.isAxiosError=function(e){return Te.isObject(e)&&!0===e.isAxiosError},nn.mergeConfig=kt,nn.AxiosHeaders=Oe,nn.formToJSON=function(e){return rt(Te.isHTMLForm(e)?new FormData(e):e)},nn.getAdapter=Wt.getAdapter,nn.HttpStatusCode=tn,nn.default=nn,nn}); /** -* vue v3.5.25 +* vue v3.5.34 * (c) 2018-present Yuxi (Evan) You and Vue contributors * @license MIT **/ -var Vue=function(e){"use strict";var t,n,a;let i,o,r,s,l,u,c,d,h,p,f,m,g;function _(e){let t=Object.create(null);for(let n of e.split(","))t[n]=1;return e=>e in t}let v={},b=[],y=()=>{},w=()=>!1,k=e=>111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&(e.charCodeAt(2)>122||97>e.charCodeAt(2)),x=e=>e.startsWith("onUpdate:"),S=Object.assign,C=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},T=Object.prototype.hasOwnProperty,P=(e,t)=>T.call(e,t),E=Array.isArray,A=e=>"function"==typeof e,M=e=>"string"==typeof e,L=e=>"symbol"==typeof e,R=e=>null!==e&&"object"==typeof e,z=e=>(R(e)||A(e))&&A(e.then)&&A(e.catch),N=Object.prototype.toString,O=e=>M(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,I=_(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),q=_("bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo"),D=e=>{let t=Object.create(null);return n=>t[n]||(t[n]=e(n))},j=/-\w/g,B=D(e=>e.replace(j,e=>e.slice(1).toUpperCase())),F=/\B([A-Z])/g,$=D(e=>e.replace(F,"-$1").toLowerCase()),V=D(e=>e.charAt(0).toUpperCase()+e.slice(1)),U=D(e=>e?`on${V(e)}`:""),H=(e,t)=>!Object.is(e,t),W=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:a,value:n})},K=e=>{let t=parseFloat(e);return isNaN(t)?e:t},Y=e=>{let t=M(e)?Number(e):NaN;return isNaN(t)?e:t},Q=()=>i||(i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:{}),Z=_("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol");function J(e){if(E(e)){let t={};for(let n=0;n{if(e){let n=e.split(ee);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function ae(e){let t="";if(M(e))t=e;else if(E(e))for(let n=0;nue(e,t))}let de=e=>!(!e||!0!==e.__v_isRef),he=e=>M(e)?e:null==e?"":E(e)||R(e)&&(e.toString===N||!A(e.toString))?de(e)?he(e.value):JSON.stringify(e,pe,2):String(e),pe=(e,t)=>{let n;if(de(t))return pe(e,t.value);if("[object Map]"===(n=t,N.call(n)))return{[`Map(${t.size})`]:[...t.entries()].reduce((e,[t,n],a)=>(e[fe(t,a)+" =>"]=n,e),{})};{let e;if("[object Set]"===(e=t,N.call(e)))return{[`Set(${t.size})`]:[...t.values()].map(e=>fe(e))};{if(L(t))return fe(t);let e;if(R(t)&&!E(t)&&"[object Object]"!==(e=t,N.call(e)))return String(t)}}return t},fe=(e,t="")=>{var n;return L(e)?`Symbol(${null!=(n=e.description)?n:t})`:e};class me{constructor(e=!1){this.detached=e,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this.parent=o,!e&&o&&(this.index=(o.scopes||(o.scopes=[])).push(this)-1)}get active(){return this._active}pause(){if(this._active){let e,t;if(this._isPaused=!0,this.scopes)for(e=0,t=this.scopes.length;e0&&0==--this._on&&(o=this.prevScope,this.prevScope=void 0)}stop(e){if(this._active){let t,n;for(t=0,this._active=!1,n=this.effects.length;t0)){if(l){let e=l;for(l=void 0;e;){let t=e.next;e.next=void 0,e.flags&=-9,e=t}}for(;s;){let t=s;for(s=void 0;t;){let n=t.next;if(t.next=void 0,t.flags&=-9,1&t.flags)try{t.trigger()}catch(t){e||(e=t)}t=n}}if(e)throw e}}function we(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function ke(e){let t,n=e.depsTail,a=n;for(;a;){let e=a.prevDep;-1===a.version?(a===n&&(n=e),Ce(a),function(e){let{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}(a)):t=a,a.dep.activeLink=a.prevActiveLink,a.prevActiveLink=void 0,a=e}e.deps=t,e.depsTail=n}function xe(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Se(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Se(e){if(4&e.flags&&!(16&e.flags)||(e.flags&=-17,e.globalVersion===Le)||(e.globalVersion=Le,!e.isSSR&&128&e.flags&&(!e.deps&&!e._dirty||!xe(e))))return;e.flags|=2;let t=e.dep,n=r,a=Te;r=e,Te=!0;try{we(e);let n=e.fn(e._value);(0===t.version||H(n,e._value))&&(e.flags|=128,e._value=n,t.version++)}catch(e){throw t.version++,e}finally{r=n,Te=a,ke(e),e.flags&=-3}}function Ce(e,t=!1){let{dep:n,prevSub:a,nextSub:i}=e;if(a&&(a.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=a,e.nextSub=void 0),n.subs===e&&(n.subs=a,!a&&n.computed)){n.computed.flags&=-5;for(let e=n.computed.deps;e;e=e.nextDep)Ce(e,!0)}t||--n.sc||!n.map||n.map.delete(n.key)}let Te=!0,Pe=[];function Ee(){Pe.push(Te),Te=!1}function Ae(){let e=Pe.pop();Te=void 0===e||e}function Me(e){let{cleanup:t}=e;if(e.cleanup=void 0,t){let e=r;r=void 0;try{t()}finally{r=e}}}let Le=0;class Re{constructor(e,t){this.sub=e,this.dep=t,this.version=t.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class ze{constructor(e){this.computed=e,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(e){if(!r||!Te||r===this.computed)return;let t=this.activeLink;if(void 0===t||t.sub!==r)t=this.activeLink=new Re(r,this),r.deps?(t.prevDep=r.depsTail,r.depsTail.nextDep=t,r.depsTail=t):r.deps=r.depsTail=t,function e(t){if(t.dep.sc++,4&t.sub.flags){let n=t.dep.computed;if(n&&!t.dep.subs){n.flags|=20;for(let t=n.deps;t;t=t.nextDep)e(t)}let a=t.dep.subs;a!==t&&(t.prevSub=a,a&&(a.nextSub=t)),t.dep.subs=t}}(t);else if(-1===t.version&&(t.version=this.version,t.nextDep)){let e=t.nextDep;e.prevDep=t.prevDep,t.prevDep&&(t.prevDep.nextDep=e),t.prevDep=r.depsTail,t.nextDep=void 0,r.depsTail.nextDep=t,r.depsTail=t,r.deps===t&&(r.deps=e)}return t}trigger(e){this.version++,Le++,this.notify(e)}notify(e){ve++;try{for(let e=this.subs;e;e=e.prevSub)e.sub.notify()&&e.sub.dep.notify()}finally{ye()}}}let Ne=new WeakMap,Oe=Symbol(""),Ie=Symbol(""),qe=Symbol("");function De(e,t,n){if(Te&&r){let t=Ne.get(e);t||Ne.set(e,t=new Map);let a=t.get(n);a||(t.set(n,a=new ze),a.map=t,a.key=n),a.track()}}function je(e,t,n,a,i,o){let r=Ne.get(e);if(!r)return void Le++;let s=e=>{e&&e.trigger()};if(ve++,"clear"===t)r.forEach(s);else{let i=E(e),o=i&&O(n);if(i&&"length"===n){let e=Number(a);r.forEach((t,n)=>{("length"===n||n===qe||!L(n)&&n>=e)&&s(t)})}else switch((void 0!==n||r.has(void 0))&&s(r.get(n)),o&&s(r.get(qe)),t){case"add":if(i)o&&s(r.get("length"));else{let t;s(r.get(Oe)),"[object Map]"===(t=e,N.call(t))&&s(r.get(Ie))}break;case"delete":if(!i){let t;s(r.get(Oe)),"[object Map]"===(t=e,N.call(t))&&s(r.get(Ie))}break;case"set":let t;"[object Map]"===(t=e,N.call(t))&&s(r.get(Oe))}}ye()}function Be(e){let t=Ct(e);return t===e?t:(De(t,0,qe),xt(e)?t:t.map(Pt))}function Fe(e){return De(e=Ct(e),0,qe),e}function $e(e,t){return kt(e)?wt(e)?Et(Pt(t)):Et(t):Pt(t)}let Ve={__proto__:null,[Symbol.iterator](){return Ue(this,Symbol.iterator,e=>$e(this,e))},concat(...e){return Be(this).concat(...e.map(e=>E(e)?Be(e):e))},entries(){return Ue(this,"entries",e=>(e[1]=$e(this,e[1]),e))},every(e,t){return We(this,"every",e,t,void 0,arguments)},filter(e,t){return We(this,"filter",e,t,e=>e.map(e=>$e(this,e)),arguments)},find(e,t){return We(this,"find",e,t,e=>$e(this,e),arguments)},findIndex(e,t){return We(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return We(this,"findLast",e,t,e=>$e(this,e),arguments)},findLastIndex(e,t){return We(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return We(this,"forEach",e,t,void 0,arguments)},includes(...e){return Ke(this,"includes",e)},indexOf(...e){return Ke(this,"indexOf",e)},join(e){return Be(this).join(e)},lastIndexOf(...e){return Ke(this,"lastIndexOf",e)},map(e,t){return We(this,"map",e,t,void 0,arguments)},pop(){return Ye(this,"pop")},push(...e){return Ye(this,"push",e)},reduce(e,...t){return Ge(this,"reduce",e,t)},reduceRight(e,...t){return Ge(this,"reduceRight",e,t)},shift(){return Ye(this,"shift")},some(e,t){return We(this,"some",e,t,void 0,arguments)},splice(...e){return Ye(this,"splice",e)},toReversed(){return Be(this).toReversed()},toSorted(e){return Be(this).toSorted(e)},toSpliced(...e){return Be(this).toSpliced(...e)},unshift(...e){return Ye(this,"unshift",e)},values(){return Ue(this,"values",e=>$e(this,e))}};function Ue(e,t,n){let a=Fe(e),i=a[t]();return a===e||xt(e)||(i._next=i.next,i.next=()=>{let e=i._next();return e.done||(e.value=n(e.value)),e}),i}let He=Array.prototype;function We(e,t,n,a,i,o){let r=Fe(e),s=r!==e&&!xt(e),l=r[t];if(l!==He[t]){let t=l.apply(e,o);return s?Pt(t):t}let u=n;r!==e&&(s?u=function(t,a){return n.call(this,$e(e,t),a,e)}:n.length>2&&(u=function(t,a){return n.call(this,t,a,e)}));let c=l.call(r,u,a);return s&&i?i(c):c}function Ge(e,t,n,a){let i=Fe(e),o=n;return i!==e&&(xt(e)?n.length>3&&(o=function(t,a,i){return n.call(this,t,a,i,e)}):o=function(t,a,i){return n.call(this,t,$e(e,a),i,e)}),i[t](o,...a)}function Ke(e,t,n){let a=Ct(e);De(a,0,qe);let i=a[t](...n);return-1!==i&&!1!==i||!St(n[0])?i:(n[0]=Ct(n[0]),a[t](...n))}function Ye(e,t,n=[]){Ee(),ve++;let a=Ct(e)[t].apply(e,n);return ye(),Ae(),a}let Qe=_("__proto__,__v_isRef,__isVue"),Ze=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>"arguments"!==e&&"caller"!==e).map(e=>Symbol[e]).filter(L));function Je(e){L(e)||(e=String(e));let t=Ct(this);return De(t,0,e),t.hasOwnProperty(e)}class Xe{constructor(e=!1,t=!1){this._isReadonly=e,this._isShallow=t}get(e,t,n){if("__v_skip"===t)return e.__v_skip;let a=this._isReadonly,i=this._isShallow;if("__v_isReactive"===t)return!a;if("__v_isReadonly"===t)return a;if("__v_isShallow"===t)return i;if("__v_raw"===t)return n===(a?i?gt:mt:i?ft:pt).get(e)||Object.getPrototypeOf(e)===Object.getPrototypeOf(n)?e:void 0;let o=E(e);if(!a){let e;if(o&&(e=Ve[t]))return e;if("hasOwnProperty"===t)return Je}let r=Reflect.get(e,t,At(e)?e:n);if((L(t)?Ze.has(t):Qe(t))||(a||De(e,0,t),i))return r;if(At(r)){let e=o&&O(t)?r:r.value;return a&&R(e)?bt(e):e}return R(r)?a?bt(r):_t(r):r}}class et extends Xe{constructor(e=!1){super(!1,e)}set(e,t,n,a){let i=e[t],o=E(e)&&O(t);if(!this._isShallow){let e=kt(i);if(xt(n)||kt(n)||(i=Ct(i),n=Ct(n)),!o&&At(i)&&!At(n))return e||(i.value=n),!0}let r=o?Number(t)e;function st(e){return function(){return"delete"!==e&&("clear"===e?void 0:this)}}function lt(e,t){let n,a=(S(n={get(n){let a=this.__v_raw,i=Ct(a),o=Ct(n);e||(H(n,o)&&De(i,0,n),De(i,0,o));let{has:r}=Reflect.getPrototypeOf(i),s=t?rt:e?Et:Pt;return r.call(i,n)?s(a.get(n)):r.call(i,o)?s(a.get(o)):void(a!==i&&a.get(n))},get size(){let t=this.__v_raw;return e||De(Ct(t),0,Oe),t.size},has(t){let n=this.__v_raw,a=Ct(n),i=Ct(t);return e||(H(t,i)&&De(a,0,t),De(a,0,i)),t===i?n.has(t):n.has(t)||n.has(i)},forEach(n,a){let i=this,o=i.__v_raw,r=Ct(o),s=t?rt:e?Et:Pt;return e||De(r,0,Oe),o.forEach((e,t)=>n.call(a,s(e),s(t),i))}},e?{add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear")}:{add(e){t||xt(e)||kt(e)||(e=Ct(e));let n=Ct(this);return Reflect.getPrototypeOf(n).has.call(n,e)||(n.add(e),je(n,"add",e,e)),this},set(e,n){t||xt(n)||kt(n)||(n=Ct(n));let a=Ct(this),{has:i,get:o}=Reflect.getPrototypeOf(a),r=i.call(a,e);r||(e=Ct(e),r=i.call(a,e));let s=o.call(a,e);return a.set(e,n),r?H(n,s)&&je(a,"set",e,n):je(a,"add",e,n),this},delete(e){let t=Ct(this),{has:n,get:a}=Reflect.getPrototypeOf(t),i=n.call(t,e);i||(e=Ct(e),i=n.call(t,e)),a&&a.call(t,e);let o=t.delete(e);return i&&je(t,"delete",e,void 0),o},clear(){let e=Ct(this),t=0!==e.size,n=e.clear();return t&&je(e,"clear",void 0,void 0),n}}),["keys","values","entries",Symbol.iterator].forEach(a=>{n[a]=function(...n){let i,o=this.__v_raw,r=Ct(o),s="[object Map]"===(i=r,N.call(i)),l="entries"===a||a===Symbol.iterator&&s,u=o[a](...n),c=t?rt:e?Et:Pt;return e||De(r,0,"keys"===a&&s?Ie:Oe),{next(){let{value:e,done:t}=u.next();return t?{value:e,done:t}:{value:l?[c(e[0]),c(e[1])]:c(e),done:t}},[Symbol.iterator](){return this}}}}),n);return(t,n,i)=>"__v_isReactive"===n?!e:"__v_isReadonly"===n?e:"__v_raw"===n?t:Reflect.get(P(a,n)&&n in t?a:t,n,i)}let ut={get:lt(!1,!1)},ct={get:lt(!1,!0)},dt={get:lt(!0,!1)},ht={get:lt(!0,!0)},pt=new WeakMap,ft=new WeakMap,mt=new WeakMap,gt=new WeakMap;function _t(e){return kt(e)?e:yt(e,!1,nt,ut,pt)}function vt(e){return yt(e,!1,it,ct,ft)}function bt(e){return yt(e,!0,at,dt,mt)}function yt(e,t,n,a,i){var o;let r;if(!R(e)||e.__v_raw&&(!t||!e.__v_isReactive))return e;let s=(o=e).__v_skip||!Object.isExtensible(o)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((r=o,N.call(r)).slice(8,-1));if(0===s)return e;let l=i.get(e);if(l)return l;let u=new Proxy(e,2===s?a:n);return i.set(e,u),u}function wt(e){return kt(e)?wt(e.__v_raw):!(!e||!e.__v_isReactive)}function kt(e){return!(!e||!e.__v_isReadonly)}function xt(e){return!(!e||!e.__v_isShallow)}function St(e){return!!e&&!!e.__v_raw}function Ct(e){let t=e&&e.__v_raw;return t?Ct(t):e}function Tt(e){return!P(e,"__v_skip")&&Object.isExtensible(e)&&G(e,"__v_skip",!0),e}let Pt=e=>R(e)?_t(e):e,Et=e=>R(e)?bt(e):e;function At(e){return!!e&&!0===e.__v_isRef}function Mt(e){return Rt(e,!1)}function Lt(e){return Rt(e,!0)}function Rt(e,t){return At(e)?e:new zt(e,t)}class zt{constructor(e,t){this.dep=new ze,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=t?e:Ct(e),this._value=t?e:Pt(e),this.__v_isShallow=t}get value(){return this.dep.track(),this._value}set value(e){let t=this._rawValue,n=this.__v_isShallow||xt(e)||kt(e);H(e=n?e:Ct(e),t)&&(this._rawValue=e,this._value=n?e:Pt(e),this.dep.trigger())}}function Nt(e){return At(e)?e.value:e}let Ot={get:(e,t,n)=>"__v_raw"===t?e:Nt(Reflect.get(e,t,n)),set:(e,t,n,a)=>{let i=e[t];return At(i)&&!At(n)?(i.value=n,!0):Reflect.set(e,t,n,a)}};function It(e){return wt(e)?e:new Proxy(e,Ot)}class qt{constructor(e){this.__v_isRef=!0,this._value=void 0;const t=this.dep=new ze,{get:n,set:a}=e(t.track.bind(t),t.trigger.bind(t));this._get=n,this._set=a}get value(){return this._value=this._get()}set value(e){this._set(e)}}function Dt(e){return new qt(e)}class jt{constructor(e,t,n){this._object=e,this._key=t,this._defaultValue=n,this.__v_isRef=!0,this._value=void 0,this._raw=Ct(e);let a=!0,i=e;if(!E(e)||!O(String(t)))do{a=!St(i)||xt(i)}while(a&&(i=i.__v_raw));this._shallow=a}get value(){let e=this._object[this._key];return this._shallow&&(e=Nt(e)),this._value=void 0===e?this._defaultValue:e}set value(e){if(this._shallow&&At(this._raw[this._key])){let t=this._object[this._key];if(At(t))return void(t.value=e)}this._object[this._key]=e}get dep(){var e,t;let n;return e=this._raw,t=this._key,(n=Ne.get(e))&&n.get(t)}}class Bt{constructor(e){this._getter=e,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}class Ft{constructor(e,t,n){this.fn=e,this.setter=t,this._value=void 0,this.dep=new ze(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=Le-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!t,this.isSSR=n}notify(){if(this.flags|=16,!(8&this.flags)&&r!==this)return be(this,!0),!0}get value(){let e=this.dep.track();return Se(this),e&&(e.version=this.dep.version),this._value}set value(e){this.setter&&this.setter(e)}}let $t={},Vt=new WeakMap;function Ut(e,t=!1,n=m){if(n){let t=Vt.get(n);t||Vt.set(n,t=[]),t.push(e)}}function Ht(e,t=1/0,n){if(t<=0||!R(e)||e.__v_skip||((n=n||new Map).get(e)||0)>=t)return e;if(n.set(e,t),t--,At(e))Ht(e.value,t,n);else if(E(e))for(let a=0;a{Ht(e,t,n)});else{let a;if("[object Object]"===(a=e,N.call(a))){for(let a in e)Ht(e[a],t,n);for(let a of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,a)&&Ht(e[a],t,n)}}}return e}function Wt(e,t,n,a){try{return a?e(...a):e()}catch(e){Kt(e,t,n)}}function Gt(e,t,n,a){if(A(e)){let i=Wt(e,t,n,a);return i&&z(i)&&i.catch(e=>{Kt(e,t,n)}),i}if(E(e)){let i=[];for(let o=0;o=un(n)?Yt.push(e):Yt.splice(function(e){let t=Qt+1,n=Yt.length;for(;t>>1,i=Yt[a],o=un(i);oun(e)-un(t));if(Zt.length=0,Jt)return void Jt.push(...e);for(Xt=0,Jt=e;Xtnull==e.id?2&e.flags?-1:1/0:e.id,cn=null,dn=null;function hn(e){let t=cn;return cn=e,dn=e&&e.type.__scopeId||null,t}function pn(e,t=cn,n){if(!t||e._n)return e;let a=(...n)=>{let i;a._d&&Vi(-1);let o=hn(t);try{i=e(...n)}finally{hn(o),a._d&&Vi(1)}return i};return a._n=!0,a._c=!0,a._d=!0,a}function fn(e,t,n,a){let i=e.dirs,o=t&&t.dirs;for(let r=0;re&&(e.disabled||""===e.disabled),_n=e=>e&&(e.defer||""===e.defer),vn=e=>"undefined"!=typeof SVGElement&&e instanceof SVGElement,bn=e=>"function"==typeof MathMLElement&&e instanceof MathMLElement,yn=(e,t)=>{let n=e&&e.to;return M(n)?t?t(n):null:n},wn={name:"Teleport",__isTeleport:!0,process(e,t,n,a,i,o,r,s,l,u){let{mc:c,pc:d,pbc:h,o:{insert:p,querySelector:f,createText:m}}=u,g=gn(t.props),{shapeFlag:_,children:v,dynamicChildren:b}=t;if(null==e){let e=t.el=m(""),u=t.anchor=m("");p(e,n,a),p(u,n,a);let d=(e,t)=>{16&_&&c(v,e,t,i,o,r,s,l)},h=()=>{let e=t.target=yn(t.props,f),n=Sn(e,t,m,p);e&&("svg"!==r&&vn(e)?r="svg":"mathml"!==r&&bn(e)&&(r="mathml"),i&&i.isCE&&(i.ce._teleportTargets||(i.ce._teleportTargets=new Set)).add(e),g||(d(e,n),xn(t,!1)))};g&&(d(n,u),xn(t,!0)),_n(t.props)?(t.el.__isMounted=!1,bi(()=>{h(),delete t.el.__isMounted},o)):h()}else{if(_n(t.props)&&!1===e.el.__isMounted)return void bi(()=>{wn.process(e,t,n,a,i,o,r,s,l,u)},o);t.el=e.el,t.targetStart=e.targetStart;let c=t.anchor=e.anchor,p=t.target=e.target,m=t.targetAnchor=e.targetAnchor,_=gn(e.props),v=_?n:p,y=_?c:m;if("svg"===r||vn(p)?r="svg":("mathml"===r||bn(p))&&(r="mathml"),b?(h(e.dynamicChildren,b,v,i,o,r,s),Ci(e,t,!0)):l||d(e,t,v,y,i,o,r,s,!1),g)_?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):kn(t,n,c,u,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){let e=t.target=yn(t.props,f);e&&kn(t,e,null,u,0)}else _&&kn(t,p,m,u,1);xn(t,g)}},remove(e,t,n,{um:a,o:{remove:i}},o){let{shapeFlag:r,children:s,anchor:l,targetStart:u,targetAnchor:c,target:d,props:h}=e;if(d&&(i(u),i(c)),o&&i(l),16&r){let e=o||!gn(h);for(let i=0;i{e.isMounted=!0}),ma(()=>{e.isUnmounting=!0}),e}let En=[Function,Array],An={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:En,onEnter:En,onAfterEnter:En,onEnterCancelled:En,onBeforeLeave:En,onLeave:En,onAfterLeave:En,onLeaveCancelled:En,onBeforeAppear:En,onAppear:En,onAfterAppear:En,onAppearCancelled:En},Mn=e=>{let t=e.subTree;return t.component?Mn(t.component):t};function Ln(e){let t=e[0];if(e.length>1)for(let n of e)if(n.type!==Ii){t=n;break}return t}let Rn={name:"BaseTransition",props:An,setup(e,{slots:t}){let n=uo(),a=Pn();return()=>{let i=t.default&&Dn(t.default(),!0);if(!i||!i.length)return;let o=Ln(i),r=Ct(e),{mode:s}=r;if(a.isLeaving)return On(o);let l=In(o);if(!l)return On(o);let u=Nn(l,r,a,n,e=>u=e);l.type!==Ii&&qn(l,u);let c=n.subTree&&In(n.subTree);if(c&&c.type!==Ii&&!Gi(c,l)&&Mn(n).type!==Ii){let e=Nn(c,r,a,n);if(qn(c,e),"out-in"===s&&l.type!==Ii)return a.isLeaving=!0,e.afterLeave=()=>{a.isLeaving=!1,8&n.job.flags||n.update(),delete e.afterLeave,c=void 0},On(o);"in-out"===s&&l.type!==Ii?e.delayLeave=(e,t,n)=>{zn(a,c)[String(c.key)]=c,e[Cn]=()=>{t(),e[Cn]=void 0,delete u.delayedLeave,c=void 0},u.delayedLeave=()=>{n(),delete u.delayedLeave,c=void 0}}:c=void 0}else c&&(c=void 0);return o}}};function zn(e,t){let{leavingVNodes:n}=e,a=n.get(t.type);return a||(a=Object.create(null),n.set(t.type,a)),a}function Nn(e,t,n,a,i){let{appear:o,mode:r,persisted:s=!1,onBeforeEnter:l,onEnter:u,onAfterEnter:c,onEnterCancelled:d,onBeforeLeave:h,onLeave:p,onAfterLeave:f,onLeaveCancelled:m,onBeforeAppear:g,onAppear:_,onAfterAppear:v,onAppearCancelled:b}=t,y=String(e.key),w=zn(n,e),k=(e,t)=>{e&&Gt(e,a,9,t)},x=(e,t)=>{let n=t[1];k(e,t),E(e)?e.every(e=>e.length<=1)&&n():e.length<=1&&n()},S={mode:r,persisted:s,beforeEnter(t){let a=l;if(!n.isMounted){if(!o)return;a=g||l}t[Cn]&&t[Cn](!0);let i=w[y];i&&Gi(e,i)&&i.el[Cn]&&i.el[Cn](),k(a,[t])},enter(e){let t=u,a=c,i=d;if(!n.isMounted){if(!o)return;t=_||u,a=v||c,i=b||d}let r=!1,s=e[Tn]=t=>{r||(r=!0,k(t?i:a,[e]),S.delayedLeave&&S.delayedLeave(),e[Tn]=void 0)};t?x(t,[e,s]):s()},leave(t,a){let i=String(e.key);if(t[Tn]&&t[Tn](!0),n.isUnmounting)return a();k(h,[t]);let o=!1,r=t[Cn]=n=>{o||(o=!0,a(),k(n?m:f,[t]),t[Cn]=void 0,w[i]===e&&delete w[i])};w[i]=e,p?x(p,[t,r]):r()},clone(e){let o=Nn(e,t,n,a,i);return i&&i(o),o}};return S}function On(e){if(na(e))return(e=Xi(e)).children=null,e}function In(e){if(!na(e))return e.type.__isTeleport&&e.children?Ln(e.children):e;if(e.component)return e.component.subTree;let{shapeFlag:t,children:n}=e;if(n){if(16&t)return n[0];if(32&t&&A(n.default))return n.default()}}function qn(e,t){6&e.shapeFlag&&e.component?(e.transition=t,qn(e.component.subTree,t)):128&e.shapeFlag?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Dn(e,t=!1,n){let a=[],i=0;for(let o=0;o1)for(let e=0;e$n(e,t&&(E(t)?t[o]:t),n,a,i));if(ea(a)&&!i)return void(512&a.shapeFlag&&a.type.__asyncResolved&&a.component.subTree.component&&$n(e,t,n,a.component.subTree));let o=4&a.shapeFlag?yo(a.component):a.el,r=i?null:o,{i:s,r:l}=e,u=t&&t.r,c=s.refs===v?s.refs={}:s.refs,d=s.setupState,h=Ct(d),p=d===v?w:e=>P(h,e);if(null!=u&&u!==l&&(Vn(t),M(u)?(c[u]=null,p(u)&&(d[u]=null)):At(u)&&(u.value=null,t.k&&(c[t.k]=null))),A(l))Wt(l,s,12,[r,c]);else{let t=M(l),a=At(l);if(t||a){let s=()=>{if(e.f){let n=t?p(l)?d[l]:c[l]:l.value;if(i)E(n)&&C(n,o);else if(E(n))n.includes(o)||n.push(o);else if(t)c[l]=[o],p(l)&&(d[l]=c[l]);else{let t=[o];l.value=t,e.k&&(c[e.k]=t)}}else t?(c[l]=r,p(l)&&(d[l]=r)):a&&(l.value=r,e.k&&(c[e.k]=r))};if(r){let t=()=>{s(),Fn.delete(e)};t.id=-1,Fn.set(e,t),bi(t,n)}else Vn(e),s()}}}function Vn(e){let t=Fn.get(e);t&&(t.flags|=8,Fn.delete(e))}let Un=!1,Hn=()=>{Un||(console.error("Hydration completed but contains mismatches."),Un=!0)},Wn=e=>{if(1===e.nodeType){if(e.namespaceURI.includes("svg")&&"foreignObject"!==e.tagName)return"svg";if(e.namespaceURI.includes("MathML"))return"mathml"}},Gn=e=>8===e.nodeType;function Kn(e){let{mt:t,p:n,o:{patchProp:a,createText:i,nextSibling:o,parentNode:r,remove:s,insert:l,createComment:u}}=e,c=(n,a,s,u,v,b=!1)=>{b=b||!!a.dynamicChildren;let y=Gn(n)&&"["===n.data,w=()=>f(n,a,s,u,v,y),{type:k,ref:x,shapeFlag:S,patchFlag:C}=a,T=n.nodeType;a.el=n,-2===C&&(b=!1,a.dynamicChildren=null);let P=null;switch(k){case Oi:3!==T?""===a.children?(l(a.el=i(""),r(n),n),P=n):P=w():(n.data!==a.children&&(Hn(),n.data=a.children),P=o(n));break;case Ii:_(n)?(P=o(n),g(a.el=n.content.firstChild,n,s)):P=8!==T||y?w():o(n);break;case qi:if(y&&(T=(n=o(n)).nodeType),1===T||3===T){P=n;let e=!a.children.length;for(let t=0;t{r=r||!!t.dynamicChildren;let{type:l,props:u,patchFlag:c,shapeFlag:d,dirs:p,transition:f}=t,m="input"===l||"option"===l;if(m||-1!==c){let l;p&&fn(t,null,n,"created");let v=!1;if(_(e)){v=Si(null,f)&&n&&n.vnode.props&&n.vnode.props.appear;let a=e.content.firstChild;if(v){let e=a.getAttribute("class");e&&(a.$cls=e),f.beforeEnter(a)}g(a,e,n),t.el=e=a}if(16&d&&(!u||!u.innerHTML&&!u.textContent)){let a=h(e.firstChild,t,e,n,i,o,r);for(;a;){Zn(e,1)||Hn();let t=a;a=a.nextSibling,s(t)}}else if(8&d){let n=t.children;"\n"===n[0]&&("PRE"===e.tagName||"TEXTAREA"===e.tagName)&&(n=n.slice(1));let{textContent:a}=e;a!==n&&a!==n.replace(/\r\n|\r/g,"\n")&&(Zn(e,0)||Hn(),e.textContent=t.children)}if(u)if(m||!r||48&c){let t=e.tagName.includes("-");for(let i in u)(m&&(i.endsWith("value")||"indeterminate"===i)||k(i)&&!I(i)||"."===i[0]||t)&&a(e,i,null,u[i],void 0,n)}else if(u.onClick)a(e,"onClick",null,u.onClick,void 0,n);else if(4&c&&wt(u.style))for(let e in u.style)u.style[e];(l=u&&u.onVnodeBeforeMount)&&oo(l,n,t),p&&fn(t,null,n,"beforeMount"),((l=u&&u.onVnodeMounted)||p||v)&&Ri(()=>{l&&oo(l,n,t),v&&f.enter(e),p&&fn(t,null,n,"mounted")},i)}return e.nextSibling},h=(e,t,a,r,s,u,d)=>{d=d||!!t.dynamicChildren;let h=t.children,p=h.length;for(let t=0;t{let{slotScopeIds:c}=t;c&&(i=i?i.concat(c):c);let d=r(e),p=h(o(e),t,d,n,a,i,s);return p&&Gn(p)&&"]"===p.data?o(t.anchor=p):(Hn(),l(t.anchor=u("]"),d,p),p)},f=(e,t,a,i,l,u)=>{if(Zn(e.parentElement,1)||Hn(),t.el=null,u){let t=m(e);for(;;){let n=o(e);if(!n||n===t)break;s(n)}}let c=o(e),d=r(e);return s(e),n(null,t,d,c,a,i,Wn(d),l),a&&(a.vnode.el=t.el,ri(a,t.el)),c},m=(e,t="[",n="]")=>{let a=0;for(;e;)if((e=o(e))&&Gn(e)&&(e.data===t&&a++,e.data===n)){if(0===a)return o(e);a--}return e},g=(e,t,n)=>{let a=t.parentNode;a&&a.replaceChild(e,t);let i=n;for(;i;)i.vnode.el===t&&(i.vnode.el=i.subTree.el=e),i=i.parent},_=e=>1===e.nodeType&&"TEMPLATE"===e.tagName;return[(e,t)=>{if(!t.hasChildNodes())return n(null,e,t),ln(),void(t._vnode=e);c(t.firstChild,e,null,null,null),ln(),t._vnode=e},c]}let Yn="data-allow-mismatch",Qn={0:"text",1:"children",2:"class",3:"style",4:"attribute"};function Zn(e,t){if(0===t||1===t)for(;e&&!e.hasAttribute(Yn);)e=e.parentElement;let n=e&&e.getAttribute(Yn);if(null==n)return!1;{if(""===n)return!0;let e=n.split(",");return!(0!==t||!e.includes("children"))||e.includes(Qn[t])}}let Jn=Q().requestIdleCallback||(e=>setTimeout(e,1)),Xn=Q().cancelIdleCallback||(e=>clearTimeout(e)),ea=e=>!!e.type.__asyncLoader;function ta(e,t){let{ref:n,props:a,children:i,ce:o}=t.vnode,r=Zi(e,a,i);return r.ref=n,r.ce=o,delete t.vnode.ce,r}let na=e=>e.type.__isKeepAlive;function aa(e,t){let n;return E(e)?e.some(e=>aa(e,t)):M(e)?e.split(",").includes(t):"[object RegExp]"===(n=e,N.call(n))&&(e.lastIndex=0,e.test(t))}function ia(e,t){ra(e,"a",t)}function oa(e,t){ra(e,"da",t)}function ra(e,t,n=lo){let a=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}return e()});if(ua(t,a,n),n){let e=n.parent;for(;e&&e.parent;)na(e.parent.vnode)&&function(e,t,n,a){let i=ua(t,e,a,!0);ga(()=>{C(a[t],i)},n)}(a,t,n,e),e=e.parent}}function sa(e){e.shapeFlag&=-257,e.shapeFlag&=-513}function la(e){return 128&e.shapeFlag?e.ssContent:e}function ua(e,t,n=lo,a=!1){if(n){let i=n[e]||(n[e]=[]),o=t.__weh||(t.__weh=(...a)=>{Ee();let i=co(n),o=Gt(t,n,e,a);return i(),Ae(),o});return a?i.unshift(o):i.push(o),o}}let ca=e=>(t,n=lo)=>{fo&&"sp"!==e||ua(e,(...e)=>t(...e),n)},da=ca("bm"),ha=ca("m"),pa=ca("bu"),fa=ca("u"),ma=ca("bum"),ga=ca("um"),_a=ca("sp"),va=ca("rtg"),ba=ca("rtc");function ya(e,t=lo){ua("ec",e,t)}let wa="components",ka=Symbol.for("v-ndc");function xa(e,t,n=!0,a=!1){let i=cn||lo;if(i){let n=i.type;if(e===wa){let e=wo(n,!1);if(e&&(e===t||e===B(t)||e===V(B(t))))return n}let o=Sa(i[e]||n[e],t)||Sa(i.appContext[e],t);return!o&&a?n:o}}function Sa(e,t){return e&&(e[t]||e[B(t)]||e[V(B(t))])}let Ca=e=>e?po(e)?yo(e):Ca(e.parent):null,Ta=S(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Ca(e.parent),$root:e=>Ca(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Na(e),$forceUpdate:e=>e.f||(e.f=()=>{an(e.update)}),$nextTick:e=>e.n||(e.n=nn.bind(e.proxy)),$watch:e=>Qa.bind(e)}),Pa=(e,t)=>e!==v&&!e.__isScriptSetup&&P(e,t),Ea={get({_:e},t){let n,a;if("__v_skip"===t)return!0;let{ctx:i,setupState:o,data:r,props:s,accessCache:l,type:u,appContext:c}=e;if("$"!==t[0]){let e=l[t];if(void 0!==e)switch(e){case 1:return o[t];case 2:return r[t];case 4:return i[t];case 3:return s[t]}else{if(Pa(o,t))return l[t]=1,o[t];if(r!==v&&P(r,t))return l[t]=2,r[t];if(P(s,t))return l[t]=3,s[t];if(i!==v&&P(i,t))return l[t]=4,i[t];Ra&&(l[t]=0)}}let d=Ta[t];return d?("$attrs"===t&&De(e.attrs,0,""),d(e)):(n=u.__cssModules)&&(n=n[t])?n:i!==v&&P(i,t)?(l[t]=4,i[t]):P(a=c.config.globalProperties,t)?a[t]:void 0},set({_:e},t,n){let{data:a,setupState:i,ctx:o}=e;return Pa(i,t)?(i[t]=n,!0):a!==v&&P(a,t)?(a[t]=n,!0):!(P(e.props,t)||"$"===t[0]&&t.slice(1)in e||(o[t]=n,0))},has({_:{data:e,setupState:t,accessCache:n,ctx:a,appContext:i,props:o,type:r}},s){let l;return!!(n[s]||e!==v&&"$"!==s[0]&&P(e,s)||Pa(t,s)||P(o,s)||P(a,s)||P(Ta,s)||P(i.config.globalProperties,s)||(l=r.__cssModules)&&l[s])},defineProperty(e,t,n){return null!=n.get?e._.accessCache[t]=0:P(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}},Aa=S({},Ea,{get(e,t){if(t!==Symbol.unscopables)return Ea.get(e,t,e)},has:(e,t)=>"_"!==t[0]&&!Z(t)});function Ma(e){let t=uo();return t.setupContext||(t.setupContext=bo(t))}function La(e){return E(e)?e.reduce((e,t)=>(e[t]=null,e),{}):e}let Ra=!0;function za(e,t,n){Gt(E(e)?e.map(e=>e.bind(t.proxy)):e.bind(t.proxy),t,n)}function Na(e){let t,n=e.type,{mixins:a,extends:i}=n,{mixins:o,optionsCache:r,config:{optionMergeStrategies:s}}=e.appContext,l=r.get(n);return l?t=l:o.length||a||i?(t={},o.length&&o.forEach(e=>Oa(t,e,s,!0)),Oa(t,n,s)):t=n,R(n)&&r.set(n,t),t}function Oa(e,t,n,a=!1){let{mixins:i,extends:o}=t;for(let r in o&&Oa(e,o,n,!0),i&&i.forEach(t=>Oa(e,t,n,!0)),t)if(a&&"expose"===r);else{let a=Ia[r]||n&&n[r];e[r]=a?a(e[r],t[r]):t[r]}return e}let Ia={data:qa,props:Fa,emits:Fa,methods:Ba,computed:Ba,beforeCreate:ja,created:ja,beforeMount:ja,mounted:ja,beforeUpdate:ja,updated:ja,beforeDestroy:ja,beforeUnmount:ja,destroyed:ja,unmounted:ja,activated:ja,deactivated:ja,errorCaptured:ja,serverPrefetch:ja,components:Ba,directives:Ba,watch:function(e,t){if(!e)return t;if(!t)return e;let n=S(Object.create(null),e);for(let a in t)n[a]=ja(e[a],t[a]);return n},provide:qa,inject:function(e,t){return Ba(Da(e),Da(t))}};function qa(e,t){return t?e?function(){return S(A(e)?e.call(this,this):e,A(t)?t.call(this,this):t)}:t:e}function Da(e){if(E(e)){let t={};for(let n=0;n1)return n&&A(t)?t.call(a&&a.proxy):t}}let Ga=Symbol.for("v-scx");function Ka(e,t){return Ya(e,null,{flush:"sync"})}function Ya(e,t,n=v){let{flush:a}=n,i=S({},n),r=lo;i.call=(e,t,n)=>Gt(e,r,t,n);let s=!1;return"post"===a?i.scheduler=e=>{bi(e,r&&r.suspense)}:"sync"!==a&&(s=!0,i.scheduler=(e,t)=>{t?e():an(e)}),i.augmentJob=e=>{t&&(e.flags|=4),s&&(e.flags|=2,r&&(e.id=r.uid,e.i=r))},function(e,t,n=v){let a,i,r,s,{immediate:l,deep:u,once:c,scheduler:d,augmentJob:h,call:p}=n,f=e=>u?e:xt(e)||!1===u||0===u?Ht(e,1):Ht(e),g=!1,_=!1;if(At(e)?(i=()=>e.value,g=xt(e)):wt(e)?(i=()=>f(e),g=!0):E(e)?(_=!0,g=e.some(e=>wt(e)||xt(e)),i=()=>e.map(e=>At(e)?e.value:wt(e)?f(e):A(e)?p?p(e,2):e():void 0)):i=A(e)?t?p?()=>p(e,2):e:()=>{if(r){Ee();try{r()}finally{Ae()}}let t=m;m=a;try{return p?p(e,3,[s]):e(s)}finally{m=t}}:y,t&&u){let e=i,t=!0===u?1/0:u;i=()=>Ht(e(),t)}let b=o,w=()=>{a.stop(),b&&b.active&&C(b.effects,a)};if(c&&t){let e=t;t=(...t)=>{e(...t),w()}}let k=_?Array(e.length).fill($t):$t,x=e=>{if(1&a.flags&&(a.dirty||e))if(t){let e=a.run();if(u||g||(_?e.some((e,t)=>H(e,k[t])):H(e,k))){r&&r();let n=m;m=a;try{let n=[e,k===$t?void 0:_&&k[0]===$t?[]:k,s];k=e,p?p(t,3,n):t(...n)}finally{m=n}}}else a.run()};return h&&h(x),(a=new _e(i)).scheduler=d?()=>d(x,!1):x,s=e=>Ut(e,!1,a),r=a.onStop=()=>{let e=Vt.get(a);if(e){if(p)p(e,4);else for(let t of e)t();Vt.delete(a)}},t?l?x(!0):k=a.run():d?d(x.bind(null,!0),!0):a.run(),w.pause=a.pause.bind(a),w.resume=a.resume.bind(a),w.stop=w,w}(e,t,i)}function Qa(e,t,n){let a,i=this.proxy,o=M(e)?e.includes(".")?Za(i,e):()=>i[e]:e.bind(i,i);A(t)?a=t:(a=t.handler,n=t);let r=co(this),s=Ya(o,a.bind(i),n);return r(),s}function Za(e,t){let n=t.split(".");return()=>{let t=e;for(let e=0;e"modelValue"===t||"model-value"===t?e.modelModifiers:e[`${t}Modifiers`]||e[`${B(t)}Modifiers`]||e[`${$(t)}Modifiers`];function Xa(e,t,...n){let a;if(e.isUnmounted)return;let i=e.vnode.props||v,o=n,r=t.startsWith("update:"),s=r&&Ja(i,t.slice(7));s&&(s.trim&&(o=n.map(e=>M(e)?e.trim():e)),s.number&&(o=n.map(K)));let l=i[a=U(t)]||i[a=U(B(t))];!l&&r&&(l=i[a=U($(t))]),l&&Gt(l,e,6,o);let u=i[a+"Once"];if(u){if(e.emitted){if(e.emitted[a])return}else e.emitted={};e.emitted[a]=!0,Gt(u,e,6,o)}}let ei=new WeakMap;function ti(e,t){return!!e&&!!k(t)&&(P(e,(t=t.slice(2).replace(/Once$/,""))[0].toLowerCase()+t.slice(1))||P(e,$(t))||P(e,t))}function ni(e){let t,n,{type:a,vnode:i,proxy:o,withProxy:r,propsOptions:[s],slots:l,attrs:u,emit:c,render:d,renderCache:h,props:p,data:f,setupState:m,ctx:g,inheritAttrs:_}=e,v=hn(e);try{if(4&i.shapeFlag){let e=r||o;t=to(d.call(e,e,h,p,m,f,g)),n=u}else t=to(a.length>1?a(p,{attrs:u,slots:l,emit:c}):a(p,null)),n=a.props?u:ai(u)}catch(n){Di.length=0,Kt(n,e,1),t=Zi(Ii)}let b=t;if(n&&!1!==_){let e=Object.keys(n),{shapeFlag:t}=b;e.length&&7&t&&(s&&e.some(x)&&(n=ii(n,s)),b=Xi(b,n,!1,!0))}return i.dirs&&((b=Xi(b,null,!1,!0)).dirs=b.dirs?b.dirs.concat(i.dirs):i.dirs),i.transition&&qn(b,i.transition),t=b,hn(v),t}let ai=e=>{let t;for(let n in e)("class"===n||"style"===n||k(n))&&((t||(t={}))[n]=e[n]);return t},ii=(e,t)=>{let n={};for(let a in e)x(a)&&a.slice(9)in t||(n[a]=e[a]);return n};function oi(e,t,n){let a=Object.keys(t);if(a.length!==Object.keys(e).length)return!0;for(let i=0;iObject.getPrototypeOf(e)===si;function ui(e,t,n,a){let i,[o,r]=e.propsOptions,s=!1;if(t)for(let l in t){let u;if(I(l))continue;let c=t[l];o&&P(o,u=B(l))?r&&r.includes(u)?(i||(i={}))[u]=c:n[u]=c:ti(e.emitsOptions,l)||l in a&&c===a[l]||(a[l]=c,s=!0)}if(r){let t=Ct(n),a=i||v;for(let i=0;i"_"===e||"_ctx"===e||"$stable"===e,fi=e=>E(e)?e.map(to):[to(e)],mi=(e,t,n)=>{if(t._n)return t;let a=pn((...e)=>fi(t(...e)),n);return a._c=!1,a},gi=(e,t,n)=>{let a=e._ctx;for(let n in e){if(pi(n))continue;let i=e[n];if(A(i))t[n]=mi(0,i,a);else if(null!=i){let e=fi(i);t[n]=()=>e}}},_i=(e,t)=>{let n=fi(t);e.slots.default=()=>n},vi=(e,t,n)=>{for(let a in t)(n||!pi(a))&&(e[a]=t[a])},bi=Ri;function yi(e){return wi(e,Kn)}function wi(e,t){var n;let a,i;Q().__VUE__=!0;let{insert:o,remove:r,patchProp:s,createElement:l,createText:u,createComment:d,setText:h,setElementText:p,parentNode:f,nextSibling:m,setScopeId:g=y,insertStaticContent:_}=e,w=(e,t,n,a=null,i=null,o=null,r,s=null,l=!!t.dynamicChildren)=>{if(e===t)return;e&&!Gi(e,t)&&(a=oe(e),ee(e,i,o,!0),e=null),-2===t.patchFlag&&(l=!1,t.dynamicChildren=null);let{type:u,ref:c,shapeFlag:d}=t;switch(u){case Oi:k(e,t,n,a);break;case Ii:x(e,t,n,a);break;case qi:null==e&&C(t,n,a,r);break;case Ni:j(e,t,n,a,i,o,r,s,l);break;default:1&d?T(e,t,n,a,i,o,r,s,l):6&d?F(e,t,n,a,i,o,r,s,l):(64&d||128&d)&&u.process(e,t,n,a,i,o,r,s,l,le)}null!=c&&i?$n(c,e&&e.ref,o,t||e,!t):null==c&&e&&null!=e.ref&&$n(e.ref,null,o,e,!0)},k=(e,t,n,a)=>{if(null==e)o(t.el=u(t.children),n,a);else{let n=t.el=e.el;t.children!==e.children&&h(n,t.children)}},x=(e,t,n,a)=>{null==e?o(t.el=d(t.children||""),n,a):t.el=e.el},C=(e,t,n,a)=>{[e.el,e.anchor]=_(e.children,t,n,a,e.el,e.anchor)},T=(e,t,n,a,i,o,r,s,l)=>{if("svg"===t.type?r="svg":"math"===t.type&&(r="mathml"),null==e)M(t,n,a,i,o,r,s,l);else{let n=e.el&&e.el._isVueCE?e.el:null;try{n&&n._beginPatch(),O(e,t,i,o,r,s,l)}finally{n&&n._endPatch()}}},M=(e,t,n,a,i,r,u,c)=>{let d,h,{props:f,shapeFlag:m,transition:g,dirs:_}=e;if(d=e.el=l(e.type,r,f&&f.is,f),8&m?p(d,e.children):16&m&&N(e.children,d,null,a,i,ki(e,r),u,c),_&&fn(e,null,a,"created"),L(d,e,e.scopeId,u,a),f){for(let e in f)"value"===e||I(e)||s(d,e,null,f[e],r,a);"value"in f&&s(d,"value",null,f.value,r),(h=f.onVnodeBeforeMount)&&oo(h,a,e)}_&&fn(e,null,a,"beforeMount");let v=Si(i,g);v&&g.beforeEnter(d),o(d,t,n),((h=f&&f.onVnodeMounted)||v||_)&&bi(()=>{h&&oo(h,a,e),v&&g.enter(d),_&&fn(e,null,a,"mounted")},i)},L=(e,t,n,a,i)=>{if(n&&g(e,n),a)for(let t=0;t{for(let u=l;u{let l,u=t.el=e.el,{patchFlag:c,dynamicChildren:d,dirs:h}=t;c|=16&e.patchFlag;let f=e.props||v,m=t.props||v;if(n&&xi(n,!1),(l=m.onVnodeBeforeUpdate)&&oo(l,n,t,e),h&&fn(t,e,n,"beforeUpdate"),n&&xi(n,!0),(f.innerHTML&&null==m.innerHTML||f.textContent&&null==m.textContent)&&p(u,""),d?q(e.dynamicChildren,d,u,n,a,ki(t,i),o):r||Y(e,t,u,null,n,a,ki(t,i),o,!1),c>0){if(16&c)D(u,f,m,n,i);else if(2&c&&f.class!==m.class&&s(u,"class",null,m.class,i),4&c&&s(u,"style",f.style,m.style,i),8&c){let e=t.dynamicProps;for(let t=0;t{l&&oo(l,n,t,e),h&&fn(t,e,n,"updated")},a)},q=(e,t,n,a,i,o,r)=>{for(let s=0;s{if(t!==n){if(t!==v)for(let o in t)I(o)||o in n||s(e,o,t[o],null,i,a);for(let o in n){if(I(o))continue;let r=n[o],l=t[o];r!==l&&"value"!==o&&s(e,o,l,r,i,a)}"value"in n&&s(e,"value",t.value,n.value,i)}},j=(e,t,n,a,i,r,s,l,c)=>{let d=t.el=e?e.el:u(""),h=t.anchor=e?e.anchor:u(""),{patchFlag:p,dynamicChildren:f,slotScopeIds:m}=t;m&&(l=l?l.concat(m):m),null==e?(o(d,n,a),o(h,n,a),N(t.children||[],n,h,i,r,s,l,c)):p>0&&64&p&&f&&e.dynamicChildren?(q(e.dynamicChildren,f,n,i,r,s,l),(null!=t.key||i&&t===i.subTree)&&Ci(e,t,!0)):Y(e,t,n,h,i,r,s,l,c)},F=(e,t,n,a,i,o,r,s,l)=>{t.slotScopeIds=s,null==e?512&t.shapeFlag?i.ctx.activate(t,n,a,r,l):V(t,n,a,i,o,r,l):U(e,t,l)},V=(e,t,n,a,i,o,r)=>{var s,l,u;let d,h,p,f=(l=a,u=i,d=(s=e).type,h=(l?l.appContext:s.appContext)||ro,(p={uid:so++,vnode:s,type:d,parent:l,appContext:h,root:null,next:null,subTree:null,effect:null,update:null,job:null,scope:new me(!0),render:null,proxy:null,exposed:null,exposeProxy:null,withProxy:null,provides:l?l.provides:Object.create(h.provides),ids:l?l.ids:["",0,0],accessCache:null,renderCache:[],components:null,directives:null,propsOptions:function e(t,n,a=!1){let i=a?di:n.propsCache,o=i.get(t);if(o)return o;let r=t.props,s={},l=[],u=!1;if(!A(t)){let i=t=>{u=!0;let[a,i]=e(t,n,!0);S(s,a),i&&l.push(...i)};!a&&n.mixins.length&&n.mixins.forEach(i),t.extends&&i(t.extends),t.mixins&&t.mixins.forEach(i)}if(!r&&!u)return R(t)&&i.set(t,b),b;if(E(r))for(let e=0;e{let a=e(t,n,!0);a&&(l=!0,S(s,a))};!a&&n.mixins.length&&n.mixins.forEach(i),t.extends&&i(t.extends),t.mixins&&t.mixins.forEach(i)}return r||l?(E(r)?r.forEach(e=>s[e]=null):S(s,r),R(t)&&i.set(t,s),s):(R(t)&&i.set(t,null),null)}(d,h),emit:null,emitted:null,propsDefaults:v,inheritAttrs:d.inheritAttrs,ctx:v,data:v,props:v,attrs:v,slots:v,refs:v,setupState:v,setupContext:null,suspense:u,suspenseId:u?u.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null,sp:null}).ctx={_:p},p.root=l?l.root:p,p.emit=Xa.bind(null,p),s.ce&&s.ce(p),e.component=p);if(na(e)&&(f.ctx.renderer=le),function(e,t=!1,n=!1){t&&c(t);let{props:a,children:i}=e.vnode,o=po(e);!function(e,t,n,a=!1){let i={},o=Object.create(si);for(let n in e.propsDefaults=Object.create(null),ui(e,t,i,o),e.propsOptions[0])n in i||(i[n]=void 0);n?e.props=a?i:vt(i):e.type.props?e.props=i:e.props=o,e.attrs=o}(e,a,o,t);var r=n||t;let s=e.slots=Object.create(si);if(32&e.vnode.shapeFlag){let e=i._;e?(vi(s,i,r),r&&G(s,"_",e,!0)):gi(i,s)}else i&&_i(e,i);o&&function(e,t){let n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,Ea);let{setup:a}=n;if(a){Ee();let n=e.setupContext=a.length>1?bo(e):null,i=co(e),o=Wt(a,e,0,[e.props,n]),r=z(o);if(Ae(),i(),(r||e.sp)&&!ea(e)&&Bn(e),r){if(o.then(ho,ho),t)return o.then(n=>{mo(e,n,t)}).catch(t=>{Kt(t,e,0)});e.asyncDep=o}else mo(e,o,t)}else _o(e,t)}(e,t),t&&c(!1)}(f,!1,r),f.asyncDep){if(i&&i.registerDep(f,H,r),!e.el){let a=f.subTree=Zi(Ii);x(null,a,t,n),e.placeholder=a.el}}else H(f,e,t,n,i,o,r)},U=(e,t,n)=>{let a=t.component=e.component;if(function(e,t,n){let{props:a,children:i,component:o}=e,{props:r,children:s,patchFlag:l}=t,u=o.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&l>=0))return(!!i||!!s)&&(!s||!s.$stable)||a!==r&&(a?!r||oi(a,r,u):!!r);if(1024&l)return!0;if(16&l)return a?oi(a,r,u):!!r;if(8&l){let e=t.dynamicProps;for(let t=0;t{let l=()=>{if(e.isMounted){let t,{next:n,bu:a,u:i,parent:u,vnode:c}=e;{let t=function e(t){let n=t.subTree.component;if(n)return n.asyncDep&&!n.asyncResolved?n:e(n)}(e);if(t)return n&&(n.el=c.el,K(e,n,s)),void t.asyncDep.then(()=>{e.isUnmounted||l()})}let d=n;xi(e,!1),n?(n.el=c.el,K(e,n,s)):n=c,a&&W(a),(t=n.props&&n.props.onVnodeBeforeUpdate)&&oo(t,u,n,c),xi(e,!0);let h=ni(e),p=e.subTree;e.subTree=h,w(p,h,f(p.el),oe(p),e,o,r),n.el=h.el,null===d&&ri(e,h.el),i&&bi(i,o),(t=n.props&&n.props.onVnodeUpdated)&&bi(()=>oo(t,u,n,c),o)}else{let s,{el:l,props:u}=t,{bm:c,m:d,parent:h,root:p,type:f}=e,m=ea(t);if(xi(e,!1),c&&W(c),!m&&(s=u&&u.onVnodeBeforeMount)&&oo(s,h,t),xi(e,!0),l&&i){let t=()=>{e.subTree=ni(e),i(l,e.subTree,e,o,null)};m&&f.__asyncHydrate?f.__asyncHydrate(l,e,t):t()}else{p.ce&&!1!==p.ce._def.shadowRoot&&p.ce._injectChildStyle(f);let i=e.subTree=ni(e);w(null,i,n,a,e,o,r),t.el=i.el}if(d&&bi(d,o),!m&&(s=u&&u.onVnodeMounted)){let e=t;bi(()=>oo(s,h,e),o)}(256&t.shapeFlag||h&&ea(h.vnode)&&256&h.vnode.shapeFlag)&&e.a&&bi(e.a,o),e.isMounted=!0,t=n=a=null}};e.scope.on();let u=e.effect=new _e(l);e.scope.off();let c=e.update=u.run.bind(u),d=e.job=u.runIfDirty.bind(u);d.i=e,d.id=e.uid,u.scheduler=()=>an(d),xi(e,!0),c()},K=(e,t,n)=>{t.component=e;let a=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,a){let{props:i,attrs:o,vnode:{patchFlag:r}}=e,s=Ct(i),[l]=e.propsOptions,u=!1;if(!(a||r>0)||16&r){let a;for(let r in ui(e,t,i,o)&&(u=!0),s)t&&(P(t,r)||(a=$(r))!==r&&P(t,a))||(l?n&&(void 0!==n[r]||void 0!==n[a])&&(i[r]=ci(l,s,r,void 0,e,!0)):delete i[r]);if(o!==s)for(let e in o)t&&P(t,e)||(delete o[e],u=!0)}else if(8&r){let n=e.vnode.dynamicProps;for(let a=0;a{let{vnode:a,slots:i}=e,o=!0,r=v;if(32&a.shapeFlag){let e=t._;e?n&&1===e?o=!1:vi(i,t,n):(o=!t.$stable,gi(t,i)),r=t}else t&&(_i(e,t),r={default:1});if(o)for(let e in i)pi(e)||null!=r[e]||delete i[e]})(e,t.children,n),Ee(),sn(e),Ae()},Y=(e,t,n,a,i,o,r,s,l=!1)=>{let u=e&&e.children,c=e?e.shapeFlag:0,d=t.children,{patchFlag:h,shapeFlag:f}=t;if(h>0){if(128&h)return void J(u,d,n,a,i,o,r,s,l);if(256&h)return void Z(u,d,n,a,i,o,r,s,l)}8&f?(16&c&&ie(u,i,o),d!==u&&p(n,d)):16&c?16&f?J(u,d,n,a,i,o,r,s,l):ie(u,i,o,!0):(8&c&&p(n,""),16&f&&N(d,n,a,i,o,r,s,l))},Z=(e,t,n,a,i,o,r,s,l)=>{let u;t=t||b;let c=(e=e||b).length,d=t.length,h=Math.min(c,d);for(u=0;ud?ie(e,i,o,!0,!1,h):N(t,n,a,i,o,r,s,l,h)},J=(e,t,n,a,i,o,r,s,l)=>{let u=0,c=t.length,d=e.length-1,h=c-1;for(;u<=d&&u<=h;){let a=e[u],c=t[u]=l?no(t[u]):to(t[u]);if(!Gi(a,c))break;w(a,c,n,null,i,o,r,s,l),u++}for(;u<=d&&u<=h;){let a=e[d],u=t[h]=l?no(t[h]):to(t[h]);if(!Gi(a,u))break;w(a,u,n,null,i,o,r,s,l),d--,h--}if(u>d){if(u<=h){let e=h+1,d=eh)for(;u<=d;)ee(e[u],i,o,!0),u++;else{let p,f=u,m=u,g=new Map;for(u=m;u<=h;u++){let e=t[u]=l?no(t[u]):to(t[u]);null!=e.key&&g.set(e.key,u)}let _=0,v=h-m+1,y=!1,k=0,x=Array(v);for(u=0;u=v)ee(c,i,o,!0);else{if(null!=c.key)a=g.get(c.key);else for(p=m;p<=h;p++)if(0===x[p-m]&&Gi(c,t[p])){a=p;break}void 0===a?ee(c,i,o,!0):(x[a-m]=u+1,a>=k?k=a:y=!0,w(c,t[a],n,null,i,o,r,s,l),_++)}}let S=y?function(e){let t,n,a,i,o,r=e.slice(),s=[0],l=e.length;for(t=0;t>1]]0&&(r[t]=s[a-1]),s[a]=t)}}for(a=s.length,i=s[a-1];a-- >0;)s[a]=i,i=r[i];return s}(x):b;for(p=S.length-1,u=v-1;u>=0;u--){let e=m+u,d=t[e],h=t[e+1],f=e+1{let{el:s,type:l,transition:u,children:c,shapeFlag:d}=e;if(6&d)X(e.component.subTree,t,n,a);else if(128&d)e.suspense.move(t,n,a);else if(64&d)l.move(e,t,n,le);else if(l!==Ni)if(l!==qi)if(2!==a&&1&d&&u)if(0===a)u.beforeEnter(s),o(s,t,n),bi(()=>u.enter(s),i);else{let{leave:a,delayLeave:i,afterLeave:l}=u,c=()=>{e.ctx.isUnmounted?r(s):o(s,t,n)},d=()=>{s._isLeaving&&s[Cn](!0),a(s,()=>{c(),l&&l()})};i?i(s,c,d):d()}else o(s,t,n);else(({el:e,anchor:t},n,a)=>{let i;for(;e&&e!==t;)i=m(e),o(e,n,a),e=i;o(t,n,a)})(e,t,n);else{o(s,t,n);for(let e=0;e{let o,{type:r,props:s,ref:l,children:u,dynamicChildren:c,shapeFlag:d,patchFlag:h,dirs:p,cacheIndex:f}=e;if(-2===h&&(i=!1),null!=l&&(Ee(),$n(l,null,n,e,!0),Ae()),null!=f&&(t.renderCache[f]=void 0),256&d)return void t.ctx.deactivate(e);let m=1&d&&p,g=!ea(e);if(g&&(o=s&&s.onVnodeBeforeUnmount)&&oo(o,t,e),6&d)ae(e.component,n,a);else{if(128&d)return void e.suspense.unmount(n,a);m&&fn(e,null,t,"beforeUnmount"),64&d?e.type.remove(e,t,n,le,a):c&&!c.hasOnce&&(r!==Ni||h>0&&64&h)?ie(c,t,n,!1,!0):(r===Ni&&384&h||!i&&16&d)&&ie(u,t,n),a&&te(e)}(g&&(o=s&&s.onVnodeUnmounted)||m)&&bi(()=>{o&&oo(o,t,e),m&&fn(e,null,t,"unmounted")},n)},te=e=>{let{type:t,el:n,anchor:a,transition:i}=e;if(t===Ni)return void ne(n,a);if(t===qi)return void(({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=m(e),r(e),e=n;r(t)})(e);let o=()=>{r(n),i&&!i.persisted&&i.afterLeave&&i.afterLeave()};if(1&e.shapeFlag&&i&&!i.persisted){let{leave:t,delayLeave:a}=i,r=()=>t(n,o);a?a(e.el,o,r):r()}else o()},ne=(e,t)=>{let n;for(;e!==t;)n=m(e),r(e),e=n;r(t)},ae=(e,t,n)=>{let{bum:a,scope:i,job:o,subTree:r,um:s,m:l,a:u}=e;Ti(l),Ti(u),a&&W(a),i.stop(),o&&(o.flags|=8,ee(r,e,t,n)),s&&bi(s,t),bi(()=>{e.isUnmounted=!0},t)},ie=(e,t,n,a=!1,i=!1,o=0)=>{for(let r=o;r{if(6&e.shapeFlag)return oe(e.component.subTree);if(128&e.shapeFlag)return e.suspense.next();let t=m(e.anchor||e.el),n=t&&t[mn];return n?m(n):t},re=!1,se=(e,t,n)=>{null==e?t._vnode&&ee(t._vnode,null,null,!0):w(t._vnode||null,e,t,null,null,null,n),t._vnode=e,re||(re=!0,sn(),ln(),re=!1)},le={p:w,um:ee,m:X,r:te,mt:V,mc:N,pc:Y,pbc:q,n:oe,o:e};return t&&([a,i]=t(le)),{render:se,hydrate:a,createApp:(n=a,function(e,t=null){A(e)||(e=S({},e)),null==t||R(t)||(t=null);let a=$a(),i=new WeakSet,o=[],r=!1,s=a.app={_uid:Va++,_component:e,_props:t,_container:null,_context:a,_instance:null,version:Co,get config(){return a.config},set config(e){},use:(e,...t)=>(i.has(e)||(e&&A(e.install)?(i.add(e),e.install(s,...t)):A(e)&&(i.add(e),e(s,...t))),s),mixin:e=>(a.mixins.includes(e)||a.mixins.push(e),s),component:(e,t)=>t?(a.components[e]=t,s):a.components[e],directive:(e,t)=>t?(a.directives[e]=t,s):a.directives[e],mount(i,o,l){if(!r){let u=s._ceVNode||Zi(e,t);return u.appContext=a,!0===l?l="svg":!1===l&&(l=void 0),o&&n?n(u,i):se(u,i,l),r=!0,s._container=i,i.__vue_app__=s,yo(u.component)}},onUnmount(e){o.push(e)},unmount(){r&&(Gt(o,s._instance,16),se(null,s._container),delete s._container.__vue_app__)},provide:(e,t)=>(a.provides[e]=t,s),runWithContext(e){let t=Ua;Ua=s;try{return e()}finally{Ua=t}}};return s})}}function ki({type:e,props:t},n){return"svg"===n&&"foreignObject"===e||"mathml"===n&&"annotation-xml"===e&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function xi({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Si(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Ci(e,t,n=!1){let a=e.children,i=t.children;if(E(a)&&E(i))for(let e=0;ee.__isSuspense,Ei=0;function Ai(e,t){let n=e.props&&e.props[t];A(n)&&n()}function Mi(e,t,n,a,i,o,r,s,l,u,c=!1){var d;let h,p,{p:f,m:m,um:g,n:_,o:{parentNode:v,remove:b}}=u,y=null!=(h=(d=e).props&&d.props.suspensible)&&!1!==h;y&&t&&t.pendingBranch&&(p=t.pendingId,t.deps++);let w=e.props?Y(e.props.timeout):void 0,k=o,x={vnode:e,parent:t,parentComponent:n,namespace:r,container:a,hiddenContainer:i,deps:0,pendingId:Ei++,timeout:"number"==typeof w?w:-1,activeBranch:null,pendingBranch:null,isInFallback:!c,isHydrating:c,isUnmounted:!1,effects:[],resolve(e=!1,n=!1){let{vnode:a,activeBranch:i,pendingBranch:r,pendingId:s,effects:l,parentComponent:u,container:c,isInFallback:d}=x,h=!1;x.isHydrating?x.isHydrating=!1:!e&&((h=i&&r.transition&&"out-in"===r.transition.mode)&&(i.transition.afterLeave=()=>{s===x.pendingId&&(m(r,c,o===k?_(i):o,0),rn(l),d&&a.ssFallback&&(a.ssFallback.el=null))}),i&&(v(i.el)===c&&(o=_(i)),g(i,u,x,!0),!h&&d&&a.ssFallback&&bi(()=>a.ssFallback.el=null,x)),h||m(r,c,o,0)),zi(x,r),x.pendingBranch=null,x.isInFallback=!1;let f=x.parent,b=!1;for(;f;){if(f.pendingBranch){f.effects.push(...l),b=!0;break}f=f.parent}b||h||rn(l),x.effects=[],y&&t&&t.pendingBranch&&p===t.pendingId&&(t.deps--,0!==t.deps||n||t.resolve()),Ai(a,"onResolve")},fallback(e){if(!x.pendingBranch)return;let{vnode:t,activeBranch:n,parentComponent:a,container:i,namespace:o}=x;Ai(t,"onFallback");let r=_(n),u=()=>{x.isInFallback&&(f(null,e,i,r,a,null,o,s,l),zi(x,e))},c=e.transition&&"out-in"===e.transition.mode;c&&(n.transition.afterLeave=u),x.isInFallback=!0,g(n,a,null,!0),c||u()},move(e,t,n){x.activeBranch&&m(x.activeBranch,e,t,n),x.container=e},next:()=>x.activeBranch&&_(x.activeBranch),registerDep(e,t,n){let a=!!x.pendingBranch;a&&x.deps++;let i=e.vnode.el;e.asyncDep.catch(t=>{Kt(t,e,0)}).then(o=>{if(e.isUnmounted||x.isUnmounted||x.pendingId!==e.suspenseId)return;e.asyncResolved=!0;let{vnode:s}=e;mo(e,o,!1),i&&(s.el=i);let l=!i&&e.subTree.el;t(e,s,v(i||e.subTree.el),i?null:_(e.subTree),x,r,n),l&&(s.placeholder=null,b(l)),ri(e,s.el),a&&0==--x.deps&&x.resolve()})},unmount(e,t){x.isUnmounted=!0,x.activeBranch&&g(x.activeBranch,n,e,t),x.pendingBranch&&g(x.pendingBranch,n,e,t)}};return x}function Li(e){let t;if(A(e)){let n=$i&&e._c;n&&(e._d=!1,Bi()),e=e(),n&&(e._d=!0,t=ji,Fi())}return E(e)&&(e=function(e){let t;for(let n=0;nt!==e)),e}function Ri(e,t){t&&t.pendingBranch?E(e)?t.effects.push(...e):t.effects.push(e):rn(e)}function zi(e,t){e.activeBranch=t;let{vnode:n,parentComponent:a}=e,i=t.el;for(;!i&&t.component;)i=(t=t.component.subTree).el;n.el=i,a&&a.subTree===n&&(a.vnode.el=i,ri(a,i))}let Ni=Symbol.for("v-fgt"),Oi=Symbol.for("v-txt"),Ii=Symbol.for("v-cmt"),qi=Symbol.for("v-stc"),Di=[],ji=null;function Bi(e=!1){Di.push(ji=e?null:[])}function Fi(){Di.pop(),ji=Di[Di.length-1]||null}let $i=1;function Vi(e,t=!1){$i+=e,e<0&&ji&&t&&(ji.hasOnce=!0)}function Ui(e){return e.dynamicChildren=$i>0?ji||b:null,Fi(),$i>0&&ji&&ji.push(e),e}function Hi(e,t,n,a,i){return Ui(Zi(e,t,n,a,i,!0))}function Wi(e){return!!e&&!0===e.__v_isVNode}function Gi(e,t){return e.type===t.type&&e.key===t.key}let Ki=({key:e})=>null!=e?e:null,Yi=({ref:e,ref_key:t,ref_for:n})=>("number"==typeof e&&(e=""+e),null!=e?M(e)||At(e)||A(e)?{i:cn,r:e,k:t,f:!!n}:e:null);function Qi(e,t=null,n=null,a=0,i=null,o=+(e!==Ni),r=!1,s=!1){let l={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Ki(t),ref:t&&Yi(t),scopeId:dn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:o,patchFlag:a,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:cn};return s?(ao(l,n),128&o&&e.normalize(l)):n&&(l.shapeFlag|=M(n)?8:16),$i>0&&!r&&ji&&(l.patchFlag>0||6&o)&&32!==l.patchFlag&&ji.push(l),l}let Zi=function(e,t=null,n=null,a=0,i=null,o=!1){var r;if(e&&e!==ka||(e=Ii),Wi(e)){let a=Xi(e,t,!0);return n&&ao(a,n),$i>0&&!o&&ji&&(6&a.shapeFlag?ji[ji.indexOf(e)]=a:ji.push(a)),a.patchFlag=-2,a}if(A(r=e)&&"__vccOpts"in r&&(e=e.__vccOpts),t){let{class:e,style:n}=t=Ji(t);e&&!M(e)&&(t.class=ae(e)),R(n)&&(St(n)&&!E(n)&&(n=S({},n)),t.style=J(n))}return Qi(e,t,n,a,i,M(e)?1:Pi(e)?128:e.__isTeleport?64:R(e)?4:2*!!A(e),o,!0)};function Ji(e){return e?St(e)||li(e)?S({},e):e:null}function Xi(e,t,n=!1,a=!1){let{props:i,ref:o,patchFlag:r,children:s,transition:l}=e,u=t?io(i||{},t):i,c={__v_isVNode:!0,__v_skip:!0,type:e.type,props:u,key:u&&Ki(u),ref:t&&t.ref?n&&o?E(o)?o.concat(Yi(t)):[o,Yi(t)]:Yi(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:s,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Ni?-1===r?16:16|r:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:l,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Xi(e.ssContent),ssFallback:e.ssFallback&&Xi(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return l&&a&&qn(c,l.clone(c)),c}function eo(e=" ",t=0){return Zi(Oi,null,e,t)}function to(e){return null==e||"boolean"==typeof e?Zi(Ii):E(e)?Zi(Ni,null,e.slice()):Wi(e)?no(e):Zi(Oi,null,String(e))}function no(e){return null===e.el&&-1!==e.patchFlag||e.memo?e:Xi(e)}function ao(e,t){let n=0,{shapeFlag:a}=e;if(null==t)t=null;else if(E(t))n=16;else if("object"==typeof t){if(65&a){let n=t.default;return void(n&&(n._c&&(n._d=!1),ao(e,n()),n._c&&(n._d=!0)))}{n=32;let a=t._;a||li(t)?3===a&&cn&&(1===cn.slots._?t._=1:(t._=2,e.patchFlag|=1024)):t._ctx=cn}}else A(t)?(t={default:t,_ctx:cn},n=32):(t=String(t),64&a?(n=16,t=[eo(t)]):n=8);e.children=t,e.shapeFlag|=n}function io(...e){let t={};for(let n=0;nlo||cn;u=e=>{lo=e},c=e=>{fo=e};let co=e=>{let t=lo;return u(e),e.scope.on(),()=>{e.scope.off(),u(t)}},ho=()=>{lo&&lo.scope.off(),u(null)};function po(e){return 4&e.vnode.shapeFlag}let fo=!1;function mo(e,t,n){A(t)?e.render=t:R(t)&&(e.setupState=It(t)),_o(e,n)}function go(e){d=e,h=e=>{e.render._rc&&(e.withProxy=new Proxy(e.ctx,Aa))}}function _o(e,t,n){let a=e.type;if(!e.render){if(!t&&d&&!a.render){let t=a.template||Na(e).template;if(t){let{isCustomElement:n,compilerOptions:i}=e.appContext.config,{delimiters:o,compilerOptions:r}=a,s=S(S({isCustomElement:n,delimiters:o},i),r);a.render=d(t,s)}}e.render=a.render||y,h&&h(e)}{let t=co(e);Ee();try{!function(e){let t=Na(e),n=e.proxy,a=e.ctx;Ra=!1,t.beforeCreate&&za(t.beforeCreate,e,"bc");let{data:i,computed:o,methods:r,watch:s,provide:l,inject:u,created:c,beforeMount:d,mounted:h,beforeUpdate:p,updated:f,activated:m,deactivated:g,beforeUnmount:_,unmounted:v,render:b,renderTracked:w,renderTriggered:k,errorCaptured:x,serverPrefetch:S,expose:C,inheritAttrs:T,components:P,directives:L}=t;if(u&&function(e,t){for(let n in E(e)&&(e=Da(e)),e){let a,i=e[n];At(a=R(i)?"default"in i?Wa(i.from||n,i.default,!0):Wa(i.from||n):Wa(i))?Object.defineProperty(t,n,{enumerable:!0,configurable:!0,get:()=>a.value,set:e=>a.value=e}):t[n]=a}}(u,a,null),r)for(let e in r){let t=r[e];A(t)&&(a[e]=t.bind(n))}if(i){let t=i.call(n,n);R(t)&&(e.data=_t(t))}if(Ra=!0,o)for(let e in o){let t=o[e],i=A(t)?t.bind(n,n):A(t.get)?t.get.bind(n,n):y,r=ko({get:i,set:!A(t)&&A(t.set)?t.set.bind(n):y});Object.defineProperty(a,e,{enumerable:!0,configurable:!0,get:()=>r.value,set:e=>r.value=e})}if(s)for(let e in s)!function e(t,n,a,i){let o=i.includes(".")?Za(a,i):()=>a[i];if(M(t)){let e=n[t];A(e)&&Ya(o,e,void 0)}else if(A(t))Ya(o,t.bind(a),void 0);else if(R(t))if(E(t))t.forEach(t=>e(t,n,a,i));else{let e=A(t.handler)?t.handler.bind(a):n[t.handler];A(e)&&Ya(o,e,t)}}(s[e],a,n,e);if(l){let e=A(l)?l.call(n):l;Reflect.ownKeys(e).forEach(t=>{Ha(t,e[t])})}function z(e,t){E(t)?t.forEach(t=>e(t.bind(n))):t&&e(t.bind(n))}if(c&&za(c,e,"c"),z(da,d),z(ha,h),z(pa,p),z(fa,f),z(ia,m),z(oa,g),z(ya,x),z(ba,w),z(va,k),z(ma,_),z(ga,v),z(_a,S),E(C))if(C.length){let t=e.exposed||(e.exposed={});C.forEach(e=>{Object.defineProperty(t,e,{get:()=>n[e],set:t=>n[e]=t,enumerable:!0})})}else e.exposed||(e.exposed={});b&&e.render===y&&(e.render=b),null!=T&&(e.inheritAttrs=T),P&&(e.components=P),L&&(e.directives=L)}(e)}finally{Ae(),t()}}}let vo={get:(e,t)=>(De(e,0,""),e[t])};function bo(e){return{attrs:new Proxy(e.attrs,vo),slots:e.slots,emit:e.emit,expose:t=>{e.exposed=t||{}}}}function yo(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(It(Tt(e.exposed)),{get:(t,n)=>n in t?t[n]:n in Ta?Ta[n](e):void 0,has:(e,t)=>t in e||t in Ta})):e.proxy}function wo(e,t=!0){return A(e)?e.displayName||e.name:e.name||t&&e.__name}let ko=(e,t)=>function(e,t,n=!1){let a,i;return A(e)?a=e:(a=e.get,i=e.set),new Ft(a,i,n)}(e,0,fo);function xo(e,t,n){try{Vi(-1);let a=arguments.length;return 2!==a?(a>3?n=Array.prototype.slice.call(arguments,2):3===a&&Wi(n)&&(n=[n]),Zi(e,t,n)):!R(t)||E(t)?Zi(e,null,t):Wi(t)?Zi(e,null,[t]):Zi(e,t)}finally{Vi(1)}}function So(e,t){let n=e.memo;if(n.length!=t.length)return!1;for(let e=0;e0&&ji&&ji.push(e),!0}let Co="3.5.25",To="undefined"!=typeof window&&window.trustedTypes;if(To)try{g=To.createPolicy("vue",{createHTML:e=>e})}catch(e){}let Po=g?e=>g.createHTML(e):e=>e,Eo="undefined"!=typeof document?document:null,Ao=Eo&&Eo.createElement("template"),Mo={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{let t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,a)=>{let i="svg"===t?Eo.createElementNS("http://www.w3.org/2000/svg",e):"mathml"===t?Eo.createElementNS("http://www.w3.org/1998/Math/MathML",e):n?Eo.createElement(e,{is:n}):Eo.createElement(e);return"select"===e&&a&&null!=a.multiple&&i.setAttribute("multiple",a.multiple),i},createText:e=>Eo.createTextNode(e),createComment:e=>Eo.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Eo.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,a,i,o){let r=n?n.previousSibling:t.lastChild;if(i&&(i===o||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),i!==o&&(i=i.nextSibling););else{Ao.innerHTML=Po("svg"===a?`${e}`:"mathml"===a?`${e}`:e);let i=Ao.content;if("svg"===a||"mathml"===a){let e=i.firstChild;for(;e.firstChild;)i.appendChild(e.firstChild);i.removeChild(e)}t.insertBefore(i,n)}return[r?r.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Lo="transition",Ro="animation",zo=Symbol("_vtc"),No={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Oo=S({},An,No),Io=((t=(e,{slots:t})=>xo(Rn,jo(e),t)).displayName="Transition",t.props=Oo,t),qo=(e,t=[])=>{E(e)?e.forEach(e=>e(...t)):e&&e(...t)},Do=e=>!!e&&(E(e)?e.some(e=>e.length>1):e.length>1);function jo(e){let t={};for(let n in e)n in No||(t[n]=e[n]);if(!1===e.css)return t;let{name:n="v",type:a,duration:i,enterFromClass:o=`${n}-enter-from`,enterActiveClass:r=`${n}-enter-active`,enterToClass:s=`${n}-enter-to`,appearFromClass:l=o,appearActiveClass:u=r,appearToClass:c=s,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:p=`${n}-leave-to`}=e,f=function(e){if(null==e)return null;{if(R(e))return[function(e){return Y(e)}(e.enter),function(e){return Y(e)}(e.leave)];let t=function(e){return Y(e)}(e);return[t,t]}}(i),m=f&&f[0],g=f&&f[1],{onBeforeEnter:_,onEnter:v,onEnterCancelled:b,onLeave:y,onLeaveCancelled:w,onBeforeAppear:k=_,onAppear:x=v,onAppearCancelled:C=b}=t,T=(e,t,n,a)=>{e._enterCancelled=a,Fo(e,t?c:s),Fo(e,t?u:r),n&&n()},P=(e,t)=>{e._isLeaving=!1,Fo(e,d),Fo(e,p),Fo(e,h),t&&t()},E=e=>(t,n)=>{let i=e?x:v,r=()=>T(t,e,n);qo(i,[t,r]),$o(()=>{Fo(t,e?l:o),Bo(t,e?c:s),Do(i)||Uo(t,a,m,r)})};return S(t,{onBeforeEnter(e){qo(_,[e]),Bo(e,o),Bo(e,r)},onBeforeAppear(e){qo(k,[e]),Bo(e,l),Bo(e,u)},onEnter:E(!1),onAppear:E(!0),onLeave(e,t){e._isLeaving=!0;let n=()=>P(e,t);Bo(e,d),e._enterCancelled?(Bo(e,h),Ko(e)):(Ko(e),Bo(e,h)),$o(()=>{e._isLeaving&&(Fo(e,d),Bo(e,p),Do(y)||Uo(e,a,g,n))}),qo(y,[e,n])},onEnterCancelled(e){T(e,!1,void 0,!0),qo(b,[e])},onAppearCancelled(e){T(e,!0,void 0,!0),qo(C,[e])},onLeaveCancelled(e){P(e),qo(w,[e])}})}function Bo(e,t){t.split(/\s+/).forEach(t=>t&&e.classList.add(t)),(e[zo]||(e[zo]=new Set)).add(t)}function Fo(e,t){t.split(/\s+/).forEach(t=>t&&e.classList.remove(t));let n=e[zo];n&&(n.delete(t),n.size||(e[zo]=void 0))}function $o(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Vo=0;function Uo(e,t,n,a){let i=e._endId=++Vo,o=()=>{i===e._endId&&a()};if(null!=n)return setTimeout(o,n);let{type:r,timeout:s,propCount:l}=Ho(e,t);if(!r)return a();let u=r+"end",c=0,d=()=>{e.removeEventListener(u,h),o()},h=t=>{t.target===e&&++c>=l&&d()};setTimeout(()=>{c(n[e]||"").split(", "),i=a(`${Lo}Delay`),o=a(`${Lo}Duration`),r=Wo(i,o),s=a(`${Ro}Delay`),l=a(`${Ro}Duration`),u=Wo(s,l),c=null,d=0,h=0;return t===Lo?r>0&&(c=Lo,d=r,h=o.length):t===Ro?u>0&&(c=Ro,d=u,h=l.length):h=(c=(d=Math.max(r,u))>0?r>u?Lo:Ro:null)?c===Lo?o.length:l.length:0,{type:c,timeout:d,propCount:h,hasTransform:c===Lo&&/\b(?:transform|all)(?:,|$)/.test(a(`${Lo}Property`).toString())}}function Wo(e,t){for(;e.lengthGo(t)+Go(e[n])))}function Go(e){return"auto"===e?0:1e3*Number(e.slice(0,-1).replace(",","."))}function Ko(e){return(e?e.ownerDocument:document).body.offsetHeight}let Yo=Symbol("_vod"),Qo=Symbol("_vsh");function Zo(e,t){e.style.display=t?e[Yo]:"none",e[Qo]=!t}let Jo=Symbol("");function Xo(e,t){if(1===e.nodeType){let a=e.style,i="";for(let e in t){var n;let o=null==(n=t[e])?"initial":"string"==typeof n?""===n?" ":n:String(n);a.setProperty(`--${e}`,o),i+=`--${e}: ${o};`}a[Jo]=i}}let er=/(?:^|;)\s*display\s*:/,tr=/\s*!important$/;function nr(e,t,n){if(E(n))n.forEach(n=>nr(e,t,n));else if(null==n&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{let a=function(e,t){let n=ir[t];if(n)return n;let a=B(t);if("filter"!==a&&a in e)return ir[t]=a;a=V(a);for(let n=0;n111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&e.charCodeAt(2)>96&&123>e.charCodeAt(2),fr=(e,t,n,a,i,o)=>{let r="svg"===i;if("class"===t){var s;let t;s=a,(t=e[zo])&&(s=(s?[s,...t]:[...t]).join(" ")),null==s?e.removeAttribute("class"):r?e.setAttribute("class",s):e.className=s}else"style"===t?function(e,t,n){let a=e.style,i=M(n),o=!1;if(n&&!i){if(t)if(M(t))for(let e of t.split(";")){let t=e.slice(0,e.indexOf(":")).trim();null==n[t]&&nr(a,t,"")}else for(let e in t)null==n[e]&&nr(a,e,"");for(let e in n)"display"===e&&(o=!0),nr(a,e,n[e])}else if(i){if(t!==n){let e=a[Jo];e&&(n+=";"+e),a.cssText=n,o=er.test(n)}}else t&&e.removeAttribute("style");Yo in e&&(e[Yo]=o?a.display:"",e[Qo]&&(a.display="none"))}(e,n,a):k(t)?x(t)||function(e,t,n,a,i=null){let o=e[ur]||(e[ur]={}),r=o[t];if(a&&r)r.value=a;else{let[n,l]=function(e){let t;if(cr.test(e)){let n;for(t={};n=e.match(cr);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[":"===e[2]?e.slice(3):$(e.slice(2)),t]}(t);if(a){var s;let r;lr(e,n,o[t]=(s=i,(r=e=>{if(e._vts){if(e._vts<=r.attached)return}else e._vts=Date.now();Gt(function(e,t){if(!E(t))return t;{let n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(e=>t=>!t._stopped&&e&&e(t))}}(e,r.value),s,5,[e])}).value=a,r.attached=dr||(hr.then(()=>dr=0),dr=Date.now()),r),l)}else r&&(e.removeEventListener(n,r,l),o[t]=void 0)}}(e,t,0,a,o):("."===t[0]?(t=t.slice(1),0):"^"===t[0]?(t=t.slice(1),1):!function(e,t,n,a){if(a)return!!("innerHTML"===t||"textContent"===t||t in e&&pr(t)&&A(n));if("spellcheck"===t||"draggable"===t||"translate"===t||"autocorrect"===t||"sandbox"===t&&"IFRAME"===e.tagName||"form"===t||"list"===t&&"INPUT"===e.tagName||"type"===t&&"TEXTAREA"===e.tagName)return!1;if("width"===t||"height"===t){let t=e.tagName;if("IMG"===t||"VIDEO"===t||"CANVAS"===t||"SOURCE"===t)return!1}return!(pr(t)&&M(n))&&t in e}(e,t,a,r))?!e._isVueCE||!/[A-Z]/.test(t)&&M(a)?("true-value"===t?e._trueValue=a:"false-value"===t&&(e._falseValue=a),rr(e,t,a,r)):sr(e,B(t),a,0,t):(sr(e,t,a),e.tagName.includes("-")||"value"!==t&&"checked"!==t&&"selected"!==t||rr(e,t,a,r,0,"value"!==t))},mr={};function gr(e,t,n){let a,i=jn(e,t);"[object Object]"===(a=i,N.call(a))&&(i=S({},i,t));class o extends vr{constructor(e){super(i,e,n)}}return o.def=i,o}let _r="undefined"!=typeof HTMLElement?HTMLElement:class{};class vr extends _r{constructor(e,t={},n=Yr){super(),this._def=e,this._props=t,this._createApp=n,this._isVueCE=!0,this._instance=null,this._app=null,this._nonce=this._def.nonce,this._connected=!1,this._resolved=!1,this._patching=!1,this._dirty=!1,this._numberProps=null,this._styleChildren=new WeakSet,this._ob=null,this.shadowRoot&&n!==Yr?this._root=this.shadowRoot:!1!==e.shadowRoot?(this.attachShadow(S({},e.shadowRootOptions,{mode:"open"})),this._root=this.shadowRoot):this._root=this}connectedCallback(){if(!this.isConnected)return;this.shadowRoot||this._resolved||this._parseSlots(),this._connected=!0;let e=this;for(;e=e&&(e.parentNode||e.host);)if(e instanceof vr){this._parent=e;break}this._instance||(this._resolved?this._mount(this._def):e&&e._pendingResolve?this._pendingResolve=e._pendingResolve.then(()=>{this._pendingResolve=void 0,this._resolveDef()}):this._resolveDef())}_setParent(e=this._parent){e&&(this._instance.parent=e._instance,this._inheritParentContext(e))}_inheritParentContext(e=this._parent){e&&this._app&&Object.setPrototypeOf(this._app._context.provides,e._instance.provides)}disconnectedCallback(){this._connected=!1,nn(()=>{!this._connected&&(this._ob&&(this._ob.disconnect(),this._ob=null),this._app&&this._app.unmount(),this._instance&&(this._instance.ce=void 0),this._app=this._instance=null,this._teleportTargets&&(this._teleportTargets.clear(),this._teleportTargets=void 0))})}_processMutations(e){for(let t of e)this._setAttr(t.attributeName)}_resolveDef(){if(this._pendingResolve)return;for(let e=0;e{let n;this._resolved=!0,this._pendingResolve=void 0;let{props:a,styles:i}=e;if(a&&!E(a))for(let e in a){let t=a[e];(t===Number||t&&t.type===Number)&&(e in this._props&&(this._props[e]=Y(this._props[e])),(n||(n=Object.create(null)))[B(e)]=!0)}this._numberProps=n,this._resolveProps(e),this.shadowRoot&&this._applyStyles(i),this._mount(e)},t=this._def.__asyncLoader;t?this._pendingResolve=t().then(t=>{t.configureApp=this._def.configureApp,e(this._def=t,!0)}):e(this._def)}_mount(e){this._app=this._createApp(e),this._inheritParentContext(),e.configureApp&&e.configureApp(this._app),this._app._ceVNode=this._createVNode(),this._app.mount(this._root);let t=this._instance&&this._instance.exposed;if(t)for(let e in t)P(this,e)||Object.defineProperty(this,e,{get:()=>Nt(t[e])})}_resolveProps(e){let{props:t}=e,n=E(t)?t:Object.keys(t||{});for(let e of Object.keys(this))"_"!==e[0]&&n.includes(e)&&this._setProp(e,this[e]);for(let e of n.map(B))Object.defineProperty(this,e,{get(){return this._getProp(e)},set(t){this._setProp(e,t,!0,!this._patching)}})}_setAttr(e){if(e.startsWith("data-v-"))return;let t=this.hasAttribute(e),n=t?this.getAttribute(e):mr,a=B(e);t&&this._numberProps&&this._numberProps[a]&&(n=Y(n)),this._setProp(a,n,!1,!0)}_getProp(e){return this._props[e]}_setProp(e,t,n=!0,a=!1){if(t!==this._props[e]&&(this._dirty=!0,t===mr?delete this._props[e]:(this._props[e]=t,"key"===e&&this._app&&(this._app._ceVNode.key=t)),a&&this._instance&&this._update(),n)){let n=this._ob;n&&(this._processMutations(n.takeRecords()),n.disconnect()),!0===t?this.setAttribute($(e),""):"string"==typeof t||"number"==typeof t?this.setAttribute($(e),t+""):t||this.removeAttribute($(e)),n&&n.observe(this,{attributes:!0})}}_update(){let e=this._createVNode();this._app&&(e.appContext=this._app._context),Kr(e,this._root)}_createVNode(){let e={};this.shadowRoot||(e.onVnodeMounted=e.onVnodeUpdated=this._renderSlots.bind(this));let t=Zi(this._def,S(e,this._props));return this._instance||(t.ce=e=>{this._instance=e,e.ce=this,e.isCE=!0;let t=(e,t)=>{let n;this.dispatchEvent(new CustomEvent(e,"[object Object]"===(n=t[0],N.call(n))?S({detail:t},t[0]):{detail:t}))};e.emit=(e,...n)=>{t(e,n),$(e)!==e&&t($(e),n)},this._setParent()}),t}_applyStyles(e,t){if(!e)return;if(t){if(t===this._def||this._styleChildren.has(t))return;this._styleChildren.add(t)}let n=this._nonce;for(let t=e.length-1;t>=0;t--){let a=document.createElement("style");n&&a.setAttribute("nonce",n),a.textContent=e[t],this.shadowRoot.prepend(a)}}_parseSlots(){let e,t=this._slots={};for(;e=this.firstChild;){let n=1===e.nodeType&&e.getAttribute("slot")||"default";(t[n]||(t[n]=[])).push(e),this.removeChild(e)}}_renderSlots(){let e=this._getSlots(),t=this._instance.type.__scopeId;for(let n=0;n{if(!n.length)return;let t=e.moveClass||`${e.name||"v"}-move`;if(!function(e,t,n){let a=e.cloneNode(),i=e[zo];i&&i.forEach(e=>{e.split(/\s+/).forEach(e=>e&&a.classList.remove(e))}),n.split(/\s+/).forEach(e=>e&&a.classList.add(e)),a.style.display="none";let o=1===t.nodeType?t:t.parentNode;o.appendChild(a);let{hasTransform:r}=Ho(a);return o.removeChild(a),r}(n[0].el,i.vnode.el,t))return void(n=[]);n.forEach(Cr),n.forEach(Tr);let a=n.filter(Pr);Ko(i.vnode.el),a.forEach(e=>{let n=e.el,a=n.style;Bo(n,t),a.transform=a.webkitTransform=a.transitionDuration="";let i=n[kr]=e=>{(!e||e.target===n)&&(!e||e.propertyName.endsWith("transform"))&&(n.removeEventListener("transitionend",i),n[kr]=null,Fo(n,t))};n.addEventListener("transitionend",i)}),n=[]}),()=>{let r=Ct(e),s=jo(r),l=r.tag||Ni;if(n=[],a)for(let e=0;e{let t=e.props["onUpdate:modelValue"]||!1;return E(t)?e=>W(t,e):t};function Ar(e){e.target.composing=!0}function Mr(e){let t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}let Lr=Symbol("_assign");function Rr(e,t,n){return t&&(e=e.trim()),n&&(e=K(e)),e}let zr={created(e,{modifiers:{lazy:t,trim:n,number:a}},i){e[Lr]=Er(i);let o=a||i.props&&"number"===i.props.type;lr(e,t?"change":"input",t=>{t.target.composing||e[Lr](Rr(e.value,n,o))}),(n||o)&&lr(e,"change",()=>{e.value=Rr(e.value,n,o)}),t||(lr(e,"compositionstart",Ar),lr(e,"compositionend",Mr),lr(e,"change",Mr))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:a,trim:i,number:o}},r){if(e[Lr]=Er(r),e.composing)return;let s=null==t?"":t;if((!o&&"number"!==e.type||/^0\d/.test(e.value)?e.value:K(e.value))!==s){if(document.activeElement===e&&"range"!==e.type&&(a&&t===n||i&&e.value.trim()===s))return;e.value=s}}},Nr={deep:!0,created(e,t,n){e[Lr]=Er(n),lr(e,"change",()=>{let t=e._modelValue,n=jr(e),a=e.checked,i=e[Lr];if(E(t)){let e=ce(t,n),o=-1!==e;if(a&&!o)i(t.concat(n));else if(!a&&o){let n=[...t];n.splice(e,1),i(n)}}else{let o;if("[object Set]"===(o=t,N.call(o))){let e=new Set(t);a?e.add(n):e.delete(n),i(e)}else i(Br(e,a))}})},mounted:Or,beforeUpdate(e,t,n){e[Lr]=Er(n),Or(e,t,n)}};function Or(e,{value:t,oldValue:n},a){let i;if(e._modelValue=t,E(t))i=ce(t,a.props.value)>-1;else{let o;if("[object Set]"===(o=t,N.call(o)))i=t.has(a.props.value);else{if(t===n)return;i=ue(t,Br(e,!0))}}e.checked!==i&&(e.checked=i)}let Ir={created(e,{value:t},n){e.checked=ue(t,n.props.value),e[Lr]=Er(n),lr(e,"change",()=>{e[Lr](jr(e))})},beforeUpdate(e,{value:t,oldValue:n},a){e[Lr]=Er(a),t!==n&&(e.checked=ue(t,a.props.value))}},qr={deep:!0,created(e,{value:t,modifiers:{number:n}},a){let i,o="[object Set]"===(i=t,N.call(i));lr(e,"change",()=>{let t=Array.prototype.filter.call(e.options,e=>e.selected).map(e=>n?K(jr(e)):jr(e));e[Lr](e.multiple?o?new Set(t):t:t[0]),e._assigning=!0,nn(()=>{e._assigning=!1})}),e[Lr]=Er(a)},mounted(e,{value:t}){Dr(e,t)},beforeUpdate(e,t,n){e[Lr]=Er(n)},updated(e,{value:t}){e._assigning||Dr(e,t)}};function Dr(e,t){let n,a=e.multiple,i=E(t);if(!a||i||"[object Set]"===(n=t,N.call(n))){for(let n=0,o=e.options.length;nString(e)===String(r)):ce(t,r)>-1}else o.selected=t.has(r);else if(ue(jr(o),t))return void(e.selectedIndex!==n&&(e.selectedIndex=n))}a||-1===e.selectedIndex||(e.selectedIndex=-1)}}function jr(e){return"_value"in e?e._value:e.value}function Br(e,t){let n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}function Fr(e,t,n,a,i){let o=function(e,t){switch(e){case"SELECT":return qr;case"TEXTAREA":return zr;default:switch(t){case"checkbox":return Nr;case"radio":return Ir;default:return zr}}}(e.tagName,n.props&&n.props.type)[i];o&&o(e,t,n,a)}let $r=["ctrl","shift","alt","meta"],Vr={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>$r.some(n=>e[`${n}Key`]&&!t.includes(n))},Ur={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Hr=S({patchProp:fr},Mo),Wr=!1;function Gr(){return p=Wr?p:yi(Hr),Wr=!0,p}let Kr=(...e)=>{(p||(p=wi(Hr))).render(...e)},Yr=(...e)=>{let t=(p||(p=wi(Hr))).createApp(...e),{mount:n}=t;return t.mount=e=>{let a=Jr(e);if(!a)return;let i=t._component;A(i)||i.render||i.template||(i.template=a.innerHTML),1===a.nodeType&&(a.textContent="");let o=n(a,!1,Zr(a));return a instanceof Element&&(a.removeAttribute("v-cloak"),a.setAttribute("data-v-app","")),o},t},Qr=(...e)=>{let t=Gr().createApp(...e),{mount:n}=t;return t.mount=e=>{let t=Jr(e);if(t)return n(t,!0,Zr(t))},t};function Zr(e){return e instanceof SVGElement?"svg":"function"==typeof MathMLElement&&e instanceof MathMLElement?"mathml":void 0}function Jr(e){return M(e)?document.querySelector(e):e}let Xr=Symbol(""),es=Symbol(""),ts=Symbol(""),ns=Symbol(""),as=Symbol(""),is=Symbol(""),os=Symbol(""),rs=Symbol(""),ss=Symbol(""),ls=Symbol(""),us=Symbol(""),cs=Symbol(""),ds=Symbol(""),hs=Symbol(""),ps=Symbol(""),fs=Symbol(""),ms=Symbol(""),gs=Symbol(""),_s=Symbol(""),vs=Symbol(""),bs=Symbol(""),ys=Symbol(""),ws=Symbol(""),ks=Symbol(""),xs=Symbol(""),Ss=Symbol(""),Cs=Symbol(""),Ts=Symbol(""),Ps=Symbol(""),Es=Symbol(""),As=Symbol(""),Ms=Symbol(""),Ls=Symbol(""),Rs=Symbol(""),zs=Symbol(""),Ns=Symbol(""),Os=Symbol(""),Is=Symbol(""),qs=Symbol(""),Ds={[Xr]:"Fragment",[es]:"Teleport",[ts]:"Suspense",[ns]:"KeepAlive",[as]:"BaseTransition",[is]:"openBlock",[os]:"createBlock",[rs]:"createElementBlock",[ss]:"createVNode",[ls]:"createElementVNode",[us]:"createCommentVNode",[cs]:"createTextVNode",[ds]:"createStaticVNode",[hs]:"resolveComponent",[ps]:"resolveDynamicComponent",[fs]:"resolveDirective",[ms]:"resolveFilter",[gs]:"withDirectives",[_s]:"renderList",[vs]:"renderSlot",[bs]:"createSlots",[ys]:"toDisplayString",[ws]:"mergeProps",[ks]:"normalizeClass",[xs]:"normalizeStyle",[Ss]:"normalizeProps",[Cs]:"guardReactiveProps",[Ts]:"toHandlers",[Ps]:"camelize",[Es]:"capitalize",[As]:"toHandlerKey",[Ms]:"setBlockTracking",[Ls]:"pushScopeId",[Rs]:"popScopeId",[zs]:"withCtx",[Ns]:"unref",[Os]:"isRef",[Is]:"withMemo",[qs]:"isMemoSame"},js={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0},source:""};function Bs(e,t,n,a,i,o,r,s=!1,l=!1,u=!1,c=js){return e&&(s?(e.helper(is),e.helper(e.inSSR||u?os:rs)):e.helper(e.inSSR||u?ss:ls),r&&e.helper(gs)),{type:13,tag:t,props:n,children:a,patchFlag:i,dynamicProps:o,directives:r,isBlock:s,disableTracking:l,isComponent:u,loc:c}}function Fs(e,t=js){return{type:17,loc:t,elements:e}}function $s(e,t=js){return{type:15,loc:t,properties:e}}function Vs(e,t){return{type:16,loc:js,key:M(e)?Us(e,!0):e,value:t}}function Us(e,t=!1,n=js,a=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:a}}function Hs(e,t=js){return{type:8,loc:t,children:e}}function Ws(e,t=[],n=js){return{type:14,loc:n,callee:e,arguments:t}}function Gs(e,t,n=!1,a=!1,i=js){return{type:18,params:e,returns:t,newline:n,isSlot:a,loc:i}}function Ks(e,t,n,a=!0){return{type:19,test:e,consequent:t,alternate:n,newline:a,loc:js}}function Ys(e,{helper:t,removeHelper:n,inSSR:a}){var i,o;e.isBlock||(e.isBlock=!0,n((i=e.isComponent,a||i?ss:ls)),t(is),t((o=e.isComponent,a||o?os:rs)))}let Qs=new Uint8Array([123,123]),Zs=new Uint8Array([125,125]);function Js(e){return e>=97&&e<=122||e>=65&&e<=90}function Xs(e){return 32===e||10===e||9===e||12===e||13===e}function el(e){return 47===e||62===e||Xs(e)}function tl(e){let t=new Uint8Array(e.length);for(let n=0;n4===e.type&&e.isStatic;function sl(e){switch(e){case"Teleport":case"teleport":return es;case"Suspense":case"suspense":return ts;case"KeepAlive":case"keep-alive":return ns;case"BaseTransition":case"base-transition":return as}}let ll=/^$|^\d|[^\$\w\xA0-\uFFFF]/,ul=/[A-Za-z_$\xA0-\uFFFF]/,cl=/[\.\?\w$\xA0-\uFFFF]/,dl=/\s+[.[]\s*|\s*[.[]\s+/g,hl=e=>4===e.type?e.content:e.loc.source,pl=e=>{let t=hl(e).trim().replace(dl,e=>e.trim()),n=0,a=[],i=0,o=0,r=null;for(let e=0;e|^\s*(?:async\s+)?function(?:\s+[\w$]+)?\s*\(/;function ml(e,t,n=!1){for(let a=0;a4===e.key.type&&e.key.content===a)}return n}function Tl(e,t){return`_${t}_${e.replace(/[^\w]/g,(t,n)=>"-"===t?"_":e.charCodeAt(n).toString())}`}let Pl=/([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/;function El(e){for(let t=0;t0,isVoidTag:w,isPreTag:w,isIgnoreNewlineTag:w,isCustomElement:w,onError:al,onWarn:il,comments:!1,prefixIdentifiers:!1},Rl=Ll,zl=null,Nl="",Ol=null,Il=null,ql="",Dl=-1,jl=-1,Bl=0,Fl=!1,$l=null,Vl=[],Ul=new class{constructor(e,t){this.stack=e,this.cbs=t,this.state=1,this.buffer="",this.sectionStart=0,this.index=0,this.entityStart=0,this.baseState=1,this.inRCDATA=!1,this.inXML=!1,this.inVPre=!1,this.newlines=[],this.mode=0,this.delimiterOpen=Qs,this.delimiterClose=Zs,this.delimiterIndex=-1,this.currentSequence=void 0,this.sequenceIndex=0}get inSFCRoot(){return 2===this.mode&&0===this.stack.length}reset(){this.state=1,this.mode=0,this.buffer="",this.sectionStart=0,this.index=0,this.baseState=1,this.inRCDATA=!1,this.currentSequence=void 0,this.newlines.length=0,this.delimiterOpen=Qs,this.delimiterClose=Zs}getPos(e){let t=1,n=e+1;for(let a=this.newlines.length-1;a>=0;a--){let i=this.newlines[a];if(e>i){t=a+2,n=e-i;break}}return{column:n,line:t,offset:e}}peek(){return this.buffer.charCodeAt(this.index+1)}stateText(e){60===e?(this.index>this.sectionStart&&this.cbs.ontext(this.sectionStart,this.index),this.state=5,this.sectionStart=this.index):this.inVPre||e!==this.delimiterOpen[0]||(this.state=2,this.delimiterIndex=0,this.stateInterpolationOpen(e))}stateInterpolationOpen(e){if(e===this.delimiterOpen[this.delimiterIndex])if(this.delimiterIndex===this.delimiterOpen.length-1){let e=this.index+1-this.delimiterOpen.length;e>this.sectionStart&&this.cbs.ontext(this.sectionStart,e),this.state=3,this.sectionStart=e}else this.delimiterIndex++;else this.inRCDATA?(this.state=32,this.stateInRCDATA(e)):(this.state=1,this.stateText(e))}stateInterpolation(e){e===this.delimiterClose[0]&&(this.state=4,this.delimiterIndex=0,this.stateInterpolationClose(e))}stateInterpolationClose(e){e===this.delimiterClose[this.delimiterIndex]?this.delimiterIndex===this.delimiterClose.length-1?(this.cbs.oninterpolation(this.sectionStart,this.index+1),this.inRCDATA?this.state=32:this.state=1,this.sectionStart=this.index+1):this.delimiterIndex++:(this.state=3,this.stateInterpolation(e))}stateSpecialStartSequence(e){let t=this.sequenceIndex===this.currentSequence.length;if(t?el(e):(32|e)===this.currentSequence[this.sequenceIndex]){if(!t)return void this.sequenceIndex++}else this.inRCDATA=!1;this.sequenceIndex=0,this.state=6,this.stateInTagName(e)}stateInRCDATA(e){if(this.sequenceIndex===this.currentSequence.length){if(62===e||Xs(e)){let t=this.index-this.currentSequence.length;if(this.sectionStart=e||(28===this.state?this.currentSequence===nl.CdataEnd?this.cbs.oncdata(this.sectionStart,e):this.cbs.oncomment(this.sectionStart,e):6===this.state||11===this.state||18===this.state||17===this.state||12===this.state||13===this.state||14===this.state||15===this.state||16===this.state||20===this.state||19===this.state||21===this.state||9===this.state||this.cbs.ontext(this.sectionStart,e))}emitCodePoint(e,t){}}(Vl,{onerr:ru,ontext(e,t){Yl(Gl(e,t),e,t)},ontextentity(e,t,n){Yl(e,t,n)},oninterpolation(e,t){if(Fl)return Yl(Gl(e,t),e,t);let n=e+Ul.delimiterOpen.length,a=t-Ul.delimiterClose.length;for(;Xs(Nl.charCodeAt(n));)n++;for(;Xs(Nl.charCodeAt(a-1));)a--;let i=Gl(n,a);i.includes("&")&&(i=Rl.decodeEntities(i,!1)),nu({type:5,content:ou(i,!1,au(n,a)),loc:au(e,t)})},onopentagname(e,t){let n=Gl(e,t);Ol={type:1,tag:n,ns:Rl.getNamespace(n,Vl[0],Rl.ns),tagType:0,props:[],children:[],loc:au(e-1,t),codegenNode:void 0}},onopentagend(e){Kl(e)},onclosetag(e,t){let n=Gl(e,t);if(!Rl.isVoidTag(n)){let a=!1;for(let e=0;e0&&Vl[0].loc.start.offset;for(let n=0;n<=e;n++)Ql(Vl.shift(),t,n(7===e.type?e.rawName:e.name)===t)},onattribend(e,t){Ol&&Il&&(iu(Il.loc,t),0!==e&&(ql.includes("&")&&(ql=Rl.decodeEntities(ql,!0)),6===Il.type?("class"===Il.name&&(ql=tu(ql).trim()),Il.value={type:2,content:ql,loc:1===e?au(Dl,jl):au(Dl-1,jl+1)},Ul.inSFCRoot&&"template"===Ol.tag&&"lang"===Il.name&&ql&&"html"!==ql&&Ul.enterRCDATA(tl("{let i=t.start.offset+n;return ou(e,!1,au(i,i+e.length),0,+!!a)},s={source:r(o.trim(),n.indexOf(o,i.length)),value:void 0,key:void 0,index:void 0,finalized:!1},l=i.trim().replace(Wl,"").trim(),u=i.indexOf(l),c=l.match(Hl);if(c){let e;l=l.replace(Hl,"").trim();let t=c[1].trim();if(t&&(e=n.indexOf(t,u+l.length),s.key=r(t,e,!0)),c[2]){let a=c[2].trim();a&&(s.index=r(a,n.indexOf(a,s.key?e+t.length:u+l.length),!0))}}return l&&(s.value=r(l,u,!0)),s}(Il.exp)))),(7!==Il.type||"pre"!==Il.name)&&Ol.props.push(Il)),ql="",Dl=jl=-1},oncomment(e,t){Rl.comments&&nu({type:3,content:Gl(e,t),loc:au(e-4,t+3)})},onend(){let e=Nl.length;for(let t=0;t64&&n<91||sl(e)||Rl.isBuiltInComponent&&Rl.isBuiltInComponent(e)||Rl.isNativeTag&&!Rl.isNativeTag(e))return!0;for(let e=0;e=0;)n--;return n}let Jl=new Set(["if","else","else-if","for","slot"]),Xl=/\r\n/g;function eu(e){let t="preserve"!==Rl.whitespace,n=!1;for(let a=0;a3!==e.type);return 1!==t.length||1!==t[0].type||kl(t[0])?null:t[0]}function lu(e,t){let{constantCache:n}=t;switch(e.type){case 1:if(0!==e.tagType)return 0;let s=n.get(e);if(void 0!==s)return s;let l=e.codegenNode;if(13!==l.type||l.isBlock&&"svg"!==e.tag&&"foreignObject"!==e.tag&&"math"!==e.tag)return 0;if(void 0!==l.patchFlag)return n.set(e,0),0;{let s=3,u=cu(e,t);if(0===u)return n.set(e,0),0;u1)for(let a=0;a{n--};for(;nt===e:t=>e.test(t);return(e,a)=>{if(1===e.type){let{props:i}=e;if(3===e.tagType&&i.some(yl))return;let o=[];for(let r=0;r`${Ds[e]}: _${Ds[e]}`;function gu(e,t,{helper:n,push:a,newline:i,isTS:o}){let r=n("component"===t?hs:fs);for(let n=0;n3;t.push("["),n&&t.indent(),vu(e,t,n),n&&t.deindent(),t.push("]")}function vu(e,t,n=!1,a=!0){let{push:i,newline:o}=t;for(let r=0;re||"null")}([r,s,l,n,c]),t),a(")"),h&&a(")"),d&&(a(", "),bu(d,t),a(")"))}(e,t);break;case 14:!function(e,t){let{push:n,helper:a,pure:i}=t,o=M(e.callee)?e.callee:a(e.callee);i&&n(fu),n(o+"(",-2,e),vu(e.arguments,t),n(")")}(e,t);break;case 15:!function(e,t){let{push:n,indent:a,deindent:i,newline:o}=t,{properties:r}=e;if(!r.length)return n("{}",-2,e);let s=r.length>1;n(s?"{":"{ "),s&&a();for(let e=0;e "),(l||s)&&(n("{"),a()),r?(l&&n("return "),E(r)?_u(r,t):bu(r,t)):s&&bu(s,t),(l||s)&&(i(),n("}")),u&&n(")")}(e,t);break;case 19:!function(e,t){let{test:n,consequent:a,alternate:i,newline:o}=e,{push:r,indent:s,deindent:l,newline:u}=t;if(4===n.type){let e,a=(e=n.content,!!ll.test(e));a&&r("("),yu(n,t),a&&r(")")}else r("("),bu(n,t),r(")");o&&s(),t.indentLevel++,o||r(" "),r("? "),bu(a,t),t.indentLevel--,o&&u(),o||r(" "),r(": ");let c=19===i.type;!c&&t.indentLevel++,bu(i,t),!c&&t.indentLevel--,o&&l(!0)}(e,t);break;case 20:!function(e,t){let{push:n,helper:a,indent:i,deindent:o,newline:r}=t,{needPauseTracking:s,needArraySpread:l}=e;l&&n("[...("),n(`_cache[${e.index}] || (`),s&&(i(),n(`${a(Ms)}(-1`),e.inVOnce&&n(", true"),n("),"),r(),n("(")),n(`_cache[${e.index}] = `),bu(e.value,t),s&&(n(`).cacheIndex = ${e.index},`),r(),n(`${a(Ms)}(1),`),r(),n(`_cache[${e.index}]`),o()),n(")"),l&&n(")]")}(e,t);break;case 21:vu(e.body,t,!0,!1)}}function yu(e,t){let{content:n,isStatic:a}=e;t.push(a?JSON.stringify(n):n,-3,e)}function wu(e,t){for(let n=0;nfunction(e,t,n,a){if(!("else"===t.name||t.exp&&t.exp.content.trim())){let a=t.exp?t.exp.loc:e.loc;n.onError(ol(28,t.loc)),t.exp=Us("true",!1,a)}if("if"===t.name){var i;let o=xu(e,t),r={type:9,loc:au((i=e.loc).start.offset,i.end.offset),branches:[o]};if(n.replaceNode(r),a)return a(r,o,!0)}else{let i=n.parent.children,o=i.indexOf(e);for(;o-- >=-1;){let r=i[o];if(!r||!Ml(r)){if(r&&9===r.type){("else-if"===t.name||"else"===t.name)&&void 0===r.branches[r.branches.length-1].condition&&n.onError(ol(30,e.loc)),n.removeNode();let i=xu(e,t);r.branches.push(i);let o=a&&a(r,i,!1);hu(i,n),o&&o(),n.currentNode=null}else n.onError(ol(30,e.loc));break}n.removeNode(r)}}}(e,t,n,(e,t,a)=>{let i=n.parent.children,o=i.indexOf(e),r=0;for(;o-- >=0;){let e=i[o];e&&9===e.type&&(r+=e.branches.length)}return()=>{a?e.codegenNode=Su(t,r,n):(function(e){for(;;)if(19===e.type){if(19!==e.alternate.type)return e;e=e.alternate}else 20===e.type&&(e=e.value)}(e.codegenNode)).alternate=Su(t,r+e.branches.length-1,n)}}));function xu(e,t){let n=3===e.tagType;return{type:10,loc:e.loc,condition:"else"===t.name?void 0:t.exp,children:n&&!ml(e,"for")?e.children:[e],userKey:gl(e,"key"),isTemplateIf:n}}function Su(e,t,n){return e.condition?Ks(e.condition,Cu(e,t,n),Ws(n.helper(us),['""',"true"])):Cu(e,t,n)}function Cu(e,t,n){let{helper:a}=n,i=Vs("key",Us(`${t}`,!1,js,2)),{children:o}=e,r=o[0];if(1!==o.length||1!==r.type){if(1!==o.length||11!==r.type)return Bs(n,a(Xr),$s([i]),o,64,void 0,void 0,!0,!1,!1,e.loc);{let e=r.codegenNode;return Sl(e,i,n),e}}{let e=r.codegenNode,t=14===e.type&&e.callee===Is?e.arguments[1].returns:e;return 13===t.type&&Ys(t,n),Sl(t,i,n),e}}let Tu=pu("for",(e,t,n)=>{let{helper:a,removeHelper:i}=n;return function(e,t,n,a){if(!t.exp)return void n.onError(ol(31,t.loc));let i=t.forParseResult;if(!i)return void n.onError(ol(32,t.loc));Pu(i);let{scopes:o}=n,{source:r,value:s,key:l,index:u}=i,c={type:11,loc:t.loc,source:r,valueAlias:s,keyAlias:l,objectIndexAlias:u,parseResult:i,children:wl(e)?e.children:[e]};n.replaceNode(c),o.vFor++;let d=a&&a(c);return()=>{o.vFor--,d&&d()}}(e,t,n,t=>{let o=Ws(a(_s),[t.source]),r=wl(e),s=ml(e,"memo"),l=gl(e,"key",!1,!0);l&&l.type;let u=l&&(6===l.type?l.value?Us(l.value.content,!0):void 0:l.exp),c=l&&u?Vs("key",u):null,d=4===t.source.type&&t.source.constType>0,h=d?64:l?128:256;return t.codegenNode=Bs(n,a(Xr),void 0,o,h,void 0,void 0,!0,!d,!1,e.loc),()=>{let l,{children:h}=t,p=1!==h.length||1!==h[0].type,f=kl(e)?e:r&&1===e.children.length&&kl(e.children[0])?e.children[0]:null;if(f)l=f.codegenNode,r&&c&&Sl(l,c,n);else if(p)l=Bs(n,a(Xr),c?$s([c]):void 0,e.children,64,void 0,void 0,!0,void 0,!1);else{var m,g,_,v,b,y,w,k;l=h[0].codegenNode,r&&c&&Sl(l,c,n),!d!==l.isBlock&&(l.isBlock?(i(is),i((m=n.inSSR,g=l.isComponent,m||g?os:rs))):i((_=n.inSSR,v=l.isComponent,_||v?ss:ls))),l.isBlock=!d,l.isBlock?(a(is),a((b=n.inSSR,y=l.isComponent,b||y?os:rs))):a((w=n.inSSR,k=l.isComponent,w||k?ss:ls))}if(s){let e=Gs(Eu(t.parseResult,[Us("_cached")]));e.body={type:21,body:[Hs(["const _memo = (",s.exp,")"]),Hs(["if (_cached",...u?[" && _cached.key === ",u]:[],` && ${n.helperString(qs)}(_cached, _memo)) return _cached`]),Hs(["const _item = ",l]),Us("_item.memo = _memo"),Us("return _item")],loc:js},o.arguments.push(e,Us("_cache"),Us(String(n.cached.length))),n.cached.push(null)}else o.arguments.push(Gs(Eu(t.parseResult),l,!0))}})});function Pu(e,t){e.finalized||(e.finalized=!0)}function Eu({value:e,key:t,index:n},a=[]){var i=[e,t,n,...a];let o=i.length;for(;o--&&!i[o];);return i.slice(0,o+1).map((e,t)=>e||Us("_".repeat(t+1),!1))}let Au=Us("undefined",!1),Mu=(e,t)=>{if(1===e.type&&(1===e.tagType||3===e.tagType)){let n=ml(e,"slot");if(n)return n.exp,t.scopes.vSlot++,()=>{t.scopes.vSlot--}}};function Lu(e,t,n){let a=[Vs("name",e),Vs("fn",t)];return null!=n&&a.push(Vs("key",Us(String(n),!0))),$s(a)}let Ru=new WeakMap,zu=(e,t)=>function(){let n,a,i,o,r;if(1!==(e=t.currentNode).type||0!==e.tagType&&1!==e.tagType)return;let{tag:s,props:l}=e,u=1===e.tagType,c=u?function(e,t,n=!1){let{tag:a}=e,i=Iu(a),o=gl(e,"is",!1,!0);if(o)if(i){let e;if(6===o.type?e=o.value&&Us(o.value.content,!0):(e=o.exp)||(e=Us("is",!1,o.arg.loc)),e)return Ws(t.helper(ps),[e])}else 6===o.type&&o.value.content.startsWith("vue:")&&(a=o.value.content.slice(4));let r=sl(a)||t.isBuiltInComponent(a);return r?(n||t.helper(r),r):(t.helper(hs),t.components.add(a),Tl(a,"component"))}(e,t):`"${s}"`,d=R(c)&&c.callee===ps,h=0,p=d||c===es||c===ts||!u&&("svg"===s||"foreignObject"===s||"math"===s);if(l.length>0){let a=Nu(e,t,void 0,u,d);n=a.props,h=a.patchFlag,o=a.dynamicPropNames;let i=a.directives;r=i&&i.length?Fs(i.map(e=>function(e,t){let n=[],a=Ru.get(e);a?n.push(t.helperString(a)):(t.helper(fs),t.directives.add(e.name),n.push(Tl(e.name,"directive")));let{loc:i}=e;if(e.exp&&n.push(e.exp),e.arg&&(e.exp||n.push("void 0"),n.push(e.arg)),Object.keys(e.modifiers).length){e.arg||(e.exp||n.push("void 0"),n.push("void 0"));let t=Us("true",!1,i);n.push($s(e.modifiers.map(e=>Vs(e,t)),i))}return Fs(n,e.loc)}(e,t))):void 0,a.shouldUseBlock&&(p=!0)}if(e.children.length>0)if(c===ns&&(p=!0,h|=1024),u&&c!==es&&c!==ns){let{slots:n,hasDynamicSlots:i}=function(e,t,n=(e,t,n,a)=>Gs(e,n,!1,!0,n.length?n[0].loc:a)){t.helper(zs);let{children:a,loc:i}=e,o=[],r=[],s=t.scopes.vSlot>0||t.scopes.vFor>0,l=ml(e,"slot",!0);if(l){let{arg:e,exp:t}=l;e&&!rl(e)&&(s=!0),o.push(Vs(e||Us("default",!0),n(t,void 0,a,i)))}let u=!1,c=!1,d=[],h=new Set,p=0;for(let e=0;eVs("default",n(e,void 0,t,i));u?d.length&&!d.every(Al)&&(c?t.onError(ol(39,d[0].loc)):o.push(e(void 0,d))):o.push(e(void 0,a))}let f=s?2:function e(t){for(let n=0;n0,f=!1,m=0,g=!1,_=!1,v=!1,b=!1,y=!1,w=!1,x=[],S=e=>{c.length&&(d.push($s(Ou(c),l)),c=[]),e&&d.push(e)},C=()=>{t.scopes.vFor>0&&c.push(Vs(Us("ref_for",!0),Us("true")))},T=({key:e,value:n})=>{if(rl(e)){let o=e.content,r=k(o);r&&(!a||i)&&"onclick"!==o.toLowerCase()&&"onUpdate:modelValue"!==o&&!I(o)&&(b=!0),r&&I(o)&&(w=!0),r&&14===n.type&&(n=n.arguments[0]),20===n.type||(4===n.type||8===n.type)&&lu(n,t)>0||("ref"===o?g=!0:"class"===o?_=!0:"style"===o?v=!0:"key"===o||x.includes(o)||x.push(o),a&&("class"===o||"style"===o)&&!x.includes(o)&&x.push(o))}else y=!0};for(let i=0;i"prop"===e.content)&&(m|=32);let w=t.directiveTransforms[n];if(w){let{props:n,needRuntime:a}=w(r,e,t);o||n.forEach(T),b&&i&&!rl(i)?S($s(n,l)):c.push(...n),a&&(h.push(r),L(a)&&Ru.set(r,a))}else!q(n)&&(h.push(r),p&&(f=!0))}}if(d.length?(S(),r=d.length>1?Ws(t.helper(ws),d,l):d[0]):c.length&&(r=$s(Ou(c),l)),y?m|=16:(_&&!a&&(m|=2),v&&!a&&(m|=4),x.length&&(m|=8),b&&(m|=32)),!f&&(0===m||32===m)&&(g||w||h.length>0)&&(m|=512),!t.inSSR&&r)switch(r.type){case 15:let e=-1,n=-1,a=!1;for(let t=0;t{if(kl(e)){let{children:n,loc:a}=e,{slotName:i,slotProps:o}=function(e,t){let n,a='"default"',i=[];for(let t=0;t0){let{props:a,directives:o}=Nu(e,t,i,!1,!1);n=a,o.length&&t.onError(ol(36,o[0].loc))}return{slotName:a,slotProps:n}}(e,t),r=[t.prefixIdentifiers?"_ctx.$slots":"$slots",i,"{}","undefined","true"],s=2;o&&(r[2]=o,s=3),n.length&&(r[3]=Gs([],n,!1,!1,a),s=4),t.scopeId&&!t.slotted&&(s=5),r.splice(s),e.codegenNode=Ws(t.helper(vs),r,a)}},Du=(e,t,n,a)=>{let i,{loc:o,modifiers:r,arg:s}=e;if(!e.exp&&r.length,4===s.type)if(s.isStatic){let e=s.content;e.startsWith("vue:")&&(e=`vnode-${e.slice(4)}`),i=Us(0!==t.tagType||e.startsWith("vnode")||!/[A-Z]/.test(e)?U(B(e)):`on:${e}`,!0,s.loc)}else i=Hs([`${n.helperString(As)}(`,s,")"]);else(i=s).children.unshift(`${n.helperString(As)}(`),i.children.push(")");let l=e.exp;l&&!l.content.trim()&&(l=void 0);let u=n.cacheHandlers&&!l&&!n.inVOnce;if(l){let e,t=pl(l),n=!(t||(e=l,fl.test(hl(e)))),a=l.content.includes(";");(n||u&&t)&&(l=Hs([`${n?"$event":"(...args)"} => ${a?"{":"("}`,l,a?"}":")"]))}let c={props:[Vs(i,l||Us("() => {}",!1,o))]};return a&&(c=a(c)),u&&(c.props[0].value=n.cache(c.props[0].value)),c.props.forEach(e=>e.key.isHandlerKey=!0),c},ju=(e,t,n)=>{let{modifiers:a}=e,i=e.arg,{exp:o}=e;return o&&4===o.type&&!o.content.trim()&&(o=void 0),4!==i.type?(i.children.unshift("("),i.children.push(') || ""')):i.isStatic||(i.content=i.content?`${i.content} || ""`:'""'),a.some(e=>"camel"===e.content)&&(4===i.type?i.isStatic?i.content=B(i.content):i.content=`${n.helperString(Ps)}(${i.content})`:(i.children.unshift(`${n.helperString(Ps)}(`),i.children.push(")"))),!n.inSSR&&(a.some(e=>"prop"===e.content)&&Bu(i,"."),a.some(e=>"attr"===e.content)&&Bu(i,"^")),{props:[Vs(i,o)]}},Bu=(e,t)=>{4===e.type?e.isStatic?e.content=t+e.content:e.content=`\`${t}\${${e.content}}\``:(e.children.unshift(`'${t}' + (`),e.children.push(")"))},Fu=(e,t)=>{if(0===e.type||1===e.type||11===e.type||10===e.type)return()=>{let n,a=e.children,i=!1;for(let e=0;e7===e.type&&!t.directiveTransforms[e.name]))))for(let e=0;e{if(1===e.type&&ml(e,"once",!0)&&!$u.has(e)&&!t.inVOnce&&!t.inSSR)return $u.add(e),t.inVOnce=!0,t.helper(Ms),()=>{t.inVOnce=!1;let e=t.currentNode;e.codegenNode&&(e.codegenNode=t.cache(e.codegenNode,!0,!0))}},Uu=(e,t,n)=>{let a,{exp:i,arg:o}=e;if(!i)return n.onError(ol(41,e.loc)),Hu();let r=i.loc.source.trim(),s=4===i.type?i.content:r,l=n.bindingMetadata[r];if("props"===l||"props-aliased"===l)return i.loc,Hu();if(!s.trim()||!pl(i))return n.onError(ol(42,i.loc)),Hu();let u=o||Us("modelValue",!0),c=o?rl(o)?`onUpdate:${B(o.content)}`:Hs(['"onUpdate:" + ',o]):"onUpdate:modelValue";a=Hs([`${n.isTS?"($event: any)":"$event"} => ((`,i,") = $event)"]);let d=[Vs(u,e.exp),Vs(c,a)];if(e.modifiers.length&&1===t.tagType){let t=e.modifiers.map(e=>e.content).map(e=>(ll.test(e)?JSON.stringify(e):e)+": true").join(", "),n=o?rl(o)?`${o.content}Modifiers`:Hs([o,' + "Modifiers"']):"modelModifiers";d.push(Vs(n,Us(`{ ${t} }`,!1,e.loc,2)))}return Hu(d)};function Hu(e=[]){return{props:e}}let Wu=new WeakSet,Gu=(e,t)=>{if(1===e.type){let n=ml(e,"memo");if(n&&!Wu.has(e)&&!t.inSSR)return Wu.add(e),()=>{let a=e.codegenNode||t.currentNode.codegenNode;a&&13===a.type&&(1!==e.tagType&&Ys(a,t),e.codegenNode=Ws(t.helper(Is),[n.exp,Gs(void 0,a),"_cache",String(t.cached.length)]),t.cached.push(null))}}},Ku=(e,t)=>{if(1===e.type)for(let n of e.props)if(7===n.type&&"bind"===n.name&&(!n.exp||4===n.exp.type&&!n.exp.content.trim())&&n.arg){let e=n.arg;if(4===e.type&&e.isStatic){let t=B(e.content);(ul.test(t[0])||"-"===t[0])&&(n.exp=Us(t,!1,e.loc))}else t.onError(ol(52,e.loc)),n.exp=Us("",!0,e.loc)}},Yu=Symbol(""),Qu=Symbol(""),Zu=Symbol(""),Ju=Symbol(""),Xu=Symbol(""),ec=Symbol(""),tc=Symbol(""),nc=Symbol(""),ac=Symbol(""),ic=Symbol("");Object.getOwnPropertySymbols(a={[Yu]:"vModelRadio",[Qu]:"vModelCheckbox",[Zu]:"vModelText",[Ju]:"vModelSelect",[Xu]:"vModelDynamic",[ec]:"withModifiers",[tc]:"withKeys",[nc]:"vShow",[ac]:"Transition",[ic]:"TransitionGroup"}).forEach(e=>{Ds[e]=a[e]});let oc={parseMode:"html",isVoidTag:se,isNativeTag:e=>ie(e)||oe(e)||re(e),isPreTag:e=>"pre"===e,isIgnoreNewlineTag:e=>"pre"===e||"textarea"===e,decodeEntities:function(e,t=!1){return f||(f=document.createElement("div")),t?(f.innerHTML=`
`,f.children[0].getAttribute("foo")):(f.innerHTML=e,f.textContent)},isBuiltInComponent:e=>"Transition"===e||"transition"===e?ac:"TransitionGroup"===e||"transition-group"===e?ic:void 0,getNamespace(e,t,n){let a=t?t.ns:n;if(t&&2===a)if("annotation-xml"===t.tag){if("svg"===e)return 1;t.props.some(e=>6===e.type&&"encoding"===e.name&&null!=e.value&&("text/html"===e.value.content||"application/xhtml+xml"===e.value.content))&&(a=0)}else/^m(?:[ions]|text)$/.test(t.tag)&&"mglyph"!==e&&"malignmark"!==e&&(a=0);else t&&1===a&&("foreignObject"===t.tag||"desc"===t.tag||"title"===t.tag)&&(a=0);if(0===a){if("svg"===e)return 1;if("math"===e)return 2}return a}},rc=_("passive,once,capture"),sc=_("stop,prevent,self,ctrl,shift,alt,meta,exact,middle"),lc=_("left,right"),uc=_("onkeyup,onkeydown,onkeypress"),cc=(e,t)=>rl(e)&&"onclick"===e.content.toLowerCase()?Us(t,!0):4!==e.type?Hs(["(",e,`) === "onClick" ? "${t}" : (`,e,")"]):e,dc=(e,t)=>{1===e.type&&0===e.tagType&&("script"===e.tag||"style"===e.tag)&&t.removeNode()},hc=[e=>{1===e.type&&e.props.forEach((t,n)=>{let a,i;6===t.type&&"style"===t.name&&t.value&&(e.props[n]={type:7,name:"bind",arg:Us("style",!0,t.loc),exp:(a=t.value.content,i=t.loc,Us(JSON.stringify(ne(a)),!1,i,3)),modifiers:[],loc:t.loc})})}],pc={cloak:()=>({props:[]}),html:(e,t,n)=>{let{exp:a,loc:i}=e;return a||n.onError(ol(53,i)),t.children.length&&(n.onError(ol(54,i)),t.children.length=0),{props:[Vs(Us("innerHTML",!0,i),a||Us("",!0))]}},text:(e,t,n)=>{let{exp:a,loc:i}=e;return a||n.onError(ol(55,i)),t.children.length&&(n.onError(ol(56,i)),t.children.length=0),{props:[Vs(Us("textContent",!0),a?lu(a,n)>0?a:Ws(n.helperString(ys),[a],i):Us("",!0))]}},model:(e,t,n)=>{let a=Uu(e,t,n);if(!a.props.length||1===t.tagType)return a;e.arg&&n.onError(ol(58,e.arg.loc));let{tag:i}=t,o=n.isCustomElement(i);if("input"===i||"textarea"===i||"select"===i||o){let r=Zu,s=!1;if("input"===i||o){let a=gl(t,"type");if(a){if(7===a.type)r=Xu;else if(a.value)switch(a.value.content){case"radio":r=Yu;break;case"checkbox":r=Qu;break;case"file":s=!0,n.onError(ol(59,e.loc))}}else t.props.some(e=>!(7!==e.type||"bind"!==e.name||e.arg&&4===e.arg.type&&e.arg.isStatic))&&(r=Xu)}else"select"===i&&(r=Ju);s||(a.needRuntime=n.helper(r))}else n.onError(ol(57,e.loc));return a.props=a.props.filter(e=>4!==e.key.type||"modelValue"!==e.key.content),a},on:(e,t,n)=>Du(e,t,n,t=>{let{modifiers:a}=e;if(!a.length)return t;let{key:i,value:o}=t.props[0],{keyModifiers:r,nonKeyModifiers:s,eventOptionModifiers:l}=((e,t)=>{let n=[],a=[],i=[];for(let o=0;o{let{exp:a,loc:i}=e;return a||n.onError(ol(61,i)),{props:[],needRuntime:n.helper(nc)}}},fc=Object.create(null);function mc(e,t){if(!M(e)){if(!e.nodeType)return y;e=e.innerHTML}let n=e+JSON.stringify(t,(e,t)=>"function"==typeof t?t.toString():t),a=fc[n];if(a)return a;if("#"===e[0]){let t=document.querySelector(e);e=t?t.innerHTML:""}let i=S({hoistStatic:!0,onError:void 0,onWarn:y},t);i.isCustomElement||"undefined"==typeof customElements||(i.isCustomElement=e=>!!customElements.get(e));let{code:o}=function(e,t={}){return function(e,t={}){var n;let a,i=t.onError||al,o="module"===t.mode;!0===t.prefixIdentifiers?i(ol(47)):o&&i(ol(48)),t.cacheHandlers&&i(ol(49)),t.scopeId&&!o&&i(ol(50));let r=S({},t,{prefixIdentifiers:!1}),s=M(e)?function(e,t){if(Ul.reset(),Ol=null,Il=null,ql="",Dl=-1,jl=-1,Vl.length=0,Nl=e,Rl=S({},Ll),t){let e;for(e in t)null!=t[e]&&(Rl[e]=t[e])}Ul.mode="html"===Rl.parseMode?1:2*("sfc"===Rl.parseMode),Ul.inXML=1===Rl.ns||2===Rl.ns;let n=t&&t.delimiters;n&&(Ul.delimiterOpen=tl(n[0]),Ul.delimiterClose=tl(n[1]));let a=zl=function(e,t=""){return{type:0,source:t,children:[],helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:js}}(0,e);return Ul.parse(Nl),a.loc=au(0,e.length),a.children=eu(a.children),zl=null,a}(e,r):e,[l,u]=[[Ku,Vu,ku,Gu,Tu,qu,zu,Mu,Fu],{on:Du,bind:ju,model:Uu}];return a=function(e,{filename:t="",prefixIdentifiers:n=!1,hoistStatic:a=!1,hmr:i=!1,cacheHandlers:o=!1,nodeTransforms:r=[],directiveTransforms:s={},transformHoist:l=null,isBuiltInComponent:u=y,isCustomElement:c=y,expressionPlugins:d=[],scopeId:h=null,slotted:p=!0,ssr:f=!1,inSSR:m=!1,ssrCssVars:g="",bindingMetadata:_=v,inline:b=!1,isTS:w=!1,onError:k=al,onWarn:x=il,compatConfig:S}){let C=t.replace(/\?.*$/,"").match(/([^/\\]+)\.\w+$/),T={filename:t,selfName:C&&V(B(C[1])),prefixIdentifiers:n,hoistStatic:a,hmr:i,cacheHandlers:o,nodeTransforms:r,directiveTransforms:s,transformHoist:l,isBuiltInComponent:u,isCustomElement:c,expressionPlugins:d,scopeId:h,slotted:p,ssr:f,inSSR:m,ssrCssVars:g,bindingMetadata:_,inline:b,isTS:w,onError:k,onWarn:x,compatConfig:S,root:e,helpers:new Map,components:new Set,directives:new Set,hoists:[],imports:[],cached:[],constantCache:new WeakMap,temps:0,identifiers:Object.create(null),scopes:{vFor:0,vSlot:0,vPre:0,vOnce:0},parent:null,grandParent:null,currentNode:e,childIndex:0,inVOnce:!1,helper(e){let t=T.helpers.get(e)||0;return T.helpers.set(e,t+1),e},removeHelper(e){let t=T.helpers.get(e);if(t){let n=t-1;n?T.helpers.set(e,n):T.helpers.delete(e)}},helperString:e=>`_${Ds[T.helper(e)]}`,replaceNode(e){T.parent.children[T.childIndex]=T.currentNode=e},removeNode(e){let t=T.parent.children,n=e?t.indexOf(e):T.currentNode?T.childIndex:-1;e&&e!==T.currentNode?T.childIndex>n&&(T.childIndex--,T.onNodeRemoved()):(T.currentNode=null,T.onNodeRemoved()),T.parent.children.splice(n,1)},onNodeRemoved:y,addIdentifiers(e){},removeIdentifiers(e){},hoist(e){M(e)&&(e=Us(e)),T.hoists.push(e);let t=Us(`_hoisted_${T.hoists.length}`,!1,e.loc,2);return t.hoisted=e,t},cache(e,t=!1,n=!1){let a=function(e,t,n=!1,a=!1){return{type:20,index:e,value:t,needPauseTracking:n,inVOnce:a,needArraySpread:!1,loc:js}}(T.cached.length,e,t,n);return T.cached.push(a),a}};return T}(s,n=S({},r,{nodeTransforms:[...l,...t.nodeTransforms||[]],directiveTransforms:S({},u,t.directiveTransforms||{})})),hu(s,a),n.hoistStatic&&function e(t,n,a,i=!1,o=!1){let{children:r}=t,s=[];for(let n=0;n0){if(e>=2){l.codegenNode.patchFlag=-1,s.push(l);continue}}else{let e=l.codegenNode;if(13===e.type){let t=e.patchFlag;if((void 0===t||512===t||1===t)&&cu(l,a)>=2){let t=du(l);t&&(e.props=a.hoist(t))}e.dynamicProps&&(e.dynamicProps=a.hoist(e.dynamicProps))}}}else if(12===l.type&&(i?0:lu(l,a))>=2){14===l.codegenNode.type&&l.codegenNode.arguments.length>0&&l.codegenNode.arguments.push("-1"),s.push(l);continue}if(1===l.type){let n=1===l.tagType;n&&a.scopes.vSlot++,e(l,t,a,!1,o),n&&a.scopes.vSlot--}else if(11===l.type)e(l,t,a,1===l.children.length,!0);else if(9===l.type)for(let n=0;ne.key===t||e.key.content===t);return n&&n.value}}s.length&&a.transformHoist&&a.transformHoist(r,a,t)}(s,void 0,a,!!su(s)),n.ssr||function(e,t){let{helper:n}=t,{children:a}=e;if(1===a.length){let n=su(e);if(n&&n.codegenNode){let a=n.codegenNode;13===a.type&&Ys(a,t),e.codegenNode=a}else e.codegenNode=a[0]}else a.length>1&&(e.codegenNode=Bs(t,n(Xr),void 0,e.children,64,void 0,void 0,!0,void 0,!1))}(s,a),s.helpers=new Set([...a.helpers.keys()]),s.components=[...a.components],s.directives=[...a.directives],s.imports=a.imports,s.hoists=a.hoists,s.temps=a.temps,s.cached=a.cached,s.transformed=!0,function(e,t={}){let n=function(e,{mode:t="function",prefixIdentifiers:n="module"===t,sourceMap:a=!1,filename:i="template.vue.html",scopeId:o=null,optimizeImports:r=!1,runtimeGlobalName:s="Vue",runtimeModuleName:l="vue",ssrRuntimeModuleName:u="vue/server-renderer",ssr:c=!1,isTS:d=!1,inSSR:h=!1}){let p={mode:t,prefixIdentifiers:n,sourceMap:a,filename:i,scopeId:o,optimizeImports:r,runtimeGlobalName:s,runtimeModuleName:l,ssrRuntimeModuleName:u,ssr:c,isTS:d,inSSR:h,source:e.source,code:"",column:1,line:1,offset:0,indentLevel:0,pure:!1,map:void 0,helper:e=>`_${Ds[e]}`,push(e,t=-2,n){p.code+=e},indent(){f(++p.indentLevel)},deindent(e=!1){e?--p.indentLevel:f(--p.indentLevel)},newline(){f(p.indentLevel)}};function f(e){p.push("\n"+" ".repeat(e),0)}return p}(e,t);t.onContextCreated&&t.onContextCreated(n);let{mode:a,push:i,prefixIdentifiers:o,indent:r,deindent:s,newline:l,ssr:u}=n,c=Array.from(e.helpers),d=c.length>0,h=!o&&"module"!==a;if(function(e,t){let{push:n,newline:a,runtimeGlobalName:i}=t,o=Array.from(e.helpers);if(o.length>0&&(n(`const _Vue = ${i}\n`,-1),e.hoists.length)){n(`const { ${[ss,ls,us,cs,ds].filter(e=>o.includes(e)).map(mu).join(", ")} } = _Vue\n`,-1)}(function(e,t){if(!e.length)return;t.pure=!0;let{push:n,newline:a}=t;a();for(let i=0;i0)&&l()),e.directives.length&&(gu(e.directives,"directive",n),e.temps>0&&l()),e.temps>0){i("let ");for(let t=0;t0?", ":""}_temp${t}`)}return(e.components.length||e.directives.length||e.temps)&&(i("\n",0),l()),u||i("return "),e.codegenNode?bu(e.codegenNode,n):i("null"),h&&(s(),i("}")),s(),i("}"),{ast:e,code:n.code,preamble:"",map:n.map?n.map.toJSON():void 0}}(s,r)}(e,S({},oc,t,{nodeTransforms:[dc,...hc,...t.nodeTransforms||[]],directiveTransforms:S({},pc,t.directiveTransforms||{}),transformHoist:null}))}(e,i),r=Function(o)();return r._rc=!0,fc[n]=r}return go(mc),e.BaseTransition=Rn,e.BaseTransitionPropsValidators=An,e.Comment=Ii,e.DeprecationTypes=null,e.EffectScope=me,e.ErrorCodes={SETUP_FUNCTION:0,0:"SETUP_FUNCTION",RENDER_FUNCTION:1,1:"RENDER_FUNCTION",NATIVE_EVENT_HANDLER:5,5:"NATIVE_EVENT_HANDLER",COMPONENT_EVENT_HANDLER:6,6:"COMPONENT_EVENT_HANDLER",VNODE_HOOK:7,7:"VNODE_HOOK",DIRECTIVE_HOOK:8,8:"DIRECTIVE_HOOK",TRANSITION_HOOK:9,9:"TRANSITION_HOOK",APP_ERROR_HANDLER:10,10:"APP_ERROR_HANDLER",APP_WARN_HANDLER:11,11:"APP_WARN_HANDLER",FUNCTION_REF:12,12:"FUNCTION_REF",ASYNC_COMPONENT_LOADER:13,13:"ASYNC_COMPONENT_LOADER",SCHEDULER:14,14:"SCHEDULER",COMPONENT_UPDATE:15,15:"COMPONENT_UPDATE",APP_UNMOUNT_CLEANUP:16,16:"APP_UNMOUNT_CLEANUP"},e.ErrorTypeStrings=null,e.Fragment=Ni,e.KeepAlive={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){let n=uo(),a=n.ctx,i=new Map,o=new Set,r=null,s=n.suspense,{renderer:{p:l,m:u,um:c,o:{createElement:d}}}=a,h=d("div");function p(e){sa(e),c(e,n,s,!0)}function f(e){i.forEach((t,n)=>{let a=wo(t.type);a&&!e(a)&&m(n)})}function m(e){let t=i.get(e);!t||r&&Gi(t,r)?r&&sa(r):p(t),i.delete(e),o.delete(e)}a.activate=(e,t,n,a,i)=>{let o=e.component;u(e,t,n,0,s),l(o.vnode,e,t,n,o,s,a,e.slotScopeIds,i),bi(()=>{o.isDeactivated=!1,o.a&&W(o.a);let t=e.props&&e.props.onVnodeMounted;t&&oo(t,o.parent,e)},s)},a.deactivate=e=>{let t=e.component;Ti(t.m),Ti(t.a),u(e,h,null,1,s),bi(()=>{t.da&&W(t.da);let n=e.props&&e.props.onVnodeUnmounted;n&&oo(n,t.parent,e),t.isDeactivated=!0},s)},Ya(()=>[e.include,e.exclude],([e,t])=>{e&&f(t=>aa(e,t)),t&&f(e=>!aa(t,e))},{flush:"post",deep:!0});let g=null,_=()=>{null!=g&&(Pi(n.subTree.type)?bi(()=>{i.set(g,la(n.subTree))},n.subTree.suspense):i.set(g,la(n.subTree)))};return ha(_),fa(_),ma(()=>{i.forEach(e=>{let{subTree:t,suspense:a}=n,i=la(t);if(e.type===i.type&&e.key===i.key){sa(i);let e=i.component.da;return void(e&&bi(e,a))}p(e)})}),()=>{if(g=null,!t.default)return r=null;let n=t.default(),a=n[0];if(n.length>1)return r=null,n;if(!(Wi(a)&&(4&a.shapeFlag||128&a.shapeFlag)))return r=null,a;let s=la(a);if(s.type===Ii)return r=null,s;let l=s.type,u=wo(ea(s)?s.type.__asyncResolved||{}:l),{include:c,exclude:d,max:h}=e;if(c&&(!u||!aa(c,u))||d&&u&&aa(d,u))return s.shapeFlag&=-257,r=s,a;let p=null==s.key?l:s.key,f=i.get(p);return s.el&&(s=Xi(s),128&a.shapeFlag&&(a.ssContent=s)),g=p,f?(s.el=f.el,s.component=f.component,s.transition&&qn(s,s.transition),s.shapeFlag|=512,o.delete(p),o.add(p)):(o.add(p),h&&o.size>parseInt(h,10)&&m(o.values().next().value)),s.shapeFlag|=256,r=s,Pi(a.type)?a:s}}},e.ReactiveEffect=_e,e.Static=qi,e.Suspense={name:"Suspense",__isSuspense:!0,process(e,t,n,a,i,o,r,s,l,u){if(null==e)!function(e,t,n,a,i,o,r,s,l){let{p:u,o:{createElement:c}}=l,d=c("div"),h=e.suspense=Mi(e,i,a,t,d,n,o,r,s,l);u(null,h.pendingBranch=e.ssContent,d,null,a,h,o,r),h.deps>0?(Ai(e,"onPending"),Ai(e,"onFallback"),u(null,e.ssFallback,t,n,a,null,o,r),zi(h,e.ssFallback)):h.resolve(!1,!0)}(t,n,a,i,o,r,s,l,u);else{if(o&&o.deps>0&&!e.suspense.isInFallback)return t.suspense=e.suspense,t.suspense.vnode=t,void(t.el=e.el);!function(e,t,n,a,i,o,r,s,{p:l,um:u,o:{createElement:c}}){let d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;let h=t.ssContent,p=t.ssFallback,{activeBranch:f,pendingBranch:m,isInFallback:g,isHydrating:_}=d;if(m)d.pendingBranch=h,Gi(m,h)?(l(m,h,d.hiddenContainer,null,i,d,o,r,s),d.deps<=0?d.resolve():g&&!_&&(l(f,p,n,a,i,null,o,r,s),zi(d,p))):(d.pendingId=Ei++,_?(d.isHydrating=!1,d.activeBranch=m):u(m,i,d),d.deps=0,d.effects.length=0,d.hiddenContainer=c("div"),g?(l(null,h,d.hiddenContainer,null,i,d,o,r,s),d.deps<=0?d.resolve():(l(f,p,n,a,i,null,o,r,s),zi(d,p))):f&&Gi(f,h)?(l(f,h,n,a,i,d,o,r,s),d.resolve(!0)):(l(null,h,d.hiddenContainer,null,i,d,o,r,s),d.deps<=0&&d.resolve()));else if(f&&Gi(f,h))l(f,h,n,a,i,d,o,r,s),zi(d,h);else if(Ai(t,"onPending"),d.pendingBranch=h,512&h.shapeFlag?d.pendingId=h.component.suspenseId:d.pendingId=Ei++,l(null,h,d.hiddenContainer,null,i,d,o,r,s),d.deps<=0)d.resolve();else{let{timeout:e,pendingId:t}=d;e>0?setTimeout(()=>{d.pendingId===t&&d.fallback(p)},e):0===e&&d.fallback(p)}}(e,t,n,a,i,r,s,l,u)}},hydrate:function(e,t,n,a,i,o,r,s,l){let u=t.suspense=Mi(t,a,n,e.parentNode,document.createElement("div"),null,i,o,r,s,!0),c=l(e,u.pendingBranch=t.ssContent,n,u,o,r);return 0===u.deps&&u.resolve(!1,!0),c},normalize:function(e){let{shapeFlag:t,children:n}=e,a=32&t;e.ssContent=Li(a?n.default:n),e.ssFallback=a?Li(n.fallback):Zi(Ii)}},e.Teleport=wn,e.Text=Oi,e.TrackOpTypes={GET:"get",HAS:"has",ITERATE:"iterate"},e.Transition=Io,e.TransitionGroup=Sr,e.TriggerOpTypes={SET:"set",ADD:"add",DELETE:"delete",CLEAR:"clear"},e.VueElement=vr,e.assertNumber=function(e,t){},e.callWithAsyncErrorHandling=Gt,e.callWithErrorHandling=Wt,e.camelize=B,e.capitalize=V,e.cloneVNode=Xi,e.compatUtils=null,e.compile=mc,e.computed=ko,e.createApp=Yr,e.createBlock=Hi,e.createCommentVNode=function(e="",t=!1){return t?(Bi(),Hi(Ii,null,e)):Zi(Ii,null,e)},e.createElementBlock=function(e,t,n,a,i,o){return Ui(Qi(e,t,n,a,i,o,!0))},e.createElementVNode=Qi,e.createHydrationRenderer=yi,e.createPropsRestProxy=function(e,t){let n={};for(let a in e)t.includes(a)||Object.defineProperty(n,a,{enumerable:!0,get:()=>e[a]});return n},e.createRenderer=function(e){return wi(e)},e.createSSRApp=Qr,e.createSlots=function(e,t){for(let n=0;n{let t=a.fn(...e);return t&&(t.key=a.key),t}:a.fn)}return e},e.createStaticVNode=function(e,t){let n=Zi(qi,null,e);return n.staticCount=t,n},e.createTextVNode=eo,e.createVNode=Zi,e.customRef=Dt,e.defineAsyncComponent=function(e){let t;A(e)&&(e={loader:e});let{loader:n,loadingComponent:a,errorComponent:i,delay:o=200,hydrate:r,timeout:s,suspensible:l=!0,onError:u}=e,c=null,d=0,h=()=>{let e;return c||(e=c=n().catch(e=>{if(e=e instanceof Error?e:Error(String(e)),u)return new Promise((t,n)=>{u(e,()=>t((d++,c=null,h())),()=>n(e),d+1)});throw e}).then(n=>e!==c&&c?c:(n&&(n.__esModule||"Module"===n[Symbol.toStringTag])&&(n=n.default),t=n,n)))};return jn({name:"AsyncComponentWrapper",__asyncLoader:h,__asyncHydrate(e,n,a){let i=!1;(n.bu||(n.bu=[])).push(()=>i=!0);let o=()=>{i||a()},s=r?()=>{let t=r(o,t=>function(e,t){if(Gn(e)&&"["===e.data){let n=1,a=e.nextSibling;for(;a;){if(1===a.nodeType){if(!1===t(a))break}else if(Gn(a))if("]"===a.data){if(0==--n)break}else"["===a.data&&n++;a=a.nextSibling}}else t(e)}(e,t));t&&(n.bum||(n.bum=[])).push(t)}:o;t?s():h().then(()=>!n.isUnmounted&&s())},get __asyncResolved(){return t},setup(){let e=lo;if(Bn(e),t)return()=>ta(t,e);let n=t=>{c=null,Kt(t,e,13,!i)};if(l&&e.suspense)return h().then(t=>()=>ta(t,e)).catch(e=>(n(e),()=>i?Zi(i,{error:e}):null));let r=Mt(!1),u=Mt(),d=Mt(!!o);return o&&setTimeout(()=>{d.value=!1},o),null!=s&&setTimeout(()=>{if(!r.value&&!u.value){let e=Error(`Async component timed out after ${s}ms.`);n(e),u.value=e}},s),h().then(()=>{r.value=!0,e.parent&&na(e.parent.vnode)&&e.parent.update()}).catch(e=>{n(e),u.value=e}),()=>r.value&&t?ta(t,e):u.value&&i?Zi(i,{error:u.value}):a&&!d.value?ta(a,e):void 0}})},e.defineComponent=jn,e.defineCustomElement=gr,e.defineEmits=function(){return null},e.defineExpose=function(e){},e.defineModel=function(){},e.defineOptions=function(e){},e.defineProps=function(){return null},e.defineSSRCustomElement=(e,t)=>gr(e,t,Qr),e.defineSlots=function(){return null},e.devtools=void 0,e.effect=function(e,t){e.effect instanceof _e&&(e=e.effect.fn);let n=new _e(e);t&&S(n,t);try{n.run()}catch(e){throw n.stop(),e}let a=n.run.bind(n);return a.effect=n,a},e.effectScope=function(e){return new me(e)},e.getCurrentInstance=uo,e.getCurrentScope=function(){return o},e.getCurrentWatcher=function(){return m},e.getTransitionRawChildren=Dn,e.guardReactiveProps=Ji,e.h=xo,e.handleError=Kt,e.hasInjectionContext=function(){return!(!uo()&&!Ua)},e.hydrate=(...e)=>{Gr().hydrate(...e)},e.hydrateOnIdle=(e=1e4)=>t=>{let n=Jn(t,{timeout:e});return()=>Xn(n)},e.hydrateOnInteraction=(e=[])=>(t,n)=>{M(e)&&(e=[e]);let a=!1,i=e=>{a||(a=!0,o(),t(),e.target.dispatchEvent(new e.constructor(e.type,e)))},o=()=>{n(t=>{for(let n of e)t.removeEventListener(n,i)})};return n(t=>{for(let n of e)t.addEventListener(n,i,{once:!0})}),o},e.hydrateOnMediaQuery=e=>t=>{if(e){let n=matchMedia(e);if(!n.matches)return n.addEventListener("change",t,{once:!0}),()=>n.removeEventListener("change",t);t()}},e.hydrateOnVisible=e=>(t,n)=>{let a=new IntersectionObserver(e=>{for(let n of e)if(n.isIntersecting){a.disconnect(),t();break}},e);return n(e=>{if(e instanceof Element){if(function(e){let{top:t,left:n,bottom:a,right:i}=e.getBoundingClientRect(),{innerHeight:o,innerWidth:r}=window;return(t>0&&t0&&a0&&n0&&ia.disconnect()},e.initCustomFormatter=function(){},e.initDirectivesForSSR=y,e.inject=Wa,e.isMemoSame=So,e.isProxy=St,e.isReactive=wt,e.isReadonly=kt,e.isRef=At,e.isRuntimeOnly=()=>!d,e.isShallow=xt,e.isVNode=Wi,e.markRaw=Tt,e.mergeDefaults=function(e,t){let n=La(e);for(let e in t){if(e.startsWith("__skip"))continue;let a=n[e];a?E(a)||A(a)?a=n[e]={type:a,default:t[e]}:a.default=t[e]:null===a&&(a=n[e]={default:t[e]}),a&&t[`__skip_${e}`]&&(a.skipFactory=!0)}return n},e.mergeModels=function(e,t){return e&&t?E(e)&&E(t)?e.concat(t):S({},La(e),La(t)):e||t},e.mergeProps=io,e.nextTick=nn,e.nodeOps=Mo,e.normalizeClass=ae,e.normalizeProps=function(e){if(!e)return null;let{class:t,style:n}=e;return t&&!M(t)&&(e.class=ae(t)),n&&(e.style=J(n)),e},e.normalizeStyle=J,e.onActivated=ia,e.onBeforeMount=da,e.onBeforeUnmount=ma,e.onBeforeUpdate=pa,e.onDeactivated=oa,e.onErrorCaptured=ya,e.onMounted=ha,e.onRenderTracked=ba,e.onRenderTriggered=va,e.onScopeDispose=function(e,t=!1){o&&o.cleanups.push(e)},e.onServerPrefetch=_a,e.onUnmounted=ga,e.onUpdated=fa,e.onWatcherCleanup=Ut,e.openBlock=Bi,e.patchProp=fr,e.popScopeId=function(){dn=null},e.provide=Ha,e.proxyRefs=It,e.pushScopeId=function(e){dn=e},e.queuePostFlushCb=rn,e.reactive=_t,e.readonly=bt,e.ref=Mt,e.registerRuntimeCompiler=go,e.render=Kr,e.renderList=function(e,t,n,a){let i,o=n&&n[a],r=E(e);if(r||M(e)){let n=!1,a=!1;r&&wt(e)&&(n=!xt(e),a=kt(e),e=Fe(e)),i=Array(e.length);for(let r=0,s=e.length;rt(e,n,void 0,o&&o[n]));else{let n=Object.keys(e);i=Array(n.length);for(let a=0,r=n.length;a0;return"default"!==t&&(n.name=t),Bi(),Hi(Ni,null,[Zi("slot",n,a&&a())],e?-2:64)}let o=e[t];o&&o._c&&(o._d=!1),Bi();let r=o&&function e(t){return t.some(t=>!Wi(t)||t.type!==Ii&&(t.type!==Ni||!!e(t.children)))?t:null}(o(n)),s=n.key||r&&r.key,l=Hi(Ni,{key:(s&&!L(s)?s:`_${t}`)+(!r&&a?"_fb":"")},r||(a?a():[]),r&&1===e._?64:-2);return!i&&l.scopeId&&(l.slotScopeIds=[l.scopeId+"-s"]),o&&o._c&&(o._d=!0),l},e.resolveComponent=function(e,t){return xa(wa,e,!0,t)||e},e.resolveDirective=function(e){return xa("directives",e)},e.resolveDynamicComponent=function(e){return M(e)?xa(wa,e,!1)||e:e||ka},e.resolveFilter=null,e.resolveTransitionHooks=Nn,e.setBlockTracking=Vi,e.setDevtoolsHook=y,e.setTransitionHooks=qn,e.shallowReactive=vt,e.shallowReadonly=function(e){return yt(e,!0,ot,ht,gt)},e.shallowRef=Lt,e.ssrContextKey=Ga,e.ssrUtils=null,e.stop=function(e){e.effect.stop()},e.toDisplayString=he,e.toHandlerKey=U,e.toHandlers=function(e,t){let n={};for(let a in e)n[t&&/[A-Z]/.test(a)?`on:${a}`:U(a)]=e[a];return n},e.toRaw=Ct,e.toRef=function(e,t,n){return At(e)?e:A(e)?new Bt(e):R(e)&&arguments.length>1?new jt(e,t,n):Mt(e)},e.toRefs=function(e){let t=E(e)?Array(e.length):{};for(let n in e)t[n]=new jt(e,n,void 0);return t},e.toValue=function(e){return A(e)?e():Nt(e)},e.transformVNodeArgs=function(e){},e.triggerRef=function(e){e.dep&&e.dep.trigger()},e.unref=Nt,e.useAttrs=function(){return Ma().attrs},e.useCssModule=function(e="$style"){return v},e.useCssVars=function(e){let t=uo();if(!t)return;let n=t.ut=(n=e(t.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${t.uid}"]`)).forEach(e=>Xo(e,n))},a=()=>{let a=e(t.proxy);t.ce?Xo(t.ce,a):function e(t,n){if(128&t.shapeFlag){let a=t.suspense;t=a.activeBranch,a.pendingBranch&&!a.isHydrating&&a.effects.push(()=>{e(a.activeBranch,n)})}for(;t.component;)t=t.component.subTree;if(1&t.shapeFlag&&t.el)Xo(t.el,n);else if(t.type===Ni)t.children.forEach(t=>e(t,n));else if(t.type===qi){let{el:e,anchor:a}=t;for(;e&&(Xo(e,n),e!==a);)e=e.nextSibling}}(t.subTree,a),n(a)};pa(()=>{rn(a)}),ha(()=>{Ya(a,y,{flush:"post"});let e=new MutationObserver(a);e.observe(t.subTree.el.parentNode,{childList:!0}),ga(()=>e.disconnect())})},e.useHost=br,e.useId=function(){let e=uo();return e?(e.appContext.config.idPrefix||"v")+"-"+e.ids[0]+e.ids[1]++:""},e.useModel=function(e,t,n=v){let a=uo(),i=B(t),o=$(t),r=Ja(e,i),s=Dt((r,s)=>{let l,u,c=v;return Ka(()=>{let t=e[i];H(l,t)&&(l=t,s())}),{get:()=>(r(),n.get?n.get(l):l),set(e){let r=n.set?n.set(e):e;if(!(H(r,l)||c!==v&&H(e,c)))return;let d=a.vnode.props;d&&(t in d||i in d||o in d)&&(`onUpdate:${t}`in d||`onUpdate:${i}`in d||`onUpdate:${o}`in d)||(l=e,s()),a.emit(`update:${t}`,r),H(e,r)&&H(e,c)&&!H(r,u)&&s(),c=e,u=r}}});return s[Symbol.iterator]=()=>{let e=0;return{next:()=>e<2?{value:e++?r||v:s,done:!1}:{done:!0}}},s},e.useSSRContext=()=>{},e.useShadowRoot=function(){let e=br();return e&&e.shadowRoot},e.useSlots=function(){return Ma().slots},e.useTemplateRef=function(e){let t=uo(),n=Lt(null);return t&&Object.defineProperty(t.refs===v?t.refs={}:t.refs,e,{enumerable:!0,get:()=>n.value,set:e=>n.value=e}),n},e.useTransitionState=Pn,e.vModelCheckbox=Nr,e.vModelDynamic={created(e,t,n){Fr(e,t,n,null,"created")},mounted(e,t,n){Fr(e,t,n,null,"mounted")},beforeUpdate(e,t,n,a){Fr(e,t,n,a,"beforeUpdate")},updated(e,t,n,a){Fr(e,t,n,a,"updated")}},e.vModelRadio=Ir,e.vModelSelect=qr,e.vModelText=zr,e.vShow={name:"show",beforeMount(e,{value:t},{transition:n}){e[Yo]="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):Zo(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:a}){!t!=!n&&(a?t?(a.beforeEnter(e),Zo(e,!0),a.enter(e)):a.leave(e,()=>{Zo(e,!1)}):Zo(e,t))},beforeUnmount(e,{value:t}){Zo(e,t)}},e.version=Co,e.warn=y,e.watch=function(e,t,n){return Ya(e,t,n)},e.watchEffect=function(e,t){return Ya(e,null,t)},e.watchPostEffect=function(e,t){return Ya(e,null,{flush:"post"})},e.watchSyncEffect=Ka,e.withAsyncContext=function(e){let t=uo(),n=e();return ho(),z(n)&&(n=n.catch(e=>{throw co(t),e})),[n,()=>co(t)]},e.withCtx=pn,e.withDefaults=function(e,t){return null},e.withDirectives=function(e,t){if(null===cn)return e;let n=yo(cn),a=e.dirs||(e.dirs=[]);for(let e=0;e{let n=e._withKeys||(e._withKeys={}),a=t.join(".");return n[a]||(n[a]=n=>{if(!("key"in n))return;let a=$(n.key);return t.some(e=>e===a||Ur[e]===a)?e(n):void 0})},e.withMemo=function(e,t,n,a){let i=n[a];if(i&&So(i,e))return i;let o=t();return o.memo=e.slice(),o.cacheIndex=a,n[a]=o},e.withModifiers=(e,t)=>{let n=e._withMods||(e._withMods={}),a=t.join(".");return n[a]||(n[a]=(n,...a)=>{for(let e=0;epn,e}({}); +var Vue=function(e){"use strict";var t,n,a;let i,r,o,s,l,u,c,d,h,p,f,m,_;function g(e){let t=Object.create(null);for(let n of e.split(","))t[n]=1;return e=>e in t}let v={},b=[],y=()=>{},w=()=>!1,k=e=>111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&(e.charCodeAt(2)>122||97>e.charCodeAt(2)),x=e=>e.startsWith("onUpdate:"),S=Object.assign,C=(e,t)=>{let n=e.indexOf(t);n>-1&&e.splice(n,1)},T=Object.prototype.hasOwnProperty,P=(e,t)=>T.call(e,t),E=Array.isArray,A=e=>"function"==typeof e,L=e=>"string"==typeof e,M=e=>"symbol"==typeof e,R=e=>null!==e&&"object"==typeof e,z=e=>(R(e)||A(e))&&A(e.then)&&A(e.catch),I=Object.prototype.toString,N=e=>L(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,O=g(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),j=g("bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo"),D=e=>{let t=Object.create(null);return n=>t[n]||(t[n]=e(n))},q=/-\w/g,B=D(e=>e.replace(q,e=>e.slice(1).toUpperCase())),F=/\B([A-Z])/g,V=D(e=>e.replace(F,"-$1").toLowerCase()),U=D(e=>e.charAt(0).toUpperCase()+e.slice(1)),$=D(e=>e?`on${U(e)}`:""),H=(e,t)=>!Object.is(e,t),W=(e,...t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:a,value:n})},K=e=>{let t=parseFloat(e);return isNaN(t)?e:t},Y=e=>{let t=L(e)?Number(e):NaN;return isNaN(t)?e:t},Q=()=>i||(i="u">typeof globalThis?globalThis:"u">typeof self?self:"u">typeof window?window:"u">typeof global?global:{}),Z=g("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol");function J(e){if(E(e)){let t={};for(let n=0;n{if(e){let n=e.split(ee);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function ae(e){let t="";if(L(e))t=e;else if(E(e))for(let n=0;nue(e,t))}let de=e=>!(!e||!0!==e.__v_isRef),he=e=>L(e)?e:null==e?"":E(e)||R(e)&&(e.toString===I||!A(e.toString))?de(e)?he(e.value):JSON.stringify(e,pe,2):String(e),pe=(e,t)=>{let n;if(de(t))return pe(e,t.value);if("[object Map]"===(n=t,I.call(n)))return{[`Map(${t.size})`]:[...t.entries()].reduce((e,[t,n],a)=>(e[fe(t,a)+" =>"]=n,e),{})};{let e;if("[object Set]"===(e=t,I.call(e)))return{[`Set(${t.size})`]:[...t.values()].map(e=>fe(e))};{if(M(t))return fe(t);let e;if(R(t)&&!E(t)&&"[object Object]"!==(e=t,I.call(e)))return String(t)}}return t},fe=(e,t="")=>{var n;return M(e)?`Symbol(${null!=(n=e.description)?n:t})`:e};class me{constructor(e=!1){this.detached=e,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!e&&r&&(r.active?(this.parent=r,this.index=(r.scopes||(r.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){let e,t;if(this._isPaused=!0,this.scopes)for(e=0,t=this.scopes.length;e0&&0==--this._on){if(r===this)r=this.prevScope;else{let e=r;for(;e;){if(e.prevScope===this){e.prevScope=this.prevScope;break}e=e.prevScope}}this.prevScope=void 0}}stop(e){if(this._active){let t,n;for(this._active=!1,t=0,n=this.effects.length;t0)){if(l){let e=l;for(l=void 0;e;){let t=e.next;e.next=void 0,e.flags&=-9,e=t}}for(;s;){let t=s;for(s=void 0;t;){let n=t.next;if(t.next=void 0,t.flags&=-9,1&t.flags)try{t.trigger()}catch(t){e||(e=t)}t=n}}if(e)throw e}}function we(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function ke(e){let t,n=e.depsTail,a=n;for(;a;){let e=a.prevDep;-1===a.version?(a===n&&(n=e),Ce(a),function(e){let{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}(a)):t=a,a.dep.activeLink=a.prevActiveLink,a.prevActiveLink=void 0,a=e}e.deps=t,e.depsTail=n}function xe(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Se(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Se(e){if(4&e.flags&&!(16&e.flags)||(e.flags&=-17,e.globalVersion===Me)||(e.globalVersion=Me,!e.isSSR&&128&e.flags&&(!e.deps&&!e._dirty||!xe(e))))return;e.flags|=2;let t=e.dep,n=o,a=Te;o=e,Te=!0;try{we(e);let n=e.fn(e._value);(0===t.version||H(n,e._value))&&(e.flags|=128,e._value=n,t.version++)}catch(e){throw t.version++,e}finally{o=n,Te=a,ke(e),e.flags&=-3}}function Ce(e,t=!1){let{dep:n,prevSub:a,nextSub:i}=e;if(a&&(a.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=a,e.nextSub=void 0),n.subs===e&&(n.subs=a,!a&&n.computed)){n.computed.flags&=-5;for(let e=n.computed.deps;e;e=e.nextDep)Ce(e,!0)}t||--n.sc||!n.map||n.map.delete(n.key)}let Te=!0,Pe=[];function Ee(){Pe.push(Te),Te=!1}function Ae(){let e=Pe.pop();Te=void 0===e||e}function Le(e){let{cleanup:t}=e;if(e.cleanup=void 0,t){let e=o;o=void 0;try{t()}finally{o=e}}}let Me=0;class Re{constructor(e,t){this.sub=e,this.dep=t,this.version=t.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class ze{constructor(e){this.computed=e,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(e){if(!o||!Te||o===this.computed)return;let t=this.activeLink;if(void 0===t||t.sub!==o)t=this.activeLink=new Re(o,this),o.deps?(t.prevDep=o.depsTail,o.depsTail.nextDep=t,o.depsTail=t):o.deps=o.depsTail=t,function e(t){if(t.dep.sc++,4&t.sub.flags){let n=t.dep.computed;if(n&&!t.dep.subs){n.flags|=20;for(let t=n.deps;t;t=t.nextDep)e(t)}let a=t.dep.subs;a!==t&&(t.prevSub=a,a&&(a.nextSub=t)),t.dep.subs=t}}(t);else if(-1===t.version&&(t.version=this.version,t.nextDep)){let e=t.nextDep;e.prevDep=t.prevDep,t.prevDep&&(t.prevDep.nextDep=e),t.prevDep=o.depsTail,t.nextDep=void 0,o.depsTail.nextDep=t,o.depsTail=t,o.deps===t&&(o.deps=e)}return t}trigger(e){this.version++,Me++,this.notify(e)}notify(e){ve++;try{for(let e=this.subs;e;e=e.prevSub)e.sub.notify()&&e.sub.dep.notify()}finally{ye()}}}let Ie=new WeakMap,Ne=Symbol(""),Oe=Symbol(""),je=Symbol("");function De(e,t,n){if(Te&&o){let t=Ie.get(e);t||Ie.set(e,t=new Map);let a=t.get(n);a||(t.set(n,a=new ze),a.map=t,a.key=n),a.track()}}function qe(e,t,n,a,i,r){let o=Ie.get(e);if(!o)return void Me++;let s=e=>{e&&e.trigger()};if(ve++,"clear"===t)o.forEach(s);else{let i=E(e),r=i&&N(n);if(i&&"length"===n){let e=Number(a);o.forEach((t,n)=>{("length"===n||n===je||!M(n)&&n>=e)&&s(t)})}else switch((void 0!==n||o.has(void 0))&&s(o.get(n)),r&&s(o.get(je)),t){case"add":if(i)r&&s(o.get("length"));else{let t;s(o.get(Ne)),"[object Map]"===(t=e,I.call(t))&&s(o.get(Oe))}break;case"delete":if(!i){let t;s(o.get(Ne)),"[object Map]"===(t=e,I.call(t))&&s(o.get(Oe))}break;case"set":let t;"[object Map]"===(t=e,I.call(t))&&s(o.get(Ne))}}ye()}function Be(e){let t=Ct(e);return t===e?t:(De(t,0,je),xt(e)?t:t.map(Pt))}function Fe(e){return De(e=Ct(e),0,je),e}function Ve(e,t){return kt(e)?wt(e)?Et(Pt(t)):Et(t):Pt(t)}let Ue={__proto__:null,[Symbol.iterator](){return $e(this,Symbol.iterator,e=>Ve(this,e))},concat(...e){return Be(this).concat(...e.map(e=>E(e)?Be(e):e))},entries(){return $e(this,"entries",e=>(e[1]=Ve(this,e[1]),e))},every(e,t){return We(this,"every",e,t,void 0,arguments)},filter(e,t){return We(this,"filter",e,t,e=>e.map(e=>Ve(this,e)),arguments)},find(e,t){return We(this,"find",e,t,e=>Ve(this,e),arguments)},findIndex(e,t){return We(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return We(this,"findLast",e,t,e=>Ve(this,e),arguments)},findLastIndex(e,t){return We(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return We(this,"forEach",e,t,void 0,arguments)},includes(...e){return Ke(this,"includes",e)},indexOf(...e){return Ke(this,"indexOf",e)},join(e){return Be(this).join(e)},lastIndexOf(...e){return Ke(this,"lastIndexOf",e)},map(e,t){return We(this,"map",e,t,void 0,arguments)},pop(){return Ye(this,"pop")},push(...e){return Ye(this,"push",e)},reduce(e,...t){return Ge(this,"reduce",e,t)},reduceRight(e,...t){return Ge(this,"reduceRight",e,t)},shift(){return Ye(this,"shift")},some(e,t){return We(this,"some",e,t,void 0,arguments)},splice(...e){return Ye(this,"splice",e)},toReversed(){return Be(this).toReversed()},toSorted(e){return Be(this).toSorted(e)},toSpliced(...e){return Be(this).toSpliced(...e)},unshift(...e){return Ye(this,"unshift",e)},values(){return $e(this,"values",e=>Ve(this,e))}};function $e(e,t,n){let a=Fe(e),i=a[t]();return a===e||xt(e)||(i._next=i.next,i.next=()=>{let e=i._next();return e.done||(e.value=n(e.value)),e}),i}let He=Array.prototype;function We(e,t,n,a,i,r){let o=Fe(e),s=o!==e&&!xt(e),l=o[t];if(l!==He[t]){let t=l.apply(e,r);return s?Pt(t):t}let u=n;o!==e&&(s?u=function(t,a){return n.call(this,Ve(e,t),a,e)}:n.length>2&&(u=function(t,a){return n.call(this,t,a,e)}));let c=l.call(o,u,a);return s&&i?i(c):c}function Ge(e,t,n,a){let i=Fe(e),r=i!==e&&!xt(e),o=n,s=!1;i!==e&&(r?(s=0===a.length,o=function(t,a,i){return s&&(s=!1,t=Ve(e,t)),n.call(this,t,Ve(e,a),i,e)}):n.length>3&&(o=function(t,a,i){return n.call(this,t,a,i,e)}));let l=i[t](o,...a);return s?Ve(e,l):l}function Ke(e,t,n){let a=Ct(e);De(a,0,je);let i=a[t](...n);return-1!==i&&!1!==i||!St(n[0])?i:(n[0]=Ct(n[0]),a[t](...n))}function Ye(e,t,n=[]){Ee(),ve++;let a=Ct(e)[t].apply(e,n);return ye(),Ae(),a}let Qe=g("__proto__,__v_isRef,__isVue"),Ze=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>"arguments"!==e&&"caller"!==e).map(e=>Symbol[e]).filter(M));function Je(e){M(e)||(e=String(e));let t=Ct(this);return De(t,0,e),t.hasOwnProperty(e)}class Xe{constructor(e=!1,t=!1){this._isReadonly=e,this._isShallow=t}get(e,t,n){if("__v_skip"===t)return e.__v_skip;let a=this._isReadonly,i=this._isShallow;if("__v_isReactive"===t)return!a;if("__v_isReadonly"===t)return a;if("__v_isShallow"===t)return i;if("__v_raw"===t)return n===(a?i?_t:mt:i?ft:pt).get(e)||Object.getPrototypeOf(e)===Object.getPrototypeOf(n)?e:void 0;let r=E(e);if(!a){let e;if(r&&(e=Ue[t]))return e;if("hasOwnProperty"===t)return Je}let o=Reflect.get(e,t,At(e)?e:n);if((M(t)?Ze.has(t):Qe(t))||(a||De(e,0,t),i))return o;if(At(o)){let e=r&&N(t)?o:o.value;return a&&R(e)?bt(e):e}return R(o)?a?bt(o):gt(o):o}}class et extends Xe{constructor(e=!1){super(!1,e)}set(e,t,n,a){let i=e[t],r=E(e)&&N(t);if(!this._isShallow){let e=kt(i);if(xt(n)||kt(n)||(i=Ct(i),n=Ct(n)),!r&&At(i)&&!At(n))return e||(i.value=n),!0}let o=r?Number(t)e;function st(e){return function(){return"delete"!==e&&("clear"===e?void 0:this)}}function lt(e,t){let n,a=(S(n={get(n){let a=this.__v_raw,i=Ct(a),r=Ct(n);e||(H(n,r)&&De(i,0,n),De(i,0,r));let{has:o}=Reflect.getPrototypeOf(i),s=t?ot:e?Et:Pt;return o.call(i,n)?s(a.get(n)):o.call(i,r)?s(a.get(r)):void(a!==i&&a.get(n))},get size(){let t=this.__v_raw;return e||De(Ct(t),0,Ne),t.size},has(t){let n=this.__v_raw,a=Ct(n),i=Ct(t);return e||(H(t,i)&&De(a,0,t),De(a,0,i)),t===i?n.has(t):n.has(t)||n.has(i)},forEach(n,a){let i=this,r=i.__v_raw,o=Ct(r),s=t?ot:e?Et:Pt;return e||De(o,0,Ne),r.forEach((e,t)=>n.call(a,s(e),s(t),i))}},e?{add:st("add"),set:st("set"),delete:st("delete"),clear:st("clear")}:{add(e){let n=Ct(this),a=Reflect.getPrototypeOf(n),i=Ct(e),r=t||xt(e)||kt(e)?e:i;return a.has.call(n,r)||H(e,r)&&a.has.call(n,e)||H(i,r)&&a.has.call(n,i)||(n.add(r),qe(n,"add",r,r)),this},set(e,n){t||xt(n)||kt(n)||(n=Ct(n));let a=Ct(this),{has:i,get:r}=Reflect.getPrototypeOf(a),o=i.call(a,e);o||(e=Ct(e),o=i.call(a,e));let s=r.call(a,e);return a.set(e,n),o?H(n,s)&&qe(a,"set",e,n):qe(a,"add",e,n),this},delete(e){let t=Ct(this),{has:n,get:a}=Reflect.getPrototypeOf(t),i=n.call(t,e);i||(e=Ct(e),i=n.call(t,e)),a&&a.call(t,e);let r=t.delete(e);return i&&qe(t,"delete",e,void 0),r},clear(){let e=Ct(this),t=0!==e.size,n=e.clear();return t&&qe(e,"clear",void 0,void 0),n}}),["keys","values","entries",Symbol.iterator].forEach(a=>{n[a]=function(...n){let i,r=this.__v_raw,o=Ct(r),s="[object Map]"===(i=o,I.call(i)),l="entries"===a||a===Symbol.iterator&&s,u=r[a](...n),c=t?ot:e?Et:Pt;return e||De(o,0,"keys"===a&&s?Oe:Ne),S(Object.create(u),{next(){let{value:e,done:t}=u.next();return t?{value:e,done:t}:{value:l?[c(e[0]),c(e[1])]:c(e),done:t}}})}}),n);return(t,n,i)=>"__v_isReactive"===n?!e:"__v_isReadonly"===n?e:"__v_raw"===n?t:Reflect.get(P(a,n)&&n in t?a:t,n,i)}let ut={get:lt(!1,!1)},ct={get:lt(!1,!0)},dt={get:lt(!0,!1)},ht={get:lt(!0,!0)},pt=new WeakMap,ft=new WeakMap,mt=new WeakMap,_t=new WeakMap;function gt(e){return kt(e)?e:yt(e,!1,nt,ut,pt)}function vt(e){return yt(e,!1,it,ct,ft)}function bt(e){return yt(e,!0,at,dt,mt)}function yt(e,t,n,a,i){var r;let o;if(!R(e)||e.__v_raw&&(!t||!e.__v_isReactive))return e;let s=(r=e).__v_skip||!Object.isExtensible(r)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((o=r,I.call(o)).slice(8,-1));if(0===s)return e;let l=i.get(e);if(l)return l;let u=new Proxy(e,2===s?a:n);return i.set(e,u),u}function wt(e){return kt(e)?wt(e.__v_raw):!(!e||!e.__v_isReactive)}function kt(e){return!(!e||!e.__v_isReadonly)}function xt(e){return!(!e||!e.__v_isShallow)}function St(e){return!!e&&!!e.__v_raw}function Ct(e){let t=e&&e.__v_raw;return t?Ct(t):e}function Tt(e){return!P(e,"__v_skip")&&Object.isExtensible(e)&&G(e,"__v_skip",!0),e}let Pt=e=>R(e)?gt(e):e,Et=e=>R(e)?bt(e):e;function At(e){return!!e&&!0===e.__v_isRef}function Lt(e){return Rt(e,!1)}function Mt(e){return Rt(e,!0)}function Rt(e,t){return At(e)?e:new zt(e,t)}class zt{constructor(e,t){this.dep=new ze,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=t?e:Ct(e),this._value=t?e:Pt(e),this.__v_isShallow=t}get value(){return this.dep.track(),this._value}set value(e){let t=this._rawValue,n=this.__v_isShallow||xt(e)||kt(e);H(e=n?e:Ct(e),t)&&(this._rawValue=e,this._value=n?e:Pt(e),this.dep.trigger())}}function It(e){return At(e)?e.value:e}let Nt={get:(e,t,n)=>"__v_raw"===t?e:It(Reflect.get(e,t,n)),set:(e,t,n,a)=>{let i=e[t];return At(i)&&!At(n)?(i.value=n,!0):Reflect.set(e,t,n,a)}};function Ot(e){return wt(e)?e:new Proxy(e,Nt)}class jt{constructor(e){this.__v_isRef=!0,this._value=void 0;const t=this.dep=new ze,{get:n,set:a}=e(t.track.bind(t),t.trigger.bind(t));this._get=n,this._set=a}get value(){return this._value=this._get()}set value(e){this._set(e)}}function Dt(e){return new jt(e)}class qt{constructor(e,t,n){this._object=e,this._defaultValue=n,this.__v_isRef=!0,this._value=void 0,this._key=M(t)?t:String(t),this._raw=Ct(e);let a=!0,i=e;if(!E(e)||M(this._key)||!N(this._key))do{a=!St(i)||xt(i)}while(a&&(i=i.__v_raw));this._shallow=a}get value(){let e=this._object[this._key];return this._shallow&&(e=It(e)),this._value=void 0===e?this._defaultValue:e}set value(e){if(this._shallow&&At(this._raw[this._key])){let t=this._object[this._key];if(At(t))return void(t.value=e)}this._object[this._key]=e}get dep(){var e,t;let n;return e=this._raw,t=this._key,(n=Ie.get(e))&&n.get(t)}}class Bt{constructor(e){this._getter=e,this.__v_isRef=!0,this.__v_isReadonly=!0,this._value=void 0}get value(){return this._value=this._getter()}}class Ft{constructor(e,t,n){this.fn=e,this.setter=t,this._value=void 0,this.dep=new ze(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=Me-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!t,this.isSSR=n}notify(){if(this.flags|=16,!(8&this.flags)&&o!==this)return be(this,!0),!0}get value(){let e=this.dep.track();return Se(this),e&&(e.version=this.dep.version),this._value}set value(e){this.setter&&this.setter(e)}}let Vt={},Ut=new WeakMap;function $t(e,t=!1,n=m){if(n){let t=Ut.get(n);t||Ut.set(n,t=[]),t.push(e)}}function Ht(e,t=1/0,n){if(t<=0||!R(e)||e.__v_skip||((n=n||new Map).get(e)||0)>=t)return e;if(n.set(e,t),t--,At(e))Ht(e.value,t,n);else if(E(e))for(let a=0;a{Ht(e,t,n)});else{let a;if("[object Object]"===(a=e,I.call(a))){for(let a in e)Ht(e[a],t,n);for(let a of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,a)&&Ht(e[a],t,n)}}}return e}function Wt(e,t,n,a){try{return a?e(...a):e()}catch(e){Kt(e,t,n)}}function Gt(e,t,n,a){if(A(e)){let i=Wt(e,t,n,a);return i&&z(i)&&i.catch(e=>{Kt(e,t,n)}),i}if(E(e)){let i=[];for(let r=0;r=un(n)?Yt.push(e):Yt.splice(function(e){let t=Qt+1,n=Yt.length;for(;t>>1,i=Yt[a],r=un(i);run(e)-un(t));if(Zt.length=0,Jt)return void Jt.push(...e);for(Jt=e,Xt=0;Xtnull==e.id?2&e.flags?-1:1/0:e.id,cn=null,dn=null;function hn(e){let t=cn;return cn=e,dn=e&&e.type.__scopeId||null,t}function pn(e,t=cn,n){if(!t||e._n)return e;let a=(...n)=>{let i;a._d&&$i(-1);let r=hn(t);try{i=e(...n)}finally{hn(r),a._d&&$i(1)}return i};return a._n=!0,a._c=!0,a._d=!0,a}function fn(e,t,n,a){let i=e.dirs,r=t&&t.dirs;for(let o=0;o1)return n&&A(t)?t.call(a&&a.proxy):t}}let gn=Symbol.for("v-scx");function vn(e,t){return bn(e,null,{flush:"sync"})}function bn(e,t,n=v){let{flush:a}=n,i=S({},n),o=cr;i.call=(e,t,n)=>Gt(e,o,t,n);let s=!1;return"post"===a?i.scheduler=e=>{yi(e,o&&o.suspense)}:"sync"!==a&&(s=!0,i.scheduler=(e,t)=>{t?e():an(e)}),i.augmentJob=e=>{t&&(e.flags|=4),s&&(e.flags|=2,o&&(e.id=o.uid,e.i=o))},function(e,t,n=v){let a,i,o,s,{immediate:l,deep:u,once:c,scheduler:d,augmentJob:h,call:p}=n,f=e=>u?e:xt(e)||!1===u||0===u?Ht(e,1):Ht(e),_=!1,g=!1;if(At(e)?(i=()=>e.value,_=xt(e)):wt(e)?(i=()=>f(e),_=!0):E(e)?(g=!0,_=e.some(e=>wt(e)||xt(e)),i=()=>e.map(e=>At(e)?e.value:wt(e)?f(e):A(e)?p?p(e,2):e():void 0)):i=A(e)?t?p?()=>p(e,2):e:()=>{if(o){Ee();try{o()}finally{Ae()}}let t=m;m=a;try{return p?p(e,3,[s]):e(s)}finally{m=t}}:y,t&&u){let e=i,t=!0===u?1/0:u;i=()=>Ht(e(),t)}let b=r,w=()=>{a.stop(),b&&b.active&&C(b.effects,a)};if(c&&t){let e=t;t=(...t)=>{e(...t),w()}}let k=g?Array(e.length).fill(Vt):Vt,x=e=>{if(1&a.flags&&(a.dirty||e))if(t){let e=a.run();if(u||_||(g?e.some((e,t)=>H(e,k[t])):H(e,k))){o&&o();let n=m;m=a;try{let n=[e,k===Vt?void 0:g&&k[0]===Vt?[]:k,s];k=e,p?p(t,3,n):t(...n)}finally{m=n}}}else a.run()};return h&&h(x),(a=new ge(i)).scheduler=d?()=>d(x,!1):x,s=e=>$t(e,!1,a),o=a.onStop=()=>{let e=Ut.get(a);if(e){if(p)p(e,4);else for(let t of e)t();Ut.delete(a)}},t?l?x(!0):k=a.run():d?d(x.bind(null,!0),!0):a.run(),w.pause=a.pause.bind(a),w.resume=a.resume.bind(a),w.stop=w,w}(e,t,i)}function yn(e,t,n){let a,i=this.proxy,r=L(e)?e.includes(".")?wn(i,e):()=>i[e]:e.bind(i,i);A(t)?a=t:(a=t.handler,n=t);let o=hr(this),s=bn(r,a.bind(i),n);return o(),s}function wn(e,t){let n=t.split(".");return()=>{let t=e;for(let e=0;ee&&(e.disabled||""===e.disabled),Cn=e=>"u">typeof SVGElement&&e instanceof SVGElement,Tn=e=>"function"==typeof MathMLElement&&e instanceof MathMLElement,Pn=(e,t)=>{let n=e&&e.to;return L(n)?t?t(n):null:n};function En(e,t,n,{o:{insert:a},m:i},r=2){0===r&&a(e.targetAnchor,t,n);let{el:o,anchor:s,shapeFlag:l,children:u,props:c}=e,d=2===r;if(d&&a(o,t,n),!kn.has(e)&&(!d||Sn(c))&&16&l)for(let e=0;e{e.isMounted=!0}),ka(()=>{e.isUnmounting=!0}),e}let In=[Function,Array],Nn={mode:String,appear:Boolean,persisted:Boolean,onBeforeEnter:In,onEnter:In,onAfterEnter:In,onEnterCancelled:In,onBeforeLeave:In,onLeave:In,onAfterLeave:In,onLeaveCancelled:In,onBeforeAppear:In,onAppear:In,onAfterAppear:In,onAppearCancelled:In},On=e=>{let t=e.subTree;return t.component?On(t.component):t};function jn(e){let t=e[0];if(e.length>1)for(let n of e)if(n.type!==ji){t=n;break}return t}let Dn={name:"BaseTransition",props:Nn,setup(e,{slots:t}){let n=dr(),a=zn();return()=>{let i=t.default&&$n(t.default(),!0),r=i&&i.length?jn(i):n.subTree?nr():void 0;if(!r)return;let o=Ct(e),{mode:s}=o;if(a.isLeaving)return Fn(r);let l=Vn(r);if(!l)return Fn(r);let u=Bn(l,o,a,n,e=>u=e);l.type!==ji&&Un(l,u);let c=n.subTree&&Vn(n.subTree);if(c&&c.type!==ji&&!Ki(c,l)&&On(n).type!==ji){let e=Bn(c,o,a,n);if(Un(c,e),"out-in"===s&&l.type!==ji)return a.isLeaving=!0,e.afterLeave=()=>{a.isLeaving=!1,8&n.job.flags||n.update(),delete e.afterLeave,c=void 0},Fn(r);"in-out"===s&&l.type!==ji?e.delayLeave=(e,t,n)=>{qn(a,c)[String(c.key)]=c,e[Mn]=()=>{t(),e[Mn]=void 0,delete u.delayedLeave,c=void 0},u.delayedLeave=()=>{n(),delete u.delayedLeave,c=void 0}}:c=void 0}else c&&(c=void 0);return r}}};function qn(e,t){let{leavingVNodes:n}=e,a=n.get(t.type);return a||(a=Object.create(null),n.set(t.type,a)),a}function Bn(e,t,n,a,i){let{appear:r,mode:o,persisted:s=!1,onBeforeEnter:l,onEnter:u,onAfterEnter:c,onEnterCancelled:d,onBeforeLeave:h,onLeave:p,onAfterLeave:f,onLeaveCancelled:m,onBeforeAppear:_,onAppear:g,onAfterAppear:v,onAppearCancelled:b}=t,y=String(e.key),w=qn(n,e),k=(e,t)=>{e&&Gt(e,a,9,t)},x=(e,t)=>{let n=t[1];k(e,t),E(e)?e.every(e=>e.length<=1)&&n():e.length<=1&&n()},S={mode:o,persisted:s,beforeEnter(t){let a=l;if(!n.isMounted){if(!r)return;a=_||l}t[Mn]&&t[Mn](!0);let i=w[y];i&&Ki(e,i)&&i.el[Mn]&&i.el[Mn](),k(a,[t])},enter(t){if(w[y]===e)return;let a=u,i=c,o=d;if(!n.isMounted){if(!r)return;a=g||u,i=v||c,o=b||d}let s=!1;t[Rn]=e=>{s||(s=!0,k(e?o:i,[t]),S.delayedLeave&&S.delayedLeave(),t[Rn]=void 0)};let l=t[Rn].bind(null,!1);a?x(a,[t,l]):l()},leave(t,a){let i=String(e.key);if(t[Rn]&&t[Rn](!0),n.isUnmounting)return a();k(h,[t]);let r=!1;t[Mn]=n=>{r||(r=!0,a(),k(n?m:f,[t]),t[Mn]=void 0,w[i]===e&&delete w[i])};let o=t[Mn].bind(null,!1);w[i]=e,p?x(p,[t,o]):o()},clone(e){let r=Bn(e,t,n,a,i);return i&&i(r),r}};return S}function Fn(e){if(ua(e))return(e=er(e)).children=null,e}function Vn(e){if(!ua(e))return e.type.__isTeleport&&e.children?jn(e.children):e;if(e.component)return e.component.subTree;let{shapeFlag:t,children:n}=e;if(n){if(16&t)return n[0];if(32&t&&A(n.default))return n.default()}}function Un(e,t){6&e.shapeFlag&&e.component?(e.transition=t,Un(e.component.subTree,t)):128&e.shapeFlag?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function $n(e,t=!1,n){let a=[],i=0;for(let r=0;r1)for(let e=0;eYn(e,t&&(E(t)?t[r]:t),n,a,i));if(sa(a)&&!i)return void(512&a.shapeFlag&&a.type.__asyncResolved&&a.component.subTree.component&&Yn(e,t,n,a.component.subTree));let r=4&a.shapeFlag?wr(a.component):a.el,o=i?null:r,{i:s,r:l}=e,u=t&&t.r,c=s.refs===v?s.refs={}:s.refs,d=s.setupState,h=Ct(d),p=d===v?w:e=>!Gn(c,e)&&P(h,e),f=(e,t)=>!(t&&Gn(c,t));if(null!=u&&u!==l&&(Qn(t),L(u)?(c[u]=null,p(u)&&(d[u]=null)):At(u)&&(f(0,t.k)&&(u.value=null),t.k&&(c[t.k]=null))),A(l))Wt(l,s,12,[o,c]);else{let t=L(l),a=At(l);if(t||a){let s=()=>{if(e.f){let n=t?p(l)?d[l]:c[l]:f()||!e.k?l.value:c[e.k];if(i)E(n)&&C(n,r);else if(E(n))n.includes(r)||n.push(r);else if(t)c[l]=[r],p(l)&&(d[l]=c[l]);else{let t=[r];f(0,e.k)&&(l.value=t),e.k&&(c[e.k]=t)}}else t?(c[l]=o,p(l)&&(d[l]=o)):a&&(f(0,e.k)&&(l.value=o),e.k&&(c[e.k]=o))};if(o){let t=()=>{s(),Kn.delete(e)};t.id=-1,Kn.set(e,t),yi(t,n)}else Qn(e),s()}}}function Qn(e){let t=Kn.get(e);t&&(t.flags|=8,Kn.delete(e))}let Zn=!1,Jn=()=>{Zn||(console.error("Hydration completed but contains mismatches."),Zn=!0)},Xn=e=>{if(1===e.nodeType){if(e.namespaceURI.includes("svg")&&"foreignObject"!==e.tagName)return"svg";if(e.namespaceURI.includes("MathML"))return"mathml"}},ea=e=>8===e.nodeType;function ta(e){let{mt:t,p:n,o:{patchProp:a,createText:i,nextSibling:r,parentNode:o,remove:s,insert:l,createComment:u}}=e,c=(n,a,s,u,v,b=!1)=>{b=b||!!a.dynamicChildren;let y=ea(n)&&"["===n.data,w=()=>f(n,a,s,u,v,y),{type:k,ref:x,shapeFlag:S,patchFlag:C}=a,T=n.nodeType;a.el=n,-2===C&&(b=!1,a.dynamicChildren=null);let P=null;switch(k){case Oi:3!==T?""===a.children?(l(a.el=i(""),o(n),n),P=n):P=w():(n.data!==a.children&&(Jn(),n.data=a.children),P=r(n));break;case ji:g(n)?(P=r(n),_(a.el=n.content.firstChild,n,s)):P=8!==T||y?w():r(n);break;case Di:if(y&&(T=(n=r(n)).nodeType),1===T||3===T){P=n;let e=!a.children.length;for(let t=0;t{o=o||!!t.dynamicChildren;let{type:l,props:u,patchFlag:c,shapeFlag:d,dirs:p,transition:f}=t,m="input"===l||"option"===l;if(m||-1!==c){let l;p&&fn(t,null,n,"created");let v=!1;if(g(e)){v=Ci(null,f)&&n&&n.vnode.props&&n.vnode.props.appear;let a=e.content.firstChild;if(v){let e=a.getAttribute("class");e&&(a.$cls=e),f.beforeEnter(a)}_(a,e,n),t.el=e=a}if(16&d&&(!u||!u.innerHTML&&!u.textContent)){let a=h(e.firstChild,t,e,n,i,r,o);for(;a;){ia(e,1)||Jn();let t=a;a=a.nextSibling,s(t)}}else if(8&d){let n=t.children;"\n"===n[0]&&("PRE"===e.tagName||"TEXTAREA"===e.tagName)&&(n=n.slice(1));let{textContent:a}=e;a!==n&&a!==n.replace(/\r\n|\r/g,"\n")&&(ia(e,0)||Jn(),e.textContent=t.children)}if(u)if(m||!o||48&c){let t=e.tagName.includes("-");for(let i in u)(m&&(i.endsWith("value")||"indeterminate"===i)||k(i)&&!O(i)||"."===i[0]||t&&!O(i))&&a(e,i,null,u[i],void 0,n)}else if(u.onClick)a(e,"onClick",null,u.onClick,void 0,n);else if(4&c&&wt(u.style))for(let e in u.style)u.style[e];(l=u&&u.onVnodeBeforeMount)&&sr(l,n,t),p&&fn(t,null,n,"beforeMount"),((l=u&&u.onVnodeMounted)||p||v)&&zi(()=>{l&&sr(l,n,t),v&&f.enter(e),p&&fn(t,null,n,"mounted")},i)}return e.nextSibling},h=(e,t,a,o,s,u,d)=>{d=d||!!t.dynamicChildren;let h=t.children,p=h.length;for(let t=0;t{let{slotScopeIds:c}=t;c&&(i=i?i.concat(c):c);let d=o(e),p=h(r(e),t,d,n,a,i,s);return p&&ea(p)&&"]"===p.data?r(t.anchor=p):(Jn(),l(t.anchor=u("]"),d,p),p)},f=(e,t,a,i,l,u)=>{if(ia(e.parentElement,1)||Jn(),t.el=null,u){let t=m(e);for(;;){let n=r(e);if(!n||n===t)break;s(n)}}let c=r(e),d=o(e);return s(e),n(null,t,d,c,a,i,Xn(d),l),a&&(a.vnode.el=t.el,si(a,t.el)),c},m=(e,t="[",n="]")=>{let a=0;for(;e;)if((e=r(e))&&ea(e)&&(e.data===t&&a++,e.data===n)){if(0===a)return r(e);a--}return e},_=(e,t,n)=>{let a=t.parentNode;a&&a.replaceChild(e,t);let i=n;for(;i;)i.vnode.el===t&&(i.vnode.el=i.subTree.el=e),i=i.parent},g=e=>1===e.nodeType&&"TEMPLATE"===e.tagName;return[(e,t)=>{if(!t.hasChildNodes())return n(null,e,t),ln(),void(t._vnode=e);c(t.firstChild,e,null,null,null),ln(),t._vnode=e},c]}let na="data-allow-mismatch",aa={0:"text",1:"children",2:"class",3:"style",4:"attribute"};function ia(e,t){if(0===t||1===t)for(;e&&!e.hasAttribute(na);)e=e.parentElement;let n=e&&e.getAttribute(na);if(null==n)return!1;{if(""===n)return!0;let e=n.split(",");return!(0!==t||!e.includes("children"))||e.includes(aa[t])}}let ra=Q().requestIdleCallback||(e=>setTimeout(e,1)),oa=Q().cancelIdleCallback||(e=>clearTimeout(e)),sa=e=>!!e.type.__asyncLoader;function la(e,t){let{ref:n,props:a,children:i,ce:r}=t.vnode,o=Ji(e,a,i);return o.ref=n,o.ce=r,delete t.vnode.ce,o}let ua=e=>e.type.__isKeepAlive;function ca(e,t){let n;return E(e)?e.some(e=>ca(e,t)):L(e)?e.split(",").includes(t):"[object RegExp]"===(n=e,I.call(n))&&(e.lastIndex=0,e.test(t))}function da(e,t){pa(e,"a",t)}function ha(e,t){pa(e,"da",t)}function pa(e,t,n=cr){let a=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}return e()});if(_a(t,a,n),n){let e=n.parent;for(;e&&e.parent;)ua(e.parent.vnode)&&function(e,t,n,a){let i=_a(t,e,a,!0);xa(()=>{C(a[t],i)},n)}(a,t,n,e),e=e.parent}}function fa(e){e.shapeFlag&=-257,e.shapeFlag&=-513}function ma(e){return 128&e.shapeFlag?e.ssContent:e}function _a(e,t,n=cr,a=!1){if(n){let i=n[e]||(n[e]=[]),r=t.__weh||(t.__weh=(...a)=>{Ee();let i=hr(n),r=Gt(t,n,e,a);return i(),Ae(),r});return a?i.unshift(r):i.push(r),r}}let ga=e=>(t,n=cr)=>{mr&&"sp"!==e||_a(e,(...e)=>t(...e),n)},va=ga("bm"),ba=ga("m"),ya=ga("bu"),wa=ga("u"),ka=ga("bum"),xa=ga("um"),Sa=ga("sp"),Ca=ga("rtg"),Ta=ga("rtc");function Pa(e,t=cr){_a("ec",e,t)}let Ea="components",Aa=Symbol.for("v-ndc");function La(e,t,n=!0,a=!1){let i=cn||cr;if(i){let n=i.type;if(e===Ea){let e=kr(n,!1);if(e&&(e===t||e===B(t)||e===U(B(t))))return n}let r=Ma(i[e]||n[e],t)||Ma(i.appContext[e],t);return!r&&a?n:r}}function Ma(e,t){return e&&(e[t]||e[B(t)]||e[U(B(t))])}let Ra=e=>e?fr(e)?wr(e):Ra(e.parent):null,za=S(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>Ra(e.parent),$root:e=>Ra(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>Fa(e),$forceUpdate:e=>e.f||(e.f=()=>{an(e.update)}),$nextTick:e=>e.n||(e.n=nn.bind(e.proxy)),$watch:e=>yn.bind(e)}),Ia=(e,t)=>e!==v&&!e.__isScriptSetup&&P(e,t),Na={get({_:e},t){let n,a;if("__v_skip"===t)return!0;let{ctx:i,setupState:r,data:o,props:s,accessCache:l,type:u,appContext:c}=e;if("$"!==t[0]){let e=l[t];if(void 0!==e)switch(e){case 1:return r[t];case 2:return o[t];case 4:return i[t];case 3:return s[t]}else{if(Ia(r,t))return l[t]=1,r[t];if(o!==v&&P(o,t))return l[t]=2,o[t];if(P(s,t))return l[t]=3,s[t];if(i!==v&&P(i,t))return l[t]=4,i[t];qa&&(l[t]=0)}}let d=za[t];return d?("$attrs"===t&&De(e.attrs,0,""),d(e)):(n=u.__cssModules)&&(n=n[t])?n:i!==v&&P(i,t)?(l[t]=4,i[t]):P(a=c.config.globalProperties,t)?a[t]:void 0},set({_:e},t,n){let{data:a,setupState:i,ctx:r}=e;return Ia(i,t)?(i[t]=n,!0):a!==v&&P(a,t)?(a[t]=n,!0):!(P(e.props,t)||"$"===t[0]&&t.slice(1)in e||(r[t]=n,0))},has({_:{data:e,setupState:t,accessCache:n,ctx:a,appContext:i,props:r,type:o}},s){let l;return!!(n[s]||e!==v&&"$"!==s[0]&&P(e,s)||Ia(t,s)||P(r,s)||P(a,s)||P(za,s)||P(i.config.globalProperties,s)||(l=o.__cssModules)&&l[s])},defineProperty(e,t,n){return null!=n.get?e._.accessCache[t]=0:P(n,"value")&&this.set(e,t,n.value,null),Reflect.defineProperty(e,t,n)}},Oa=S({},Na,{get(e,t){if(t!==Symbol.unscopables)return Na.get(e,t,e)},has:(e,t)=>"_"!==t[0]&&!Z(t)});function ja(e){let t=dr();return t.setupContext||(t.setupContext=yr(t))}function Da(e){return E(e)?e.reduce((e,t)=>(e[t]=null,e),{}):e}let qa=!0;function Ba(e,t,n){Gt(E(e)?e.map(e=>e.bind(t.proxy)):e.bind(t.proxy),t,n)}function Fa(e){let t,n=e.type,{mixins:a,extends:i}=n,{mixins:r,optionsCache:o,config:{optionMergeStrategies:s}}=e.appContext,l=o.get(n);return l?t=l:r.length||a||i?(t={},r.length&&r.forEach(e=>Va(t,e,s,!0)),Va(t,n,s)):t=n,R(n)&&o.set(n,t),t}function Va(e,t,n,a=!1){let{mixins:i,extends:r}=t;for(let o in r&&Va(e,r,n,!0),i&&i.forEach(t=>Va(e,t,n,!0)),t)if(a&&"expose"===o);else{let a=Ua[o]||n&&n[o];e[o]=a?a(e[o],t[o]):t[o]}return e}let Ua={data:$a,props:Ka,emits:Ka,methods:Ga,computed:Ga,beforeCreate:Wa,created:Wa,beforeMount:Wa,mounted:Wa,beforeUpdate:Wa,updated:Wa,beforeDestroy:Wa,beforeUnmount:Wa,destroyed:Wa,unmounted:Wa,activated:Wa,deactivated:Wa,errorCaptured:Wa,serverPrefetch:Wa,components:Ga,directives:Ga,watch:function(e,t){if(!e)return t;if(!t)return e;let n=S(Object.create(null),e);for(let a in t)n[a]=Wa(e[a],t[a]);return n},provide:$a,inject:function(e,t){return Ga(Ha(e),Ha(t))}};function $a(e,t){return t?e?function(){return S(A(e)?e.call(this,this):e,A(t)?t.call(this,this):t)}:t:e}function Ha(e){if(E(e)){let t={};for(let n=0;n"modelValue"===t||"model-value"===t?e.modelModifiers:e[`${t}Modifiers`]||e[`${B(t)}Modifiers`]||e[`${V(t)}Modifiers`];function Xa(e,t,...n){let a;if(e.isUnmounted)return;let i=e.vnode.props||v,r=n,o=t.startsWith("update:"),s=o&&Ja(i,t.slice(7));s&&(s.trim&&(r=n.map(e=>L(e)?e.trim():e)),s.number&&(r=n.map(K)));let l=i[a=$(t)]||i[a=$(B(t))];!l&&o&&(l=i[a=$(V(t))]),l&&Gt(l,e,6,r);let u=i[a+"Once"];if(u){if(e.emitted){if(e.emitted[a])return}else e.emitted={};e.emitted[a]=!0,Gt(u,e,6,r)}}let ei=new WeakMap;function ti(e,t){return!!e&&!!k(t)&&(P(e,(t=t.slice(2).replace(/Once$/,""))[0].toLowerCase()+t.slice(1))||P(e,V(t))||P(e,t))}function ni(e){let t,n,{type:a,vnode:i,proxy:r,withProxy:o,propsOptions:[s],slots:l,attrs:u,emit:c,render:d,renderCache:h,props:p,data:f,setupState:m,ctx:_,inheritAttrs:g}=e,v=hn(e);try{if(4&i.shapeFlag){let e=o||r;t=ar(d.call(e,e,h,p,m,f,_)),n=u}else t=ar(a.length>1?a(p,{attrs:u,slots:l,emit:c}):a(p,null)),n=a.props?u:ai(u)}catch(n){qi.length=0,Kt(n,e,1),t=Ji(ji)}let b=t;if(n&&!1!==g){let e=Object.keys(n),{shapeFlag:t}=b;e.length&&7&t&&(s&&e.some(x)&&(n=ii(n,s)),b=er(b,n,!1,!0))}return i.dirs&&((b=er(b,null,!1,!0)).dirs=b.dirs?b.dirs.concat(i.dirs):i.dirs),i.transition&&Un(b,i.transition),t=b,hn(v),t}let ai=e=>{let t;for(let n in e)("class"===n||"style"===n||k(n))&&((t||(t={}))[n]=e[n]);return t},ii=(e,t)=>{let n={};for(let a in e)x(a)&&a.slice(9)in t||(n[a]=e[a]);return n};function ri(e,t,n){let a=Object.keys(t);if(a.length!==Object.keys(e).length)return!0;for(let i=0;iObject.getPrototypeOf(e)===li;function ci(e,t,n,a){let i,[r,o]=e.propsOptions,s=!1;if(t)for(let l in t){let u;if(O(l))continue;let c=t[l];r&&P(r,u=B(l))?o&&o.includes(u)?(i||(i={}))[u]=c:n[u]=c:ti(e.emitsOptions,l)||l in a&&c===a[l]||(a[l]=c,s=!0)}if(o){let t=Ct(n),a=i||v;for(let i=0;i"_"===e||"_ctx"===e||"$stable"===e,mi=e=>E(e)?e.map(ar):[ar(e)],_i=(e,t,n)=>{if(t._n)return t;let a=pn((...e)=>mi(t(...e)),n);return a._c=!1,a},gi=(e,t,n)=>{let a=e._ctx;for(let n in e){if(fi(n))continue;let i=e[n];if(A(i))t[n]=_i(0,i,a);else if(null!=i){let e=mi(i);t[n]=()=>e}}},vi=(e,t)=>{let n=mi(t);e.slots.default=()=>n},bi=(e,t,n)=>{for(let a in t)(n||!fi(a))&&(e[a]=t[a])},yi=zi;function wi(e){return ki(e,ta)}function ki(e,t){var n;let a,i;Q().__VUE__=!0;let{insert:r,remove:o,patchProp:s,createElement:l,createText:u,createComment:d,setText:h,setElementText:p,parentNode:f,nextSibling:m,setScopeId:_=y,insertStaticContent:g}=e,w=(e,t,n,a=null,i=null,r=null,o,s=null,l=!!t.dynamicChildren)=>{if(e===t)return;e&&!Ki(e,t)&&(a=re(e),ee(e,i,r,!0),e=null),-2===t.patchFlag&&(l=!1,t.dynamicChildren=null);let{type:u,ref:c,shapeFlag:d}=t;switch(u){case Oi:k(e,t,n,a);break;case ji:x(e,t,n,a);break;case Di:null==e&&C(t,n,a,o);break;case Ni:q(e,t,n,a,i,r,o,s,l);break;default:1&d?T(e,t,n,a,i,r,o,s,l):6&d?F(e,t,n,a,i,r,o,s,l):(64&d||128&d)&&u.process(e,t,n,a,i,r,o,s,l,le)}null!=c&&i?Yn(c,e&&e.ref,r,t||e,!t):null==c&&e&&null!=e.ref&&Yn(e.ref,null,r,e,!0)},k=(e,t,n,a)=>{if(null==e)r(t.el=u(t.children),n,a);else{let n=t.el=e.el;t.children!==e.children&&h(n,t.children)}},x=(e,t,n,a)=>{null==e?r(t.el=d(t.children||""),n,a):t.el=e.el},C=(e,t,n,a)=>{[e.el,e.anchor]=g(e.children,t,n,a,e.el,e.anchor)},T=(e,t,n,a,i,r,o,s,l)=>{if("svg"===t.type?o="svg":"math"===t.type&&(o="mathml"),null==e)L(t,n,a,i,r,o,s,l);else{let n=e.el&&e.el._isVueCE?e.el:null;try{n&&n._beginPatch(),N(e,t,i,r,o,s,l)}finally{n&&n._endPatch()}}},L=(e,t,n,a,i,o,u,c)=>{let d,h,{props:f,shapeFlag:m,transition:_,dirs:g}=e;if(d=e.el=l(e.type,o,f&&f.is,f),8&m?p(d,e.children):16&m&&I(e.children,d,null,a,i,xi(e,o),u,c),g&&fn(e,null,a,"created"),M(d,e,e.scopeId,u,a),f){for(let e in f)"value"===e||O(e)||s(d,e,null,f[e],o,a);"value"in f&&s(d,"value",null,f.value,o),(h=f.onVnodeBeforeMount)&&sr(h,a,e)}g&&fn(e,null,a,"beforeMount");let v=Ci(i,_);v&&_.beforeEnter(d),r(d,t,n),((h=f&&f.onVnodeMounted)||v||g)&&yi(()=>{h&&sr(h,a,e),v&&_.enter(d),g&&fn(e,null,a,"mounted")},i)},M=(e,t,n,a,i)=>{if(n&&_(e,n),a)for(let t=0;t{for(let u=l;u{let l,u=t.el=e.el,{patchFlag:c,dynamicChildren:d,dirs:h}=t;c|=16&e.patchFlag;let f=e.props||v,m=t.props||v;if(n&&Si(n,!1),(l=m.onVnodeBeforeUpdate)&&sr(l,n,t,e),h&&fn(t,e,n,"beforeUpdate"),n&&Si(n,!0),(f.innerHTML&&null==m.innerHTML||f.textContent&&null==m.textContent)&&p(u,""),d?j(e.dynamicChildren,d,u,n,a,xi(t,i),r):o||Y(e,t,u,null,n,a,xi(t,i),r,!1),c>0){if(16&c)D(u,f,m,n,i);else if(2&c&&f.class!==m.class&&s(u,"class",null,m.class,i),4&c&&s(u,"style",f.style,m.style,i),8&c){let e=t.dynamicProps;for(let t=0;t{l&&sr(l,n,t,e),h&&fn(t,e,n,"updated")},a)},j=(e,t,n,a,i,r,o)=>{for(let s=0;s{if(t!==n){if(t!==v)for(let r in t)O(r)||r in n||s(e,r,t[r],null,i,a);for(let r in n){if(O(r))continue;let o=n[r],l=t[r];o!==l&&"value"!==r&&s(e,r,l,o,i,a)}"value"in n&&s(e,"value",t.value,n.value,i)}},q=(e,t,n,a,i,o,s,l,c)=>{let d=t.el=e?e.el:u(""),h=t.anchor=e?e.anchor:u(""),{patchFlag:p,dynamicChildren:f,slotScopeIds:m}=t;m&&(l=l?l.concat(m):m),null==e?(r(d,n,a),r(h,n,a),I(t.children||[],n,h,i,o,s,l,c)):p>0&&64&p&&f&&e.dynamicChildren&&e.dynamicChildren.length===f.length?(j(e.dynamicChildren,f,n,i,o,s,l),(null!=t.key||i&&t===i.subTree)&&Ti(e,t,!0)):Y(e,t,n,h,i,o,s,l,c)},F=(e,t,n,a,i,r,o,s,l)=>{t.slotScopeIds=s,null==e?512&t.shapeFlag?i.ctx.activate(t,n,a,o,l):U(t,n,a,i,r,o,l):$(e,t,l)},U=(e,t,n,a,i,r,o)=>{var s,l,u;let d,h,p,f=(l=a,u=i,d=(s=e).type,h=(l?l.appContext:s.appContext)||lr,(p={uid:ur++,vnode:s,type:d,parent:l,appContext:h,root:null,next:null,subTree:null,effect:null,update:null,job:null,scope:new me(!0),render:null,proxy:null,exposed:null,exposeProxy:null,withProxy:null,provides:l?l.provides:Object.create(h.provides),ids:l?l.ids:["",0,0],accessCache:null,renderCache:[],components:null,directives:null,propsOptions:function e(t,n,a=!1){let i=a?hi:n.propsCache,r=i.get(t);if(r)return r;let o=t.props,s={},l=[],u=!1;if(!A(t)){let i=t=>{u=!0;let[a,i]=e(t,n,!0);S(s,a),i&&l.push(...i)};!a&&n.mixins.length&&n.mixins.forEach(i),t.extends&&i(t.extends),t.mixins&&t.mixins.forEach(i)}if(!o&&!u)return R(t)&&i.set(t,b),b;if(E(o))for(let e=0;e{let a=e(t,n,!0);a&&(l=!0,S(s,a))};!a&&n.mixins.length&&n.mixins.forEach(i),t.extends&&i(t.extends),t.mixins&&t.mixins.forEach(i)}return o||l?(E(o)?o.forEach(e=>s[e]=null):S(s,o),R(t)&&i.set(t,s),s):(R(t)&&i.set(t,null),null)}(d,h),emit:null,emitted:null,propsDefaults:v,inheritAttrs:d.inheritAttrs,ctx:v,data:v,props:v,attrs:v,slots:v,refs:v,setupState:v,setupContext:null,suspense:u,suspenseId:u?u.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null,sp:null}).ctx={_:p},p.root=l?l.root:p,p.emit=Xa.bind(null,p),s.ce&&s.ce(p),e.component=p);if(ua(e)&&(f.ctx.renderer=le),function(e,t=!1,n=!1){t&&c(t);let{props:a,children:i}=e.vnode,r=fr(e);!function(e,t,n,a=!1){let i={},r=Object.create(li);for(let n in e.propsDefaults=Object.create(null),ci(e,t,i,r),e.propsOptions[0])n in i||(i[n]=void 0);n?e.props=a?i:vt(i):e.type.props?e.props=i:e.props=r,e.attrs=r}(e,a,r,t);var o=n||t;let s=e.slots=Object.create(li);if(32&e.vnode.shapeFlag){let e=i._;e?(bi(s,i,o),o&&G(s,"_",e,!0)):gi(i,s)}else i&&vi(e,i);r&&function(e,t){let n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,Na);let{setup:a}=n;if(a){Ee();let n=e.setupContext=a.length>1?yr(e):null,i=hr(e),r=Wt(a,e,0,[e.props,n]),o=z(r);if(Ae(),i(),(o||e.sp)&&!sa(e)&&Wn(e),o){if(r.then(pr,pr),t)return r.then(n=>{_r(e,n,t)}).catch(t=>{Kt(t,e,0)});e.asyncDep=r}else _r(e,r,t)}else vr(e,t)}(e,t),t&&c(!1)}(f,!1,o),f.asyncDep){if(i&&i.registerDep(f,H,o),!e.el){let a=f.subTree=Ji(ji);x(null,a,t,n),e.placeholder=a.el}}else H(f,e,t,n,i,r,o)},$=(e,t,n)=>{let a=t.component=e.component;if(function(e,t,n){let{props:a,children:i,component:r}=e,{props:o,children:s,patchFlag:l}=t,u=r.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&l>=0))return(!!i||!!s)&&(!s||!s.$stable)||a!==o&&(a?!o||ri(a,o,u):!!o);if(1024&l)return!0;if(16&l)return a?ri(a,o,u):!!o;if(8&l){let e=t.dynamicProps;for(let t=0;t{e.scope.on();let l=e.effect=new ge(()=>{if(e.isMounted){let t,{next:n,bu:a,u:i,parent:l,vnode:c}=e;{let t=function e(t){let n=t.subTree.component;if(n)return n.asyncDep&&!n.asyncResolved?n:e(n)}(e);if(t)return n&&(n.el=c.el,K(e,n,s)),void t.asyncDep.then(()=>{yi(()=>{e.isUnmounted||u()},r)})}let d=n;Si(e,!1),n?(n.el=c.el,K(e,n,s)):n=c,a&&W(a),(t=n.props&&n.props.onVnodeBeforeUpdate)&&sr(t,l,n,c),Si(e,!0);let h=ni(e),p=e.subTree;e.subTree=h,w(p,h,f(p.el),re(p),e,r,o),n.el=h.el,null===d&&si(e,h.el),i&&yi(i,r),(t=n.props&&n.props.onVnodeUpdated)&&yi(()=>sr(t,l,n,c),r)}else{let s,{el:l,props:u}=t,{bm:c,m:d,parent:h,root:p,type:f}=e,m=sa(t);if(Si(e,!1),c&&W(c),!m&&(s=u&&u.onVnodeBeforeMount)&&sr(s,h,t),Si(e,!0),l&&i){let t=()=>{e.subTree=ni(e),i(l,e.subTree,e,r,null)};m&&f.__asyncHydrate?f.__asyncHydrate(l,e,t):t()}else{p.ce&&p.ce._hasShadowRoot()&&p.ce._injectChildStyle(f,e.parent?e.parent.type:void 0);let i=e.subTree=ni(e);w(null,i,n,a,e,r,o),t.el=i.el}if(d&&yi(d,r),!m&&(s=u&&u.onVnodeMounted)){let e=t;yi(()=>sr(s,h,e),r)}(256&t.shapeFlag||h&&sa(h.vnode)&&256&h.vnode.shapeFlag)&&e.a&&yi(e.a,r),e.isMounted=!0,t=n=a=null}});e.scope.off();let u=e.update=l.run.bind(l),c=e.job=l.runIfDirty.bind(l);c.i=e,c.id=e.uid,l.scheduler=()=>an(c),Si(e,!0),u()},K=(e,t,n)=>{t.component=e;let a=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,a){let{props:i,attrs:r,vnode:{patchFlag:o}}=e,s=Ct(i),[l]=e.propsOptions,u=!1;if(!(a||o>0)||16&o){let a;for(let o in ci(e,t,i,r)&&(u=!0),s)t&&(P(t,o)||(a=V(o))!==o&&P(t,a))||(l?n&&(void 0!==n[o]||void 0!==n[a])&&(i[o]=di(l,s,o,void 0,e,!0)):delete i[o]);if(r!==s)for(let e in r)t&&P(t,e)||(delete r[e],u=!0)}else if(8&o){let n=e.vnode.dynamicProps;for(let a=0;a{let{vnode:a,slots:i}=e,r=!0,o=v;if(32&a.shapeFlag){let e=t._;e?n&&1===e?r=!1:bi(i,t,n):(r=!t.$stable,gi(t,i)),o=t}else t&&(vi(e,t),o={default:1});if(r)for(let e in i)fi(e)||null!=o[e]||delete i[e]})(e,t.children,n),Ee(),sn(e),Ae()},Y=(e,t,n,a,i,r,o,s,l=!1)=>{let u=e&&e.children,c=e?e.shapeFlag:0,d=t.children,{patchFlag:h,shapeFlag:f}=t;if(h>0){if(128&h)return void J(u,d,n,a,i,r,o,s,l);if(256&h)return void Z(u,d,n,a,i,r,o,s,l)}8&f?(16&c&&ie(u,i,r),d!==u&&p(n,d)):16&c?16&f?J(u,d,n,a,i,r,o,s,l):ie(u,i,r,!0):(8&c&&p(n,""),16&f&&I(d,n,a,i,r,o,s,l))},Z=(e,t,n,a,i,r,o,s,l)=>{let u;t=t||b;let c=(e=e||b).length,d=t.length,h=Math.min(c,d);for(u=0;ud?ie(e,i,r,!0,!1,h):I(t,n,a,i,r,o,s,l,h)},J=(e,t,n,a,i,r,o,s,l)=>{let u=0,c=t.length,d=e.length-1,h=c-1;for(;u<=d&&u<=h;){let a=e[u],c=t[u]=l?ir(t[u]):ar(t[u]);if(!Ki(a,c))break;w(a,c,n,null,i,r,o,s,l),u++}for(;u<=d&&u<=h;){let a=e[d],u=t[h]=l?ir(t[h]):ar(t[h]);if(!Ki(a,u))break;w(a,u,n,null,i,r,o,s,l),d--,h--}if(u>d){if(u<=h){let e=h+1,d=eh)for(;u<=d;)ee(e[u],i,r,!0),u++;else{let p,f=u,m=u,_=new Map;for(u=m;u<=h;u++){let e=t[u]=l?ir(t[u]):ar(t[u]);null!=e.key&&_.set(e.key,u)}let g=0,v=h-m+1,y=!1,k=0,x=Array(v);for(u=0;u=v)ee(c,i,r,!0);else{if(null!=c.key)a=_.get(c.key);else for(p=m;p<=h;p++)if(0===x[p-m]&&Ki(c,t[p])){a=p;break}void 0===a?ee(c,i,r,!0):(x[a-m]=u+1,a>=k?k=a:y=!0,w(c,t[a],n,null,i,r,o,s,l),g++)}}let S=y?function(e){let t,n,a,i,r,o=e.slice(),s=[0],l=e.length;for(t=0;t>1]]0&&(o[t]=s[a-1]),s[a]=t)}}for(a=s.length,i=s[a-1];a-- >0;)s[a]=i,i=o[i];return s}(x):b;for(p=S.length-1,u=v-1;u>=0;u--){let e=m+u,d=t[e],h=t[e+1],f=e+1{let{el:s,type:l,transition:u,children:c,shapeFlag:d}=e;if(6&d)X(e.component.subTree,t,n,a);else if(128&d)e.suspense.move(t,n,a);else if(64&d)l.move(e,t,n,le);else if(l!==Ni)if(l!==Di)if(2!==a&&1&d&&u)if(0===a)u.beforeEnter(s),r(s,t,n),yi(()=>u.enter(s),i);else{let{leave:a,delayLeave:i,afterLeave:l}=u,c=()=>{e.ctx.isUnmounted?o(s):r(s,t,n)},d=()=>{s._isLeaving&&s[Mn](!0),a(s,()=>{c(),l&&l()})};i?i(s,c,d):d()}else r(s,t,n);else(({el:e,anchor:t},n,a)=>{let i;for(;e&&e!==t;)i=m(e),r(e,n,a),e=i;r(t,n,a)})(e,t,n);else{r(s,t,n);for(let e=0;e{let r,{type:o,props:s,ref:l,children:u,dynamicChildren:c,shapeFlag:d,patchFlag:h,dirs:p,cacheIndex:f,memo:m}=e;if(-2===h&&(i=!1),null!=l&&(Ee(),Yn(l,null,n,e,!0),Ae()),null!=f&&(t.renderCache[f]=void 0),256&d)return void t.ctx.deactivate(e);let _=1&d&&p,g=!sa(e);if(g&&(r=s&&s.onVnodeBeforeUnmount)&&sr(r,t,e),6&d)ae(e.component,n,a);else{if(128&d)return void e.suspense.unmount(n,a);_&&fn(e,null,t,"beforeUnmount"),64&d?e.type.remove(e,t,n,le,a):c&&!c.hasOnce&&(o!==Ni||h>0&&64&h)?ie(c,t,n,!1,!0):(o===Ni&&384&h||!i&&16&d)&&ie(u,t,n),a&&te(e)}let v=null!=m&&null==f;(g&&(r=s&&s.onVnodeUnmounted)||_||v)&&yi(()=>{r&&sr(r,t,e),_&&fn(e,null,t,"unmounted"),v&&(e.el=null)},n)},te=e=>{let{type:t,el:n,anchor:a,transition:i}=e;if(t===Ni)return void ne(n,a);if(t===Di)return void(({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=m(e),o(e),e=n;o(t)})(e);let r=()=>{o(n),i&&!i.persisted&&i.afterLeave&&i.afterLeave()};if(1&e.shapeFlag&&i&&!i.persisted){let{leave:t,delayLeave:a}=i,o=()=>t(n,r);a?a(e.el,r,o):o()}else r()},ne=(e,t)=>{let n;for(;e!==t;)n=m(e),o(e),e=n;o(t)},ae=(e,t,n)=>{let{bum:a,scope:i,job:r,subTree:o,um:s,m:l,a:u}=e;Pi(l),Pi(u),a&&W(a),i.stop(),r&&(r.flags|=8,ee(o,e,t,n)),s&&yi(s,t),yi(()=>{e.isUnmounted=!0},t)},ie=(e,t,n,a=!1,i=!1,r=0)=>{for(let o=r;o{if(6&e.shapeFlag)return re(e.component.subTree);if(128&e.shapeFlag)return e.suspense.next();let t=m(e.anchor||e.el),n=t&&t[xn];return n?m(n):t},oe=!1,se=(e,t,n)=>{let a;null==e?t._vnode&&(ee(t._vnode,null,null,!0),a=t._vnode.component):w(t._vnode||null,e,t,null,null,null,n),t._vnode=e,oe||(oe=!0,sn(a),ln(),oe=!1)},le={p:w,um:ee,m:X,r:te,mt:U,mc:I,pc:Y,pbc:j,n:re,o:e};return t&&([a,i]=t(le)),{render:se,hydrate:a,createApp:(n=a,function(e,t=null){A(e)||(e=S({},e)),null==t||R(t)||(t=null);let a=Ya(),i=new WeakSet,r=[],o=!1,s=a.app={_uid:Qa++,_component:e,_props:t,_container:null,_context:a,_instance:null,version:Tr,get config(){return a.config},set config(e){},use:(e,...t)=>(i.has(e)||(e&&A(e.install)?(i.add(e),e.install(s,...t)):A(e)&&(i.add(e),e(s,...t))),s),mixin:e=>(a.mixins.includes(e)||a.mixins.push(e),s),component:(e,t)=>t?(a.components[e]=t,s):a.components[e],directive:(e,t)=>t?(a.directives[e]=t,s):a.directives[e],mount(i,r,l){if(!o){let u=s._ceVNode||Ji(e,t);return u.appContext=a,!0===l?l="svg":!1===l&&(l=void 0),r&&n?n(u,i):se(u,i,l),o=!0,s._container=i,i.__vue_app__=s,wr(u.component)}},onUnmount(e){r.push(e)},unmount(){o&&(Gt(r,s._instance,16),se(null,s._container),delete s._container.__vue_app__)},provide:(e,t)=>(a.provides[e]=t,s),runWithContext(e){let t=Za;Za=s;try{return e()}finally{Za=t}}};return s})}}function xi({type:e,props:t},n){return"svg"===n&&"foreignObject"===e||"mathml"===n&&"annotation-xml"===e&&t&&t.encoding&&t.encoding.includes("html")?void 0:n}function Si({effect:e,job:t},n){n?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function Ci(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function Ti(e,t,n=!1){let a=e.children,i=t.children;if(E(a)&&E(i))for(let e=0;ee.__isSuspense,Ai=0;function Li(e,t){let n=e.props&&e.props[t];A(n)&&n()}function Mi(e,t,n,a,i,r,o,s,l,u,c=!1){var d;let h,p,{p:f,m:m,um:_,n:g,o:{parentNode:v,remove:b}}=u,y=null!=(h=(d=e).props&&d.props.suspensible)&&!1!==h;y&&t&&t.pendingBranch&&(p=t.pendingId,t.deps++);let w=e.props?Y(e.props.timeout):void 0,k=r,x={vnode:e,parent:t,parentComponent:n,namespace:o,container:a,hiddenContainer:i,deps:0,pendingId:Ai++,timeout:"number"==typeof w?w:-1,activeBranch:null,isFallbackMountPending:!1,pendingBranch:null,isInFallback:!c,isHydrating:c,isUnmounted:!1,effects:[],resolve(e=!1,n=!1){let{vnode:a,activeBranch:i,pendingBranch:o,pendingId:s,effects:l,parentComponent:u,container:c,isInFallback:d}=x,h=!1;if(x.isHydrating)x.isHydrating=!1;else if(!e){h=i&&o.transition&&"out-in"===o.transition.mode;let e=!1;h&&(i.transition.afterLeave=()=>{s===x.pendingId&&(m(o,c,r!==k||e?r:g(i),0),on(l),d&&a.ssFallback&&(a.ssFallback.el=null))}),i&&!x.isFallbackMountPending&&(v(i.el)===c&&(r=g(i),e=!0),_(i,u,x,!0),!h&&d&&a.ssFallback&&yi(()=>a.ssFallback.el=null,x)),h||m(o,c,r,0)}x.isFallbackMountPending=!1,Ii(x,o),x.pendingBranch=null,x.isInFallback=!1;let f=x.parent,b=!1;for(;f;){if(f.pendingBranch){f.effects.push(...l),b=!0;break}f=f.parent}b||h||on(l),x.effects=[],y&&t&&t.pendingBranch&&p===t.pendingId&&(t.deps--,0!==t.deps||n||t.resolve()),Li(a,"onResolve")},fallback(e){if(!x.pendingBranch)return;let{vnode:t,activeBranch:n,parentComponent:a,container:i,namespace:r}=x;Li(t,"onFallback");let o=g(n),u=()=>{x.isFallbackMountPending=!1,x.isInFallback&&(f(null,e,i,o,a,null,r,s,l),Ii(x,e))},c=e.transition&&"out-in"===e.transition.mode;c&&(x.isFallbackMountPending=!0,n.transition.afterLeave=u),x.isInFallback=!0,_(n,a,null,!0),c||u()},move(e,t,n){x.activeBranch&&m(x.activeBranch,e,t,n),x.container=e},next:()=>x.activeBranch&&g(x.activeBranch),registerDep(e,t,n){let a=!!x.pendingBranch;a&&x.deps++;let i=e.vnode.el;e.asyncDep.catch(t=>{Kt(t,e,0)}).then(r=>{if(e.isUnmounted||x.isUnmounted||x.pendingId!==e.suspenseId)return;pr(),e.asyncResolved=!0;let{vnode:s}=e;_r(e,r,!1),i&&(s.el=i);let l=!i&&e.subTree.el;t(e,s,v(i||e.subTree.el),i?null:g(e.subTree),x,o,n),l&&(s.placeholder=null,b(l)),si(e,s.el),a&&0==--x.deps&&x.resolve()})},unmount(e,t){x.isUnmounted=!0,x.activeBranch&&_(x.activeBranch,n,e,t),x.pendingBranch&&_(x.pendingBranch,n,e,t)}};return x}function Ri(e){let t;if(A(e)){let n=Ui&&e._c;n&&(e._d=!1,Fi()),e=e(),n&&(e._d=!0,t=Bi,Vi())}return E(e)&&(e=function(e){let t;for(let n=0;nt!==e)),e}function zi(e,t){t&&t.pendingBranch?E(e)?t.effects.push(...e):t.effects.push(e):on(e)}function Ii(e,t){e.activeBranch=t;let{vnode:n,parentComponent:a}=e,i=t.el;for(;!i&&t.component;)i=(t=t.component.subTree).el;n.el=i,a&&a.subTree===n&&(a.vnode.el=i,si(a,i))}let Ni=Symbol.for("v-fgt"),Oi=Symbol.for("v-txt"),ji=Symbol.for("v-cmt"),Di=Symbol.for("v-stc"),qi=[],Bi=null;function Fi(e=!1){qi.push(Bi=e?null:[])}function Vi(){qi.pop(),Bi=qi[qi.length-1]||null}let Ui=1;function $i(e,t=!1){Ui+=e,e<0&&Bi&&t&&(Bi.hasOnce=!0)}function Hi(e){return e.dynamicChildren=Ui>0?Bi||b:null,Vi(),Ui>0&&Bi&&Bi.push(e),e}function Wi(e,t,n,a,i){return Hi(Ji(e,t,n,a,i,!0))}function Gi(e){return!!e&&!0===e.__v_isVNode}function Ki(e,t){return e.type===t.type&&e.key===t.key}let Yi=({key:e})=>null!=e?e:null,Qi=({ref:e,ref_key:t,ref_for:n})=>("number"==typeof e&&(e=""+e),null!=e?L(e)||At(e)||A(e)?{i:cn,r:e,k:t,f:!!n}:e:null);function Zi(e,t=null,n=null,a=0,i=null,r=+(e!==Ni),o=!1,s=!1){let l={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Yi(t),ref:t&&Qi(t),scopeId:dn,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:a,dynamicProps:i,dynamicChildren:null,appContext:null,ctx:cn};return s?(rr(l,n),128&r&&e.normalize(l)):n&&(l.shapeFlag|=L(n)?8:16),Ui>0&&!o&&Bi&&(l.patchFlag>0||6&r)&&32!==l.patchFlag&&Bi.push(l),l}let Ji=function(e,t=null,n=null,a=0,i=null,r=!1){var o;if(e&&e!==Aa||(e=ji),Gi(e)){let a=er(e,t,!0);return n&&rr(a,n),Ui>0&&!r&&Bi&&(6&a.shapeFlag?Bi[Bi.indexOf(e)]=a:Bi.push(a)),a.patchFlag=-2,a}if(A(o=e)&&"__vccOpts"in o&&(e=e.__vccOpts),t){let{class:e,style:n}=t=Xi(t);e&&!L(e)&&(t.class=ae(e)),R(n)&&(St(n)&&!E(n)&&(n=S({},n)),t.style=J(n))}return Zi(e,t,n,a,i,L(e)?1:Ei(e)?128:e.__isTeleport?64:R(e)?4:2*!!A(e),r,!0)};function Xi(e){return e?St(e)||ui(e)?S({},e):e:null}function er(e,t,n=!1,a=!1){let{props:i,ref:r,patchFlag:o,children:s,transition:l}=e,u=t?or(i||{},t):i,c={__v_isVNode:!0,__v_skip:!0,type:e.type,props:u,key:u&&Yi(u),ref:t&&t.ref?n&&r?E(r)?r.concat(Qi(t)):[r,Qi(t)]:Qi(t):r,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:s,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==Ni?-1===o?16:16|o:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:l,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&er(e.ssContent),ssFallback:e.ssFallback&&er(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return l&&a&&Un(c,l.clone(c)),c}function tr(e=" ",t=0){return Ji(Oi,null,e,t)}function nr(e="",t=!1){return t?(Fi(),Wi(ji,null,e)):Ji(ji,null,e)}function ar(e){return null==e||"boolean"==typeof e?Ji(ji):E(e)?Ji(Ni,null,e.slice()):Gi(e)?ir(e):Ji(Oi,null,String(e))}function ir(e){return null===e.el&&-1!==e.patchFlag||e.memo?e:er(e)}function rr(e,t){let n=0,{shapeFlag:a}=e;if(null==t)t=null;else if(E(t))n=16;else if("object"==typeof t){if(65&a){let n=t.default;return void(n&&(n._c&&(n._d=!1),rr(e,n()),n._c&&(n._d=!0)))}{n=32;let a=t._;a||ui(t)?3===a&&cn&&(1===cn.slots._?t._=1:(t._=2,e.patchFlag|=1024)):t._ctx=cn}}else A(t)?(t={default:t,_ctx:cn},n=32):(t=String(t),64&a?(n=16,t=[tr(t)]):n=8);e.children=t,e.shapeFlag|=n}function or(...e){let t={};for(let n=0;ncr||cn;u=e=>{cr=e},c=e=>{mr=e};let hr=e=>{let t=cr;return u(e),e.scope.on(),()=>{e.scope.off(),u(t)}},pr=()=>{cr&&cr.scope.off(),u(null)};function fr(e){return 4&e.vnode.shapeFlag}let mr=!1;function _r(e,t,n){A(t)?e.render=t:R(t)&&(e.setupState=Ot(t)),vr(e,n)}function gr(e){d=e,h=e=>{e.render._rc&&(e.withProxy=new Proxy(e.ctx,Oa))}}function vr(e,t,n){let a=e.type;if(!e.render){if(!t&&d&&!a.render){let t=a.template||Fa(e).template;if(t){let{isCustomElement:n,compilerOptions:i}=e.appContext.config,{delimiters:r,compilerOptions:o}=a,s=S(S({isCustomElement:n,delimiters:r},i),o);a.render=d(t,s)}}e.render=a.render||y,h&&h(e)}{let t=hr(e);Ee();try{!function(e){let t=Fa(e),n=e.proxy,a=e.ctx;qa=!1,t.beforeCreate&&Ba(t.beforeCreate,e,"bc");let{data:i,computed:r,methods:o,watch:s,provide:l,inject:u,created:c,beforeMount:d,mounted:h,beforeUpdate:p,updated:f,activated:m,deactivated:_,beforeUnmount:g,unmounted:v,render:b,renderTracked:w,renderTriggered:k,errorCaptured:x,serverPrefetch:S,expose:C,inheritAttrs:T,components:P,directives:M}=t;if(u&&function(e,t){for(let n in E(e)&&(e=Ha(e)),e){let a,i=e[n];At(a=R(i)?"default"in i?_n(i.from||n,i.default,!0):_n(i.from||n):_n(i))?Object.defineProperty(t,n,{enumerable:!0,configurable:!0,get:()=>a.value,set:e=>a.value=e}):t[n]=a}}(u,a),o)for(let e in o){let t=o[e];A(t)&&(a[e]=t.bind(n))}if(i){let t=i.call(n,n);R(t)&&(e.data=gt(t))}if(qa=!0,r)for(let e in r){let t=r[e],i=A(t)?t.bind(n,n):A(t.get)?t.get.bind(n,n):y,o=xr({get:i,set:!A(t)&&A(t.set)?t.set.bind(n):y});Object.defineProperty(a,e,{enumerable:!0,configurable:!0,get:()=>o.value,set:e=>o.value=e})}if(s)for(let e in s)!function e(t,n,a,i){let r=i.includes(".")?wn(a,i):()=>a[i];if(L(t)){let e=n[t];A(e)&&bn(r,e,void 0)}else if(A(t))bn(r,t.bind(a),void 0);else if(R(t))if(E(t))t.forEach(t=>e(t,n,a,i));else{let e=A(t.handler)?t.handler.bind(a):n[t.handler];A(e)&&bn(r,e,t)}}(s[e],a,n,e);if(l){let e=A(l)?l.call(n):l;Reflect.ownKeys(e).forEach(t=>{mn(t,e[t])})}function z(e,t){E(t)?t.forEach(t=>e(t.bind(n))):t&&e(t.bind(n))}if(c&&Ba(c,e,"c"),z(va,d),z(ba,h),z(ya,p),z(wa,f),z(da,m),z(ha,_),z(Pa,x),z(Ta,w),z(Ca,k),z(ka,g),z(xa,v),z(Sa,S),E(C))if(C.length){let t=e.exposed||(e.exposed={});C.forEach(e=>{Object.defineProperty(t,e,{get:()=>n[e],set:t=>n[e]=t,enumerable:!0})})}else e.exposed||(e.exposed={});b&&e.render===y&&(e.render=b),null!=T&&(e.inheritAttrs=T),P&&(e.components=P),M&&(e.directives=M)}(e)}finally{Ae(),t()}}}let br={get:(e,t)=>(De(e,0,""),e[t])};function yr(e){return{attrs:new Proxy(e.attrs,br),slots:e.slots,emit:e.emit,expose:t=>{e.exposed=t||{}}}}function wr(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Ot(Tt(e.exposed)),{get:(t,n)=>n in t?t[n]:n in za?za[n](e):void 0,has:(e,t)=>t in e||t in za})):e.proxy}function kr(e,t=!0){return A(e)?e.displayName||e.name:e.name||t&&e.__name}let xr=(e,t)=>function(e,t=!1){let n,a;return A(e)?n=e:(n=e.get,a=e.set),new Ft(n,a,t)}(e,mr);function Sr(e,t,n){try{$i(-1);let a=arguments.length;return 2!==a?(a>3?n=Array.prototype.slice.call(arguments,2):3===a&&Gi(n)&&(n=[n]),Ji(e,t,n)):!R(t)||E(t)?Ji(e,null,t):Gi(t)?Ji(e,null,[t]):Ji(e,t)}finally{$i(1)}}function Cr(e,t){let n=e.memo;if(n.length!=t.length)return!1;for(let e=0;e0&&Bi&&Bi.push(e),!0}let Tr="3.5.34",Pr="u">typeof window&&window.trustedTypes;if(Pr)try{_=Pr.createPolicy("vue",{createHTML:e=>e})}catch(e){}let Er=_?e=>_.createHTML(e):e=>e,Ar="u">typeof document?document:null,Lr=Ar&&Ar.createElement("template"),Mr={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{let t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,a)=>{let i="svg"===t?Ar.createElementNS("http://www.w3.org/2000/svg",e):"mathml"===t?Ar.createElementNS("http://www.w3.org/1998/Math/MathML",e):n?Ar.createElement(e,{is:n}):Ar.createElement(e);return"select"===e&&a&&null!=a.multiple&&i.setAttribute("multiple",a.multiple),i},createText:e=>Ar.createTextNode(e),createComment:e=>Ar.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Ar.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,a,i,r){let o=n?n.previousSibling:t.lastChild;if(i&&(i===r||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),n),i!==r&&(i=i.nextSibling););else{Lr.innerHTML=Er("svg"===a?`${e}`:"mathml"===a?`${e}`:e);let i=Lr.content;if("svg"===a||"mathml"===a){let e=i.firstChild;for(;e.firstChild;)i.appendChild(e.firstChild);i.removeChild(e)}t.insertBefore(i,n)}return[o?o.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Rr="transition",zr="animation",Ir=Symbol("_vtc"),Nr={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String},Or=S({},Nn,Nr),jr=((t=(e,{slots:t})=>Sr(Dn,Br(e),t)).displayName="Transition",t.props=Or,t),Dr=(e,t=[])=>{E(e)?e.forEach(e=>e(...t)):e&&e(...t)},qr=e=>!!e&&(E(e)?e.some(e=>e.length>1):e.length>1);function Br(e){let t={};for(let n in e)n in Nr||(t[n]=e[n]);if(!1===e.css)return t;let{name:n="v",type:a,duration:i,enterFromClass:r=`${n}-enter-from`,enterActiveClass:o=`${n}-enter-active`,enterToClass:s=`${n}-enter-to`,appearFromClass:l=r,appearActiveClass:u=o,appearToClass:c=s,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:p=`${n}-leave-to`}=e,f=function(e){if(null==e)return null;{if(R(e))return[function(e){return Y(e)}(e.enter),function(e){return Y(e)}(e.leave)];let t=function(e){return Y(e)}(e);return[t,t]}}(i),m=f&&f[0],_=f&&f[1],{onBeforeEnter:g,onEnter:v,onEnterCancelled:b,onLeave:y,onLeaveCancelled:w,onBeforeAppear:k=g,onAppear:x=v,onAppearCancelled:C=b}=t,T=(e,t,n,a)=>{e._enterCancelled=a,Vr(e,t?c:s),Vr(e,t?u:o),n&&n()},P=(e,t)=>{e._isLeaving=!1,Vr(e,d),Vr(e,p),Vr(e,h),t&&t()},E=e=>(t,n)=>{let i=e?x:v,o=()=>T(t,e,n);Dr(i,[t,o]),Ur(()=>{Vr(t,e?l:r),Fr(t,e?c:s),qr(i)||Hr(t,a,m,o)})};return S(t,{onBeforeEnter(e){Dr(g,[e]),Fr(e,r),Fr(e,o)},onBeforeAppear(e){Dr(k,[e]),Fr(e,l),Fr(e,u)},onEnter:E(!1),onAppear:E(!0),onLeave(e,t){e._isLeaving=!0;let n=()=>P(e,t);Fr(e,d),e._enterCancelled?(Fr(e,h),Yr(e)):(Yr(e),Fr(e,h)),Ur(()=>{e._isLeaving&&(Vr(e,d),Fr(e,p),qr(y)||Hr(e,a,_,n))}),Dr(y,[e,n])},onEnterCancelled(e){T(e,!1,void 0,!0),Dr(b,[e])},onAppearCancelled(e){T(e,!0,void 0,!0),Dr(C,[e])},onLeaveCancelled(e){P(e),Dr(w,[e])}})}function Fr(e,t){t.split(/\s+/).forEach(t=>t&&e.classList.add(t)),(e[Ir]||(e[Ir]=new Set)).add(t)}function Vr(e,t){t.split(/\s+/).forEach(t=>t&&e.classList.remove(t));let n=e[Ir];n&&(n.delete(t),n.size||(e[Ir]=void 0))}function Ur(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let $r=0;function Hr(e,t,n,a){let i=e._endId=++$r,r=()=>{i===e._endId&&a()};if(null!=n)return setTimeout(r,n);let{type:o,timeout:s,propCount:l}=Wr(e,t);if(!o)return a();let u=o+"end",c=0,d=()=>{e.removeEventListener(u,h),r()},h=t=>{t.target===e&&++c>=l&&d()};setTimeout(()=>{c(n[e]||"").split(", "),i=a(`${Rr}Delay`),r=a(`${Rr}Duration`),o=Gr(i,r),s=a(`${zr}Delay`),l=a(`${zr}Duration`),u=Gr(s,l),c=null,d=0,h=0;return t===Rr?o>0&&(c=Rr,d=o,h=r.length):t===zr?u>0&&(c=zr,d=u,h=l.length):h=(c=(d=Math.max(o,u))>0?o>u?Rr:zr:null)?c===Rr?r.length:l.length:0,{type:c,timeout:d,propCount:h,hasTransform:c===Rr&&/\b(?:transform|all)(?:,|$)/.test(a(`${Rr}Property`).toString())}}function Gr(e,t){for(;e.lengthKr(t)+Kr(e[n])))}function Kr(e){return"auto"===e?0:1e3*Number(e.slice(0,-1).replace(",","."))}function Yr(e){return(e?e.ownerDocument:document).body.offsetHeight}let Qr=Symbol("_vod"),Zr=Symbol("_vsh");function Jr(e,t){e.style.display=t?e[Qr]:"none",e[Zr]=!t}let Xr=Symbol("");function eo(e,t){if(1===e.nodeType){let a=e.style,i="";for(let e in t){var n;let r=null==(n=t[e])?"initial":"string"==typeof n?""===n?" ":n:String(n);a.setProperty(`--${e}`,r),i+=`--${e}: ${r};`}a[Xr]=i}}let to=/(?:^|;)\s*display\s*:/,no=/\s*!important$/;function ao(e,t,n){if(E(n))n.forEach(n=>ao(e,t,n));else if(null==n&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{let a=function(e,t){let n=ro[t];if(n)return n;let a=B(t);if("filter"!==a&&a in e)return ro[t]=a;a=U(a);for(let n=0;n111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&e.charCodeAt(2)>96&&123>e.charCodeAt(2),_o=(e,t,n,a,i,r)=>{let o="svg"===i;if("class"===t){var s;let t;s=a,(t=e[Ir])&&(s=(s?[s,...t]:[...t]).join(" ")),null==s?e.removeAttribute("class"):o?e.setAttribute("class",s):e.className=s}else"style"===t?function(e,t,n){let a=e.style,i=L(n),r=!1;if(n&&!i){if(t)if(L(t))for(let e of t.split(";")){let t=e.slice(0,e.indexOf(":")).trim();null==n[t]&&ao(a,t,"")}else for(let e in t)null==n[e]&&ao(a,e,"");for(let i in n){var o,s,l,u;"display"===i&&(r=!0);let c=n[i];null!=c?(o=e,s=i,l=!L(t)&&t?t[i]:void 0,u=c,"TEXTAREA"===o.tagName&&("width"===s||"height"===s)&&L(u)&&l===u||ao(a,i,c)):ao(a,i,"")}}else if(i){if(t!==n){let e=a[Xr];e&&(n+=";"+e),a.cssText=n,r=to.test(n)}}else t&&e.removeAttribute("style");Qr in e&&(e[Qr]=r?a.display:"",e[Zr]&&(a.display="none"))}(e,n,a):k(t)?x(t)||function(e,t,n,a=null){let i=e[co]||(e[co]={}),r=i[t];if(n&&r)r.value=n;else{let[s,l]=function(e){let t;if(ho.test(e)){let n;for(t={};n=e.match(ho);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[":"===e[2]?e.slice(3):V(e.slice(2)),t]}(t);if(n){var o;let r;uo(e,s,i[t]=(o=a,(r=e=>{if(e._vts){if(e._vts<=r.attached)return}else e._vts=Date.now();Gt(function(e,t){if(!E(t))return t;{let n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(e=>t=>!t._stopped&&e&&e(t))}}(e,r.value),o,5,[e])}).value=n,r.attached=po||(fo.then(()=>po=0),po=Date.now()),r),l)}else r&&(e.removeEventListener(s,r,l),i[t]=void 0)}}(e,t,a,r):("."===t[0]?(t=t.slice(1),0):"^"===t[0]?(t=t.slice(1),1):!function(e,t,n,a){if(a)return!!("innerHTML"===t||"textContent"===t||t in e&&mo(t)&&A(n));if("spellcheck"===t||"draggable"===t||"translate"===t||"autocorrect"===t||"sandbox"===t&&"IFRAME"===e.tagName||"form"===t||"list"===t&&"INPUT"===e.tagName||"type"===t&&"TEXTAREA"===e.tagName)return!1;if("width"===t||"height"===t){let t=e.tagName;if("IMG"===t||"VIDEO"===t||"CANVAS"===t||"SOURCE"===t)return!1}return!(mo(t)&&L(n))&&t in e}(e,t,a,o))?e._isVueCE&&(function(e,t){let n=e._def.props;if(!n)return!1;let a=B(t);return Array.isArray(n)?n.some(e=>B(e)===a):Object.keys(n).some(e=>B(e)===a)}(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!L(a)))?lo(e,B(t),a,0,t):("true-value"===t?e._trueValue=a:"false-value"===t&&(e._falseValue=a),so(e,t,a,o)):(lo(e,t,a),e.tagName.includes("-")||"value"!==t&&"checked"!==t&&"selected"!==t||so(e,t,a,o,0,"value"!==t))},go={};function vo(e,t,n){let a,i=Hn(e,t);"[object Object]"===(a=i,I.call(a))&&(i=S({},i,t));class r extends yo{constructor(e){super(i,e,n)}}return r.def=i,r}let bo="u">typeof HTMLElement?HTMLElement:class{};class yo extends bo{constructor(e,t={},n=Jo){super(),this._def=e,this._props=t,this._createApp=n,this._isVueCE=!0,this._instance=null,this._app=null,this._nonce=this._def.nonce,this._connected=!1,this._resolved=!1,this._patching=!1,this._dirty=!1,this._numberProps=null,this._styleChildren=new WeakSet,this._styleAnchors=new WeakMap,this._ob=null,this.shadowRoot&&n!==Jo?this._root=this.shadowRoot:!1!==e.shadowRoot?(this.attachShadow(S({},e.shadowRootOptions,{mode:"open"})),this._root=this.shadowRoot):this._root=this}connectedCallback(){if(!this.isConnected)return;this.shadowRoot||this._resolved||this._parseSlots(),this._connected=!0;let e=this;for(;e=e&&(e.assignedSlot||e.parentNode||e.host);)if(e instanceof yo){this._parent=e;break}this._instance||(this._resolved?this._mount(this._def):e&&e._pendingResolve?this._pendingResolve=e._pendingResolve.then(()=>{this._pendingResolve=void 0,this._resolveDef()}):this._resolveDef())}_setParent(e=this._parent){e&&(this._instance.parent=e._instance,this._inheritParentContext(e))}_inheritParentContext(e=this._parent){e&&this._app&&Object.setPrototypeOf(this._app._context.provides,e._instance.provides)}disconnectedCallback(){this._connected=!1,nn(()=>{!this._connected&&(this._ob&&(this._ob.disconnect(),this._ob=null),this._app&&this._app.unmount(),this._instance&&(this._instance.ce=void 0),this._app=this._instance=null,this._teleportTargets&&(this._teleportTargets.clear(),this._teleportTargets=void 0))})}_processMutations(e){for(let t of e)this._setAttr(t.attributeName)}_resolveDef(){if(this._pendingResolve)return;for(let e=0;e{let n;this._resolved=!0,this._pendingResolve=void 0;let{props:a,styles:i}=e;if(a&&!E(a))for(let e in a){let t=a[e];(t===Number||t&&t.type===Number)&&(e in this._props&&(this._props[e]=Y(this._props[e])),(n||(n=Object.create(null)))[B(e)]=!0)}this._numberProps=n,this._resolveProps(e),this.shadowRoot&&this._applyStyles(i),this._mount(e)},t=this._def.__asyncLoader;t?this._pendingResolve=t().then(t=>{t.configureApp=this._def.configureApp,e(this._def=t,!0)}):e(this._def)}_mount(e){this._app=this._createApp(e),this._inheritParentContext(),e.configureApp&&e.configureApp(this._app),this._app._ceVNode=this._createVNode(),this._app.mount(this._root);let t=this._instance&&this._instance.exposed;if(t)for(let e in t)P(this,e)||Object.defineProperty(this,e,{get:()=>It(t[e])})}_resolveProps(e){let{props:t}=e,n=E(t)?t:Object.keys(t||{});for(let e of Object.keys(this))"_"!==e[0]&&n.includes(e)&&this._setProp(e,this[e]);for(let e of n.map(B))Object.defineProperty(this,e,{get(){return this._getProp(e)},set(t){this._setProp(e,t,!0,!this._patching)}})}_setAttr(e){if(e.startsWith("data-v-"))return;let t=this.hasAttribute(e),n=t?this.getAttribute(e):go,a=B(e);t&&this._numberProps&&this._numberProps[a]&&(n=Y(n)),this._setProp(a,n,!1,!0)}_getProp(e){return this._props[e]}_setProp(e,t,n=!0,a=!1){if(t!==this._props[e]&&(this._dirty=!0,t===go?delete this._props[e]:(this._props[e]=t,"key"===e&&this._app&&(this._app._ceVNode.key=t)),a&&this._instance&&this._update(),n)){let n=this._ob;n&&(this._processMutations(n.takeRecords()),n.disconnect()),!0===t?this.setAttribute(V(e),""):"string"==typeof t||"number"==typeof t?this.setAttribute(V(e),t+""):t||this.removeAttribute(V(e)),n&&n.observe(this,{attributes:!0})}}_update(){let e=this._createVNode();this._app&&(e.appContext=this._app._context),Zo(e,this._root)}_createVNode(){let e={};this.shadowRoot||(e.onVnodeMounted=e.onVnodeUpdated=this._renderSlots.bind(this));let t=Ji(this._def,S(e,this._props));return this._instance||(t.ce=e=>{this._instance=e,e.ce=this,e.isCE=!0;let t=(e,t)=>{let n;this.dispatchEvent(new CustomEvent(e,"[object Object]"===(n=t[0],I.call(n))?S({detail:t},t[0]):{detail:t}))};e.emit=(e,...n)=>{t(e,n),V(e)!==e&&t(V(e),n)},this._setParent()}),t}_applyStyles(e,t,n){if(!e)return;if(t){if(t===this._def||this._styleChildren.has(t))return;this._styleChildren.add(t)}let a=this._nonce,i=this.shadowRoot,r=n?this._getStyleAnchor(n)||this._getStyleAnchor(this._def):this._getRootStyleInsertionAnchor(i),o=null;for(let s=e.length-1;s>=0;s--){let l=document.createElement("style");a&&l.setAttribute("nonce",a),l.textContent=e[s],i.insertBefore(l,o||r),o=l,0===s&&(n||this._styleAnchors.set(this._def,l),t&&this._styleAnchors.set(t,l))}}_getStyleAnchor(e){if(!e)return null;let t=this._styleAnchors.get(e);return t&&t.parentNode===this.shadowRoot?t:(t&&this._styleAnchors.delete(e),null)}_getRootStyleInsertionAnchor(e){for(let t=0;t{if(!n.length)return;let t=e.moveClass||`${e.name||"v"}-move`;if(!function(e,t,n){let a=e.cloneNode(),i=e[Ir];i&&i.forEach(e=>{e.split(/\s+/).forEach(e=>e&&a.classList.remove(e))}),n.split(/\s+/).forEach(e=>e&&a.classList.add(e)),a.style.display="none";let r=1===t.nodeType?t:t.parentNode;r.appendChild(a);let{hasTransform:o}=Wr(a);return r.removeChild(a),o}(n[0].el,i.vnode.el,t))return void(n=[]);n.forEach(Po),n.forEach(Eo);let a=n.filter(Ao);Yr(i.vnode.el),a.forEach(e=>{let n=e.el,a=n.style;Fr(n,t),a.transform=a.webkitTransform=a.transitionDuration="";let i=n[So]=e=>{(!e||e.target===n)&&(!e||e.propertyName.endsWith("transform"))&&(n.removeEventListener("transitionend",i),n[So]=null,Vr(n,t))};n.addEventListener("transitionend",i)}),n=[]}),()=>{let o=Ct(e),s=Br(o),l=o.tag||Ni;if(n=[],a)for(let e=0;eMath.abs(o-1)&&(o=1),.01>Math.abs(s-1)&&(s=1),n.transform=n.webkitTransform=`translate(${a/o}px,${i/s}px)`,n.transitionDuration="0s",e}}function Lo(e){let t=e.getBoundingClientRect();return{left:t.left,top:t.top}}let Mo=e=>{let t=e.props["onUpdate:modelValue"]||!1;return E(t)?e=>W(t,e):t};function Ro(e){e.target.composing=!0}function zo(e){let t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}let Io=Symbol("_assign");function No(e,t,n){return t&&(e=e.trim()),n&&(e=K(e)),e}let Oo={created(e,{modifiers:{lazy:t,trim:n,number:a}},i){e[Io]=Mo(i);let r=a||i.props&&"number"===i.props.type;uo(e,t?"change":"input",t=>{t.target.composing||e[Io](No(e.value,n,r))}),(n||r)&&uo(e,"change",()=>{e.value=No(e.value,n,r)}),t||(uo(e,"compositionstart",Ro),uo(e,"compositionend",zo),uo(e,"change",zo))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,oldValue:n,modifiers:{lazy:a,trim:i,number:r}},o){if(e[Io]=Mo(o),e.composing)return;let s=null==t?"":t;if((!r&&"number"!==e.type||/^0\d/.test(e.value)?e.value:K(e.value))===s)return;let l=e.getRootNode();(l instanceof Document||l instanceof ShadowRoot)&&l.activeElement===e&&"range"!==e.type&&(a&&t===n||i&&e.value.trim()===s)||(e.value=s)}},jo={deep:!0,created(e,t,n){e[Io]=Mo(n),uo(e,"change",()=>{let t=e._modelValue,n=Vo(e),a=e.checked,i=e[Io];if(E(t)){let e=ce(t,n),r=-1!==e;if(a&&!r)i(t.concat(n));else if(!a&&r){let n=[...t];n.splice(e,1),i(n)}}else{let r;if("[object Set]"===(r=t,I.call(r))){let e=new Set(t);a?e.add(n):e.delete(n),i(e)}else i(Uo(e,a))}})},mounted:Do,beforeUpdate(e,t,n){e[Io]=Mo(n),Do(e,t,n)}};function Do(e,{value:t,oldValue:n},a){let i;if(e._modelValue=t,E(t))i=ce(t,a.props.value)>-1;else{let r;if("[object Set]"===(r=t,I.call(r)))i=t.has(a.props.value);else{if(t===n)return;i=ue(t,Uo(e,!0))}}e.checked!==i&&(e.checked=i)}let qo={created(e,{value:t},n){e.checked=ue(t,n.props.value),e[Io]=Mo(n),uo(e,"change",()=>{e[Io](Vo(e))})},beforeUpdate(e,{value:t,oldValue:n},a){e[Io]=Mo(a),t!==n&&(e.checked=ue(t,a.props.value))}},Bo={deep:!0,created(e,{value:t,modifiers:{number:n}},a){let i,r="[object Set]"===(i=t,I.call(i));uo(e,"change",()=>{let t=Array.prototype.filter.call(e.options,e=>e.selected).map(e=>n?K(Vo(e)):Vo(e));e[Io](e.multiple?r?new Set(t):t:t[0]),e._assigning=!0,nn(()=>{e._assigning=!1})}),e[Io]=Mo(a)},mounted(e,{value:t}){Fo(e,t)},beforeUpdate(e,t,n){e[Io]=Mo(n)},updated(e,{value:t}){e._assigning||Fo(e,t)}};function Fo(e,t){let n,a=e.multiple,i=E(t);if(!a||i||"[object Set]"===(n=t,I.call(n))){for(let n=0,r=e.options.length;nString(e)===String(o)):ce(t,o)>-1}else r.selected=t.has(o);else if(ue(Vo(r),t))return void(e.selectedIndex!==n&&(e.selectedIndex=n))}a||-1===e.selectedIndex||(e.selectedIndex=-1)}}function Vo(e){return"_value"in e?e._value:e.value}function Uo(e,t){let n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}function $o(e,t,n,a,i){let r=function(e,t){switch(e){case"SELECT":return Bo;case"TEXTAREA":return Oo;default:switch(t){case"checkbox":return jo;case"radio":return qo;default:return Oo}}}(e.tagName,n.props&&n.props.type)[i];r&&r(e,t,n,a)}let Ho=["ctrl","shift","alt","meta"],Wo={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>Ho.some(n=>e[`${n}Key`]&&!t.includes(n))},Go={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},Ko=S({patchProp:_o},Mr),Yo=!1;function Qo(){return p=Yo?p:wi(Ko),Yo=!0,p}let Zo=(...e)=>{(p||(p=ki(Ko))).render(...e)},Jo=(...e)=>{let t=(p||(p=ki(Ko))).createApp(...e),{mount:n}=t;return t.mount=e=>{let a=ts(e);if(!a)return;let i=t._component;A(i)||i.render||i.template||(i.template=a.innerHTML),1===a.nodeType&&(a.textContent="");let r=n(a,!1,es(a));return a instanceof Element&&(a.removeAttribute("v-cloak"),a.setAttribute("data-v-app","")),r},t},Xo=(...e)=>{let t=Qo().createApp(...e),{mount:n}=t;return t.mount=e=>{let t=ts(e);if(t)return n(t,!0,es(t))},t};function es(e){return e instanceof SVGElement?"svg":"function"==typeof MathMLElement&&e instanceof MathMLElement?"mathml":void 0}function ts(e){return L(e)?document.querySelector(e):e}let ns=Symbol(""),as=Symbol(""),is=Symbol(""),rs=Symbol(""),os=Symbol(""),ss=Symbol(""),ls=Symbol(""),us=Symbol(""),cs=Symbol(""),ds=Symbol(""),hs=Symbol(""),ps=Symbol(""),fs=Symbol(""),ms=Symbol(""),_s=Symbol(""),gs=Symbol(""),vs=Symbol(""),bs=Symbol(""),ys=Symbol(""),ws=Symbol(""),ks=Symbol(""),xs=Symbol(""),Ss=Symbol(""),Cs=Symbol(""),Ts=Symbol(""),Ps=Symbol(""),Es=Symbol(""),As=Symbol(""),Ls=Symbol(""),Ms=Symbol(""),Rs=Symbol(""),zs=Symbol(""),Is=Symbol(""),Ns=Symbol(""),Os=Symbol(""),js=Symbol(""),Ds=Symbol(""),qs=Symbol(""),Bs=Symbol(""),Fs={[ns]:"Fragment",[as]:"Teleport",[is]:"Suspense",[rs]:"KeepAlive",[os]:"BaseTransition",[ss]:"openBlock",[ls]:"createBlock",[us]:"createElementBlock",[cs]:"createVNode",[ds]:"createElementVNode",[hs]:"createCommentVNode",[ps]:"createTextVNode",[fs]:"createStaticVNode",[ms]:"resolveComponent",[_s]:"resolveDynamicComponent",[gs]:"resolveDirective",[vs]:"resolveFilter",[bs]:"withDirectives",[ys]:"renderList",[ws]:"renderSlot",[ks]:"createSlots",[xs]:"toDisplayString",[Ss]:"mergeProps",[Cs]:"normalizeClass",[Ts]:"normalizeStyle",[Ps]:"normalizeProps",[Es]:"guardReactiveProps",[As]:"toHandlers",[Ls]:"camelize",[Ms]:"capitalize",[Rs]:"toHandlerKey",[zs]:"setBlockTracking",[Is]:"pushScopeId",[Ns]:"popScopeId",[Os]:"withCtx",[js]:"unref",[Ds]:"isRef",[qs]:"withMemo",[Bs]:"isMemoSame"},Vs={start:{line:1,column:1,offset:0},end:{line:1,column:1,offset:0},source:""};function Us(e,t,n,a,i,r,o,s=!1,l=!1,u=!1,c=Vs){return e&&(s?(e.helper(ss),e.helper(e.inSSR||u?ls:us)):e.helper(e.inSSR||u?cs:ds),o&&e.helper(bs)),{type:13,tag:t,props:n,children:a,patchFlag:i,dynamicProps:r,directives:o,isBlock:s,disableTracking:l,isComponent:u,loc:c}}function $s(e,t=Vs){return{type:17,loc:t,elements:e}}function Hs(e,t=Vs){return{type:15,loc:t,properties:e}}function Ws(e,t){return{type:16,loc:Vs,key:L(e)?Gs(e,!0):e,value:t}}function Gs(e,t=!1,n=Vs,a=0){return{type:4,loc:n,content:e,isStatic:t,constType:t?3:a}}function Ks(e,t=Vs){return{type:8,loc:t,children:e}}function Ys(e,t=[],n=Vs){return{type:14,loc:n,callee:e,arguments:t}}function Qs(e,t,n=!1,a=!1,i=Vs){return{type:18,params:e,returns:t,newline:n,isSlot:a,loc:i}}function Zs(e,t,n,a=!0){return{type:19,test:e,consequent:t,alternate:n,newline:a,loc:Vs}}function Js(e,{helper:t,removeHelper:n,inSSR:a}){var i,r;e.isBlock||(e.isBlock=!0,n((i=e.isComponent,a||i?cs:ds)),t(ss),t((r=e.isComponent,a||r?ls:us)))}let Xs=new Uint8Array([123,123]),el=new Uint8Array([125,125]);function tl(e){return e>=97&&e<=122||e>=65&&e<=90}function nl(e){return 32===e||10===e||9===e||12===e||13===e}function al(e){return 47===e||62===e||nl(e)}function il(e){let t=new Uint8Array(e.length);for(let n=0;n4===e.type&&e.isStatic;function cl(e){switch(e){case"Teleport":case"teleport":return as;case"Suspense":case"suspense":return is;case"KeepAlive":case"keep-alive":return rs;case"BaseTransition":case"base-transition":return os}}let dl=/^$|^\d|[^\$\w\xA0-\uFFFF]/,hl=/[A-Za-z_$\xA0-\uFFFF]/,pl=/[\.\?\w$\xA0-\uFFFF]/,fl=/\s+[.[]\s*|\s*[.[]\s+/g,ml=e=>4===e.type?e.content:e.loc.source,_l=e=>{let t=ml(e).trim().replace(fl,e=>e.trim()),n=0,a=[],i=0,r=0,o=null;for(let e=0;e|^\s*(?:async\s+)?function(?:\s+[\w$]+)?\s*\(/;function vl(e,t,n=!1){for(let a=0;a4===e.key.type&&e.key.content===a)}return n}function Al(e,t){return`_${t}_${e.replace(/[^\w]/g,(t,n)=>"-"===t?"_":e.charCodeAt(n).toString())}`}let Ll=/([\s\S]*?)\s+(?:in|of)\s+(\S[\s\S]*)/;function Ml(e){for(let t=0;t0,isVoidTag:w,isPreTag:w,isIgnoreNewlineTag:w,isCustomElement:w,onError:ol,onWarn:sl,comments:!1,prefixIdentifiers:!1},Nl=Il,Ol=null,jl="",Dl=null,ql=null,Bl="",Fl=-1,Vl=-1,Ul=0,$l=!1,Hl=null,Wl=[],Gl=new class{constructor(e,t){this.stack=e,this.cbs=t,this.state=1,this.buffer="",this.sectionStart=0,this.index=0,this.entityStart=0,this.baseState=1,this.inRCDATA=!1,this.inXML=!1,this.inVPre=!1,this.newlines=[],this.mode=0,this.delimiterOpen=Xs,this.delimiterClose=el,this.delimiterIndex=-1,this.currentSequence=void 0,this.sequenceIndex=0}get inSFCRoot(){return 2===this.mode&&0===this.stack.length}reset(){this.state=1,this.mode=0,this.buffer="",this.sectionStart=0,this.index=0,this.baseState=1,this.inRCDATA=!1,this.currentSequence=void 0,this.newlines.length=0,this.delimiterOpen=Xs,this.delimiterClose=el}getPos(e){let t=1,n=e+1,a=this.newlines.length,i=-1;if(a>100){let t=-1,n=a;for(;t+1>>1;this.newlines[a]=0;t--)if(e>this.newlines[t]){i=t;break}return i>=0&&(t=i+2,n=e-this.newlines[i]),{column:n,line:t,offset:e}}peek(){return this.buffer.charCodeAt(this.index+1)}stateText(e){60===e?(this.index>this.sectionStart&&this.cbs.ontext(this.sectionStart,this.index),this.state=5,this.sectionStart=this.index):this.inVPre||e!==this.delimiterOpen[0]||(this.state=2,this.delimiterIndex=0,this.stateInterpolationOpen(e))}stateInterpolationOpen(e){if(e===this.delimiterOpen[this.delimiterIndex])if(this.delimiterIndex===this.delimiterOpen.length-1){let e=this.index+1-this.delimiterOpen.length;e>this.sectionStart&&this.cbs.ontext(this.sectionStart,e),this.state=3,this.sectionStart=e}else this.delimiterIndex++;else this.inRCDATA?(this.state=32,this.stateInRCDATA(e)):(this.state=1,this.stateText(e))}stateInterpolation(e){e===this.delimiterClose[0]&&(this.state=4,this.delimiterIndex=0,this.stateInterpolationClose(e))}stateInterpolationClose(e){e===this.delimiterClose[this.delimiterIndex]?this.delimiterIndex===this.delimiterClose.length-1?(this.cbs.oninterpolation(this.sectionStart,this.index+1),this.inRCDATA?this.state=32:this.state=1,this.sectionStart=this.index+1):this.delimiterIndex++:(this.state=3,this.stateInterpolation(e))}stateSpecialStartSequence(e){let t=this.sequenceIndex===this.currentSequence.length;if(t?al(e):(32|e)===this.currentSequence[this.sequenceIndex]){if(!t)return void this.sequenceIndex++}else this.inRCDATA=!1;this.sequenceIndex=0,this.state=6,this.stateInTagName(e)}stateInRCDATA(e){if(this.sequenceIndex===this.currentSequence.length){if(62===e||nl(e)){let t=this.index-this.currentSequence.length;if(this.sectionStart=e||(28===this.state?this.currentSequence===rl.CdataEnd?this.cbs.oncdata(this.sectionStart,e):this.cbs.oncomment(this.sectionStart,e):6===this.state||11===this.state||18===this.state||17===this.state||12===this.state||13===this.state||14===this.state||15===this.state||16===this.state||20===this.state||19===this.state||21===this.state||9===this.state||this.cbs.ontext(this.sectionStart,e))}emitCodePoint(e,t){}}(Wl,{onerr:uu,ontext(e,t){Jl(Ql(e,t),e,t)},ontextentity(e,t,n){Jl(e,t,n)},oninterpolation(e,t){if($l)return Jl(Ql(e,t),e,t);let n=e+Gl.delimiterOpen.length,a=t-Gl.delimiterClose.length;for(;nl(jl.charCodeAt(n));)n++;for(;nl(jl.charCodeAt(a-1));)a--;let i=Ql(n,a);i.includes("&")&&(i=Nl.decodeEntities(i,!1)),ru({type:5,content:lu(i,!1,ou(n,a)),loc:ou(e,t)})},onopentagname(e,t){let n=Ql(e,t);Dl={type:1,tag:n,ns:Nl.getNamespace(n,Wl[0],Nl.ns),tagType:0,props:[],children:[],loc:ou(e-1,t),codegenNode:void 0}},onopentagend(e){Zl(e)},onclosetag(e,t){let n=Ql(e,t);if(!Nl.isVoidTag(n)){let a=!1;for(let e=0;e0&&Wl[0].loc.start.offset;for(let n=0;n<=e;n++)Xl(Wl.shift(),t,n(7===e.type?e.rawName:e.name)===t)},onattribend(e,t){Dl&&ql&&(su(ql.loc,t),0!==e&&(Bl.includes("&")&&(Bl=Nl.decodeEntities(Bl,!0)),6===ql.type?("class"===ql.name&&(Bl=iu(Bl).trim()),ql.value={type:2,content:Bl,loc:1===e?ou(Fl,Vl):ou(Fl-1,Vl+1)},Gl.inSFCRoot&&"template"===Dl.tag&&"lang"===ql.name&&Bl&&"html"!==Bl&&Gl.enterRCDATA(il("{let i=t.start.offset+n;return lu(e,!1,ou(i,i+e.length),0,+!!a)},s={source:o(r.trim(),n.indexOf(r,i.length)),value:void 0,key:void 0,index:void 0,finalized:!1},l=i.trim().replace(Yl,"").trim(),u=i.indexOf(l),c=l.match(Kl);if(c){let e;l=l.replace(Kl,"").trim();let t=c[1].trim();if(t&&(e=n.indexOf(t,u+l.length),s.key=o(t,e,!0)),c[2]){let a=c[2].trim();a&&(s.index=o(a,n.indexOf(a,s.key?e+t.length:u+l.length),!0))}}return l&&(s.value=o(l,u,!0)),s}(ql.exp)))),(7!==ql.type||"pre"!==ql.name)&&Dl.props.push(ql)),Bl="",Fl=Vl=-1},oncomment(e,t){Nl.comments&&ru({type:3,content:Ql(e,t),loc:ou(e-4,t+3)})},onend(){let e=jl.length;for(let t=0;t64&&n<91||cl(e)||Nl.isBuiltInComponent&&Nl.isBuiltInComponent(e)||Nl.isNativeTag&&!Nl.isNativeTag(e))return!0;for(let e=0;e=0;)n--;return n}let tu=new Set(["if","else","else-if","for","slot"]),nu=/\r\n/g;function au(e){let t="preserve"!==Nl.whitespace,n=!1;for(let a=0;a3!==e.type);return 1!==t.length||1!==t[0].type||Cl(t[0])?null:t[0]}function du(e,t){let{constantCache:n}=t;switch(e.type){case 1:if(0!==e.tagType)return 0;let s=n.get(e);if(void 0!==s)return s;let l=e.codegenNode;if(13!==l.type||l.isBlock&&"svg"!==e.tag&&"foreignObject"!==e.tag&&"math"!==e.tag)return 0;if(void 0!==l.patchFlag)return n.set(e,0),0;{let s=3,u=pu(e,t);if(0===u)return n.set(e,0),0;u1)for(let a=0;a{n--};for(;nt===e:t=>e.test(t);return(e,a)=>{if(1===e.type){let{props:i}=e;if(3===e.tagType&&i.some(xl))return;let r=[];for(let o=0;o`${Fs[e]}: _${Fs[e]}`;function bu(e,t,{helper:n,push:a,newline:i,isTS:r}){let o=n("component"===t?ms:gs);for(let n=0;n3;t.push("["),n&&t.indent(),wu(e,t,n),n&&t.deindent(),t.push("]")}function wu(e,t,n=!1,a=!0){let{push:i,newline:r}=t;for(let o=0;oe||"null")}([o,s,l,n,c]),t),a(")"),h&&a(")"),d&&(a(", "),ku(d,t),a(")"))}(e,t);break;case 14:!function(e,t){let{push:n,helper:a,pure:i}=t,r=L(e.callee)?e.callee:a(e.callee);i&&n(gu),n(r+"(",-2,e),wu(e.arguments,t),n(")")}(e,t);break;case 15:!function(e,t){let{push:n,indent:a,deindent:i,newline:r}=t,{properties:o}=e;if(!o.length)return n("{}",-2,e);let s=o.length>1;n(s?"{":"{ "),s&&a();for(let e=0;e "),(l||s)&&(n("{"),a()),o?(l&&n("return "),E(o)?yu(o,t):ku(o,t)):s&&ku(s,t),(l||s)&&(i(),n("}")),u&&n(")")}(e,t);break;case 19:!function(e,t){let{test:n,consequent:a,alternate:i,newline:r}=e,{push:o,indent:s,deindent:l,newline:u}=t;if(4===n.type){let e,a=(e=n.content,!!dl.test(e));a&&o("("),xu(n,t),a&&o(")")}else o("("),ku(n,t),o(")");r&&s(),t.indentLevel++,r||o(" "),o("? "),ku(a,t),t.indentLevel--,r&&u(),r||o(" "),o(": ");let c=19===i.type;!c&&t.indentLevel++,ku(i,t),!c&&t.indentLevel--,r&&l(!0)}(e,t);break;case 20:!function(e,t){let{push:n,helper:a,indent:i,deindent:r,newline:o}=t,{needPauseTracking:s,needArraySpread:l}=e;l&&n("[...("),n(`_cache[${e.index}] || (`),s&&(i(),n(`${a(zs)}(-1`),e.inVOnce&&n(", true"),n("),"),o(),n("(")),n(`_cache[${e.index}] = `),ku(e.value,t),s&&(n(`).cacheIndex = ${e.index},`),o(),n(`${a(zs)}(1),`),o(),n(`_cache[${e.index}]`),r()),n(")"),l&&n(")]")}(e,t);break;case 21:wu(e.body,t,!0,!1)}}function xu(e,t){let{content:n,isStatic:a}=e;t.push(a?JSON.stringify(n):n,-3,e)}function Su(e,t){for(let n=0;nfunction(e,t,n,a){if(!("else"===t.name||t.exp&&t.exp.content.trim())){let a=t.exp?t.exp.loc:e.loc;n.onError(ll(28,t.loc)),t.exp=Gs("true",!1,a)}if("if"===t.name){var i;let r=Tu(e,t),o={type:9,loc:ou((i=e.loc).start.offset,i.end.offset),branches:[r]};if(n.replaceNode(o),a)return a(o,r,!0)}else{let i=n.parent.children,r=i.indexOf(e);for(;r-- >=-1;){let o=i[r];if(!o||!zl(o)){if(o&&9===o.type){("else-if"===t.name||"else"===t.name)&&void 0===o.branches[o.branches.length-1].condition&&n.onError(ll(30,e.loc)),n.removeNode();let i=Tu(e,t);o.branches.push(i);let r=a&&a(o,i,!1);mu(i,n),r&&r(),n.currentNode=null}else n.onError(ll(30,e.loc));break}n.removeNode(o)}}}(e,t,n,(e,t,a)=>{let i=n.parent.children,r=i.indexOf(e),o=0;for(;r-- >=0;){let e=i[r];e&&9===e.type&&(o+=e.branches.length)}return()=>{a?e.codegenNode=Pu(t,o,n):(function(e){for(;;)if(19===e.type){if(19!==e.alternate.type)return e;e=e.alternate}else 20===e.type&&(e=e.value)}(e.codegenNode)).alternate=Pu(t,o+e.branches.length-1,n)}}));function Tu(e,t){let n=3===e.tagType;return{type:10,loc:e.loc,condition:"else"===t.name?void 0:t.exp,children:n&&!vl(e,"for")?e.children:[e],userKey:bl(e,"key"),isTemplateIf:n}}function Pu(e,t,n){return e.condition?Zs(e.condition,Eu(e,t,n),Ys(n.helper(hs),['""',"true"])):Eu(e,t,n)}function Eu(e,t,n){let{helper:a}=n,i=Ws("key",Gs(`${t}`,!1,Vs,2)),{children:r}=e,o=r[0];if(1!==r.length||1!==o.type){if(1!==r.length||11!==o.type)return Us(n,a(ns),Hs([i]),r,64,void 0,void 0,!0,!1,!1,e.loc);{let e=o.codegenNode;return Pl(e,i,n),e}}{let e=o.codegenNode,t=14===e.type&&e.callee===qs?e.arguments[1].returns:e;return 13===t.type&&Js(t,n),Pl(t,i,n),e}}let Au=_u("for",(e,t,n)=>{let{helper:a,removeHelper:i}=n;return function(e,t,n,a){if(!t.exp)return void n.onError(ll(31,t.loc));let i=t.forParseResult;if(!i)return void n.onError(ll(32,t.loc));Lu(i);let{scopes:r}=n,{source:o,value:s,key:l,index:u}=i,c={type:11,loc:t.loc,source:o,valueAlias:s,keyAlias:l,objectIndexAlias:u,parseResult:i,children:Sl(e)?e.children:[e]};n.replaceNode(c),r.vFor++;let d=a&&a(c);return()=>{r.vFor--,d&&d()}}(e,t,n,t=>{let r=Ys(a(ys),[t.source]),o=Sl(e),s=vl(e,"memo"),l=bl(e,"key",!1,!0);l&&l.type;let u=l&&(6===l.type?l.value?Gs(l.value.content,!0):void 0:l.exp),c=l&&u?Ws("key",u):null,d=4===t.source.type&&t.source.constType>0,h=d?64:l?128:256;return t.codegenNode=Us(n,a(ns),void 0,r,h,void 0,void 0,!0,!d,!1,e.loc),()=>{let l,{children:h}=t,p=1!==h.length||1!==h[0].type,f=Cl(e)?e:o&&1===e.children.length&&Cl(e.children[0])?e.children[0]:null;if(f)l=f.codegenNode,o&&c&&Pl(l,c,n);else if(p)l=Us(n,a(ns),c?Hs([c]):void 0,e.children,64,void 0,void 0,!0,void 0,!1);else{var m,_,g,v,b,y,w,k;l=h[0].codegenNode,o&&c&&Pl(l,c,n),!d!==l.isBlock&&(l.isBlock?(i(ss),i((m=n.inSSR,_=l.isComponent,m||_?ls:us))):i((g=n.inSSR,v=l.isComponent,g||v?cs:ds))),l.isBlock=!d,l.isBlock?(a(ss),a((b=n.inSSR,y=l.isComponent,b||y?ls:us))):a((w=n.inSSR,k=l.isComponent,w||k?cs:ds))}if(s){let e=Qs(Mu(t.parseResult,[Gs("_cached")]));e.body={type:21,body:[Ks(["const _memo = (",s.exp,")"]),Ks(["if (_cached && _cached.el",...u?[" && _cached.key === ",u]:[],` && ${n.helperString(Bs)}(_cached, _memo)) return _cached`]),Ks(["const _item = ",l]),Gs("_item.memo = _memo"),Gs("return _item")],loc:Vs},r.arguments.push(e,Gs("_cache"),Gs(String(n.cached.length))),n.cached.push(null)}else r.arguments.push(Qs(Mu(t.parseResult),l,!0))}})});function Lu(e,t){e.finalized||(e.finalized=!0)}function Mu({value:e,key:t,index:n},a=[]){var i=[e,t,n,...a];let r=i.length;for(;r--&&!i[r];);return i.slice(0,r+1).map((e,t)=>e||Gs("_".repeat(t+1),!1))}let Ru=Gs("undefined",!1),zu=(e,t)=>{if(1===e.type&&(1===e.tagType||3===e.tagType)){let n=vl(e,"slot");if(n)return n.exp,t.scopes.vSlot++,()=>{t.scopes.vSlot--}}};function Iu(e,t,n){let a=[Ws("name",e),Ws("fn",t)];return null!=n&&a.push(Ws("key",Gs(String(n),!0))),Hs(a)}let Nu=new WeakMap,Ou=(e,t)=>function(){let n,a,i,r,o;if(1!==(e=t.currentNode).type||0!==e.tagType&&1!==e.tagType)return;let{tag:s,props:l}=e,u=1===e.tagType,c=u?function(e,t,n=!1){let{tag:a}=e,i=qu(a),r=bl(e,"is",!1,!0);if(r)if(i){let e;if(6===r.type?e=r.value&&Gs(r.value.content,!0):(e=r.exp)||(e=Gs("is",!1,r.arg.loc)),e)return Ys(t.helper(_s),[e])}else 6===r.type&&r.value.content.startsWith("vue:")&&(a=r.value.content.slice(4));let o=cl(a)||t.isBuiltInComponent(a);return o?(n||t.helper(o),o):(t.helper(ms),t.components.add(a),Al(a,"component"))}(e,t):`"${s}"`,d=R(c)&&c.callee===_s,h=0,p=d||c===as||c===is||!u&&("svg"===s||"foreignObject"===s||"math"===s);if(l.length>0){let a=ju(e,t,void 0,u,d);n=a.props,h=a.patchFlag,r=a.dynamicPropNames;let i=a.directives;o=i&&i.length?$s(i.map(e=>function(e,t){let n=[],a=Nu.get(e);a?n.push(t.helperString(a)):(t.helper(gs),t.directives.add(e.name),n.push(Al(e.name,"directive")));let{loc:i}=e;if(e.exp&&n.push(e.exp),e.arg&&(e.exp||n.push("void 0"),n.push(e.arg)),Object.keys(e.modifiers).length){e.arg||(e.exp||n.push("void 0"),n.push("void 0"));let t=Gs("true",!1,i);n.push(Hs(e.modifiers.map(e=>Ws(e,t)),i))}return $s(n,e.loc)}(e,t))):void 0,a.shouldUseBlock&&(p=!0)}if(e.children.length>0)if(c===rs&&(p=!0,h|=1024),u&&c!==as&&c!==rs){let{slots:n,hasDynamicSlots:i}=function(e,t,n=(e,t,n,a)=>Qs(e,n,!1,!0,n.length?n[0].loc:a)){t.helper(Os);let{children:a,loc:i}=e,r=[],o=[],s=t.scopes.vSlot>0||t.scopes.vFor>0,l=vl(e,"slot",!0);if(l){let{arg:e,exp:t}=l;e&&!ul(e)&&(s=!0),r.push(Ws(e||Gs("default",!0),n(t,void 0,a,i)))}let u=!1,c=!1,d=[],h=new Set,p=0;for(let e=0;eWs("default",n(e,void 0,t,i));u?d.length&&!d.every(Rl)&&(c?t.onError(ll(39,d[0].loc)):r.push(e(void 0,d))):r.push(e(void 0,a))}let f=s?2:function e(t){for(let n=0;n0,f=!1,m=0,_=!1,g=!1,v=!1,b=!1,y=!1,w=!1,x=[],S=e=>{c.length&&(d.push(Hs(Du(c),l)),c=[]),e&&d.push(e)},C=()=>{t.scopes.vFor>0&&c.push(Ws(Gs("ref_for",!0),Gs("true")))},T=({key:e,value:n})=>{if(ul(e)){let r=e.content,o=k(r);o&&(!a||i)&&"onclick"!==r.toLowerCase()&&"onUpdate:modelValue"!==r&&!O(r)&&(b=!0),o&&O(r)&&(w=!0),o&&14===n.type&&(n=n.arguments[0]),20===n.type||(4===n.type||8===n.type)&&du(n,t)>0||("ref"===r?_=!0:"class"===r?g=!0:"style"===r?v=!0:"key"===r||x.includes(r)||x.push(r),a&&("class"===r||"style"===r)&&!x.includes(r)&&x.push(r))}else y=!0};for(let i=0;i"prop"===e.content)&&(m|=32);let w=t.directiveTransforms[n];if(w){let{props:n,needRuntime:a}=w(o,e,t);r||n.forEach(T),b&&i&&!ul(i)?S(Hs(n,l)):c.push(...n),a&&(h.push(o),M(a)&&Nu.set(o,a))}else!j(n)&&(h.push(o),p&&(f=!0))}}if(d.length?(S(),o=d.length>1?Ys(t.helper(Ss),d,l):d[0]):c.length&&(o=Hs(Du(c),l)),y?m|=16:(g&&!a&&(m|=2),v&&!a&&(m|=4),x.length&&(m|=8),b&&(m|=32)),!f&&(0===m||32===m)&&(_||w||h.length>0)&&(m|=512),!t.inSSR&&o)switch(o.type){case 15:let e=-1,n=-1,a=!1;for(let t=0;t{if(Cl(e)){let{children:n,loc:a}=e,{slotName:i,slotProps:r}=function(e,t){let n,a='"default"',i=[];for(let t=0;t0){let{props:a,directives:r}=ju(e,t,i,!1,!1);n=a,r.length&&t.onError(ll(36,r[0].loc))}return{slotName:a,slotProps:n}}(e,t),o=[t.prefixIdentifiers?"_ctx.$slots":"$slots",i,"{}","undefined","true"],s=2;r&&(o[2]=r,s=3),n.length&&(o[3]=Qs([],n,!1,!1,a),s=4),t.scopeId&&!t.slotted&&(s=5),o.splice(s),e.codegenNode=Ys(t.helper(ws),o,a)}},Fu=(e,t,n,a)=>{let i,{loc:r,modifiers:o,arg:s}=e;if(!e.exp&&o.length,4===s.type)if(s.isStatic){let e=s.content;e.startsWith("vue:")&&(e=`vnode-${e.slice(4)}`),i=Gs(0!==t.tagType||e.startsWith("vnode")||!/[A-Z]/.test(e)?$(B(e)):`on:${e}`,!0,s.loc)}else i=Ks([`${n.helperString(Rs)}(`,s,")"]);else(i=s).children.unshift(`${n.helperString(Rs)}(`),i.children.push(")");let l=e.exp;l&&!l.content.trim()&&(l=void 0);let u=n.cacheHandlers&&!l&&!n.inVOnce;if(l){let e,t=_l(l),n=!(t||(e=l,gl.test(ml(e)))),a=l.content.includes(";");(n||u&&t)&&(l=Ks([`${n?"$event":"(...args)"} => ${a?"{":"("}`,l,a?"}":")"]))}let c={props:[Ws(i,l||Gs("() => {}",!1,r))]};return a&&(c=a(c)),u&&(c.props[0].value=n.cache(c.props[0].value)),c.props.forEach(e=>e.key.isHandlerKey=!0),c},Vu=(e,t,n)=>{let{modifiers:a}=e,i=e.arg,{exp:r}=e;return r&&4===r.type&&!r.content.trim()&&(r=void 0),4!==i.type?(i.children.unshift("("),i.children.push(') || ""')):i.isStatic||(i.content=i.content?`${i.content} || ""`:'""'),a.some(e=>"camel"===e.content)&&(4===i.type?i.isStatic?i.content=B(i.content):i.content=`${n.helperString(Ls)}(${i.content})`:(i.children.unshift(`${n.helperString(Ls)}(`),i.children.push(")"))),!n.inSSR&&(a.some(e=>"prop"===e.content)&&Uu(i,"."),a.some(e=>"attr"===e.content)&&Uu(i,"^")),{props:[Ws(i,r)]}},Uu=(e,t)=>{4===e.type?e.isStatic?e.content=t+e.content:e.content=`\`${t}\${${e.content}}\``:(e.children.unshift(`'${t}' + (`),e.children.push(")"))},$u=(e,t)=>{if(0===e.type||1===e.type||11===e.type||10===e.type)return()=>{let n,a=e.children,i=!1;for(let e=0;e7===e.type&&!t.directiveTransforms[e.name]))))for(let e=0;e{if(1===e.type&&vl(e,"once",!0)&&!Hu.has(e)&&!t.inVOnce&&!t.inSSR)return Hu.add(e),t.inVOnce=!0,t.helper(zs),()=>{t.inVOnce=!1;let e=t.currentNode;e.codegenNode&&(e.codegenNode=t.cache(e.codegenNode,!0,!0))}},Gu=(e,t,n)=>{let a,{exp:i,arg:r}=e;if(!i)return n.onError(ll(41,e.loc)),Ku();let o=i.loc.source.trim(),s=4===i.type?i.content:o,l=n.bindingMetadata[o];if("props"===l||"props-aliased"===l||"literal-const"===l||"setup-const"===l)return i.loc,Ku();if(!s.trim()||!_l(i))return n.onError(ll(42,i.loc)),Ku();let u=r||Gs("modelValue",!0),c=r?ul(r)?`onUpdate:${B(r.content)}`:Ks(['"onUpdate:" + ',r]):"onUpdate:modelValue";a=Ks([`${n.isTS?"($event: any)":"$event"} => ((`,i,") = $event)"]);let d=[Ws(u,e.exp),Ws(c,a)];if(e.modifiers.length&&1===t.tagType){let t=e.modifiers.map(e=>e.content).map(e=>(dl.test(e)?JSON.stringify(e):e)+": true").join(", "),n=r?ul(r)?`${r.content}Modifiers`:Ks([r,' + "Modifiers"']):"modelModifiers";d.push(Ws(n,Gs(`{ ${t} }`,!1,e.loc,2)))}return Ku(d)};function Ku(e=[]){return{props:e}}let Yu=new WeakSet,Qu=(e,t)=>{if(1===e.type){let n=vl(e,"memo");if(n&&!Yu.has(e)&&!t.inSSR)return Yu.add(e),()=>{let a=e.codegenNode||t.currentNode.codegenNode;a&&13===a.type&&(1!==e.tagType&&Js(a,t),e.codegenNode=Ys(t.helper(qs),[n.exp,Qs(void 0,a),"_cache",String(t.cached.length)]),t.cached.push(null))}}},Zu=(e,t)=>{if(1===e.type)for(let n of e.props)if(7===n.type&&"bind"===n.name&&(!n.exp||4===n.exp.type&&!n.exp.content.trim())&&n.arg){let e=n.arg;if(4===e.type&&e.isStatic){let t=B(e.content);(hl.test(t[0])||"-"===t[0])&&(n.exp=Gs(t,!1,e.loc))}else t.onError(ll(53,e.loc)),n.exp=Gs("",!0,e.loc)}},Ju=Symbol(""),Xu=Symbol(""),ec=Symbol(""),tc=Symbol(""),nc=Symbol(""),ac=Symbol(""),ic=Symbol(""),rc=Symbol(""),oc=Symbol(""),sc=Symbol("");Object.getOwnPropertySymbols(a={[Ju]:"vModelRadio",[Xu]:"vModelCheckbox",[ec]:"vModelText",[tc]:"vModelSelect",[nc]:"vModelDynamic",[ac]:"withModifiers",[ic]:"withKeys",[rc]:"vShow",[oc]:"Transition",[sc]:"TransitionGroup"}).forEach(e=>{Fs[e]=a[e]});let lc={parseMode:"html",isVoidTag:se,isNativeTag:e=>ie(e)||re(e)||oe(e),isPreTag:e=>"pre"===e,isIgnoreNewlineTag:e=>"pre"===e||"textarea"===e,decodeEntities:function(e,t=!1){return f||(f=document.createElement("div")),t?(f.innerHTML=`
`,f.children[0].getAttribute("foo")):(f.innerHTML=e,f.textContent)},isBuiltInComponent:e=>"Transition"===e||"transition"===e?oc:"TransitionGroup"===e||"transition-group"===e?sc:void 0,getNamespace(e,t,n){let a=t?t.ns:n;if(t&&2===a)if("annotation-xml"===t.tag){if("svg"===e)return 1;t.props.some(e=>6===e.type&&"encoding"===e.name&&null!=e.value&&("text/html"===e.value.content||"application/xhtml+xml"===e.value.content))&&(a=0)}else/^m(?:[ions]|text)$/.test(t.tag)&&"mglyph"!==e&&"malignmark"!==e&&(a=0);else t&&1===a&&("foreignObject"===t.tag||"desc"===t.tag||"title"===t.tag)&&(a=0);if(0===a){if("svg"===e)return 1;if("math"===e)return 2}return a}},uc=g("passive,once,capture"),cc=g("stop,prevent,self,ctrl,shift,alt,meta,exact,middle"),dc=g("left,right"),hc=g("onkeyup,onkeydown,onkeypress"),pc=(e,t)=>ul(e)&&"onclick"===e.content.toLowerCase()?Gs(t,!0):4!==e.type?Ks(["(",e,`) === "onClick" ? "${t}" : (`,e,")"]):e,fc=(e,t)=>{1===e.type&&0===e.tagType&&("script"===e.tag||"style"===e.tag)&&t.removeNode()},mc=[e=>{1===e.type&&e.props.forEach((t,n)=>{let a,i;6===t.type&&"style"===t.name&&t.value&&(e.props[n]={type:7,name:"bind",arg:Gs("style",!0,t.loc),exp:(a=t.value.content,i=t.loc,Gs(JSON.stringify(ne(a)),!1,i,3)),modifiers:[],loc:t.loc})})}],_c={cloak:()=>({props:[]}),html:(e,t,n)=>{let{exp:a,loc:i}=e;return a||n.onError(ll(54,i)),t.children.length&&(n.onError(ll(55,i)),t.children.length=0),{props:[Ws(Gs("innerHTML",!0,i),a||Gs("",!0))]}},text:(e,t,n)=>{let{exp:a,loc:i}=e;return a||n.onError(ll(56,i)),t.children.length&&(n.onError(ll(57,i)),t.children.length=0),{props:[Ws(Gs("textContent",!0),a?du(a,n)>0?a:Ys(n.helperString(xs),[a],i):Gs("",!0))]}},model:(e,t,n)=>{let a=Gu(e,t,n);if(!a.props.length||1===t.tagType)return a;e.arg&&n.onError(ll(59,e.arg.loc));let{tag:i}=t,r=n.isCustomElement(i);if("input"===i||"textarea"===i||"select"===i||r){let o=ec,s=!1;if("input"===i||r){let a=bl(t,"type");if(a){if(7===a.type)o=nc;else if(a.value)switch(a.value.content){case"radio":o=Ju;break;case"checkbox":o=Xu;break;case"file":s=!0,n.onError(ll(60,e.loc))}}else t.props.some(e=>!(7!==e.type||"bind"!==e.name||e.arg&&4===e.arg.type&&e.arg.isStatic))&&(o=nc)}else"select"===i&&(o=tc);s||(a.needRuntime=n.helper(o))}else n.onError(ll(58,e.loc));return a.props=a.props.filter(e=>4!==e.key.type||"modelValue"!==e.key.content),a},on:(e,t,n)=>Fu(e,t,n,t=>{let{modifiers:a}=e;if(!a.length)return t;let{key:i,value:r}=t.props[0],{keyModifiers:o,nonKeyModifiers:s,eventOptionModifiers:l}=((e,t)=>{let n=[],a=[],i=[];for(let r=0;r{let{exp:a,loc:i}=e;return a||n.onError(ll(62,i)),{props:[],needRuntime:n.helper(rc)}}},gc=Object.create(null);function vc(e,t){if(!L(e)){if(!e.nodeType)return y;e=e.innerHTML}let n=e+JSON.stringify(t,(e,t)=>"function"==typeof t?t.toString():t),a=gc[n];if(a)return a;if("#"===e[0]){let t=document.querySelector(e);e=t?t.innerHTML:""}let i=S({hoistStatic:!0,onError:void 0,onWarn:y},t);!i.isCustomElement&&"u">typeof customElements&&(i.isCustomElement=e=>!!customElements.get(e));let{code:r}=function(e,t={}){return function(e,t={}){var n;let a,i=t.onError||ol,r="module"===t.mode;!0===t.prefixIdentifiers?i(ll(48)):r&&i(ll(49)),t.cacheHandlers&&i(ll(50)),t.scopeId&&!r&&i(ll(51));let o=S({},t,{prefixIdentifiers:!1}),s=L(e)?function(e,t){if(Gl.reset(),Dl=null,ql=null,Bl="",Fl=-1,Vl=-1,Wl.length=0,jl=e,Nl=S({},Il),t){let e;for(e in t)null!=t[e]&&(Nl[e]=t[e])}Gl.mode="html"===Nl.parseMode?1:2*("sfc"===Nl.parseMode),Gl.inXML=1===Nl.ns||2===Nl.ns;let n=t&&t.delimiters;n&&(Gl.delimiterOpen=il(n[0]),Gl.delimiterClose=il(n[1]));let a=Ol=function(e,t=""){return{type:0,source:t,children:[],helpers:new Set,components:[],directives:[],hoists:[],imports:[],cached:[],temps:0,codegenNode:void 0,loc:Vs}}(0,e);return Gl.parse(jl),a.loc=ou(0,e.length),a.children=au(a.children),Ol=null,a}(e,o):e,[l,u]=[[Zu,Wu,Cu,Qu,Au,Bu,Ou,zu,$u],{on:Fu,bind:Vu,model:Gu}];return a=function(e,{filename:t="",prefixIdentifiers:n=!1,hoistStatic:a=!1,hmr:i=!1,cacheHandlers:r=!1,nodeTransforms:o=[],directiveTransforms:s={},transformHoist:l=null,isBuiltInComponent:u=y,isCustomElement:c=y,expressionPlugins:d=[],scopeId:h=null,slotted:p=!0,ssr:f=!1,inSSR:m=!1,ssrCssVars:_="",bindingMetadata:g=v,inline:b=!1,isTS:w=!1,onError:k=ol,onWarn:x=sl,compatConfig:S}){let C=t.replace(/\?.*$/,"").match(/([^/\\]+)\.\w+$/),T={filename:t,selfName:C&&U(B(C[1])),prefixIdentifiers:n,hoistStatic:a,hmr:i,cacheHandlers:r,nodeTransforms:o,directiveTransforms:s,transformHoist:l,isBuiltInComponent:u,isCustomElement:c,expressionPlugins:d,scopeId:h,slotted:p,ssr:f,inSSR:m,ssrCssVars:_,bindingMetadata:g,inline:b,isTS:w,onError:k,onWarn:x,compatConfig:S,root:e,helpers:new Map,components:new Set,directives:new Set,hoists:[],imports:[],cached:[],constantCache:new WeakMap,temps:0,identifiers:Object.create(null),scopes:{vFor:0,vSlot:0,vPre:0,vOnce:0},parent:null,grandParent:null,currentNode:e,childIndex:0,inVOnce:!1,helper(e){let t=T.helpers.get(e)||0;return T.helpers.set(e,t+1),e},removeHelper(e){let t=T.helpers.get(e);if(t){let n=t-1;n?T.helpers.set(e,n):T.helpers.delete(e)}},helperString:e=>`_${Fs[T.helper(e)]}`,replaceNode(e){T.parent.children[T.childIndex]=T.currentNode=e},removeNode(e){let t=T.parent.children,n=e?t.indexOf(e):T.currentNode?T.childIndex:-1;e&&e!==T.currentNode?T.childIndex>n&&(T.childIndex--,T.onNodeRemoved()):(T.currentNode=null,T.onNodeRemoved()),T.parent.children.splice(n,1)},onNodeRemoved:y,addIdentifiers(e){},removeIdentifiers(e){},hoist(e){L(e)&&(e=Gs(e)),T.hoists.push(e);let t=Gs(`_hoisted_${T.hoists.length}`,!1,e.loc,2);return t.hoisted=e,t},cache(e,t=!1,n=!1){let a=function(e,t,n=!1,a=!1){return{type:20,index:e,value:t,needPauseTracking:n,inVOnce:a,needArraySpread:!1,loc:Vs}}(T.cached.length,e,t,n);return T.cached.push(a),a}};return T}(s,n=S({},o,{nodeTransforms:[...l,...t.nodeTransforms||[]],directiveTransforms:S({},u,t.directiveTransforms||{})})),mu(s,a),n.hoistStatic&&function e(t,n,a,i=!1,r=!1){let{children:o}=t,s=[];for(let n=0;n0){if(e>=2){l.codegenNode.patchFlag=-1,s.push(l);continue}}else{let e=l.codegenNode;if(13===e.type){let t=e.patchFlag;if((void 0===t||512===t||1===t)&&pu(l,a)>=2){let t=fu(l);t&&(e.props=a.hoist(t))}e.dynamicProps&&(e.dynamicProps=a.hoist(e.dynamicProps))}}}else if(12===l.type&&(i?0:du(l,a))>=2){14===l.codegenNode.type&&l.codegenNode.arguments.length>0&&l.codegenNode.arguments.push("-1"),s.push(l);continue}if(1===l.type){let n=1===l.tagType;n&&a.scopes.vSlot++,e(l,t,a,!1,r),n&&a.scopes.vSlot--}else if(11===l.type)e(l,t,a,1===l.children.length,!0);else if(9===l.type)for(let n=0;ne.key===t||e.key.content===t);return n&&n.value}}s.length&&a.transformHoist&&a.transformHoist(o,a,t)}(s,void 0,a,!!cu(s)),n.ssr||function(e,t){let{helper:n}=t,{children:a}=e;if(1===a.length){let n=cu(e);if(n&&n.codegenNode){let a=n.codegenNode;13===a.type&&Js(a,t),e.codegenNode=a}else e.codegenNode=a[0]}else a.length>1&&(e.codegenNode=Us(t,n(ns),void 0,e.children,64,void 0,void 0,!0,void 0,!1))}(s,a),s.helpers=new Set([...a.helpers.keys()]),s.components=[...a.components],s.directives=[...a.directives],s.imports=a.imports,s.hoists=a.hoists,s.temps=a.temps,s.cached=a.cached,s.transformed=!0,function(e,t={}){let n=function(e,{mode:t="function",prefixIdentifiers:n="module"===t,sourceMap:a=!1,filename:i="template.vue.html",scopeId:r=null,optimizeImports:o=!1,runtimeGlobalName:s="Vue",runtimeModuleName:l="vue",ssrRuntimeModuleName:u="vue/server-renderer",ssr:c=!1,isTS:d=!1,inSSR:h=!1}){let p={mode:t,prefixIdentifiers:n,sourceMap:a,filename:i,scopeId:r,optimizeImports:o,runtimeGlobalName:s,runtimeModuleName:l,ssrRuntimeModuleName:u,ssr:c,isTS:d,inSSR:h,source:e.source,code:"",column:1,line:1,offset:0,indentLevel:0,pure:!1,map:void 0,helper:e=>`_${Fs[e]}`,push(e,t=-2,n){p.code+=e},indent(){f(++p.indentLevel)},deindent(e=!1){e?--p.indentLevel:f(--p.indentLevel)},newline(){f(p.indentLevel)}};function f(e){p.push("\n"+" ".repeat(e),0)}return p}(e,t);t.onContextCreated&&t.onContextCreated(n);let{mode:a,push:i,prefixIdentifiers:r,indent:o,deindent:s,newline:l,ssr:u}=n,c=Array.from(e.helpers),d=c.length>0,h=!r&&"module"!==a;if(function(e,t){let{push:n,newline:a,runtimeGlobalName:i}=t,r=Array.from(e.helpers);if(r.length>0&&(n(`const _Vue = ${i}\n`,-1),e.hoists.length)){n(`const { ${[cs,ds,hs,ps,fs].filter(e=>r.includes(e)).map(vu).join(", ")} } = _Vue\n`,-1)}(function(e,t){if(!e.length)return;t.pure=!0;let{push:n,newline:a}=t;a();for(let i=0;i0)&&l()),e.directives.length&&(bu(e.directives,"directive",n),e.temps>0&&l()),e.temps>0){i("let ");for(let t=0;t0?", ":""}_temp${t}`)}return(e.components.length||e.directives.length||e.temps)&&(i("\n",0),l()),u||i("return "),e.codegenNode?ku(e.codegenNode,n):i("null"),h&&(s(),i("}")),s(),i("}"),{ast:e,code:n.code,preamble:"",map:n.map?n.map.toJSON():void 0}}(s,o)}(e,S({},lc,t,{nodeTransforms:[fc,...mc,...t.nodeTransforms||[]],directiveTransforms:S({},_c,t.directiveTransforms||{}),transformHoist:null}))}(e,i),o=Function(r)();return o._rc=!0,gc[n]=o}return gr(vc),e.BaseTransition=Dn,e.BaseTransitionPropsValidators=Nn,e.Comment=ji,e.DeprecationTypes=null,e.EffectScope=me,e.ErrorCodes={SETUP_FUNCTION:0,0:"SETUP_FUNCTION",RENDER_FUNCTION:1,1:"RENDER_FUNCTION",NATIVE_EVENT_HANDLER:5,5:"NATIVE_EVENT_HANDLER",COMPONENT_EVENT_HANDLER:6,6:"COMPONENT_EVENT_HANDLER",VNODE_HOOK:7,7:"VNODE_HOOK",DIRECTIVE_HOOK:8,8:"DIRECTIVE_HOOK",TRANSITION_HOOK:9,9:"TRANSITION_HOOK",APP_ERROR_HANDLER:10,10:"APP_ERROR_HANDLER",APP_WARN_HANDLER:11,11:"APP_WARN_HANDLER",FUNCTION_REF:12,12:"FUNCTION_REF",ASYNC_COMPONENT_LOADER:13,13:"ASYNC_COMPONENT_LOADER",SCHEDULER:14,14:"SCHEDULER",COMPONENT_UPDATE:15,15:"COMPONENT_UPDATE",APP_UNMOUNT_CLEANUP:16,16:"APP_UNMOUNT_CLEANUP"},e.ErrorTypeStrings=null,e.Fragment=Ni,e.KeepAlive={name:"KeepAlive",__isKeepAlive:!0,props:{include:[String,RegExp,Array],exclude:[String,RegExp,Array],max:[String,Number]},setup(e,{slots:t}){let n=dr(),a=n.ctx,i=new Map,r=new Set,o=null,s=n.suspense,{renderer:{p:l,m:u,um:c,o:{createElement:d}}}=a,h=d("div");function p(e){fa(e),c(e,n,s,!0)}function f(e){i.forEach((t,n)=>{let a=kr(sa(t)?t.type.__asyncResolved||{}:t.type);a&&!e(a)&&m(n)})}function m(e){let t=i.get(e);!t||o&&Ki(t,o)?o&&fa(o):p(t),i.delete(e),r.delete(e)}a.activate=(e,t,n,a,i)=>{let r=e.component;u(e,t,n,0,s),l(r.vnode,e,t,n,r,s,a,e.slotScopeIds,i),yi(()=>{r.isDeactivated=!1,r.a&&W(r.a);let t=e.props&&e.props.onVnodeMounted;t&&sr(t,r.parent,e)},s)},a.deactivate=e=>{let t=e.component;Pi(t.m),Pi(t.a),u(e,h,null,1,s),yi(()=>{t.da&&W(t.da);let n=e.props&&e.props.onVnodeUnmounted;n&&sr(n,t.parent,e),t.isDeactivated=!0},s)},bn(()=>[e.include,e.exclude],([e,t])=>{e&&f(t=>ca(e,t)),t&&f(e=>!ca(t,e))},{flush:"post",deep:!0});let _=null,g=()=>{null!=_&&(Ei(n.subTree.type)?yi(()=>{i.set(_,ma(n.subTree))},n.subTree.suspense):i.set(_,ma(n.subTree)))};return ba(g),wa(g),ka(()=>{i.forEach(e=>{let{subTree:t,suspense:a}=n,i=ma(t);if(e.type===i.type&&e.key===i.key){fa(i);let e=i.component.da;return void(e&&yi(e,a))}p(e)})}),()=>{if(_=null,!t.default)return o=null;let n=t.default(),a=n[0];if(n.length>1)return o=null,n;if(!(Gi(a)&&(4&a.shapeFlag||128&a.shapeFlag)))return o=null,a;let s=ma(a);if(s.type===ji)return o=null,s;let l=s.type,u=kr(sa(s)?s.type.__asyncResolved||{}:l),{include:c,exclude:d,max:h}=e;if(c&&(!u||!ca(c,u))||d&&u&&ca(d,u))return s.shapeFlag&=-257,o=s,a;let p=null==s.key?l:s.key,f=i.get(p);return s.el&&(s=er(s),128&a.shapeFlag&&(a.ssContent=s)),_=p,f?(s.el=f.el,s.component=f.component,s.transition&&Un(s,s.transition),s.shapeFlag|=512,r.delete(p),r.add(p)):(r.add(p),h&&r.size>parseInt(h,10)&&m(r.values().next().value)),s.shapeFlag|=256,o=s,Ei(a.type)?a:s}}},e.ReactiveEffect=ge,e.Static=Di,e.Suspense={name:"Suspense",__isSuspense:!0,process(e,t,n,a,i,r,o,s,l,u){if(null==e)!function(e,t,n,a,i,r,o,s,l){let{p:u,o:{createElement:c}}=l,d=c("div"),h=e.suspense=Mi(e,i,a,t,d,n,r,o,s,l);u(null,h.pendingBranch=e.ssContent,d,null,a,h,r,o),h.deps>0?(Li(e,"onPending"),Li(e,"onFallback"),u(null,e.ssFallback,t,n,a,null,r,o),Ii(h,e.ssFallback)):h.resolve(!1,!0)}(t,n,a,i,r,o,s,l,u);else{if(r&&r.deps>0&&!e.suspense.isInFallback)return t.suspense=e.suspense,t.suspense.vnode=t,void(t.el=e.el);!function(e,t,n,a,i,r,o,s,{p:l,um:u,o:{createElement:c}}){let d=t.suspense=e.suspense;d.vnode=t,t.el=e.el;let h=t.ssContent,p=t.ssFallback,{activeBranch:f,pendingBranch:m,isInFallback:_,isHydrating:g}=d;if(m)d.pendingBranch=h,Ki(m,h)?(l(m,h,d.hiddenContainer,null,i,d,r,o,s),d.deps<=0?d.resolve():_&&!g&&(l(f,p,n,a,i,null,r,o,s),Ii(d,p))):(d.pendingId=Ai++,g?(d.isHydrating=!1,d.activeBranch=m):u(m,i,d),d.deps=0,d.effects.length=0,d.hiddenContainer=c("div"),_?(l(null,h,d.hiddenContainer,null,i,d,r,o,s),d.deps<=0?d.resolve():(l(f,p,n,a,i,null,r,o,s),Ii(d,p))):f&&Ki(f,h)?(l(f,h,n,a,i,d,r,o,s),d.resolve(!0)):(l(null,h,d.hiddenContainer,null,i,d,r,o,s),d.deps<=0&&d.resolve()));else if(f&&Ki(f,h))l(f,h,n,a,i,d,r,o,s),Ii(d,h);else if(Li(t,"onPending"),d.pendingBranch=h,512&h.shapeFlag?d.pendingId=h.component.suspenseId:d.pendingId=Ai++,l(null,h,d.hiddenContainer,null,i,d,r,o,s),d.deps<=0)d.resolve();else{let{timeout:e,pendingId:t}=d;e>0?setTimeout(()=>{d.pendingId===t&&d.fallback(p)},e):0===e&&d.fallback(p)}}(e,t,n,a,i,o,s,l,u)}},hydrate:function(e,t,n,a,i,r,o,s,l){let u=t.suspense=Mi(t,a,n,e.parentNode,document.createElement("div"),null,i,r,o,s,!0),c=l(e,u.pendingBranch=t.ssContent,n,u,r,o);return 0===u.deps&&u.resolve(!1,!0),c},normalize:function(e){let{shapeFlag:t,children:n}=e,a=32&t;e.ssContent=Ri(a?n.default:n),e.ssFallback=a?Ri(n.fallback):Ji(ji)}},e.Teleport={name:"Teleport",__isTeleport:!0,process(e,t,n,a,i,r,o,s,l,u){let{mc:c,pc:d,pbc:h,o:{insert:p,querySelector:f,createText:m,parentNode:_}}=u,g=Sn(t.props),{dynamicChildren:v}=t,b=(e,t,n)=>{16&e.shapeFlag&&c(e.children,t,n,i,r,o,s,l)},y=(e=t)=>{let n=Sn(e.props),a=e.target=Pn(e.props,f),r=Ln(a,e,m,p);a&&("svg"!==o&&Cn(a)?o="svg":"mathml"!==o&&Tn(a)&&(o="mathml"),i&&i.isCE&&(i.ce._teleportTargets||(i.ce._teleportTargets=new Set)).add(a),n||(b(e,a,r),An(e,!1)))},w=e=>{let t=()=>{if(kn.get(e)===t){if(kn.delete(e),Sn(e.props)){let t=_(e.el)||n;b(e,t,e.anchor),An(e,!0)}y(e)}};kn.set(e,t),yi(t,r)};if(null==e){let e,i=t.el=m(""),o=t.anchor=m("");if(p(i,n,a),p(o,n,a),(e=t.props)&&(e.defer||""===e.defer)||r&&r.pendingBranch)return void w(t);g&&(b(t,n,o),An(t,!0)),y()}else{t.el=e.el;let a=t.anchor=e.anchor,c=kn.get(e);if(c)return c.flags|=8,kn.delete(e),void w(t);t.targetStart=e.targetStart;let p=t.target=e.target,m=t.targetAnchor=e.targetAnchor,_=Sn(e.props),b=_?n:p,y=_?a:m;if("svg"===o||Cn(p)?o="svg":("mathml"===o||Tn(p))&&(o="mathml"),v?(h(e.dynamicChildren,v,b,i,r,o,s),Ti(e,t,!0)):l||d(e,t,b,y,i,r,o,s,!1),g)_?t.props&&e.props&&t.props.to!==e.props.to&&(t.props.to=e.props.to):En(t,n,a,u,1);else if((t.props&&t.props.to)!==(e.props&&e.props.to)){let e=t.target=Pn(t.props,f);e&&En(t,e,null,u,0)}else _&&En(t,p,m,u,1);An(t,g)}},remove(e,t,n,{um:a,o:{remove:i}},r){let{shapeFlag:o,children:s,anchor:l,targetStart:u,targetAnchor:c,target:d,props:h}=e,p=r||!Sn(h),f=kn.get(e);if(f&&(f.flags|=8,kn.delete(e),p=!1),d&&(i(u),i(c)),r&&i(l),16&o)for(let e=0;ee[a]});return n},e.createRenderer=function(e){return ki(e)},e.createSSRApp=Xo,e.createSlots=function(e,t){for(let n=0;n{let t=a.fn(...e);return t&&(t.key=a.key),t}:a.fn)}return e},e.createStaticVNode=function(e,t){let n=Ji(Di,null,e);return n.staticCount=t,n},e.createTextVNode=tr,e.createVNode=Ji,e.customRef=Dt,e.defineAsyncComponent=function(e){let t;A(e)&&(e={loader:e});let{loader:n,loadingComponent:a,errorComponent:i,delay:r=200,hydrate:o,timeout:s,suspensible:l=!0,onError:u}=e,c=null,d=0,h=()=>{let e;return c||(e=c=n().catch(e=>{if(e=e instanceof Error?e:Error(String(e)),u)return new Promise((t,n)=>{u(e,()=>t((d++,c=null,h())),()=>n(e),d+1)});throw e}).then(n=>e!==c&&c?c:(n&&(n.__esModule||"Module"===n[Symbol.toStringTag])&&(n=n.default),t=n,n)))};return Hn({name:"AsyncComponentWrapper",__asyncLoader:h,__asyncHydrate(e,n,a){let i=!1;(n.bu||(n.bu=[])).push(()=>i=!0);let r=()=>{i||a()},s=o?()=>{let t=o(r,t=>function(e,t){if(ea(e)&&"["===e.data){let n=1,a=e.nextSibling;for(;a;){if(1===a.nodeType){if(!1===t(a))break}else if(ea(a))if("]"===a.data){if(0==--n)break}else"["===a.data&&n++;a=a.nextSibling}}else t(e)}(e,t));t&&(n.bum||(n.bum=[])).push(t)}:r;t?s():h().then(()=>!n.isUnmounted&&s())},get __asyncResolved(){return t},setup(){let e=cr;if(Wn(e),t)return()=>la(t,e);let n=t=>{c=null,Kt(t,e,13,!i)};if(l&&e.suspense)return h().then(t=>()=>la(t,e)).catch(e=>(n(e),()=>i?Ji(i,{error:e}):null));let o=Lt(!1),u=Lt(),d=Lt(!!r);return r&&setTimeout(()=>{d.value=!1},r),null!=s&&setTimeout(()=>{if(!o.value&&!u.value){let e=Error(`Async component timed out after ${s}ms.`);n(e),u.value=e}},s),h().then(()=>{o.value=!0,e.parent&&ua(e.parent.vnode)&&e.parent.update()}).catch(e=>{n(e),u.value=e}),()=>o.value&&t?la(t,e):u.value&&i?Ji(i,{error:u.value}):a&&!d.value?la(a,e):void 0}})},e.defineComponent=Hn,e.defineCustomElement=vo,e.defineEmits=function(){return null},e.defineExpose=function(e){},e.defineModel=function(){},e.defineOptions=function(e){},e.defineProps=function(){return null},e.defineSSRCustomElement=(e,t)=>vo(e,t,Xo),e.defineSlots=function(){return null},e.devtools=void 0,e.effect=function(e,t){e.effect instanceof ge&&(e=e.effect.fn);let n=new ge(e);t&&S(n,t);try{n.run()}catch(e){throw n.stop(),e}let a=n.run.bind(n);return a.effect=n,a},e.effectScope=function(e){return new me(e)},e.getCurrentInstance=dr,e.getCurrentScope=function(){return r},e.getCurrentWatcher=function(){return m},e.getTransitionRawChildren=$n,e.guardReactiveProps=Xi,e.h=Sr,e.handleError=Kt,e.hasInjectionContext=function(){return!(!dr()&&!Za)},e.hydrate=(...e)=>{Qo().hydrate(...e)},e.hydrateOnIdle=(e=1e4)=>t=>{let n=ra(t,{timeout:e});return()=>oa(n)},e.hydrateOnInteraction=(e=[])=>(t,n)=>{L(e)&&(e=[e]);let a=!1,i=e=>{a||(a=!0,r(),t(),e.target.dispatchEvent(new e.constructor(e.type,e)))},r=()=>{n(t=>{for(let n of e)t.removeEventListener(n,i)})};return n(t=>{for(let n of e)t.addEventListener(n,i,{once:!0})}),r},e.hydrateOnMediaQuery=e=>t=>{if(e){let n=matchMedia(e);if(!n.matches)return n.addEventListener("change",t,{once:!0}),()=>n.removeEventListener("change",t);t()}},e.hydrateOnVisible=e=>(t,n)=>{let a=new IntersectionObserver(e=>{for(let n of e)if(n.isIntersecting){a.disconnect(),t();break}},e);return n(e=>{if(e instanceof Element){if(function(e){let{top:t,left:n,bottom:a,right:i}=e.getBoundingClientRect(),{innerHeight:r,innerWidth:o}=window;return(t>0&&t0&&a0&&n0&&ia.disconnect()},e.initCustomFormatter=function(){},e.initDirectivesForSSR=y,e.inject=_n,e.isMemoSame=Cr,e.isProxy=St,e.isReactive=wt,e.isReadonly=kt,e.isRef=At,e.isRuntimeOnly=()=>!d,e.isShallow=xt,e.isVNode=Gi,e.markRaw=Tt,e.mergeDefaults=function(e,t){let n=Da(e);for(let e in t){if(e.startsWith("__skip"))continue;let a=n[e];a?E(a)||A(a)?a=n[e]={type:a,default:t[e]}:a.default=t[e]:null===a&&(a=n[e]={default:t[e]}),a&&t[`__skip_${e}`]&&(a.skipFactory=!0)}return n},e.mergeModels=function(e,t){return e&&t?E(e)&&E(t)?e.concat(t):S({},Da(e),Da(t)):e||t},e.mergeProps=or,e.nextTick=nn,e.nodeOps=Mr,e.normalizeClass=ae,e.normalizeProps=function(e){if(!e)return null;let{class:t,style:n}=e;return t&&!L(t)&&(e.class=ae(t)),n&&(e.style=J(n)),e},e.normalizeStyle=J,e.onActivated=da,e.onBeforeMount=va,e.onBeforeUnmount=ka,e.onBeforeUpdate=ya,e.onDeactivated=ha,e.onErrorCaptured=Pa,e.onMounted=ba,e.onRenderTracked=Ta,e.onRenderTriggered=Ca,e.onScopeDispose=function(e,t=!1){r&&r.cleanups.push(e)},e.onServerPrefetch=Sa,e.onUnmounted=xa,e.onUpdated=wa,e.onWatcherCleanup=$t,e.openBlock=Fi,e.patchProp=_o,e.popScopeId=function(){dn=null},e.provide=mn,e.proxyRefs=Ot,e.pushScopeId=function(e){dn=e},e.queuePostFlushCb=on,e.reactive=gt,e.readonly=bt,e.ref=Lt,e.registerRuntimeCompiler=gr,e.render=Zo,e.renderList=function(e,t,n,a){let i,r=n&&n[a],o=E(e);if(o||L(e)){let n=!1,a=!1;o&&wt(e)&&(n=!xt(e),a=kt(e),e=Fe(e)),i=Array(e.length);for(let o=0,s=e.length;ot(e,n,void 0,r&&r[n]));else{let n=Object.keys(e);i=Array(n.length);for(let a=0,o=n.length;a0;return"default"!==t&&(n.name=t),Fi(),Wi(Ni,null,[Ji("slot",n,a&&a())],e?-2:64)}let r=e[t];r&&r._c&&(r._d=!1),Fi();let o=r&&function e(t){return t.some(t=>!Gi(t)||t.type!==ji&&(t.type!==Ni||!!e(t.children)))?t:null}(r(n)),s=n.key||o&&o.key,l=Wi(Ni,{key:(s&&!M(s)?s:`_${t}`)+(!o&&a?"_fb":"")},o||(a?a():[]),o&&1===e._?64:-2);return!i&&l.scopeId&&(l.slotScopeIds=[l.scopeId+"-s"]),r&&r._c&&(r._d=!0),l},e.resolveComponent=function(e,t){return La(Ea,e,!0,t)||e},e.resolveDirective=function(e){return La("directives",e)},e.resolveDynamicComponent=function(e){return L(e)?La(Ea,e,!1)||e:e||Aa},e.resolveFilter=null,e.resolveTransitionHooks=Bn,e.setBlockTracking=$i,e.setDevtoolsHook=y,e.setTransitionHooks=Un,e.shallowReactive=vt,e.shallowReadonly=function(e){return yt(e,!0,rt,ht,_t)},e.shallowRef=Mt,e.ssrContextKey=gn,e.ssrUtils=null,e.stop=function(e){e.effect.stop()},e.toDisplayString=he,e.toHandlerKey=$,e.toHandlers=function(e,t){let n={};for(let a in e)n[t&&/[A-Z]/.test(a)?`on:${a}`:$(a)]=e[a];return n},e.toRaw=Ct,e.toRef=function(e,t,n){return At(e)?e:A(e)?new Bt(e):R(e)&&arguments.length>1?new qt(e,t,n):Lt(e)},e.toRefs=function(e){let t=E(e)?Array(e.length):{};for(let n in e)t[n]=new qt(e,n,void 0);return t},e.toValue=function(e){return A(e)?e():It(e)},e.transformVNodeArgs=function(e){},e.triggerRef=function(e){e.dep&&e.dep.trigger()},e.unref=It,e.useAttrs=function(){return ja().attrs},e.useCssModule=function(e="$style"){return v},e.useCssVars=function(e){let t=dr();if(!t)return;let n=t.ut=(n=e(t.proxy))=>{Array.from(document.querySelectorAll(`[data-v-owner="${t.uid}"]`)).forEach(e=>eo(e,n))},a=()=>{let a=e(t.proxy);t.ce?eo(t.ce,a):function e(t,n){if(128&t.shapeFlag){let a=t.suspense;t=a.activeBranch,a.pendingBranch&&!a.isHydrating&&a.effects.push(()=>{e(a.activeBranch,n)})}for(;t.component;)t=t.component.subTree;if(1&t.shapeFlag&&t.el)eo(t.el,n);else if(t.type===Ni)t.children.forEach(t=>e(t,n));else if(t.type===Di){let{el:e,anchor:a}=t;for(;e&&(eo(e,n),e!==a);)e=e.nextSibling}}(t.subTree,a),n(a)};ya(()=>{on(a)}),ba(()=>{bn(a,y,{flush:"post"});let e=new MutationObserver(a);e.observe(t.subTree.el.parentNode,{childList:!0}),xa(()=>e.disconnect())})},e.useHost=wo,e.useId=function(){let e=dr();return e?(e.appContext.config.idPrefix||"v")+"-"+e.ids[0]+e.ids[1]++:""},e.useModel=function(e,t,n=v){let a=dr(),i=B(t),r=V(t),o=Ja(e,i),s=Dt((o,s)=>{let l,u,c=v;return vn(()=>{let t=e[i];H(l,t)&&(l=t,s())}),{get:()=>(o(),n.get?n.get(l):l),set(e){let o=n.set?n.set(e):e;if(!(H(o,l)||c!==v&&H(e,c)))return;let d=a.vnode.props;d&&(t in d||i in d||r in d)&&(`onUpdate:${t}`in d||`onUpdate:${i}`in d||`onUpdate:${r}`in d)||(l=e,s()),a.emit(`update:${t}`,o),H(e,o)&&H(e,c)&&!H(o,u)&&s(),c=e,u=o}}});return s[Symbol.iterator]=()=>{let e=0;return{next:()=>e<2?{value:e++?o||v:s,done:!1}:{done:!0}}},s},e.useSSRContext=()=>{},e.useShadowRoot=function(){let e=wo();return e&&e.shadowRoot},e.useSlots=function(){return ja().slots},e.useTemplateRef=function(e){let t=dr(),n=Mt(null);return t&&Object.defineProperty(t.refs===v?t.refs={}:t.refs,e,{enumerable:!0,get:()=>n.value,set:e=>n.value=e}),n},e.useTransitionState=zn,e.vModelCheckbox=jo,e.vModelDynamic={created(e,t,n){$o(e,t,n,null,"created")},mounted(e,t,n){$o(e,t,n,null,"mounted")},beforeUpdate(e,t,n,a){$o(e,t,n,a,"beforeUpdate")},updated(e,t,n,a){$o(e,t,n,a,"updated")}},e.vModelRadio=qo,e.vModelSelect=Bo,e.vModelText=Oo,e.vShow={name:"show",beforeMount(e,{value:t},{transition:n}){e[Qr]="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):Jr(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:a}){!t!=!n&&(a?t?(a.beforeEnter(e),Jr(e,!0),a.enter(e)):a.leave(e,()=>{Jr(e,!1)}):Jr(e,t))},beforeUnmount(e,{value:t}){Jr(e,t)}},e.version=Tr,e.warn=y,e.watch=function(e,t,n){return bn(e,t,n)},e.watchEffect=function(e,t){return bn(e,null,t)},e.watchPostEffect=function(e,t){return bn(e,null,{flush:"post"})},e.watchSyncEffect=vn,e.withAsyncContext=function(e){let t=dr(),n=mr,a=e();pr(),n&&c(!1);let i=()=>{hr(t),n&&c(!0)},r=()=>{dr()!==t&&t.scope.off(),pr(),n&&c(!1)};return z(a)&&(a=a.catch(e=>{throw i(),Promise.resolve().then(()=>Promise.resolve().then(r)),e})),[a,()=>{i(),Promise.resolve().then(r)}]},e.withCtx=pn,e.withDefaults=function(e,t){return null},e.withDirectives=function(e,t){if(null===cn)return e;let n=wr(cn),a=e.dirs||(e.dirs=[]);for(let e=0;e{let n=e._withKeys||(e._withKeys={}),a=t.join(".");return n[a]||(n[a]=n=>{if(!("key"in n))return;let a=V(n.key);return t.some(e=>e===a||Go[e]===a)?e(n):void 0})},e.withMemo=function(e,t,n,a){let i=n[a];if(i&&Cr(i,e))return i;let r=t();return r.memo=e.slice(),r.cacheIndex=a,n[a]=r},e.withModifiers=(e,t)=>{if(!e)return e;let n=e._withMods||(e._withMods={}),a=t.join(".");return n[a]||(n[a]=(n,...a)=>{for(let e=0;epn,e}({}); /*! - * Quasar Framework v2.18.6 - * (c) 2015-present Razvan Stoenescu - * Released under the MIT License. - */(()=>{var e=Object.defineProperty,t=(t,n)=>{for(var a in n)e(t,a,{get:n[a],enumerable:!0})},{h:n,ref:a,computed:i,watch:o,isRef:r,toRaw:s,unref:l,reactive:u,shallowReactive:c,nextTick:d,onActivated:h,onDeactivated:p,onBeforeMount:f,onMounted:m,onBeforeUnmount:g,onUnmounted:_,onBeforeUpdate:v,onUpdated:b,inject:y,provide:w,getCurrentInstance:k,markRaw:x,Transition:S,TransitionGroup:C,KeepAlive:T,Teleport:P,useSSRContext:E,withDirectives:A,vShow:M,defineComponent:L,createApp:R}=window.Vue;function z(e,t,n,a){return Object.defineProperty(e,t,{get:n,set:a,enumerable:!0}),e}function N(e,t){for(let n in t)z(e,n,t[n]);return e}var O,I=a(!1);var q="ontouchstart"in window||window.navigator.maxTouchPoints>0;var D=navigator.userAgent||navigator.vendor||window.opera,j={userAgent:D,is:function(e){let t=e.toLowerCase(),n=function(e){return/(ipad)/.exec(e)||/(ipod)/.exec(e)||/(windows phone)/.exec(e)||/(iphone)/.exec(e)||/(kindle)/.exec(e)||/(silk)/.exec(e)||/(android)/.exec(e)||/(win)/.exec(e)||/(mac)/.exec(e)||/(linux)/.exec(e)||/(cros)/.exec(e)||/(playbook)/.exec(e)||/(bb)/.exec(e)||/(blackberry)/.exec(e)||[]}(t),a=function(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||/(opr)[\/]([\w.]+)/.exec(e)||/(vivaldi)[\/]([\w.]+)/.exec(e)||/(chrome|crios)[\/]([\w.]+)/.exec(e)||/(version)(applewebkit)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||/(firefox|fxios)[\/]([\w.]+)/.exec(e)||/(webkit)[\/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[\/]([\w.]+)/.exec(e)||[];return{browser:n[5]||n[3]||n[1]||"",version:n[4]||n[2]||"0",platform:t[0]||""}}(t,n),i={mobile:!1,desktop:!1,cordova:!1,capacitor:!1,nativeMobile:!1,electron:!1,bex:!1,linux:!1,mac:!1,win:!1,cros:!1,chrome:!1,firefox:!1,opera:!1,safari:!1,vivaldi:!1,edge:!1,edgeChromium:!1,ie:!1,webkit:!1,android:!1,ios:!1,ipad:!1,iphone:!1,ipod:!1,kindle:!1,winphone:!1,blackberry:!1,playbook:!1,silk:!1};a.browser&&(i[a.browser]=!0,i.version=a.version,i.versionNumber=parseInt(a.version,10)),a.platform&&(i[a.platform]=!0);let o=i.android||i.ios||i.bb||i.blackberry||i.ipad||i.iphone||i.ipod||i.kindle||i.playbook||i.silk||i["windows phone"];if(!0===o||-1!==t.indexOf("mobile")?i.mobile=!0:i.desktop=!0,i["windows phone"]&&(i.winphone=!0,delete i["windows phone"]),i.edga||i.edgios||i.edg?(i.edge=!0,a.browser="edge"):i.crios?(i.chrome=!0,a.browser="chrome"):i.fxios&&(i.firefox=!0,a.browser="firefox"),(i.ipod||i.ipad||i.iphone)&&(i.ios=!0),i.vivaldi&&(a.browser="vivaldi",i.vivaldi=!0),(i.chrome||i.opr||i.safari||i.vivaldi||!0===i.mobile&&!0!==i.ios&&!0!==o)&&(i.webkit=!0),i.opr&&(a.browser="opera",i.opera=!0),i.safari&&(i.blackberry||i.bb?(a.browser="blackberry",i.blackberry=!0):i.playbook?(a.browser="playbook",i.playbook=!0):i.android?(a.browser="android",i.android=!0):i.kindle?(a.browser="kindle",i.kindle=!0):i.silk&&(a.browser="silk",i.silk=!0)),i.name=a.browser,i.platform=a.platform,-1!==t.indexOf("electron"))i.electron=!0;else if(-1!==document.location.href.indexOf("-extension://"))i.bex=!0;else{if(void 0!==window.Capacitor?(i.capacitor=!0,i.nativeMobile=!0,i.nativeMobileWrapper="capacitor"):(void 0!==window._cordovaNative||void 0!==window.cordova)&&(i.cordova=!0,i.nativeMobile=!0,i.nativeMobileWrapper="cordova"),!0===I.value&&(O={is:{...i}}),!0===q&&!0===i.mac&&(!0===i.desktop&&!0===i.safari||!0===i.nativeMobile&&!0!==i.android&&!0!==i.ios&&!0!==i.ipad)){delete i.mac,delete i.desktop;let e=Math.min(window.innerHeight,window.innerWidth)>414?"ipad":"iphone";Object.assign(i,{mobile:!0,ios:!0,platform:e,[e]:!0})}!0!==i.mobile&&window.navigator.userAgentData&&window.navigator.userAgentData.mobile&&(delete i.desktop,i.mobile=!0)}return i}(D),has:{touch:q},within:{iframe:window.self!==window.top}},B={install(e){let{$q:t}=e;!0===I.value?(e.onSSRHydrated.push(()=>{Object.assign(t.platform,j),I.value=!1}),t.platform=u(this)):t.platform=this}};{let e;z(j.has,"webStorage",()=>{if(void 0!==e)return e;try{if(window.localStorage)return e=!0,!0}catch{}return e=!1,!1}),Object.assign(B,j),!0===I.value&&(Object.assign(B,O,{has:{touch:!1,webStorage:!1},within:{iframe:!1}}),O=null)}var F=B;function $(e){return x(L(e))}function V(e){return x(e)}var U=(e,t)=>{let n=u(e);for(let a in e)z(t,a,()=>n[a],e=>{n[a]=e});return t},H={hasPassive:!1,passiveCapture:!0,notPassiveCapture:!0};try{let e=Object.defineProperty({},"passive",{get(){Object.assign(H,{hasPassive:!0,passive:{passive:!0},notPassive:{passive:!1},passiveCapture:{passive:!0,capture:!0},notPassiveCapture:{passive:!1,capture:!0}})}});window.addEventListener("qtest",null,e),window.removeEventListener("qtest",null,e)}catch{}function W(){}function G(e){return 0===e.button}function K(e){return e.touches&&e.touches[0]?e=e.touches[0]:e.changedTouches&&e.changedTouches[0]?e=e.changedTouches[0]:e.targetTouches&&e.targetTouches[0]&&(e=e.targetTouches[0]),{top:e.clientY,left:e.clientX}}function Y(e){if(e.path)return e.path;if(e.composedPath)return e.composedPath();let t=[],n=e.target;for(;n;){if(t.push(n),"HTML"===n.tagName)return t.push(document),t.push(window),t;n=n.parentElement}}function Q(e){e.stopPropagation()}function Z(e){!1!==e.cancelable&&e.preventDefault()}function J(e){!1!==e.cancelable&&e.preventDefault(),e.stopPropagation()}function X(e,t){if(void 0===e||!0===t&&!0===e.__dragPrevented)return;let n=!0===t?e=>{e.__dragPrevented=!0,e.addEventListener("dragstart",Z,H.notPassiveCapture)}:e=>{delete e.__dragPrevented,e.removeEventListener("dragstart",Z,H.notPassiveCapture)};e.querySelectorAll("a, img").forEach(n)}function ee(e,t,n){let a=`__q_${t}_evt`;e[a]=void 0!==e[a]?e[a].concat(n):n,n.forEach(t=>{t[0].addEventListener(t[1],e[t[2]],H[t[3]])})}function te(e,t){let n=`__q_${t}_evt`;void 0!==e[n]&&(e[n].forEach(t=>{t[0].removeEventListener(t[1],e[t[2]],H[t[3]])}),e[n]=void 0)}var ne={listenOpts:H,leftClick:G,middleClick:function(e){return 1===e.button},rightClick:function(e){return 2===e.button},position:K,getEventPath:Y,getMouseWheelDistance:function(e){let t=e.deltaX,n=e.deltaY;if((t||n)&&e.deltaMode){let a=1===e.deltaMode?40:800;t*=a,n*=a}return e.shiftKey&&!t&&([n,t]=[t,n]),{x:t,y:n}},stop:Q,prevent:Z,stopAndPrevent:J,preventDraggable:X};function ae(e,t=250,n){let a=null;function i(){let i=arguments;null!==a?clearTimeout(a):!0===n&&e.apply(this,i),a=setTimeout(()=>{a=null,!0!==n&&e.apply(this,i)},t)}return i.cancel=()=>{null!==a&&clearTimeout(a)},i}var ie=["sm","md","lg","xl"],{passive:oe}=H,re=U({width:0,height:0,name:"xs",sizes:{sm:600,md:1024,lg:1440,xl:1920},lt:{sm:!0,md:!0,lg:!0,xl:!0},gt:{xs:!1,sm:!1,md:!1,lg:!1},xs:!0,sm:!1,md:!1,lg:!1,xl:!1},{setSizes:W,setDebounce:W,install({$q:e,onSSRHydrated:t}){if(e.screen=this,!0===this.__installed)return void(void 0!==e.config.screen&&(!1===e.config.screen.bodyClasses?document.body.classList.remove(`screen--${this.name}`):this.__update(!0)));let{visualViewport:n}=window,a=n||window,i=document.scrollingElement||document.documentElement,o=void 0===n||!0===j.is.mobile?()=>[Math.max(window.innerWidth,i.clientWidth),Math.max(window.innerHeight,i.clientHeight)]:()=>[n.width*n.scale+window.innerWidth-i.clientWidth,n.height*n.scale+window.innerHeight-i.clientHeight],r=!0===e.config.screen?.bodyClasses;this.__update=e=>{let[t,n]=o();if(n!==this.height&&(this.height=n),t!==this.width)this.width=t;else if(!0!==e)return;let a=this.sizes;this.gt.xs=t>=a.sm,this.gt.sm=t>=a.md,this.gt.md=t>=a.lg,this.gt.lg=t>=a.xl,this.lt.sm=t{ie.forEach(t=>{void 0!==e[t]&&(l[t]=e[t])})},this.setDebounce=e=>{u=e};let c=()=>{let e=getComputedStyle(document.body);e.getPropertyValue("--q-size-sm")&&ie.forEach(t=>{this.sizes[t]=parseInt(e.getPropertyValue(`--q-size-${t}`),10)}),this.setSizes=e=>{ie.forEach(t=>{e[t]&&(this.sizes[t]=e[t])}),this.__update(!0)},this.setDebounce=e=>{void 0!==s&&a.removeEventListener("resize",s,oe),s=e>0?ae(this.__update,e):this.__update,a.addEventListener("resize",s,oe)},this.setDebounce(u),0!==Object.keys(l).length?(this.setSizes(l),l=void 0):this.__update(),!0===r&&"xs"===this.name&&document.body.classList.add("screen--xs")};!0===I.value?t.push(c):c()}}),se=U({isActive:!1,mode:!1},{__media:void 0,set(e){se.mode=e,"auto"===e?(void 0===se.__media&&(se.__media=window.matchMedia("(prefers-color-scheme: dark)"),se.__updateMedia=()=>{se.set("auto")},se.__media.addListener(se.__updateMedia)),e=se.__media.matches):void 0!==se.__media&&(se.__media.removeListener(se.__updateMedia),se.__media=void 0),se.isActive=!0===e,document.body.classList.remove("body--"+(!0===e?"light":"dark")),document.body.classList.add("body--"+(!0===e?"dark":"light"))},toggle(){se.set(!1===se.isActive)},install({$q:e,ssrContext:t}){let n=e.config.dark;e.dark=this,!0!==this.__installed&&this.set(void 0!==n&&n)}}),le=se;function ue(e,t,n=document.body){if("string"!=typeof e)throw new TypeError("Expected a string as propName");if("string"!=typeof t)throw new TypeError("Expected a string as value");if(!(n instanceof Element))throw new TypeError("Expected a DOM element");n.style.setProperty(`--q-${e}`,t)}var ce=!1;function de(e){ce=!0===e.isComposing}function he(e){return!0===ce||e!==Object(e)||!0===e.isComposing||!0===e.qKeyEvent}function pe(e,t){return!0!==he(e)&&[].concat(t).includes(e.keyCode)}function fe(e){return!0===e.ios?"ios":!0===e.android?"android":void 0}var me={install(e){if(!0!==this.__installed){if(!0===I.value)!function(){let{is:e}=j,t=document.body.className,n=new Set(t.replace(/ {2}/g," ").split(" "));if(!0!==e.nativeMobile&&!0!==e.electron&&!0!==e.bex)if(!0===e.desktop)n.delete("mobile"),n.delete("platform-ios"),n.delete("platform-android"),n.add("desktop");else if(!0===e.mobile){n.delete("desktop"),n.add("mobile"),n.delete("platform-ios"),n.delete("platform-android");let t=fe(e);void 0!==t&&n.add(`platform-${t}`)}!0===j.has.touch&&(n.delete("no-touch"),n.add("touch")),!0===j.within.iframe&&n.add("within-iframe");let a=Array.from(n).join(" ");t!==a&&(document.body.className=a)}();else{let{$q:t}=e;void 0!==t.config.brand&&function(e){for(let t in e)ue(t,e[t])}(t.config.brand);let n=function({is:e,has:t,within:n},a){let i=[!0===e.desktop?"desktop":"mobile",(!1===t.touch?"no-":"")+"touch"];if(!0===e.mobile){let t=fe(e);void 0!==t&&i.push("platform-"+t)}if(!0===e.nativeMobile){let t=e.nativeMobileWrapper;i.push(t),i.push("native-mobile"),!0===e.ios&&(void 0===a[t]||!1!==a[t].iosStatusBarPadding)&&i.push("q-ios-padding")}else!0===e.electron?i.push("electron"):!0===e.bex&&i.push("bex");return!0===n.iframe&&i.push("within-iframe"),i}(j,t.config);document.body.classList.add.apply(document.body.classList,n)}!0===j.is.ios&&document.body.addEventListener("touchstart",W),window.addEventListener("keydown",de,!0)}}},ge=()=>!0;function _e(e){return"string"==typeof e&&""!==e&&"/"!==e&&"#/"!==e}function ve(e){return!0===e.startsWith("#")&&(e=e.substring(1)),!1===e.startsWith("/")&&(e="/"+e),!0===e.endsWith("/")&&(e=e.substring(0,e.length-1)),"#"+e}var be={__history:[],add:W,remove:W,install({$q:e}){if(!0===this.__installed)return;let{cordova:t,capacitor:n}=j.is;if(!0!==t&&!0!==n)return;let a=e.config[!0===t?"cordova":"capacitor"];if(!1===a?.backButton||!0===n&&(void 0===window.Capacitor||void 0===window.Capacitor.Plugins.App))return;this.add=e=>{void 0===e.condition&&(e.condition=ge),this.__history.push(e)},this.remove=e=>{let t=this.__history.indexOf(e);t>=0&&this.__history.splice(t,1)};let i=function(e){if(!1===e.backButtonExit)return()=>!1;if("*"===e.backButtonExit)return ge;let t=["#/"];return!0===Array.isArray(e.backButtonExit)&&t.push(...e.backButtonExit.filter(_e).map(ve)),()=>t.includes(window.location.hash)}(Object.assign({backButtonExit:!0},a)),o=()=>{if(this.__history.length){let e=this.__history[this.__history.length-1];!0===e.condition()&&(this.__history.pop(),e.handler())}else!0===i()?navigator.app.exitApp():window.history.back()};!0===t?document.addEventListener("deviceready",()=>{document.addEventListener("backbutton",o,!1)}):window.Capacitor.Plugins.App.addListener("backButton",o)}},ye={isoName:"en-US",nativeName:"English (US)",label:{clear:"Clear",ok:"OK",cancel:"Cancel",close:"Close",set:"Set",select:"Select",reset:"Reset",remove:"Remove",update:"Update",create:"Create",search:"Search",filter:"Filter",refresh:"Refresh",expand:e=>e?`Expand "${e}"`:"Expand",collapse:e=>e?`Collapse "${e}"`:"Collapse"},date:{days:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),daysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),firstDayOfWeek:0,format24h:!1,pluralDay:"days",prevMonth:"Previous month",nextMonth:"Next month",prevYear:"Previous year",nextYear:"Next year",today:"Today",prevRangeYears:e=>`Previous ${e} years`,nextRangeYears:e=>`Next ${e} years`},table:{noData:"No data available",noResults:"No matching records found",loading:"Loading...",selectedRecords:e=>1===e?"1 record selected.":(0===e?"No":e)+" records selected.",recordsPerPage:"Records per page:",allRows:"All",pagination:(e,t,n)=>e+"-"+t+" of "+n,columns:"Columns"},pagination:{first:"First page",prev:"Previous page",next:"Next page",last:"Last page"},editor:{url:"URL",bold:"Bold",italic:"Italic",strikethrough:"Strikethrough",underline:"Underline",unorderedList:"Unordered List",orderedList:"Ordered List",subscript:"Subscript",superscript:"Superscript",hyperlink:"Hyperlink",toggleFullscreen:"Toggle Fullscreen",quote:"Quote",left:"Left align",center:"Center align",right:"Right align",justify:"Justify align",print:"Print",outdent:"Decrease indentation",indent:"Increase indentation",removeFormat:"Remove formatting",formatting:"Formatting",fontSize:"Font Size",align:"Align",hr:"Insert Horizontal Rule",undo:"Undo",redo:"Redo",heading1:"Heading 1",heading2:"Heading 2",heading3:"Heading 3",heading4:"Heading 4",heading5:"Heading 5",heading6:"Heading 6",paragraph:"Paragraph",code:"Code",size1:"Very small",size2:"A bit small",size3:"Normal",size4:"Medium-large",size5:"Big",size6:"Very big",size7:"Maximum",defaultFont:"Default Font",viewSource:"View Source"},tree:{noNodes:"No nodes available",noResults:"No matching nodes found"}};function we(){let e=!0===Array.isArray(navigator.languages)&&0!==navigator.languages.length?navigator.languages[0]:navigator.language;if("string"==typeof e)return e.split(/[-_]/).map((e,t)=>0===t?e.toLowerCase():t>1||e.length<4?e.toUpperCase():e[0].toUpperCase()+e.slice(1).toLowerCase()).join("-")}var ke=U({__qLang:{}},{getLocale:we,set(e=ye,t){let n={...e,rtl:!0===e.rtl,getLocale:we};if(n.set=ke.set,void 0===ke.__langConfig||!0!==ke.__langConfig.noHtmlAttrs){let e=document.documentElement;e.setAttribute("dir",!0===n.rtl?"rtl":"ltr"),e.setAttribute("lang",n.isoName)}Object.assign(ke.__qLang,n)},install({$q:e,lang:t,ssrContext:n}){e.lang=ke.__qLang,ke.__langConfig=e.config.lang,!0===this.__installed?void 0!==t&&this.set(t):(this.props=new Proxy(this.__qLang,{get(){return Reflect.get(...arguments)},ownKeys:e=>Reflect.ownKeys(e).filter(e=>"set"!==e&&"getLocale"!==e)}),this.set(t||ye))}}),xe=ke,Se={name:"material-icons",type:{positive:"check_circle",negative:"warning",info:"info",warning:"priority_high"},arrow:{up:"arrow_upward",right:"arrow_forward",down:"arrow_downward",left:"arrow_back",dropdown:"arrow_drop_down"},chevron:{left:"chevron_left",right:"chevron_right"},colorPicker:{spectrum:"gradient",tune:"tune",palette:"style"},pullToRefresh:{icon:"refresh"},carousel:{left:"chevron_left",right:"chevron_right",up:"keyboard_arrow_up",down:"keyboard_arrow_down",navigationIcon:"lens"},chip:{remove:"cancel",selected:"check"},datetime:{arrowLeft:"chevron_left",arrowRight:"chevron_right",now:"access_time",today:"today"},editor:{bold:"format_bold",italic:"format_italic",strikethrough:"strikethrough_s",underline:"format_underlined",unorderedList:"format_list_bulleted",orderedList:"format_list_numbered",subscript:"vertical_align_bottom",superscript:"vertical_align_top",hyperlink:"link",toggleFullscreen:"fullscreen",quote:"format_quote",left:"format_align_left",center:"format_align_center",right:"format_align_right",justify:"format_align_justify",print:"print",outdent:"format_indent_decrease",indent:"format_indent_increase",removeFormat:"format_clear",formatting:"text_format",fontSize:"format_size",align:"format_align_left",hr:"remove",undo:"undo",redo:"redo",heading:"format_size",code:"code",size:"format_size",font:"font_download",viewSource:"code"},expansionItem:{icon:"keyboard_arrow_down",denseIcon:"arrow_drop_down"},fab:{icon:"add",activeIcon:"close"},field:{clear:"cancel",error:"error"},pagination:{first:"first_page",prev:"keyboard_arrow_left",next:"keyboard_arrow_right",last:"last_page"},rating:{icon:"grade"},stepper:{done:"check",active:"edit",error:"warning"},tabs:{left:"chevron_left",right:"chevron_right",up:"keyboard_arrow_up",down:"keyboard_arrow_down"},table:{arrowUp:"arrow_upward",warning:"warning",firstPage:"first_page",prevPage:"chevron_left",nextPage:"chevron_right",lastPage:"last_page"},tree:{icon:"play_arrow"},uploader:{done:"done",clear:"clear",add:"add_box",upload:"cloud_upload",removeQueue:"clear_all",removeUploaded:"done_all"}},Ce=U({iconMapFn:null,__qIconSet:{}},{set(e,t){let n={...e};n.set=Ce.set,Object.assign(Ce.__qIconSet,n)},install({$q:e,iconSet:t,ssrContext:n}){void 0!==e.config.iconMapFn&&(this.iconMapFn=e.config.iconMapFn),e.iconSet=this.__qIconSet,z(e,"iconMapFn",()=>this.iconMapFn,e=>{this.iconMapFn=e}),!0===this.__installed?void 0!==t&&this.set(t):(this.props=new Proxy(this.__qIconSet,{get(){return Reflect.get(...arguments)},ownKeys:e=>Reflect.ownKeys(e).filter(e=>"set"!==e)}),this.set(t||Se))}}),Te=Ce,Pe="_q_t_",Ee="_q_s_",Ae="_q_l_",Me="_q_pc_",Le="_q_f_",Re="_q_fo_",ze="_q_tabs_",Ne="_q_u_";function Oe(){}var Ie={},qe=!1;function De(e,t){if(e===t)return!0;if(null!==e&&null!==t&&"object"==typeof e&&"object"==typeof t){if(e.constructor!==t.constructor)return!1;let n,a;if(e.constructor===Array){if(n=e.length,n!==t.length)return!1;for(a=n;0!==a--;)if(!0!==De(e[a],t[a]))return!1;return!0}if(e.constructor===Map){if(e.size!==t.size)return!1;let n=e.entries();for(a=n.next();!0!==a.done;){if(!0!==t.has(a.value[0]))return!1;a=n.next()}for(n=e.entries(),a=n.next();!0!==a.done;){if(!0!==De(a.value[1],t.get(a.value[0])))return!1;a=n.next()}return!0}if(e.constructor===Set){if(e.size!==t.size)return!1;let n=e.entries();for(a=n.next();!0!==a.done;){if(!0!==t.has(a.value[0]))return!1;a=n.next()}return!0}if(null!=e.buffer&&e.buffer.constructor===ArrayBuffer){if(n=e.length,n!==t.length)return!1;for(a=n;0!==a--;)if(e[a]!==t[a])return!1;return!0}if(e.constructor===RegExp)return e.source===t.source&&e.flags===t.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===t.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===t.toString();let i=Object.keys(e).filter(t=>void 0!==e[t]);if(n=i.length,n!==Object.keys(t).filter(e=>void 0!==t[e]).length)return!1;for(a=n;0!==a--;){let n=i[a];if(!0!==De(e[n],t[n]))return!1}return!0}return e!=e&&t!=t}function je(e){return null!==e&&"object"==typeof e&&!0!==Array.isArray(e)}function Be(e){return"[object Date]"===Object.prototype.toString.call(e)}function Fe(e){return"[object RegExp]"===Object.prototype.toString.call(e)}function $e(e){return"number"==typeof e&&isFinite(e)}var Ve={deepEqual:De,object:je,date:Be,regexp:Fe,number:$e},Ue=[F,me,le,re,be,xe,Te];function He(e,t){let n=R(e);n.config.globalProperties=t.config.globalProperties;let{reload:a,...i}=t._context;return Object.assign(n._context,i),n}function We(e,t){t.forEach(t=>{t.install(e),t.__installed=!0})}var Ge=function(e,t={}){let n={version:"2.18.6"};!1===qe?(void 0!==t.config&&Object.assign(Ie,t.config),n.config={...Ie},qe=!0):n.config=t.config||{},function(e,t,n){e.config.globalProperties.$q=n.$q,e.provide("_q_",n.$q),We(n,Ue),void 0!==t.components&&Object.values(t.components).forEach(t=>{!0===je(t)&&void 0!==t.name&&e.component(t.name,t)}),void 0!==t.directives&&Object.values(t.directives).forEach(t=>{!0===je(t)&&void 0!==t.name&&e.directive(t.name,t)}),void 0!==t.plugins&&We(n,Object.values(t.plugins).filter(e=>"function"==typeof e.install&&!1===Ue.includes(e))),!0===I.value&&(n.$q.onSSRHydrated=()=>{n.onSSRHydrated.forEach(e=>{e()}),n.$q.onSSRHydrated=()=>{}})}(e,t,{parentApp:e,$q:n,lang:t.lang,iconSet:t.iconSet,onSSRHydrated:[]})},Ke={};t(Ke,{QAjaxBar:()=>st,QAvatar:()=>Lt,QBadge:()=>zt,QBanner:()=>It,QBar:()=>qt,QBreadcrumbs:()=>Kt,QBreadcrumbsEl:()=>nn,QBtn:()=>An,QBtnDropdown:()=>ni,QBtnGroup:()=>Mn,QBtnToggle:()=>si,QCard:()=>li,QCardActions:()=>ci,QCardSection:()=>ui,QCarousel:()=>Mi,QCarouselControl:()=>Ri,QCarouselSlide:()=>Li,QChatMessage:()=>zi,QCheckbox:()=>ji,QChip:()=>Fi,QCircularProgress:()=>Hi,QColor:()=>Do,QDate:()=>Ar,QDialog:()=>Yr,QDrawer:()=>Qr,QEditor:()=>gs,QExpansionItem:()=>Ss,QFab:()=>Ms,QFabAction:()=>zs,QField:()=>Vs,QFile:()=>Qs,QFooter:()=>Zs,QForm:()=>Js,QFormChildMixin:()=>Xs,QHeader:()=>el,QIcon:()=>Mt,QImg:()=>al,QInfiniteScroll:()=>ol,QInnerLoading:()=>rl,QInput:()=>kl,QIntersection:()=>Pl,QItem:()=>as,QItemLabel:()=>_s,QItemSection:()=>is,QKnob:()=>Rl,QLayout:()=>Il,QLinearProgress:()=>lu,QList:()=>Al,QMarkupTable:()=>Dl,QMenu:()=>Ka,QNoSsr:()=>jl,QOptionGroup:()=>Hl,QPage:()=>Wl,QPageContainer:()=>Gl,QPageScroller:()=>Ql,QPageSticky:()=>Zl,QPagination:()=>Xl,QParallax:()=>nu,QPopupEdit:()=>iu,QPopupProxy:()=>ou,QPullToRefresh:()=>cu,QRadio:()=>Bl,QRange:()=>fu,QRating:()=>mu,QResizeObserver:()=>lo,QResponsive:()=>gu,QRouteTab:()=>Bc,QScrollArea:()=>ku,QScrollObserver:()=>Ol,QSelect:()=>Du,QSeparator:()=>ws,QSkeleton:()=>Fu,QSlideItem:()=>Vu,QSlideTransition:()=>vs,QSlider:()=>ao,QSpace:()=>Uu,QSpinner:()=>rn,QSpinnerAudio:()=>Hu,QSpinnerBall:()=>Wu,QSpinnerBars:()=>Gu,QSpinnerBox:()=>Ku,QSpinnerClock:()=>Yu,QSpinnerComment:()=>Qu,QSpinnerCube:()=>Zu,QSpinnerDots:()=>Ju,QSpinnerFacebook:()=>Xu,QSpinnerGears:()=>ec,QSpinnerGrid:()=>tc,QSpinnerHearts:()=>nc,QSpinnerHourglass:()=>ac,QSpinnerInfinity:()=>ic,QSpinnerIos:()=>oc,QSpinnerOrbit:()=>rc,QSpinnerOval:()=>sc,QSpinnerPie:()=>lc,QSpinnerPuff:()=>uc,QSpinnerRadio:()=>cc,QSpinnerRings:()=>dc,QSpinnerTail:()=>hc,QSplitter:()=>pc,QStep:()=>_c,QStepper:()=>bc,QStepperNavigation:()=>yc,QTab:()=>_o,QTabPanel:()=>bo,QTabPanels:()=>vo,QTable:()=>qc,QTabs:()=>ho,QTd:()=>jc,QTh:()=>wc,QTime:()=>$c,QTimeline:()=>Vc,QTimelineEntry:()=>Uc,QToggle:()=>Fl,QToolbar:()=>Hc,QToolbarTitle:()=>Wc,QTooltip:()=>ns,QTr:()=>Dc,QTree:()=>Kc,QUploader:()=>od,QUploaderAddTrigger:()=>rd,QVideo:()=>sd,QVirtualScroll:()=>Cc});var Ye=["B","KB","MB","GB","TB","PB"];function Qe(e,t=1){let n=0;for(;parseInt(e,10)>=1024&&n=t?a:new Array(t-a.length+1).join(n)+a}var tt={humanStorageSize:Qe,capitalize:Ze,between:Je,normalizeToInterval:Xe,pad:et},nt=XMLHttpRequest,at=nt.prototype.open,it=["top","right","bottom","left"],ot=[],rt=0;var st=$({name:"QAjaxBar",props:{position:{type:String,default:"top",validator:e=>it.includes(e)},size:{type:String,default:"2px"},color:String,skipHijack:Boolean,reverse:Boolean,hijackFilter:Function},emits:["start","stop"],setup(e,{emit:t}){let o,r,{proxy:s}=k(),l=a(0),u=a(!1),c=a(!0),d=0,h=null,p=i(()=>`q-loading-bar q-loading-bar--${e.position}`+(void 0!==e.color?` bg-${e.color}`:"")+(!0===c.value?"":" no-transition")),f=i(()=>"top"===e.position||"bottom"===e.position),_=i(()=>!0===f.value?"height":"width"),v=i(()=>{let t=u.value,n=function({p:e,pos:t,active:n,horiz:a,reverse:i,dir:o}){let r=1,s=1;return!0===a?(!0===i&&(r=-1),"bottom"===t&&(s=-1),{transform:`translate3d(${r*(e-100)}%,${n?0:-200*s}%,0)`}):(!0===i&&(s=-1),"right"===t&&(r=-1),{transform:`translate3d(${n?0:o*r*-200}%,${s*(e-100)}%,0)`})}({p:l.value,pos:e.position,active:t,horiz:f.value,reverse:!0===s.$q.lang.rtl&&["top","bottom"].includes(e.position)?!1===e.reverse:e.reverse,dir:!0===s.$q.lang.rtl?-1:1});return n[_.value]=e.size,n.opacity=t?1:0,n}),b=i(()=>!0===u.value?{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":l.value}:{"aria-hidden":"true"});function y(e=300){let n=o;return o=Math.max(0,e)||0,d++,d>1?(0===n&&e>0?S():null!==h&&n>0&&e<=0&&(clearTimeout(h),h=null),d):(null!==h&&clearTimeout(h),t("start"),l.value=0,h=setTimeout(()=>{h=null,c.value=!0,e>0&&S()},!0===u._value?500:1),!0!==u._value&&(u.value=!0,c.value=!1),d)}function w(e){return d>0&&(l.value=function(e,t){return"number"!=typeof t&&(t=e<25?3*Math.random()+3:e<65?3*Math.random():e<85?2*Math.random():e<99?.6:0),Je(e+t,0,100)}(l.value,e)),d}function x(){if(d=Math.max(0,d-1),d>0)return d;null!==h&&(clearTimeout(h),h=null),t("stop");let e=()=>{c.value=!0,l.value=100,h=setTimeout(()=>{h=null,u.value=!1},1e3)};return 0===l.value?h=setTimeout(e,1):e(),d}function S(){l.value<100&&(h=setTimeout(()=>{h=null,w(),S()},o))}return m(()=>{!0!==e.skipHijack&&(r=!0,function(e){rt++,ot.push(e),!(rt>1)&&(nt.prototype.open=function(e,t){let n=[];this.addEventListener("loadstart",()=>{ot.forEach(e=>{(null===e.hijackFilter.value||!0===e.hijackFilter.value(t))&&(e.start(),n.push(e.stop))})},{once:!0}),this.addEventListener("loadend",()=>{n.forEach(e=>{e()})},{once:!0}),at.apply(this,arguments)})}({start:y,stop:x,hijackFilter:i(()=>e.hijackFilter||null)}))}),g(()=>{null!==h&&clearTimeout(h),!0===r&&function(e){ot=ot.filter(t=>t.start!==e),0===(rt=Math.max(0,rt-1))&&(nt.prototype.open=at)}(y)}),Object.assign(s,{start:y,stop:x,increment:w}),()=>n("div",{class:p.value,style:v.value,...b.value})}}),lt={xs:18,sm:24,md:32,lg:38,xl:46},ut={size:String};function ct(e,t=lt){return i(()=>void 0!==e.size?{fontSize:e.size in t?`${t[e.size]}px`:e.size}:null)}function dt(e,t){return void 0!==e&&e()||t}function ht(e,t){if(void 0!==e){let t=e();if(null!=t)return t.slice()}return t}function pt(e,t){return void 0!==e?t.concat(e()):t}function ft(e,t){return void 0===e?t:void 0!==t?t.concat(e()):e()}function mt(e,t,a,i,o,r){t.key=i+o;let s=n(e,t,a);return!0===o?A(s,r()):s}var gt="0 0 24 24",_t=e=>e,vt=e=>`ionicons ${e}`,bt={"mdi-":e=>`mdi ${e}`,"icon-":_t,"bt-":e=>`bt ${e}`,"eva-":e=>`eva ${e}`,"ion-md":vt,"ion-ios":vt,"ion-logo":vt,"iconfont ":_t,"ti-":e=>`themify-icon ${e}`,"bi-":e=>`bootstrap-icons ${e}`,"i-":_t},yt={o_:"-outlined",r_:"-round",s_:"-sharp"},wt={sym_o_:"-outlined",sym_r_:"-rounded",sym_s_:"-sharp"},kt=new RegExp("^("+Object.keys(bt).join("|")+")"),xt=new RegExp("^("+Object.keys(yt).join("|")+")"),St=new RegExp("^("+Object.keys(wt).join("|")+")"),Ct=/^[Mm]\s?[-+]?\.?\d/,Tt=/^img:/,Pt=/^svguse:/,Et=/^ion-/,At=/^(fa-(classic|sharp|solid|regular|light|brands|duotone|thin)|[lf]a[srlbdk]?) /,Mt=$({name:"QIcon",props:{...ut,tag:{type:String,default:"i"},name:String,color:String,left:Boolean,right:Boolean},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=ct(e),r=i(()=>"q-icon"+(!0===e.left?" on-left":"")+(!0===e.right?" on-right":"")+(void 0!==e.color?` text-${e.color}`:"")),s=i(()=>{let t,i=e.name;if("none"===i||!i)return{none:!0};if(null!==a.iconMapFn){let e=a.iconMapFn(i);if(void 0!==e){if(void 0===e.icon)return{cls:e.cls,content:void 0!==e.content?e.content:" "};if(i=e.icon,"none"===i||!i)return{none:!0}}}if(!0===Ct.test(i)){let[e,t=gt]=i.split("|");return{svg:!0,viewBox:t,nodes:e.split("&&").map(e=>{let[t,a,i]=e.split("@@");return n("path",{style:a,d:t,transform:i})})}}if(!0===Tt.test(i))return{img:!0,src:i.substring(4)};if(!0===Pt.test(i)){let[e,t=gt]=i.split("|");return{svguse:!0,src:e.substring(7),viewBox:t}}let o=" ",r=i.match(kt);if(null!==r)t=bt[r[1]](i);else if(!0===At.test(i))t=i;else if(!0===Et.test(i))t=`ionicons ion-${!0===a.platform.is.ios?"ios":"md"}${i.substring(3)}`;else if(!0===St.test(i)){t="notranslate material-symbols";let e=i.match(St);null!==e&&(i=i.substring(6),t+=wt[e[1]]),o=i}else{t="notranslate material-icons";let e=i.match(xt);null!==e&&(i=i.substring(2),t+=yt[e[1]]),o=i}return{cls:t,content:o}});return()=>{let a={class:r.value,style:o.value,"aria-hidden":"true"};return!0===s.value.none?n(e.tag,a,dt(t.default)):!0===s.value.img?n(e.tag,a,pt(t.default,[n("img",{src:s.value.src})])):!0===s.value.svg?n(e.tag,a,pt(t.default,[n("svg",{viewBox:s.value.viewBox||"0 0 24 24"},s.value.nodes)])):!0===s.value.svguse?n(e.tag,a,pt(t.default,[n("svg",{viewBox:s.value.viewBox},[n("use",{"xlink:href":s.value.src})])])):(void 0!==s.value.cls&&(a.class+=" "+s.value.cls),n(e.tag,a,pt(t.default,[s.value.content])))}}}),Lt=$({name:"QAvatar",props:{...ut,fontSize:String,color:String,textColor:String,icon:String,square:Boolean,rounded:Boolean},setup(e,{slots:t}){let a=ct(e),o=i(()=>"q-avatar"+(e.color?` bg-${e.color}`:"")+(e.textColor?` text-${e.textColor} q-chip--colored`:"")+(!0===e.square?" q-avatar--square":!0===e.rounded?" rounded-borders":"")),r=i(()=>e.fontSize?{fontSize:e.fontSize}:null);return()=>{let i=void 0!==e.icon?[n(Mt,{name:e.icon})]:void 0;return n("div",{class:o.value,style:a.value},[n("div",{class:"q-avatar__content row flex-center overflow-hidden",style:r.value},ft(t.default,i))])}}}),Rt=["top","middle","bottom"],zt=$({name:"QBadge",props:{color:String,textColor:String,floating:Boolean,transparent:Boolean,multiLine:Boolean,outline:Boolean,rounded:Boolean,label:[Number,String],align:{type:String,validator:e=>Rt.includes(e)}},setup(e,{slots:t}){let a=i(()=>void 0!==e.align?{verticalAlign:e.align}:null),o=i(()=>{let t=!0===e.outline&&e.color||e.textColor;return`q-badge flex inline items-center no-wrap q-badge--${!0===e.multiLine?"multi":"single"}-line`+(!0===e.outline?" q-badge--outline":void 0!==e.color?` bg-${e.color}`:"")+(void 0!==t?` text-${t}`:"")+(!0===e.floating?" q-badge--floating":"")+(!0===e.rounded?" q-badge--rounded":"")+(!0===e.transparent?" q-badge--transparent":"")});return()=>n("div",{class:o.value,style:a.value,role:"status","aria-label":e.label},pt(t.default,void 0!==e.label?[e.label]:[]))}}),Nt={dark:{type:Boolean,default:null}};function Ot(e,t){return i(()=>null===e.dark?t.dark.isActive:e.dark)}var It=$({name:"QBanner",props:{...Nt,inlineActions:Boolean,dense:Boolean,rounded:Boolean},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=Ot(e,a),r=i(()=>"q-banner row items-center"+(!0===e.dense?" q-banner--dense":"")+(!0===o.value?" q-banner--dark q-dark":"")+(!0===e.rounded?" rounded-borders":"")),s=i(()=>"q-banner__actions row items-center justify-end col-"+(!0===e.inlineActions?"auto":"all"));return()=>{let a=[n("div",{class:"q-banner__avatar col-auto row items-center self-start"},dt(t.avatar)),n("div",{class:"q-banner__content col text-body2"},dt(t.default))],i=dt(t.action);return void 0!==i&&a.push(n("div",{class:s.value},i)),n("div",{class:r.value+(!1===e.inlineActions&&void 0!==i?" q-banner--top-padding":""),role:"alert"},a)}}}),qt=$({name:"QBar",props:{...Nt,dense:Boolean},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=Ot(e,a),r=i(()=>`q-bar row no-wrap items-center q-bar--${!0===e.dense?"dense":"standard"} q-bar--${!0===o.value?"dark":"light"}`);return()=>n("div",{class:r.value,role:"toolbar"},dt(t.default))}}),Dt={left:"start",center:"center",right:"end",between:"between",around:"around",evenly:"evenly",stretch:"stretch"},jt=Object.keys(Dt),Bt={align:{type:String,validator:e=>jt.includes(e)}};function Ft(e){return i(()=>{let t=void 0===e.align?!0===e.vertical?"stretch":"left":e.align;return`${!0===e.vertical?"items":"justify"}-${Dt[t]}`})}function $t(e){if(Object(e.$parent)===e.$parent)return e.$parent;let{parent:t}=e.$;for(;Object(t)===t;){if(Object(t.proxy)===t.proxy)return t.proxy;t=t.parent}}function Vt(e,t){"symbol"==typeof t.type?!0===Array.isArray(t.children)&&t.children.forEach(t=>{Vt(e,t)}):e.add(t)}function Ut(e){let t=new Set;return e.forEach(e=>{Vt(t,e)}),Array.from(t)}function Ht(e){return void 0!==e.appContext.config.globalProperties.$router}function Wt(e){return!0===e.isUnmounted||!0===e.isDeactivated}var Gt=["",!0],Kt=$({name:"QBreadcrumbs",props:{...Bt,separator:{type:String,default:"/"},separatorColor:String,activeColor:{type:String,default:"primary"},gutter:{type:String,validator:e=>["none","xs","sm","md","lg","xl"].includes(e),default:"sm"}},setup(e,{slots:t}){let a=Ft(e),o=i(()=>`flex items-center ${a.value}${"none"===e.gutter?"":` q-gutter-${e.gutter}`}`),r=i(()=>e.separatorColor?` text-${e.separatorColor}`:""),s=i(()=>` text-${e.activeColor}`);return()=>{if(void 0===t.default)return;let a=Ut(dt(t.default));if(0===a.length)return;let i=1,l=[],u=a.filter(e=>"QBreadcrumbsEl"===e.type?.name).length,c=void 0!==t.separator?t.separator:()=>e.separator;return a.forEach(e=>{if("QBreadcrumbsEl"===e.type?.name){let t=ie===t[n]):1===e.length&&e[0]===t}function Jt(e,t){return!0===Array.isArray(e)?Zt(e,t):!0===Array.isArray(t)?Zt(t,e):e===t}var Xt={to:[String,Object],replace:Boolean,href:String,target:String,disable:Boolean},en={...Xt,exact:Boolean,activeClass:{type:String,default:"q-router-link--active"},exactActiveClass:{type:String,default:"q-router-link--exact-active"}};function tn({fallbackTag:e,useDisableForRouterLinkProps:t=!0}={}){let n=k(),{props:a,proxy:o,emit:r}=n,s=Ht(n),l=i(()=>!0!==a.disable&&void 0!==a.href),u=i(!0===t?()=>!0===s&&!0!==a.disable&&!0!==l.value&&void 0!==a.to&&null!==a.to&&""!==a.to:()=>!0===s&&!0!==l.value&&void 0!==a.to&&null!==a.to&&""!==a.to),c=i(()=>!0===u.value?b(a.to):null),d=i(()=>null!==c.value),h=i(()=>!0===l.value||!0===d.value),p=i(()=>"a"===a.type||!0===h.value?"a":a.tag||e||"div"),f=i(()=>!0===l.value?{href:a.href,target:a.target}:!0===d.value?{href:c.value.href,target:a.target}:{}),m=i(()=>{if(!1===d.value)return-1;let{matched:e}=c.value,{length:t}=e,n=e[t-1];if(void 0===n)return-1;let a=o.$route.matched;if(0===a.length)return-1;let i=a.findIndex(Qt.bind(null,n));if(-1!==i)return i;let r=Yt(e[t-2]);return t>1&&Yt(n)===r&&a[a.length-1].path!==r?a.findIndex(Qt.bind(null,e[t-2])):i}),g=i(()=>!0===d.value&&-1!==m.value&&function(e,t){for(let n in t){let a=t[n],i=e[n];if("string"==typeof a){if(a!==i)return!1}else if(!1===Array.isArray(i)||i.length!==a.length||a.some((e,t)=>e!==i[t]))return!1}return!0}(o.$route.params,c.value.params)),_=i(()=>!0===g.value&&m.value===o.$route.matched.length-1&&function(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(let n in e)if(!1===Jt(e[n],t[n]))return!1;return!0}(o.$route.params,c.value.params)),v=i(()=>!0===d.value?!0===_.value?` ${a.exactActiveClass} ${a.activeClass}`:!0===a.exact?"":!0===g.value?` ${a.activeClass}`:"":"");function b(e){try{return o.$router.resolve(e)}catch{}return null}function y(e,{returnRouterError:t,to:n=a.to,replace:i=a.replace}={}){if(!0===a.disable)return e.preventDefault(),Promise.resolve(!1);if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey||void 0!==e.button&&0!==e.button||"_blank"===a.target)return Promise.resolve(!1);e.preventDefault();let r=o.$router[!0===i?"replace":"push"](n);return!0===t?r:r.then(()=>{}).catch(()=>{})}return{hasRouterLink:d,hasHrefLink:l,hasLink:h,linkTag:p,resolvedLink:c,linkIsActive:g,linkIsExactActive:_,linkClass:v,linkAttrs:f,getLink:b,navigateToRouterLink:y,navigateOnClick:function(e){if(!0===d.value){let t=t=>y(e,t);r("click",e,t),!0!==e.defaultPrevented&&t()}else r("click",e)}}}var nn=$({name:"QBreadcrumbsEl",props:{...en,label:String,icon:String,tag:{type:String,default:"span"}},emits:["click"],setup(e,{slots:t}){let{linkTag:a,linkAttrs:o,linkClass:r,navigateOnClick:s}=tn(),l=i(()=>({class:"q-breadcrumbs__el q-link flex inline items-center relative-position "+(!0!==e.disable?"q-link--focusable"+r.value:"q-breadcrumbs__el--disable"),...o.value,onClick:s})),u=i(()=>"q-breadcrumbs__el-icon"+(void 0!==e.label?" q-breadcrumbs__el-icon--with-label":""));return()=>{let i=[];return void 0!==e.icon&&i.push(n(Mt,{class:u.value,name:e.icon})),void 0!==e.label&&i.push(e.label),n(a.value,{...l.value},pt(t.default,i))}}}),an={size:{type:[String,Number],default:"1em"},color:String};function on(e){return{cSize:i(()=>e.size in lt?`${lt[e.size]}px`:e.size),classes:i(()=>"q-spinner"+(e.color?` text-${e.color}`:""))}}var rn=$({name:"QSpinner",props:{...an,thickness:{type:Number,default:5}},setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value+" q-spinner-mat",width:t.value,height:t.value,viewBox:"25 25 50 50"},[n("circle",{class:"path",cx:"50",cy:"50",r:"20",fill:"none",stroke:"currentColor","stroke-width":e.thickness,"stroke-miterlimit":"10"})])}});function sn(e){if(e===window)return{top:0,left:0};let{top:t,left:n}=e.getBoundingClientRect();return{top:t,left:n}}function ln(e){return e===window?window.innerHeight:e.getBoundingClientRect().height}function un(e,t){let n=e.style;for(let e in t)n[e]=t[e]}function cn(e,t){if(null==e||!0===e.contains(t))return!0;for(let n=e.nextElementSibling;null!==n;n=n.nextElementSibling)if(n.contains(t))return!0;return!1}var dn={offset:sn,style:function(e,t){return window.getComputedStyle(e).getPropertyValue(t)},height:ln,width:function(e){return e===window?window.innerWidth:e.getBoundingClientRect().width},css:un,cssBatch:function(e,t){e.forEach(e=>un(e,t))},ready:function(e){if("function"==typeof e){if("loading"!==document.readyState)return e();document.addEventListener("DOMContentLoaded",e,!1)}}};function hn(e,t=250){let n,a=!1;return function(){return!1===a&&(a=!0,setTimeout(()=>{a=!1},t),n=e.apply(this,arguments)),n}}function pn(e,t,n,a){!0===n.modifiers.stop&&Q(e);let i=n.modifiers.color,o=n.modifiers.center;o=!0===o||!0===a;let r=document.createElement("span"),s=document.createElement("span"),l=K(e),{left:u,top:c,width:d,height:h}=t.getBoundingClientRect(),p=Math.sqrt(d*d+h*h),f=p/2,m=(d-p)/2+"px",g=o?m:l.left-u-f+"px",_=(h-p)/2+"px",v=o?_:l.top-c-f+"px";s.className="q-ripple__inner",un(s,{height:`${p}px`,width:`${p}px`,transform:`translate3d(${g},${v},0) scale3d(.2,.2,1)`,opacity:0}),r.className="q-ripple"+(i?" text-"+i:""),r.setAttribute("dir","ltr"),r.appendChild(s),t.appendChild(r);let b=()=>{r.remove(),clearTimeout(y)};n.abort.push(b);let y=setTimeout(()=>{s.classList.add("q-ripple__inner--enter"),s.style.transform=`translate3d(${m},${_},0) scale3d(1,1,1)`,s.style.opacity=.2,y=setTimeout(()=>{s.classList.remove("q-ripple__inner--enter"),s.classList.add("q-ripple__inner--leave"),s.style.opacity=0,y=setTimeout(()=>{r.remove(),n.abort.splice(n.abort.indexOf(b),1)},275)},250)},50)}function fn(e,{modifiers:t,value:n,arg:a}){let i=Object.assign({},e.cfg.ripple,t,n);e.modifiers={early:!0===i.early,stop:!0===i.stop,center:!0===i.center,color:i.color||a,keyCodes:[].concat(i.keyCodes||13)}}var mn=V({name:"ripple",beforeMount(e,t){let n=t.instance.$.appContext.config.globalProperties.$q.config||{};if(!1===n.ripple)return;let a={cfg:n,enabled:!1!==t.value,modifiers:{},abort:[],start(t){!0===a.enabled&&!0!==t.qSkipRipple&&t.type===(!0===a.modifiers.early?"pointerdown":"click")&&pn(t,e,a,!0===t.qKeyEvent)},keystart:hn(t=>{!0===a.enabled&&!0!==t.qSkipRipple&&!0===pe(t,a.modifiers.keyCodes)&&t.type==="key"+(!0===a.modifiers.early?"down":"up")&&pn(t,e,a,!0)},300)};fn(a,t),e.__qripple=a,ee(a,"main",[[e,"pointerdown","start","passive"],[e,"click","start","passive"],[e,"keydown","keystart","passive"],[e,"keyup","keystart","passive"]])},updated(e,t){if(t.oldValue!==t.value){let n=e.__qripple;void 0!==n&&(n.enabled=!1!==t.value,!0===n.enabled&&Object(t.value)===t.value&&fn(n,t))}},beforeUnmount(e){let t=e.__qripple;void 0!==t&&(t.abort.forEach(e=>{e()}),te(t,"main"),delete e._qripple)}}),gn={none:0,xs:4,sm:8,md:16,lg:24,xl:32},_n={xs:8,sm:10,md:14,lg:20,xl:24},vn=["button","submit","reset"],bn=/[^\s]\/[^\s]/,yn=["flat","outline","push","unelevated"];function wn(e,t){return!0===e.flat?"flat":!0===e.outline?"outline":!0===e.push?"push":!0===e.unelevated?"unelevated":t}function kn(e){let t=wn(e);return void 0!==t?{[t]:!0}:{}}var xn={...ut,...Xt,type:{type:String,default:"button"},label:[Number,String],icon:String,iconRight:String,...yn.reduce((e,t)=>(e[t]=Boolean)&&e,{}),square:Boolean,rounded:Boolean,glossy:Boolean,size:String,fab:Boolean,fabMini:Boolean,padding:String,color:String,textColor:String,noCaps:Boolean,noWrap:Boolean,dense:Boolean,tabindex:[Number,String],ripple:{type:[Boolean,Object],default:!0},align:{...Bt.align,default:"center"},stack:Boolean,stretch:Boolean,loading:{type:Boolean,default:null},disable:Boolean},Sn={...xn,round:Boolean};var{passiveCapture:Cn}=H,Tn=null,Pn=null,En=null,An=$({name:"QBtn",props:{...Sn,percentage:Number,darkPercentage:Boolean,onTouchstart:[Function,Array]},emits:["click","keydown","mousedown","keyup"],setup(e,{slots:t,emit:o}){let r,{proxy:s}=k(),{classes:l,style:u,innerClasses:c,attributes:d,hasLink:h,linkTag:p,navigateOnClick:f,isActionable:m}=function(e){let t=ct(e,_n),n=Ft(e),{hasRouterLink:a,hasLink:o,linkTag:r,linkAttrs:s,navigateOnClick:l}=tn({fallbackTag:"button"}),u=i(()=>{let n=!1===e.fab&&!1===e.fabMini?t.value:{};return void 0!==e.padding?Object.assign({},n,{padding:e.padding.split(/\s+/).map(e=>e in gn?gn[e]+"px":e).join(" "),minWidth:"0",minHeight:"0"}):n}),c=i(()=>!0===e.rounded||!0===e.fab||!0===e.fabMini),d=i(()=>!0!==e.disable&&!0!==e.loading),h=i(()=>!0===d.value?e.tabindex||0:-1),p=i(()=>wn(e,"standard")),f=i(()=>{let t={tabindex:h.value};return!0===o.value?Object.assign(t,s.value):!0===vn.includes(e.type)&&(t.type=e.type),"a"===r.value?(!0===e.disable?t["aria-disabled"]="true":void 0===t.href&&(t.role="button"),!0!==a.value&&!0===bn.test(e.type)&&(t.type=e.type)):!0===e.disable&&(t.disabled="",t["aria-disabled"]="true"),!0===e.loading&&void 0!==e.percentage&&Object.assign(t,{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":e.percentage}),t});return{classes:i(()=>{let t;void 0!==e.color?t=!0===e.flat||!0===e.outline?`text-${e.textColor||e.color}`:`bg-${e.color} text-${e.textColor||"white"}`:e.textColor&&(t=`text-${e.textColor}`);let n=!0===e.round?"round":"rectangle"+(!0===c.value?" q-btn--rounded":!0===e.square?" q-btn--square":"");return`q-btn--${p.value} q-btn--${n}`+(void 0!==t?" "+t:"")+(!0===d.value?" q-btn--actionable q-focusable q-hoverable":!0===e.disable?" disabled":"")+(!0===e.fab?" q-btn--fab":!0===e.fabMini?" q-btn--fab-mini":"")+(!0===e.noCaps?" q-btn--no-uppercase":"")+(!0===e.dense?" q-btn--dense":"")+(!0===e.stretch?" no-border-radius self-stretch":"")+(!0===e.glossy?" glossy":"")+(e.square?" q-btn--square":"")}),style:u,innerClasses:i(()=>n.value+(!0===e.stack?" column":" row")+(!0===e.noWrap?" no-wrap text-no-wrap":"")+(!0===e.loading?" q-btn__content--hidden":"")),attributes:f,hasLink:o,linkTag:r,navigateOnClick:l,isActionable:d}}(e),_=a(null),v=a(null),b=null,y=null,w=i(()=>void 0!==e.label&&null!==e.label&&""!==e.label),x=i(()=>!0!==e.disable&&!1!==e.ripple&&{keyCodes:!0===h.value?[13,32]:[13],...!0===e.ripple?{}:e.ripple}),C=i(()=>({center:e.round})),T=i(()=>{let t=Math.max(0,Math.min(100,e.percentage));return t>0?{transition:"transform 0.6s",transform:`translateX(${t-100}%)`}:{}}),P=i(()=>{if(!0===e.loading)return{onMousedown:I,onTouchstart:I,onClick:I,onKeydown:I,onKeyup:I};if(!0===m.value){let t={onClick:M,onKeydown:L,onMousedown:z};if(!0===s.$q.platform.has.touch){t[`onTouchstart${void 0!==e.onTouchstart?"":"Passive"}`]=R}return t}return{onClick:J}}),E=i(()=>({ref:_,class:"q-btn q-btn-item non-selectable no-outline "+l.value,style:u.value,...d.value,...P.value}));function M(t){if(null!==_.value){if(void 0!==t){if(!0===t.defaultPrevented)return;let n=document.activeElement;if("submit"===e.type&&n!==document.body&&!1===_.value.contains(n)&&!1===n.contains(_.value)){!0!==t.qAvoidFocus&&_.value.focus();let e=()=>{document.removeEventListener("keydown",J,!0),document.removeEventListener("keyup",e,Cn),_.value?.removeEventListener("blur",e,Cn)};document.addEventListener("keydown",J,!0),document.addEventListener("keyup",e,Cn),_.value.addEventListener("blur",e,Cn)}}f(t)}}function L(e){null!==_.value&&(o("keydown",e),!0===pe(e,[13,32])&&Pn!==_.value&&(null!==Pn&&O(),!0!==e.defaultPrevented&&(!0!==e.qAvoidFocus&&_.value.focus(),Pn=_.value,_.value.classList.add("q-btn--active"),document.addEventListener("keyup",N,!0),_.value.addEventListener("blur",N,Cn)),J(e)))}function R(e){null!==_.value&&(o("touchstart",e),!0!==e.defaultPrevented&&(Tn!==_.value&&(null!==Tn&&O(),Tn=_.value,b=e.target,b.addEventListener("touchcancel",N,Cn),b.addEventListener("touchend",N,Cn)),r=!0,null!==y&&clearTimeout(y),y=setTimeout(()=>{y=null,r=!1},200)))}function z(e){null!==_.value&&(e.qSkipRipple=!0===r,o("mousedown",e),!0!==e.defaultPrevented&&En!==_.value&&(null!==En&&O(),En=_.value,_.value.classList.add("q-btn--active"),document.addEventListener("mouseup",N,Cn)))}function N(e){if(null!==_.value&&("blur"!==e?.type||document.activeElement!==_.value)){if("keyup"===e?.type){if(Pn===_.value&&!0===pe(e,[13,32])){let t=new MouseEvent("click",e);t.qKeyEvent=!0,!0===e.defaultPrevented&&Z(t),!0===e.cancelBubble&&Q(t),_.value.dispatchEvent(t),J(e),e.qKeyEvent=!0}o("keyup",e)}O()}}function O(e){let t=v.value;!0!==e&&(Tn===_.value||En===_.value)&&null!==t&&t!==document.activeElement&&(t.setAttribute("tabindex",-1),t.focus()),Tn===_.value&&(null!==b&&(b.removeEventListener("touchcancel",N,Cn),b.removeEventListener("touchend",N,Cn)),Tn=b=null),En===_.value&&(document.removeEventListener("mouseup",N,Cn),En=null),Pn===_.value&&(document.removeEventListener("keyup",N,!0),_.value?.removeEventListener("blur",N,Cn),Pn=null),_.value?.classList.remove("q-btn--active")}function I(e){J(e),e.qSkipRipple=!0}return g(()=>{O(!0)}),Object.assign(s,{click:e=>{!0===m.value&&M(e)}}),()=>{let a=[];void 0!==e.icon&&a.push(n(Mt,{name:e.icon,left:!0!==e.stack&&!0===w.value,role:"img"})),!0===w.value&&a.push(n("span",{class:"block"},[e.label])),a=pt(t.default,a),void 0!==e.iconRight&&!1===e.round&&a.push(n(Mt,{name:e.iconRight,right:!0!==e.stack&&!0===w.value,role:"img"}));let i=[n("span",{class:"q-focus-helper",ref:v})];return!0===e.loading&&void 0!==e.percentage&&i.push(n("span",{class:"q-btn__progress absolute-full overflow-hidden"+(!0===e.darkPercentage?" q-btn__progress--dark":"")},[n("span",{class:"q-btn__progress-indicator fit block",style:T.value})])),i.push(n("span",{class:"q-btn__content text-center col items-center q-anchor--skip "+c.value},a)),null!==e.loading&&i.push(n(S,{name:"q-transition--fade"},()=>!0===e.loading?[n("span",{key:"loading",class:"absolute-full flex flex-center"},void 0!==t.loading?t.loading():[n(rn)])]:null)),A(n(p.value,E.value,i),[[mn,x.value,void 0,C.value]])}}}),Mn=$({name:"QBtnGroup",props:{unelevated:Boolean,outline:Boolean,flat:Boolean,rounded:Boolean,square:Boolean,push:Boolean,stretch:Boolean,glossy:Boolean,spread:Boolean},setup(e,{slots:t}){let a=i(()=>{let t=["unelevated","outline","flat","rounded","square","push","stretch","glossy"].filter(t=>!0===e[t]).map(e=>`q-btn-group--${e}`).join(" ");return"q-btn-group row no-wrap"+(0!==t.length?" "+t:"")+(!0===e.spread?" q-btn-group--spread":" inline")});return()=>n("div",{class:a.value},dt(t.default))}});function Ln(){if(void 0!==window.getSelection){let e=window.getSelection();void 0!==e.empty?e.empty():void 0!==e.removeAllRanges&&(e.removeAllRanges(),!0!==F.is.mobile&&e.addRange(document.createRange()))}else void 0!==document.selection&&document.selection.empty()}var Rn={target:{type:[Boolean,String,Element],default:!0},noParentEvent:Boolean},zn={...Rn,contextMenu:Boolean};function Nn({showing:e,avoidEmit:t,configureAnchorEl:n}){let{props:i,proxy:r,emit:s}=k(),l=a(null),u=null;function c(e){return null!==l.value&&(void 0===e||void 0===e.touches||e.touches.length<=1)}let h={};function p(){te(h,"anchor")}function f(){if(!1===i.target||""===i.target||null===r.$el.parentNode)l.value=null;else if(!0===i.target)!function(e){for(l.value=e;l.value.classList.contains("q-anchor--skip");)l.value=l.value.parentNode;n()}(r.$el.parentNode);else{let e=i.target;if("string"==typeof i.target)try{e=document.querySelector(i.target)}catch{e=void 0}null!=e?(l.value=e.$el||e,n()):(l.value=null,console.error(`Anchor: target "${i.target}" not found`))}}return void 0===n&&(Object.assign(h,{hide(e){r.hide(e)},toggle(e){r.toggle(e),e.qAnchorHandled=!0},toggleKey(e){!0===pe(e,13)&&h.toggle(e)},contextClick(e){r.hide(e),Z(e),d(()=>{r.show(e),e.qAnchorHandled=!0})},prevent:Z,mobileTouch(e){if(h.mobileCleanup(e),!0!==c(e))return;r.hide(e),l.value.classList.add("non-selectable");let t=e.target;ee(h,"anchor",[[t,"touchmove","mobileCleanup","passive"],[t,"touchend","mobileCleanup","passive"],[t,"touchcancel","mobileCleanup","passive"],[l.value,"contextmenu","prevent","notPassive"]]),u=setTimeout(()=>{u=null,r.show(e),e.qAnchorHandled=!0},300)},mobileCleanup(t){l.value.classList.remove("non-selectable"),null!==u&&(clearTimeout(u),u=null),!0===e.value&&void 0!==t&&Ln()}}),n=function(e=i.contextMenu){if(!0===i.noParentEvent||null===l.value)return;let t;t=!0===e?!0===r.$q.platform.is.mobile?[[l.value,"touchstart","mobileTouch","passive"]]:[[l.value,"mousedown","hide","passive"],[l.value,"contextmenu","contextClick","notPassive"]]:[[l.value,"click","toggle","passive"],[l.value,"keyup","toggleKey","passive"]],ee(h,"anchor",t)}),o(()=>i.contextMenu,e=>{null!==l.value&&(p(),n(e))}),o(()=>i.target,()=>{null!==l.value&&p(),f()}),o(()=>i.noParentEvent,e=>{null!==l.value&&(!0===e?p():n())}),m(()=>{f(),!0!==t&&!0===i.modelValue&&null===l.value&&s("update:modelValue",!1)}),g(()=>{null!==u&&clearTimeout(u),p()}),{anchorEl:l,canShow:c,anchorEvents:h}}function On(e,t){let n,i=a(null);function r(e,t){let a=(void 0!==t?"add":"remove")+"EventListener",i=void 0!==t?t:n;e!==window&&e[a]("scroll",i,H.passive),window[a]("scroll",i,H.passive),n=t}function s(){null!==i.value&&(r(i.value),i.value=null)}let l=o(()=>e.noParentEvent,()=>{null!==i.value&&(s(),t())});return g(l),{localScrollTarget:i,unconfigureScrollTarget:s,changeScrollEvent:r}}var In={modelValue:{type:Boolean,default:null},"onUpdate:modelValue":[Function,Array]},qn=["beforeShow","show","beforeHide","hide"];function Dn({showing:e,canShow:t,hideOnRouteChange:n,handleShow:a,handleHide:i,processOnMount:r}){let s,l=k(),{props:u,emit:c,proxy:h}=l;function p(e){if(!0===u.disable||!0===e?.qAnchorHandled||void 0!==t&&!0!==t(e))return;let n=void 0!==u["onUpdate:modelValue"];!0===n&&(c("update:modelValue",!0),s=e,d(()=>{s===e&&(s=void 0)})),(null===u.modelValue||!1===n)&&f(e)}function f(t){!0!==e.value&&(e.value=!0,c("beforeShow",t),void 0!==a?a(t):c("show",t))}function g(e){if(!0===u.disable)return;let t=void 0!==u["onUpdate:modelValue"];!0===t&&(c("update:modelValue",!1),s=e,d(()=>{s===e&&(s=void 0)})),(null===u.modelValue||!1===t)&&_(e)}function _(t){!1!==e.value&&(e.value=!1,c("beforeHide",t),void 0!==i?i(t):c("hide",t))}function v(t){!0===u.disable&&!0===t?void 0!==u["onUpdate:modelValue"]&&c("update:modelValue",!1):!0===t!==e.value&&(!0===t?f:_)(s)}o(()=>u.modelValue,v),void 0!==n&&!0===Ht(l)&&o(()=>h.$route.fullPath,()=>{!0===n.value&&!0===e.value&&g()}),!0===r&&m(()=>{v(u.modelValue)});let b={show:p,hide:g,toggle:function(t){!0===e.value?g(t):p(t)}};return Object.assign(h,b),b}var jn=[],Bn=[];function Fn(e){Bn=Bn.filter(t=>t!==e)}function $n(e){Fn(e),0===Bn.length&&0!==jn.length&&(jn[jn.length-1](),jn=[])}function Vn(e){0===Bn.length?e():jn.push(e)}var Un=[],Hn=[],Wn=1,Gn=document.body;function Kn(e,t){let n=document.createElement("div");if(n.id=void 0!==t?`q-portal--${t}--${Wn++}`:e,void 0!==Ie.globalNodes){let e=Ie.globalNodes.class;void 0!==e&&(n.className=e)}return Gn.appendChild(n),Un.push(n),Hn.push(t),n}function Yn(e){let t=Un.indexOf(e);Un.splice(t,1),Hn.splice(t,1),e.remove()}var Qn=[];function Zn(e,t){do{if("QMenu"===e.$options.name){if(e.hide(t),!0===e.$props.separateClosePopup)return $t(e)}else if(!0===e.__qPortal){let n=$t(e);return"QPopupProxy"===n?.$options.name?(e.hide(t),n):e}e=$t(e)}while(null!=e)}var Jn=$({name:"QPortal",setup:(e,{slots:t})=>()=>t.default()});function Xn(e,t,i,o){let r=a(!1),s=a(!1),l=null,u={},c="dialog"===o&&function(e){for(e=e.parent;null!=e;){if("QGlobalDialog"===e.type.name)return!0;if("QDialog"===e.type.name||"QMenu"===e.type.name)return!1;e=e.parent}return!1}(e);function d(t){if(s.value=!1,!0!==t)return;$n(u),r.value=!1;let n=Qn.indexOf(e.proxy);-1!==n&&Qn.splice(n,1),null!==l&&(Yn(l),l=null)}return _(()=>{d(!0)}),e.proxy.__qPortal=!0,z(e.proxy,"contentEl",()=>t.value),{showPortal:function(t){if(!0===t)return $n(u),void(s.value=!0);s.value=!1,!1===r.value&&(!1===c&&null===l&&(l=Kn(!1,o)),r.value=!0,Qn.push(e.proxy),function(e){Fn(e),Bn.push(e)}(u))},hidePortal:d,portalIsActive:r,portalIsAccessible:s,renderPortal:()=>!0===c?i():!0===r.value?[n(P,{to:l},n(Jn,i))]:void 0}}var ea={transitionShow:{type:String,default:"fade"},transitionHide:{type:String,default:"fade"},transitionDuration:{type:[String,Number],default:300}};function ta(e,t=()=>{},n=()=>{}){return{transitionProps:i(()=>{let a=`q-transition--${e.transitionShow||t()}`,i=`q-transition--${e.transitionHide||n()}`;return{appear:!0,enterFromClass:`${a}-enter-from`,enterActiveClass:`${a}-enter-active`,enterToClass:`${a}-enter-to`,leaveFromClass:`${i}-leave-from`,leaveActiveClass:`${i}-leave-active`,leaveToClass:`${i}-leave-to`}}),transitionStyle:i(()=>`--q-transition-duration: ${e.transitionDuration}ms`)}}function na(){let e,t=k();function n(){e=void 0}return p(n),g(n),{removeTick:n,registerTick(n){e=n,d(()=>{e===n&&(!1===Wt(t)&&e(),e=void 0)})}}}function aa(){let e=null,t=k();function n(){null!==e&&(clearTimeout(e),e=null)}return p(n),g(n),{removeTimeout:n,registerTimeout(a,i){n(),!1===Wt(t)&&(e=setTimeout(()=>{e=null,a()},i))}}}var ia,oa=[Element,String],ra=[null,document,document.body,document.scrollingElement,document.documentElement];function sa(e,t){let n=function(e){if(null==e)return;if("string"==typeof e)try{return document.querySelector(e)||void 0}catch{return}let t=l(e);return t?t.$el||t:void 0}(t);if(void 0===n){if(null==e)return window;n=e.closest(".scroll,.scroll-y,.overflow-auto")}return ra.includes(n)?window:n}function la(e){return(e===window?document.body:e).scrollHeight}function ua(e){return e===window?window.pageYOffset||window.scrollY||document.body.scrollTop||0:e.scrollTop}function ca(e){return e===window?window.pageXOffset||window.scrollX||document.body.scrollLeft||0:e.scrollLeft}function da(e,t,n=0){let a=void 0===arguments[3]?performance.now():arguments[3],i=ua(e);n<=0?i!==t&&pa(e,t):requestAnimationFrame(o=>{let r=o-a,s=i+(t-i)/Math.max(r,n)*r;pa(e,s),s!==t&&da(e,t,n-r,o)})}function ha(e,t,n=0){let a=void 0===arguments[3]?performance.now():arguments[3],i=ca(e);n<=0?i!==t&&fa(e,t):requestAnimationFrame(o=>{let r=o-a,s=i+(t-i)/Math.max(r,n)*r;fa(e,s),s!==t&&ha(e,t,n-r,o)})}function pa(e,t){e!==window?e.scrollTop=t:window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,t)}function fa(e,t){e!==window?e.scrollLeft=t:window.scrollTo(t,window.pageYOffset||window.scrollY||document.body.scrollTop||0)}function ma(e,t,n){n?da(e,t,n):pa(e,t)}function ga(e,t,n){n?ha(e,t,n):fa(e,t)}function _a(){if(void 0!==ia)return ia;let e=document.createElement("p"),t=document.createElement("div");un(e,{width:"100%",height:"200px"}),un(t,{position:"absolute",top:"0px",left:"0px",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),t.appendChild(e),document.body.appendChild(t);let n=e.offsetWidth;t.style.overflow="scroll";let a=e.offsetWidth;return n===a&&(a=t.clientWidth),t.remove(),ia=n-a}function va(e,t=!0){return!(!e||e.nodeType!==Node.ELEMENT_NODE)&&(t?e.scrollHeight>e.clientHeight&&(e.classList.contains("scroll")||e.classList.contains("overflow-auto")||["auto","scroll"].includes(window.getComputedStyle(e)["overflow-y"])):e.scrollWidth>e.clientWidth&&(e.classList.contains("scroll")||e.classList.contains("overflow-auto")||["auto","scroll"].includes(window.getComputedStyle(e)["overflow-x"])))}var ba,ya={getScrollTarget:sa,getScrollHeight:la,getScrollWidth:function(e){return(e===window?document.body:e).scrollWidth},getVerticalScrollPosition:ua,getHorizontalScrollPosition:ca,animVerticalScrollTo:da,animHorizontalScrollTo:ha,setVerticalScrollPosition:ma,setHorizontalScrollPosition:ga,getScrollbarWidth:_a,hasScrollbar:va},wa=[];function ka(e){ba=27===e.keyCode}function xa(){!0===ba&&(ba=!1)}function Sa(e){!0===ba&&(ba=!1,!0===pe(e,27)&&wa[wa.length-1](e))}function Ca(e){window[e]("keydown",ka),window[e]("blur",xa),window[e]("keyup",Sa),ba=!1}function Ta(e){!0===j.is.desktop&&(wa.push(e),1===wa.length&&Ca("addEventListener"))}function Pa(e){let t=wa.indexOf(e);-1!==t&&(wa.splice(t,1),0===wa.length&&Ca("removeEventListener"))}var Ea=[];function Aa(e){Ea[Ea.length-1](e)}function Ma(e){!0===j.is.desktop&&(Ea.push(e),1===Ea.length&&document.body.addEventListener("focusin",Aa))}function La(e){let t=Ea.indexOf(e);-1!==t&&(Ea.splice(t,1),0===Ea.length&&document.body.removeEventListener("focusin",Aa))}var Ra,za,Na=null,{notPassiveCapture:Oa}=H,Ia=[];function qa(e){null!==Na&&(clearTimeout(Na),Na=null);let t=e.target;if(void 0===t||8===t.nodeType||!0===t.classList.contains("no-pointer-events"))return;let n=Qn.length-1;for(;n>=0;){let e=Qn[n].$;if("QTooltip"!==e.type.name){if("QDialog"!==e.type.name)break;if(!0!==e.props.seamless)return;n--}else n--}for(let n=Ia.length-1;n>=0;n--){let a=Ia[n];if(null!==a.anchorEl.value&&!1!==a.anchorEl.value.contains(t)||t!==document.body&&(null===a.innerRef.value||!1!==a.innerRef.value.contains(t)))return;e.qClickOutside=!0,a.onClickOutside(e)}}function Da(e){Ia.push(e),1===Ia.length&&(document.addEventListener("mousedown",qa,Oa),document.addEventListener("touchstart",qa,Oa))}function ja(e){let t=Ia.findIndex(t=>t===e);-1!==t&&(Ia.splice(t,1),0===Ia.length&&(null!==Na&&(clearTimeout(Na),Na=null),document.removeEventListener("mousedown",qa,Oa),document.removeEventListener("touchstart",qa,Oa)))}function Ba(e){let t=e.split(" ");return 2===t.length&&(!0!==["top","center","bottom"].includes(t[0])?(console.error("Anchor/Self position must start with one of top/center/bottom"),!1):!0===["left","middle","right","start","end"].includes(t[1])||(console.error("Anchor/Self position must end with one of left/middle/right/start/end"),!1))}function Fa(e){return!e||!(2!==e.length||"number"!=typeof e[0]||"number"!=typeof e[1])}var $a={"start#ltr":"left","start#rtl":"right","end#ltr":"right","end#rtl":"left"};function Va(e,t){let n=e.split(" ");return{vertical:n[0],horizontal:$a[`${n[1]}#${!0===t?"rtl":"ltr"}`]}}function Ua(e,t,n,a){return{top:e[n.vertical]-t[a.vertical],left:e[n.horizontal]-t[a.horizontal]}}function Ha(e,t=0){if(null===e.targetEl||null===e.anchorEl||t>5)return;if(0===e.targetEl.offsetHeight||0===e.targetEl.offsetWidth)return void setTimeout(()=>{Ha(e,t+1)},10);let{targetEl:n,offset:a,anchorEl:i,anchorOrigin:o,selfOrigin:r,absoluteOffset:s,fit:l,cover:u,maxHeight:c,maxWidth:d}=e;if(!0===j.is.ios&&void 0!==window.visualViewport){let e=document.body.style,{offsetLeft:t,offsetTop:n}=window.visualViewport;t!==Ra&&(e.setProperty("--q-pe-left",t+"px"),Ra=t),n!==za&&(e.setProperty("--q-pe-top",n+"px"),za=n)}let{scrollLeft:h,scrollTop:p}=n,f=void 0===s?function(e,t){let{top:n,left:a,right:i,bottom:o,width:r,height:s}=e.getBoundingClientRect();return void 0!==t&&(n-=t[1],a-=t[0],o+=t[1],i+=t[0],r+=t[0],s+=t[1]),{top:n,bottom:o,height:s,left:a,right:i,width:r,middle:a+(i-a)/2,center:n+(o-n)/2}}(i,!0===u?[0,0]:a):function(e,t,n){let{top:a,left:i}=e.getBoundingClientRect();return a+=t.top,i+=t.left,void 0!==n&&(a+=n[1],i+=n[0]),{top:a,bottom:a+1,height:1,left:i,right:i+1,width:1,middle:i,center:a}}(i,s,a);Object.assign(n.style,{top:0,left:0,minWidth:null,minHeight:null,maxWidth:d,maxHeight:c,visibility:"visible"});let{offsetWidth:m,offsetHeight:g}=n,{elWidth:_,elHeight:v}=!0===l||!0===u?{elWidth:Math.max(f.width,m),elHeight:!0===u?Math.max(f.height,g):g}:{elWidth:m,elHeight:g},b={maxWidth:d,maxHeight:c};(!0===l||!0===u)&&(b.minWidth=f.width+"px",!0===u&&(b.minHeight=f.height+"px")),Object.assign(n.style,b);let y=function(e,t){return{top:0,center:t/2,bottom:t,left:0,middle:e/2,right:e}}(_,v),w=Ua(f,y,o,r);if(void 0===s||void 0===a)Wa(w,f,y,o,r);else{let{top:e,left:t}=w;Wa(w,f,y,o,r);let n=!1;if(w.top!==e){n=!0;let e=2*a[1];f.center=f.top-=e,f.bottom-=e+2}if(w.left!==t){n=!0;let e=2*a[0];f.middle=f.left-=e,f.right-=e+2}!0===n&&(w=Ua(f,y,o,r),Wa(w,f,y,o,r))}b={top:w.top+"px",left:w.left+"px"},void 0!==w.maxHeight&&(b.maxHeight=w.maxHeight+"px",f.height>w.maxHeight&&(b.minHeight=b.maxHeight)),void 0!==w.maxWidth&&(b.maxWidth=w.maxWidth+"px",f.width>w.maxWidth&&(b.minWidth=b.maxWidth)),Object.assign(n.style,b),n.scrollTop!==p&&(n.scrollTop=p),n.scrollLeft!==h&&(n.scrollLeft=h)}function Wa(e,t,n,a,i){let o=n.bottom,r=n.right,s=_a(),l=window.innerHeight-s,u=document.body.clientWidth;if(e.top<0||e.top+o>l)if("center"===i.vertical)e.top=t[a.vertical]>l/2?Math.max(0,l-o):0,e.maxHeight=Math.min(o,l);else if(t[a.vertical]>l/2){let n=Math.min(l,"center"===a.vertical?t.center:a.vertical===i.vertical?t.bottom:t.top);e.maxHeight=Math.min(o,n),e.top=Math.max(0,n-o)}else e.top=Math.max(0,"center"===a.vertical?t.center:a.vertical===i.vertical?t.top:t.bottom),e.maxHeight=Math.min(o,l-e.top);if(e.left<0||e.left+r>u)if(e.maxWidth=Math.min(r,u),"middle"===i.horizontal)e.left=t[a.horizontal]>u/2?Math.max(0,u-r):0;else if(t[a.horizontal]>u/2){let n=Math.min(u,"middle"===a.horizontal?t.middle:a.horizontal===i.horizontal?t.right:t.left);e.maxWidth=Math.min(r,n),e.left=Math.max(0,n-e.maxWidth)}else e.left=Math.max(0,"middle"===a.horizontal?t.middle:a.horizontal===i.horizontal?t.left:t.right),e.maxWidth=Math.min(r,u-e.left)}["left","middle","right"].forEach(e=>{$a[`${e}#ltr`]=e,$a[`${e}#rtl`]=e});var Ga,Ka=$({name:"QMenu",inheritAttrs:!1,props:{...zn,...In,...Nt,...ea,persistent:Boolean,autoClose:Boolean,separateClosePopup:Boolean,noEscDismiss:Boolean,noRouteDismiss:Boolean,noRefocus:Boolean,noFocus:Boolean,fit:Boolean,cover:Boolean,square:Boolean,anchor:{type:String,validator:Ba},self:{type:String,validator:Ba},offset:{type:Array,validator:Fa},scrollTarget:oa,touchPosition:Boolean,maxHeight:{type:String,default:null},maxWidth:{type:String,default:null}},emits:[...qn,"click","escapeKey"],setup(e,{slots:t,emit:r,attrs:s}){let l,u,c,d=null,h=k(),{proxy:p}=h,{$q:f}=p,m=a(null),_=a(!1),v=i(()=>!0!==e.persistent&&!0!==e.noRouteDismiss),b=Ot(e,f),{registerTick:y,removeTick:w}=na(),{registerTimeout:x}=aa(),{transitionProps:C,transitionStyle:T}=ta(e),{localScrollTarget:P,changeScrollEvent:E,unconfigureScrollTarget:A}=On(e,U),{anchorEl:M,canShow:L}=Nn({showing:_}),{hide:R}=Dn({showing:_,canShow:L,handleShow:function(t){if(d=!1===e.noRefocus?document.activeElement:null,Ma(W),z(),U(),l=void 0,void 0!==t&&(e.touchPosition||e.contextMenu)){let e=K(t);if(void 0!==e.left){let{top:t,left:n}=M.value.getBoundingClientRect();l={left:e.left-n,top:e.top-t}}}void 0===u&&(u=o(()=>f.screen.width+"|"+f.screen.height+"|"+e.self+"|"+e.anchor+"|"+f.lang.rtl,Y)),!0!==e.noFocus&&document.activeElement.blur(),y(()=>{Y(),!0!==e.noFocus&&$()}),x(()=>{!0===f.platform.is.ios&&(c=e.autoClose,m.value.click()),Y(),z(!0),r("show",t)},e.transitionDuration)},handleHide:function(t){w(),N(),V(!0),null!==d&&(void 0===t||!0!==t.qClickOutside)&&(((0===t?.type.indexOf("key")?d.closest('[tabindex]:not([tabindex^="-"])'):void 0)||d).focus(),d=null),x(()=>{N(!0),r("hide",t)},e.transitionDuration)},hideOnRouteChange:v,processOnMount:!0}),{showPortal:z,hidePortal:N,renderPortal:O}=Xn(h,m,function(){return n(S,C.value,()=>!0===_.value?n("div",{role:"menu",...s,ref:m,tabindex:-1,class:["q-menu q-position-engine scroll"+j.value,s.class],style:[s.style,T.value],...B.value},dt(t.default)):null)},"menu"),I={anchorEl:M,innerRef:m,onClickOutside(t){if(!0!==e.persistent&&!0===_.value)return R(t),("touchstart"===t.type||t.target.classList.contains("q-dialog__backdrop"))&&J(t),!0}},q=i(()=>Va(e.anchor||(!0===e.cover?"center middle":"bottom start"),f.lang.rtl)),D=i(()=>!0===e.cover?q.value:Va(e.self||"top start",f.lang.rtl)),j=i(()=>(!0===e.square?" q-menu--square":"")+(!0===b.value?" q-menu--dark q-dark":"")),B=i(()=>!0===e.autoClose?{onClick:H}:{}),F=i(()=>!0===_.value&&!0!==e.persistent);function $(){Vn(()=>{let e=m.value;e&&!0!==e.contains(document.activeElement)&&(e=e.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||e.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||e.querySelector("[autofocus], [data-autofocus]")||e,e.focus({preventScroll:!0}))})}function V(e){l=void 0,void 0!==u&&(u(),u=void 0),(!0===e||!0===_.value)&&(La(W),A(),ja(I),Pa(G)),!0!==e&&(d=null)}function U(){(null!==M.value||void 0!==e.scrollTarget)&&(P.value=sa(M.value,e.scrollTarget),E(P.value,Y))}function H(e){!0!==c?(Zn(p,e),r("click",e)):c=!1}function W(t){!0===F.value&&!0!==e.noFocus&&!0!==cn(m.value,t.target)&&$()}function G(t){!0!==e.noEscDismiss&&(r("escapeKey"),R(t))}function Y(){Ha({targetEl:m.value,offset:e.offset,anchorEl:M.value,anchorOrigin:q.value,selfOrigin:D.value,absoluteOffset:l,fit:e.fit,cover:e.cover,maxHeight:e.maxHeight,maxWidth:e.maxWidth})}return o(F,e=>{!0===e?(Ta(G),Da(I)):(Pa(G),ja(I))}),g(V),Object.assign(p,{focus:$,updatePosition:Y}),O}}),Ya=0,Qa=new Array(256);for(let e=0;e<256;e++)Qa[e]=(e+256).toString(16).substring(1);var Za=(()=>{let e=typeof crypto<"u"?crypto:typeof window<"u"?window.crypto||window.msCrypto:void 0;if(void 0!==e){if(void 0!==e.randomBytes)return e.randomBytes;if(void 0!==e.getRandomValues)return t=>{let n=new Uint8Array(t);return e.getRandomValues(n),n}}return e=>{let t=[];for(let n=e;n>0;n--)t.push(Math.floor(256*Math.random()));return t}})();function Ja(){(void 0===Ga||Ya+16>4096)&&(Ya=0,Ga=Za(4096));let e=Array.prototype.slice.call(Ga,Ya,Ya+=16);return e[6]=15&e[6]|64,e[8]=63&e[8]|128,Qa[e[0]]+Qa[e[1]]+Qa[e[2]]+Qa[e[3]]+"-"+Qa[e[4]]+Qa[e[5]]+"-"+Qa[e[6]]+Qa[e[7]]+"-"+Qa[e[8]]+Qa[e[9]]+"-"+Qa[e[10]]+Qa[e[11]]+Qa[e[12]]+Qa[e[13]]+Qa[e[14]]+Qa[e[15]]}function Xa(e,t){return e??(!0===t?`f_${Ja()}`:null)}function ei({getValue:e,required:t=!0}={}){if(!0===I.value){let n=a(void 0!==e?function(e){return e??null}(e()):null);return!0===t&&null===n.value&&m(()=>{n.value=`f_${Ja()}`}),void 0!==e&&o(e,e=>{n.value=Xa(e,t)}),n}return void 0!==e?i(()=>Xa(e(),t)):a(`f_${Ja()}`)}var ti=Object.keys(xn);var ni=$({name:"QBtnDropdown",props:{...xn,...ea,modelValue:Boolean,split:Boolean,dropdownIcon:String,contentClass:[Array,String,Object],contentStyle:[Array,String,Object],cover:Boolean,persistent:Boolean,noEscDismiss:Boolean,noRouteDismiss:Boolean,autoClose:Boolean,noRefocus:Boolean,noFocus:Boolean,menuAnchor:{type:String,default:"bottom end"},menuSelf:{type:String,default:"top end"},menuOffset:Array,disableMainBtn:Boolean,disableDropdown:Boolean,noIconAnimation:Boolean,toggleAriaLabel:String},emits:["update:modelValue","click","beforeShow","show","beforeHide","hide"],setup(e,{slots:t,emit:r}){let{proxy:s}=k(),l=a(e.modelValue),u=a(null),c=ei(),d=i(()=>{let t={"aria-expanded":!0===l.value?"true":"false","aria-haspopup":"true","aria-controls":c.value,"aria-label":e.toggleAriaLabel||s.$q.lang.label[!0===l.value?"collapse":"expand"](e.label)};return(!0===e.disable||!1===e.split&&!0===e.disableMainBtn||!0===e.disableDropdown)&&(t["aria-disabled"]="true"),t}),h=i(()=>"q-btn-dropdown__arrow"+(!0===l.value&&!1===e.noIconAnimation?" rotate-180":"")+(!1===e.split?" q-btn-dropdown__arrow-container":"")),p=i(()=>kn(e)),f=i(()=>function(e){return ti.reduce((t,n)=>{let a=e[n];return void 0!==a&&(t[n]=a),t},{})}(e));function g(e){l.value=!0,r("beforeShow",e)}function _(e){r("show",e),r("update:modelValue",!0)}function v(e){l.value=!1,r("beforeHide",e)}function b(e){r("hide",e),r("update:modelValue",!1)}function y(e){r("click",e)}function w(e){Q(e),S(),r("click",e)}function x(e){u.value?.show(e)}function S(e){u.value?.hide(e)}return o(()=>e.modelValue,e=>{u.value?.[e?"show":"hide"]()}),o(()=>e.split,S),Object.assign(s,{show:x,hide:S,toggle:function(e){u.value?.toggle(e)}}),m(()=>{!0===e.modelValue&&x()}),()=>{let a=[n(Mt,{class:h.value,name:e.dropdownIcon||s.$q.iconSet.arrow.dropdown})];return!0!==e.disableDropdown&&a.push(n(Ka,{ref:u,id:c.value,class:e.contentClass,style:e.contentStyle,cover:e.cover,fit:!0,persistent:e.persistent,noEscDismiss:e.noEscDismiss,noRouteDismiss:e.noRouteDismiss,autoClose:e.autoClose,noFocus:e.noFocus,noRefocus:e.noRefocus,anchor:e.menuAnchor,self:e.menuSelf,offset:e.menuOffset,separateClosePopup:!0,transitionShow:e.transitionShow,transitionHide:e.transitionHide,transitionDuration:e.transitionDuration,onBeforeShow:g,onShow:_,onBeforeHide:v,onHide:b},t.default)),!1===e.split?n(An,{class:"q-btn-dropdown q-btn-dropdown--simple",...f.value,...d.value,disable:!0===e.disable||!0===e.disableMainBtn,noWrap:!0,round:!1,onClick:y},{default:()=>dt(t.label,[]).concat(a),loading:t.loading}):n(Mn,{class:"q-btn-dropdown q-btn-dropdown--split no-wrap q-btn-item",rounded:e.rounded,square:e.square,...p.value,glossy:e.glossy,stretch:e.stretch},()=>[n(An,{class:"q-btn-dropdown--current",...f.value,disable:!0===e.disable||!0===e.disableMainBtn,noWrap:!0,round:!1,onClick:w},{default:t.label,loading:t.loading}),n(An,{class:"q-btn-dropdown__arrow-container q-anchor--skip",...d.value,...p.value,disable:!0===e.disable||!0===e.disableDropdown,rounded:e.rounded,color:e.color,textColor:e.textColor,dense:e.dense,size:e.size,padding:e.padding,ripple:e.ripple},()=>a)])}}}),ai={name:String};function ii(e){return i(()=>({type:"hidden",name:e.name,value:e.modelValue}))}function oi(e={}){return(t,a,i)=>{t[a](n("input",{class:"hidden"+(i||""),...e.value}))}}function ri(e){return i(()=>e.name||e.for)}var si=$({name:"QBtnToggle",props:{...ai,modelValue:{required:!0},options:{type:Array,required:!0,validator:e=>e.every(e=>("label"in e||"icon"in e||"slot"in e)&&"value"in e)},color:String,textColor:String,toggleColor:{type:String,default:"primary"},toggleTextColor:String,outline:Boolean,flat:Boolean,unelevated:Boolean,rounded:Boolean,push:Boolean,glossy:Boolean,size:String,padding:String,noCaps:Boolean,noWrap:Boolean,dense:Boolean,readonly:Boolean,disable:Boolean,stack:Boolean,stretch:Boolean,spread:Boolean,clearable:Boolean,ripple:{type:[Boolean,Object],default:!0}},emits:["update:modelValue","clear","click"],setup(e,{slots:t,emit:a}){let o=i(()=>void 0!==e.options.find(t=>t.value===e.modelValue)),r=oi(i(()=>({type:"hidden",name:e.name,value:e.modelValue}))),s=i(()=>kn(e)),l=i(()=>({rounded:e.rounded,dense:e.dense,...s.value})),u=i(()=>e.options.map((t,n)=>{let{attrs:i,value:o,slot:r,...s}=t;return{slot:r,props:{key:n,"aria-pressed":o===e.modelValue?"true":"false",...i,...s,...l.value,disable:!0===e.disable||!0===s.disable,color:o===e.modelValue?c(s,"toggleColor"):c(s,"color"),textColor:o===e.modelValue?c(s,"toggleTextColor"):c(s,"textColor"),noCaps:!0===c(s,"noCaps"),noWrap:!0===c(s,"noWrap"),size:c(s,"size"),padding:c(s,"padding"),ripple:c(s,"ripple"),stack:!0===c(s,"stack"),stretch:!0===c(s,"stretch"),onClick(n){!function(t,n,i){!0!==e.readonly&&(e.modelValue===t?!0===e.clearable&&(a("update:modelValue",null,null),a("clear")):a("update:modelValue",t,n),a("click",i))}(o,t,n)}}}}));function c(t,n){return void 0===t[n]?e[n]:t[n]}function d(){let a=u.value.map(e=>n(An,e.props,void 0!==e.slot?t[e.slot]:void 0));return void 0!==e.name&&!0!==e.disable&&!0===o.value&&r(a,"push"),pt(t.default,a)}return()=>n(Mn,{class:"q-btn-toggle",...s.value,rounded:e.rounded,stretch:e.stretch,glossy:e.glossy,spread:e.spread},d)}}),li=$({name:"QCard",props:{...Nt,tag:{type:String,default:"div"},square:Boolean,flat:Boolean,bordered:Boolean},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=Ot(e,a),r=i(()=>"q-card"+(!0===o.value?" q-card--dark q-dark":"")+(!0===e.bordered?" q-card--bordered":"")+(!0===e.square?" q-card--square no-border-radius":"")+(!0===e.flat?" q-card--flat no-shadow":""));return()=>n(e.tag,{class:r.value},dt(t.default))}}),ui=$({name:"QCardSection",props:{tag:{type:String,default:"div"},horizontal:Boolean},setup(e,{slots:t}){let a=i(()=>"q-card__section q-card__section--"+(!0===e.horizontal?"horiz row no-wrap":"vert"));return()=>n(e.tag,{class:a.value},dt(t.default))}}),ci=$({name:"QCardActions",props:{...Bt,vertical:Boolean},setup(e,{slots:t}){let a=Ft(e),o=i(()=>`q-card__actions ${a.value} q-card__actions--${!0===e.vertical?"vert column":"horiz row"}`);return()=>n("div",{class:o.value},dt(t.default))}}),di={left:!0,right:!0,up:!0,down:!0,horizontal:!0,vertical:!0},hi=Object.keys(di);function pi(e){let t={};for(let n of hi)!0===e[n]&&(t[n]=!0);return 0===Object.keys(t).length?di:(!0===t.horizontal?t.left=t.right=!0:!0===t.left&&!0===t.right&&(t.horizontal=!0),!0===t.vertical?t.up=t.down=!0:!0===t.up&&!0===t.down&&(t.vertical=!0),!0===t.horizontal&&!0===t.vertical&&(t.all=!0),t)}di.all=!0;var fi=["INPUT","TEXTAREA"];function mi(e,t){return void 0===t.event&&void 0!==e.target&&!0!==e.target.draggable&&"function"==typeof t.handler&&!1===fi.includes(e.target.nodeName.toUpperCase())&&(void 0===e.qClonedBy||-1===e.qClonedBy.indexOf(t.uid))}function gi(e){let t=[.06,6,50];return"string"==typeof e&&e.length&&e.split(":").forEach((e,n)=>{let a=parseFloat(e);a&&(t[n]=a)}),t}var _i=V({name:"touch-swipe",beforeMount(e,{value:t,arg:n,modifiers:a}){if(!0!==a.mouse&&!0!==j.has.touch)return;let i=!0===a.mouseCapture?"Capture":"",o={handler:t,sensitivity:gi(n),direction:pi(a),noop:W,mouseStart(e){mi(e,o)&&G(e)&&(ee(o,"temp",[[document,"mousemove","move",`notPassive${i}`],[document,"mouseup","end","notPassiveCapture"]]),o.start(e,!0))},touchStart(e){if(mi(e,o)){let t=e.target;ee(o,"temp",[[t,"touchmove","move","notPassiveCapture"],[t,"touchcancel","end","notPassiveCapture"],[t,"touchend","end","notPassiveCapture"]]),o.start(e)}},start(t,n){!0===j.is.firefox&&X(e,!0);let a=K(t);o.event={x:a.left,y:a.top,time:Date.now(),mouse:!0===n,dir:!1}},move(e){if(void 0===o.event)return;if(!1!==o.event.dir)return void J(e);let t=Date.now()-o.event.time;if(0===t)return;let n=K(e),a=n.left-o.event.x,i=Math.abs(a),r=n.top-o.event.y,s=Math.abs(r);if(!0!==o.event.mouse){if(io.sensitivity[0]&&(o.event.dir=r<0?"up":"down"),!0===o.direction.horizontal&&i>s&&s<100&&l>o.sensitivity[0]&&(o.event.dir=a<0?"left":"right"),!0===o.direction.up&&io.sensitivity[0]&&(o.event.dir="up"),!0===o.direction.down&&i0&&i<100&&u>o.sensitivity[0]&&(o.event.dir="down"),!0===o.direction.left&&i>s&&a<0&&s<100&&l>o.sensitivity[0]&&(o.event.dir="left"),!0===o.direction.right&&i>s&&a>0&&s<100&&l>o.sensitivity[0]&&(o.event.dir="right"),!1!==o.event.dir?(J(e),!0===o.event.mouse&&(document.body.classList.add("no-pointer-events--children"),document.body.classList.add("non-selectable"),Ln(),o.styleCleanup=e=>{o.styleCleanup=void 0,document.body.classList.remove("non-selectable");let t=()=>{document.body.classList.remove("no-pointer-events--children")};!0===e?setTimeout(t,50):t()}),o.handler({evt:e,touch:!0!==o.event.mouse,mouse:o.event.mouse,direction:o.event.dir,duration:t,distance:{x:i,y:s}})):o.end(e)},end(t){void 0!==o.event&&(te(o,"temp"),!0===j.is.firefox&&X(e,!1),o.styleCleanup?.(!0),void 0!==t&&!1!==o.event.dir&&J(t),o.event=void 0)}};if(e.__qtouchswipe=o,!0===a.mouse){let t=!0===a.mouseCapture||!0===a.mousecapture?"Capture":"";ee(o,"main",[[e,"mousedown","mouseStart",`passive${t}`]])}!0===j.has.touch&&ee(o,"main",[[e,"touchstart","touchStart","passive"+(!0===a.capture?"Capture":"")],[e,"touchmove","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchswipe;void 0!==n&&(t.oldValue!==t.value&&("function"!=typeof t.value&&n.end(),n.handler=t.value),n.direction=pi(t.modifiers))},beforeUnmount(e){let t=e.__qtouchswipe;void 0!==t&&(te(t,"main"),te(t,"temp"),!0===j.is.firefox&&X(e,!1),t.styleCleanup?.(),delete e.__qtouchswipe)}});function vi(){let e=Object.create(null);return{getCache:(t,n)=>void 0===e[t]?e[t]="function"==typeof n?n():n:e[t],setCache(t,n){e[t]=n},hasCache:t=>Object.hasOwnProperty.call(e,t),clearCache(t){void 0!==t?delete e[t]:e=Object.create(null)}}}var bi={name:{required:!0},disable:Boolean},yi={setup:(e,{slots:t})=>()=>n("div",{class:"q-panel scroll",role:"tabpanel"},dt(t.default))},wi={modelValue:{required:!0},animated:Boolean,infinite:Boolean,swipeable:Boolean,vertical:Boolean,transitionPrev:String,transitionNext:String,transitionDuration:{type:[String,Number],default:300},keepAlive:Boolean,keepAliveInclude:[String,Array,RegExp],keepAliveExclude:[String,Array,RegExp],keepAliveMax:Number},ki=["update:modelValue","beforeTransition","transition"];function xi(){let e,t,{props:r,emit:s,proxy:l}=k(),{getCache:u}=vi(),{registerTimeout:c}=aa(),d=a(null),h={value:null};function p(e){let t=!0===r.vertical?"up":"left";M((!0===l.$q.lang.rtl?-1:1)*(e.direction===t?1:-1))}let f=i(()=>[[_i,p,void 0,{horizontal:!0!==r.vertical,vertical:r.vertical,mouse:!0}]]),m=i(()=>r.transitionPrev||"slide-"+(!0===r.vertical?"down":"right")),g=i(()=>r.transitionNext||"slide-"+(!0===r.vertical?"up":"left")),_=i(()=>`--q-transition-duration: ${r.transitionDuration}ms`),v=i(()=>"string"==typeof r.modelValue||"number"==typeof r.modelValue?r.modelValue:String(r.modelValue)),b=i(()=>({include:r.keepAliveInclude,exclude:r.keepAliveExclude,max:r.keepAliveMax})),y=i(()=>void 0!==r.keepAliveInclude||void 0!==r.keepAliveExclude);function w(){M(1)}function x(){M(-1)}function C(e){s("update:modelValue",e)}function P(e){return null!=e&&""!==e}function E(t){return e.findIndex(e=>e.props.name===t&&""!==e.props.disable&&!0!==e.props.disable)}function A(e){let t=0!==e&&!0===r.animated&&-1!==h.value?"q-transition--"+(-1===e?m.value:g.value):null;d.value!==t&&(d.value=t)}function M(n,a=h.value){let i=a+n;for(;-1!==i&&i{t=!1});i+=n}!0===r.infinite&&0!==e.length&&-1!==a&&a!==e.length&&M(n,-1===n?e.length:-1)}function L(){let e=E(r.modelValue);return h.value!==e&&(h.value=e),!0}function R(){let t=!0===P(r.modelValue)&&L()&&e[h.value];return!0===r.keepAlive?[n(T,b.value,[n(!0===y.value?u(v.value,()=>({...yi,name:v.value})):yi,{key:v.value,style:_.value},()=>t)])]:[n("div",{class:"q-panel scroll",style:_.value,key:v.value,role:"tabpanel"},[t])]}return o(()=>r.modelValue,(e,n)=>{let a=!0===P(e)?E(e):-1;!0!==t&&A(-1===a?0:a{s("transition",e,n)},r.transitionDuration))}),Object.assign(l,{next:w,previous:x,goTo:C}),{panelIndex:h,panelDirectives:f,updatePanelsList:function(t){return e=Ut(dt(t.default,[])).filter(e=>null!==e.props&&void 0===e.props.slot&&!0===P(e.props.name)),e.length},updatePanelIndex:L,getPanelContent:function(){if(0!==e.length)return!0===r.animated?[n(S,{name:d.value},R)]:R()},getEnabledPanels:function(){return e.filter(e=>""!==e.props.disable&&!0!==e.props.disable)},getPanels:function(){return e},isValidPanelName:P,keepAliveProps:b,needsUniqueKeepAliveWrapper:y,goToPanelByOffset:M,goToPanel:C,nextPanel:w,previousPanel:x}}var Si=0,Ci={fullscreen:Boolean,noRouteFullscreenExit:Boolean},Ti=["update:fullscreen","fullscreen"];function Pi(){let e,t,n,i=k(),{props:r,emit:s,proxy:l}=i,u=a(!1);function c(){!0===u.value?h():d()}function d(){!0!==u.value&&(u.value=!0,n=l.$el.parentNode,n.replaceChild(t,l.$el),document.body.appendChild(l.$el),1===++Si&&document.body.classList.add("q-body--fullscreen-mixin"),e={handler:h},be.add(e))}function h(){!0===u.value&&(void 0!==e&&(be.remove(e),e=void 0),n.replaceChild(l.$el,t),u.value=!1,0===(Si=Math.max(0,Si-1))&&(document.body.classList.remove("q-body--fullscreen-mixin"),void 0!==l.$el.scrollIntoView&&setTimeout(()=>{l.$el.scrollIntoView()})))}return!0===Ht(i)&&o(()=>l.$route.fullPath,()=>{!0!==r.noRouteFullscreenExit&&h()}),o(()=>r.fullscreen,e=>{u.value!==e&&c()}),o(u,e=>{s("update:fullscreen",e),s("fullscreen",e)}),f(()=>{t=document.createElement("span")}),m(()=>{!0===r.fullscreen&&d()}),g(h),Object.assign(l,{toggleFullscreen:c,setFullscreen:d,exitFullscreen:h}),{inFullscreen:u,toggleFullscreen:c}}var Ei=["top","right","bottom","left"],Ai=["regular","flat","outline","push","unelevated"],Mi=$({name:"QCarousel",props:{...Nt,...wi,...Ci,transitionPrev:{type:String,default:"fade"},transitionNext:{type:String,default:"fade"},height:String,padding:Boolean,controlColor:String,controlTextColor:String,controlType:{type:String,validator:e=>Ai.includes(e),default:"flat"},autoplay:[Number,Boolean],arrows:Boolean,prevIcon:String,nextIcon:String,navigation:Boolean,navigationPosition:{type:String,validator:e=>Ei.includes(e)},navigationIcon:String,navigationActiveIcon:String,thumbnails:Boolean},emits:[...Ti,...ki],setup(e,{slots:t}){let a,{proxy:{$q:r}}=k(),s=Ot(e,r),l=null,{updatePanelsList:u,getPanelContent:c,panelDirectives:d,goToPanel:h,previousPanel:p,nextPanel:f,getEnabledPanels:_,panelIndex:v}=xi(),{inFullscreen:b}=Pi(),y=i(()=>!0!==b.value&&void 0!==e.height?{height:e.height}:{}),w=i(()=>!0===e.vertical?"vertical":"horizontal"),x=i(()=>e.navigationPosition||(!0===e.vertical?"right":"bottom")),S=i(()=>`q-carousel q-panel-parent q-carousel--with${!0===e.padding?"":"out"}-padding`+(!0===b.value?" fullscreen":"")+(!0===s.value?" q-carousel--dark q-dark":"")+(!0===e.arrows?` q-carousel--arrows-${w.value}`:"")+(!0===e.navigation?` q-carousel--navigation-${x.value}`:"")),C=i(()=>{let t=[e.prevIcon||r.iconSet.carousel[!0===e.vertical?"up":"left"],e.nextIcon||r.iconSet.carousel[!0===e.vertical?"down":"right"]];return!1===e.vertical&&!0===r.lang.rtl?t.reverse():t}),T=i(()=>e.navigationIcon||r.iconSet.carousel.navigationIcon),P=i(()=>e.navigationActiveIcon||T.value),E=i(()=>({color:e.controlColor,textColor:e.controlTextColor,round:!0,[e.controlType]:!0,dense:!0}));function A(){let t=!0===$e(e.autoplay)?Math.abs(e.autoplay):5e3;null!==l&&clearTimeout(l),l=setTimeout(()=>{l=null,t>=0?f():p()},t)}function M(t,a){return n("div",{class:`q-carousel__control q-carousel__navigation no-wrap absolute flex q-carousel__navigation--${t} q-carousel__navigation--${x.value}`+(void 0!==e.controlColor?` text-${e.controlColor}`:"")},[n("div",{class:"q-carousel__navigation-inner flex flex-center no-wrap"},_().map(a))])}return o(()=>e.modelValue,()=>{e.autoplay&&A()}),o(()=>e.autoplay,e=>{e?A():null!==l&&(clearTimeout(l),l=null)}),m(()=>{e.autoplay&&A()}),g(()=>{null!==l&&clearTimeout(l)}),()=>(a=u(t),n("div",{class:S.value,style:y.value},[mt("div",{class:"q-carousel__slides-container"},c(),"sl-cont",e.swipeable,()=>d.value)].concat(function(){let i=[];if(!0===e.navigation){let e=void 0!==t["navigation-icon"]?t["navigation-icon"]:e=>n(An,{key:"nav"+e.name,class:`q-carousel__navigation-icon q-carousel__navigation-icon--${!0===e.active?"":"in"}active`,...e.btnProps,onClick:e.onClick}),o=a-1;i.push(M("buttons",(t,n)=>{let a=t.props.name,i=v.value===n;return e({index:n,maxIndex:o,name:a,active:i,btnProps:{icon:!0===i?P.value:T.value,size:"sm",...E.value},onClick:()=>{h(a)}})}))}else if(!0===e.thumbnails){let t=void 0!==e.controlColor?` text-${e.controlColor}`:"";i.push(M("thumbnails",a=>{let i=a.props;return n("img",{key:"tmb#"+i.name,class:`q-carousel__thumbnail q-carousel__thumbnail--${i.name===e.modelValue?"":"in"}active`+t,src:i.imgSrc||i["img-src"],onClick:()=>{h(i.name)}})}))}return!0===e.arrows&&v.value>=0&&((!0===e.infinite||v.value>0)&&i.push(n("div",{key:"prev",class:`q-carousel__control q-carousel__arrow q-carousel__prev-arrow q-carousel__prev-arrow--${w.value} absolute flex flex-center`},[n(An,{icon:C.value[0],...E.value,onClick:p})])),(!0===e.infinite||v.valuee.imgSrc?{backgroundImage:`url("${e.imgSrc}")`}:{});return()=>n("div",{class:"q-carousel__slide",style:a.value},dt(t.default))}}),Ri=$({name:"QCarouselControl",props:{position:{type:String,default:"bottom-right",validator:e=>["top-right","top-left","bottom-right","bottom-left","top","right","bottom","left"].includes(e)},offset:{type:Array,default:()=>[18,18],validator:e=>2===e.length}},setup(e,{slots:t}){let a=i(()=>`q-carousel__control absolute absolute-${e.position}`),o=i(()=>({margin:`${e.offset[1]}px ${e.offset[0]}px`}));return()=>n("div",{class:a.value,style:o.value},dt(t.default))}}),zi=$({name:"QChatMessage",props:{sent:Boolean,label:String,bgColor:String,textColor:String,name:String,avatar:String,text:Array,stamp:String,size:String,labelHtml:Boolean,nameHtml:Boolean,textHtml:Boolean,stampHtml:Boolean},setup(e,{slots:t}){let a=i(()=>!0===e.sent?"sent":"received"),o=i(()=>`q-message-text-content q-message-text-content--${a.value}`+(void 0!==e.textColor?` text-${e.textColor}`:"")),r=i(()=>`q-message-text q-message-text--${a.value}`+(void 0!==e.bgColor?` text-${e.bgColor}`:"")),s=i(()=>"q-message-container row items-end no-wrap"+(!0===e.sent?" reverse":"")),l=i(()=>void 0!==e.size?`col-${e.size}`:""),u=i(()=>({msg:!0===e.textHtml?"innerHTML":"textContent",stamp:!0===e.stampHtml?"innerHTML":"textContent",name:!0===e.nameHtml?"innerHTML":"textContent",label:!0===e.labelHtml?"innerHTML":"textContent"}));function c(a){return void 0!==t.stamp?[a,n("div",{class:"q-message-stamp"},t.stamp())]:e.stamp?[a,n("div",{class:"q-message-stamp",[u.value.stamp]:e.stamp})]:[a]}function d(e,t){let a=!0===t?e.length>1?e=>e:e=>n("div",[e]):e=>n("div",{[u.value.msg]:e});return e.map((e,t)=>n("div",{key:t,class:r.value},[n("div",{class:o.value},c(a(e)))]))}return()=>{let i=[];void 0!==t.avatar?i.push(t.avatar()):void 0!==e.avatar&&i.push(n("img",{class:`q-message-avatar q-message-avatar--${a.value}`,src:e.avatar,"aria-hidden":"true"}));let o=[];void 0!==t.name?o.push(n("div",{class:`q-message-name q-message-name--${a.value}`},t.name())):void 0!==e.name&&o.push(n("div",{class:`q-message-name q-message-name--${a.value}`,[u.value.name]:e.name})),void 0!==t.default?o.push(d(Ut(t.default()),!0)):void 0!==e.text&&o.push(d(e.text)),i.push(n("div",{class:l.value},o));let r=[];return void 0!==t.label?r.push(n("div",{class:"q-message-label"},t.label())):void 0!==e.label&&r.push(n("div",{class:"q-message-label",[u.value.label]:e.label})),r.push(n("div",{class:s.value},i)),n("div",{class:`q-message q-message-${a.value}`},r)}}});function Ni(e,t){let o=a(null);return{refocusTargetEl:i(()=>!0===e.disable?null:n("span",{ref:o,class:"no-outline",tabindex:-1})),refocusTarget:function(e){let n=t.value;!0!==e?.qAvoidFocus&&(0===e?.type.indexOf("key")?document.activeElement!==n&&!0===n?.contains(document.activeElement)&&n.focus():null!==o.value&&(void 0===e||!0===n?.contains(e.target))&&o.value.focus())}}}var Oi={xs:30,sm:35,md:40,lg:50,xl:60},Ii={...Nt,...ut,...ai,modelValue:{required:!0,default:null},val:{},trueValue:{default:!0},falseValue:{default:!1},indeterminateValue:{default:null},checkedIcon:String,uncheckedIcon:String,indeterminateIcon:String,toggleOrder:{type:String,validator:e=>"tf"===e||"ft"===e},toggleIndeterminate:Boolean,label:String,leftLabel:Boolean,color:String,keepColor:Boolean,dense:Boolean,disable:Boolean,tabindex:[String,Number]},qi=["update:modelValue"];function Di(e,t){let{props:o,slots:r,emit:l,proxy:u}=k(),{$q:c}=u,d=Ot(o,c),h=a(null),{refocusTargetEl:p,refocusTarget:f}=Ni(o,h),m=ct(o,Oi),g=i(()=>void 0!==o.val&&Array.isArray(o.modelValue)),_=i(()=>{let e=s(o.val);return!0===g.value?o.modelValue.findIndex(t=>s(t)===e):-1}),v=i(()=>!0===g.value?-1!==_.value:s(o.modelValue)===s(o.trueValue)),b=i(()=>!0===g.value?-1===_.value:s(o.modelValue)===s(o.falseValue)),y=i(()=>!1===v.value&&!1===b.value),w=i(()=>!0===o.disable?-1:o.tabindex||0),x=i(()=>`q-${e} cursor-pointer no-outline row inline no-wrap items-center`+(!0===o.disable?" disabled":"")+(!0===d.value?` q-${e}--dark`:"")+(!0===o.dense?` q-${e}--dense`:"")+(!0===o.leftLabel?" reverse":"")),S=i(()=>{let t=!0===v.value?"truthy":!0===b.value?"falsy":"indet",n=void 0===o.color||!0!==o.keepColor&&("toggle"===e?!0!==v.value:!0===b.value)?"":` text-${o.color}`;return`q-${e}__inner relative-position non-selectable q-${e}__inner--${t}${n}`}),C=oi(i(()=>{let e={type:"checkbox"};return void 0!==o.name&&Object.assign(e,{".checked":v.value,"^checked":!0===v.value?"checked":void 0,name:o.name,value:!0===g.value?o.val:o.trueValue}),e})),T=i(()=>{let t={tabindex:w.value,role:"toggle"===e?"switch":"checkbox","aria-label":o.label,"aria-checked":!0===y.value?"mixed":!0===v.value?"true":"false"};return!0===o.disable&&(t["aria-disabled"]="true"),t});function P(e){void 0!==e&&(J(e),f(e)),!0!==o.disable&&l("update:modelValue",function(){if(!0===g.value){if(!0===v.value){let e=o.modelValue.slice();return e.splice(_.value,1),e}return o.modelValue.concat([o.val])}if(!0===v.value){if("ft"!==o.toggleOrder||!1===o.toggleIndeterminate)return o.falseValue}else{if(!0!==b.value)return"ft"!==o.toggleOrder?o.trueValue:o.falseValue;if("ft"===o.toggleOrder||!1===o.toggleIndeterminate)return o.trueValue}return o.indeterminateValue}(),e)}function E(e){(13===e.keyCode||32===e.keyCode)&&J(e)}function A(e){(13===e.keyCode||32===e.keyCode)&&P(e)}let M=t(v,y);return Object.assign(u,{toggle:P}),()=>{let t=M();!0!==o.disable&&C(t,"unshift",` q-${e}__native absolute q-ma-none q-pa-none`);let a=[n("div",{class:S.value,style:m.value,"aria-hidden":"true"},t)];null!==p.value&&a.push(p.value);let i=void 0!==o.label?pt(r.default,[o.label]):dt(r.default);return void 0!==i&&a.push(n("div",{class:`q-${e}__label q-anchor--skip`},i)),n("div",{ref:h,class:x.value,...T.value,onClick:P,onKeydown:E,onKeyup:A},a)}}var ji=$({name:"QCheckbox",props:Ii,emits:qi,setup(e){let t=n("div",{key:"svg",class:"q-checkbox__bg absolute"},[n("svg",{class:"q-checkbox__svg fit absolute-full",viewBox:"0 0 24 24"},[n("path",{class:"q-checkbox__truthy",fill:"none",d:"M1.73,12.91 8.1,19.28 22.79,4.59"}),n("path",{class:"q-checkbox__indet",d:"M4,14H20V10H4"})])]);return Di("checkbox",function(a,o){let r=i(()=>(!0===a.value?e.checkedIcon:!0===o.value?e.indeterminateIcon:e.uncheckedIcon)||null);return()=>null!==r.value?[n("div",{key:"icon",class:"q-checkbox__icon-container absolute-full flex flex-center no-wrap"},[n(Mt,{class:"q-checkbox__icon",name:r.value})])]:[t]})}}),Bi={xs:8,sm:10,md:14,lg:20,xl:24},Fi=$({name:"QChip",props:{...Nt,...ut,dense:Boolean,icon:String,iconRight:String,iconRemove:String,iconSelected:String,label:[String,Number],color:String,textColor:String,modelValue:{type:Boolean,default:!0},selected:{type:Boolean,default:null},square:Boolean,outline:Boolean,clickable:Boolean,removable:Boolean,removeAriaLabel:String,tabindex:[String,Number],disable:Boolean,ripple:{type:[Boolean,Object],default:!0}},emits:["update:modelValue","update:selected","remove","click"],setup(e,{slots:t,emit:a}){let{proxy:{$q:o}}=k(),r=Ot(e,o),s=ct(e,Bi),l=i(()=>!0===e.selected||void 0!==e.icon),u=i(()=>!0===e.selected?e.iconSelected||o.iconSet.chip.selected:e.icon),c=i(()=>e.iconRemove||o.iconSet.chip.remove),d=i(()=>!1===e.disable&&(!0===e.clickable||null!==e.selected)),h=i(()=>{let t=!0===e.outline&&e.color||e.textColor;return"q-chip row inline no-wrap items-center"+(!1===e.outline&&void 0!==e.color?` bg-${e.color}`:"")+(t?` text-${t} q-chip--colored`:"")+(!0===e.disable?" disabled":"")+(!0===e.dense?" q-chip--dense":"")+(!0===e.outline?" q-chip--outline":"")+(!0===e.selected?" q-chip--selected":"")+(!0===d.value?" q-chip--clickable cursor-pointer non-selectable q-hoverable":"")+(!0===e.square?" q-chip--square":"")+(!0===r.value?" q-chip--dark q-dark":"")}),p=i(()=>{let t=!0===e.disable?{tabindex:-1,"aria-disabled":"true"}:{tabindex:e.tabindex||0};return{chip:t,remove:{...t,role:"button","aria-hidden":"false","aria-label":e.removeAriaLabel||o.lang.label.remove}}});function f(e){13===e.keyCode&&m(e)}function m(t){e.disable||(a("update:selected",!e.selected),a("click",t))}function g(t){(void 0===t.keyCode||13===t.keyCode)&&(J(t),!1===e.disable&&(a("update:modelValue",!1),a("remove")))}return()=>{if(!1===e.modelValue)return;let a={class:h.value,style:s.value};return!0===d.value&&Object.assign(a,p.value.chip,{onClick:m,onKeyup:f}),mt("div",a,function(){let a=[];!0===d.value&&a.push(n("div",{class:"q-focus-helper"})),!0===l.value&&a.push(n(Mt,{class:"q-chip__icon q-chip__icon--left",name:u.value}));let i=void 0!==e.label?[n("div",{class:"ellipsis"},[e.label])]:void 0;return a.push(n("div",{class:"q-chip__content col row no-wrap items-center q-anchor--skip"},ft(t.default,i))),e.iconRight&&a.push(n(Mt,{class:"q-chip__icon q-chip__icon--right",name:e.iconRight})),!0===e.removable&&a.push(n(Mt,{class:"q-chip__icon q-chip__icon--remove cursor-pointer",name:c.value,...p.value.remove,onClick:g,onKeyup:g})),a}(),"ripple",!1!==e.ripple&&!0!==e.disable,()=>[[mn,e.ripple]])}}}),$i={...ut,min:{type:Number,default:0},max:{type:Number,default:100},color:String,centerColor:String,trackColor:String,fontSize:String,rounded:Boolean,thickness:{type:Number,default:.2,validator:e=>e>=0&&e<=1},angle:{type:Number,default:0},showValue:Boolean,reverse:Boolean,instantFeedback:Boolean},Vi=100*Math.PI,Ui=Math.round(1e3*Vi)/1e3,Hi=$({name:"QCircularProgress",props:{...$i,value:{type:Number,default:0},animationSpeed:{type:[String,Number],default:600},indeterminate:Boolean},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=ct(e),r=i(()=>{let t=(!0===a.lang.rtl?-1:1)*e.angle;return{transform:e.reverse!==(!0===a.lang.rtl)?`scale3d(-1, 1, 1) rotate3d(0, 0, 1, ${-90-t}deg)`:`rotate3d(0, 0, 1, ${t-90}deg)`}}),s=i(()=>!0!==e.instantFeedback&&!0!==e.indeterminate?{transition:`stroke-dashoffset ${e.animationSpeed}ms ease 0s, stroke ${e.animationSpeed}ms ease`}:""),l=i(()=>100/(1-e.thickness/2)),u=i(()=>`${l.value/2} ${l.value/2} ${l.value} ${l.value}`),c=i(()=>Je(e.value,e.min,e.max)),d=i(()=>e.max-e.min),h=i(()=>e.thickness/2*l.value),p=i(()=>{let t=(e.max-c.value)/d.value,n=!0===e.rounded&&c.value{let a=[];void 0!==e.centerColor&&"transparent"!==e.centerColor&&a.push(n("circle",{class:`q-circular-progress__center text-${e.centerColor}`,fill:"currentColor",r:50-h.value/2,cx:l.value,cy:l.value})),void 0!==e.trackColor&&"transparent"!==e.trackColor&&a.push(f({cls:"track",thickness:h.value,offset:0,color:e.trackColor})),a.push(f({cls:"circle",thickness:h.value,offset:p.value,color:e.color,rounded:!0===e.rounded?"round":void 0}));let i=[n("svg",{class:"q-circular-progress__svg",style:r.value,viewBox:u.value,"aria-hidden":"true"},a)];return!0===e.showValue&&i.push(n("div",{class:"q-circular-progress__text absolute-full row flex-center content-center",style:{fontSize:e.fontSize}},void 0!==t.default?t.default():[n("div",c.value)])),n("div",{class:`q-circular-progress q-circular-progress--${!0===e.indeterminate?"in":""}determinate`,style:o.value,role:"progressbar","aria-valuemin":e.min,"aria-valuemax":e.max,"aria-valuenow":!0===e.indeterminate?void 0:c.value},ft(t.internal,i))}}});function Wi(e,t,n){let a,i=K(e),o=i.left-t.event.x,r=i.top-t.event.y,s=Math.abs(o),l=Math.abs(r),u=t.direction;!0===u.horizontal&&!0!==u.vertical?a=o<0?"left":"right":!0!==u.horizontal&&!0===u.vertical?a=r<0?"up":"down":!0===u.up&&r<0?(a="up",s>l&&(!0===u.left&&o<0?a="left":!0===u.right&&o>0&&(a="right"))):!0===u.down&&r>0?(a="down",s>l&&(!0===u.left&&o<0?a="left":!0===u.right&&o>0&&(a="right"))):!0===u.left&&o<0?(a="left",s0&&(a="down"))):!0===u.right&&o>0&&(a="right",s0&&(a="down")));let c=!1;if(void 0===a&&!1===n){if(!0===t.event.isFirst||void 0===t.event.lastDir)return{};a=t.event.lastDir,c=!0,"left"===a||"right"===a?(i.left-=o,s=0,o=0):(i.top-=r,l=0,r=0)}return{synthetic:c,payload:{evt:e,touch:!0!==t.event.mouse,mouse:!0===t.event.mouse,position:i,direction:a,isFirst:t.event.isFirst,isFinal:!0===n,duration:Date.now()-t.event.time,distance:{x:s,y:l},offset:{x:o,y:r},delta:{x:i.left-t.event.lastX,y:i.top-t.event.lastY}}}}var Gi=0,Ki=V({name:"touch-pan",beforeMount(e,{value:t,modifiers:n}){if(!0!==n.mouse&&!0!==j.has.touch)return;function a(e,t){!0===n.mouse&&!0===t?J(e):(!0===n.stop&&Q(e),!0===n.prevent&&Z(e))}let i={uid:"qvtp_"+Gi++,handler:t,modifiers:n,direction:pi(n),noop:W,mouseStart(e){mi(e,i)&&G(e)&&(ee(i,"temp",[[document,"mousemove","move","notPassiveCapture"],[document,"mouseup","end","passiveCapture"]]),i.start(e,!0))},touchStart(e){if(mi(e,i)){let t=e.target;ee(i,"temp",[[t,"touchmove","move","notPassiveCapture"],[t,"touchcancel","end","passiveCapture"],[t,"touchend","end","passiveCapture"]]),i.start(e)}},start(t,a){if(!0===j.is.firefox&&X(e,!0),i.lastEvt=t,!0===a||!0===n.stop){if(!0!==i.direction.all&&(!0!==a||!0!==i.modifiers.mouseAllDir&&!0!==i.modifiers.mousealldir)){let e=-1!==t.type.indexOf("mouse")?new MouseEvent(t.type,t):new TouchEvent(t.type,t);!0===t.defaultPrevented&&Z(e),!0===t.cancelBubble&&Q(e),Object.assign(e,{qKeyEvent:t.qKeyEvent,qClickOutside:t.qClickOutside,qAnchorHandled:t.qAnchorHandled,qClonedBy:void 0===t.qClonedBy?[i.uid]:t.qClonedBy.concat(i.uid)}),i.initialEvent={target:t.target,event:e}}Q(t)}let{left:o,top:r}=K(t);i.event={x:o,y:r,time:Date.now(),mouse:!0===a,detected:!1,isFirst:!0,isFinal:!1,lastX:o,lastY:r}},move(e){if(void 0===i.event)return;let t=K(e),o=t.left-i.event.x,r=t.top-i.event.y;if(0===o&&0===r)return;i.lastEvt=e;let s=!0===i.event.mouse,l=()=>{let t;a(e,s),!0!==n.preserveCursor&&!0!==n.preservecursor&&(t=document.documentElement.style.cursor||"",document.documentElement.style.cursor="grabbing"),!0===s&&document.body.classList.add("no-pointer-events--children"),document.body.classList.add("non-selectable"),Ln(),i.styleCleanup=e=>{if(i.styleCleanup=void 0,void 0!==t&&(document.documentElement.style.cursor=t),document.body.classList.remove("non-selectable"),!0===s){let t=()=>{document.body.classList.remove("no-pointer-events--children")};void 0!==e?setTimeout(()=>{t(),e()},50):t()}else void 0!==e&&e()}};if(!0===i.event.detected){!0!==i.event.isFirst&&a(e,i.event.mouse);let{payload:t,synthetic:n}=Wi(e,i,!1);return void(void 0!==t&&(!1===i.handler(t)?i.end(e):(void 0===i.styleCleanup&&!0===i.event.isFirst&&l(),i.event.lastX=t.position.left,i.event.lastY=t.position.top,i.event.lastDir=!0===n?void 0:t.direction,i.event.isFirst=!1)))}if(!0===i.direction.all||!0===s&&(!0===i.modifiers.mouseAllDir||!0===i.modifiers.mousealldir))return l(),i.event.detected=!0,void i.move(e);let u=Math.abs(o),c=Math.abs(r);u!==c&&(!0===i.direction.horizontal&&u>c||!0===i.direction.vertical&&u0||!0===i.direction.left&&u>c&&o<0||!0===i.direction.right&&u>c&&o>0?(i.event.detected=!0,i.move(e)):i.end(e,!0))},end(t,n){if(void 0!==i.event){if(te(i,"temp"),!0===j.is.firefox&&X(e,!1),!0===n)i.styleCleanup?.(),!0!==i.event.detected&&void 0!==i.initialEvent&&i.initialEvent.target.dispatchEvent(i.initialEvent.event);else if(!0===i.event.detected){!0===i.event.isFirst&&i.handler(Wi(void 0===t?i.lastEvt:t,i).payload);let{payload:e}=Wi(void 0===t?i.lastEvt:t,i,!0),n=()=>{i.handler(e)};void 0!==i.styleCleanup?i.styleCleanup(n):n()}i.event=void 0,i.initialEvent=void 0,i.lastEvt=void 0}}};if(e.__qtouchpan=i,!0===n.mouse){let t=!0===n.mouseCapture||!0===n.mousecapture?"Capture":"";ee(i,"main",[[e,"mousedown","mouseStart",`passive${t}`]])}!0===j.has.touch&&ee(i,"main",[[e,"touchstart","touchStart","passive"+(!0===n.capture?"Capture":"")],[e,"touchmove","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchpan;void 0!==n&&(t.oldValue!==t.value&&("function"!=typeof value&&n.end(),n.handler=t.value),n.direction=pi(t.modifiers))},beforeUnmount(e){let t=e.__qtouchpan;void 0!==t&&(void 0!==t.event&&t.end(),te(t,"main"),te(t,"temp"),!0===j.is.firefox&&X(e,!1),t.styleCleanup?.(),delete e.__qtouchpan)}}),Yi="q-slider__marker-labels",Qi=e=>({value:e}),Zi=({marker:e})=>n("div",{key:e.value,style:e.style,class:e.classes},e.label),Ji=[34,37,40,33,39,38],Xi={...Nt,...ai,min:{type:Number,default:0},max:{type:Number,default:100},innerMin:Number,innerMax:Number,step:{type:Number,default:1,validator:e=>e>=0},snap:Boolean,vertical:Boolean,reverse:Boolean,color:String,markerLabelsClass:String,label:Boolean,labelColor:String,labelTextColor:String,labelAlways:Boolean,switchLabelSide:Boolean,markers:[Boolean,Number],markerLabels:[Boolean,Array,Object,Function],switchMarkerLabelsSide:Boolean,trackImg:String,trackColor:String,innerTrackImg:String,innerTrackColor:String,selectionColor:String,selectionImg:String,thumbSize:{type:String,default:"20px"},trackSize:{type:String,default:"4px"},disable:Boolean,readonly:Boolean,dense:Boolean,tabindex:[String,Number],thumbColor:String,thumbPath:{type:String,default:"M 4, 10 a 6,6 0 1,0 12,0 a 6,6 0 1,0 -12,0"}},eo=["pan","update:modelValue","change"];function to({updateValue:e,updatePosition:t,getDragging:o,formAttrs:r}){let{props:s,emit:l,slots:u,proxy:{$q:c}}=k(),d=Ot(s,c),h=oi(r),p=a(!1),f=a(!1),m=a(!1),_=a(!1),v=i(()=>!0===s.vertical?"--v":"--h"),b=i(()=>"-"+(!0===s.switchLabelSide?"switched":"standard")),y=i(()=>!0===s.vertical?!0===s.reverse:s.reverse!==(!0===c.lang.rtl)),w=i(()=>!0===isNaN(s.innerMin)||s.innerMin!0===isNaN(s.innerMax)||s.innerMax>s.max?s.max:s.innerMax),S=i(()=>!0!==s.disable&&!0!==s.readonly&&w.value{if(0===s.step)return e=>e;let e=(String(s.step).trim().split(".")[1]||"").length;return t=>parseFloat(t.toFixed(e))}),T=i(()=>0===s.step?1:s.step),P=i(()=>!0===S.value?s.tabindex||0:-1),E=i(()=>s.max-s.min),A=i(()=>x.value-w.value),M=i(()=>J(w.value)),L=i(()=>J(x.value)),R=i(()=>!0===s.vertical?!0===y.value?"bottom":"top":!0===y.value?"right":"left"),z=i(()=>!0===s.vertical?"height":"width"),N=i(()=>!0===s.vertical?"width":"height"),O=i(()=>!0===s.vertical?"vertical":"horizontal"),I=i(()=>{let e={role:"slider","aria-valuemin":w.value,"aria-valuemax":x.value,"aria-orientation":O.value,"data-step":s.step};return!0===s.disable?e["aria-disabled"]="true":!0===s.readonly&&(e["aria-readonly"]="true"),e}),q=i(()=>`q-slider q-slider${v.value} q-slider--${!0===p.value?"":"in"}active inline no-wrap `+(!0===s.vertical?"row":"column")+(!0===s.disable?" disabled":" q-slider--enabled"+(!0===S.value?" q-slider--editable":""))+("both"===m.value?" q-slider--focus":"")+(s.label||!0===s.labelAlways?" q-slider--label":"")+(!0===s.labelAlways?" q-slider--label-always":"")+(!0===d.value?" q-slider--dark":"")+(!0===s.dense?" q-slider--dense q-slider--dense"+v.value:""));function D(e){let t="q-slider__"+e;return`${t} ${t}${v.value} ${t}${v.value}${b.value}`}function j(e){let t="q-slider__"+e;return`${t} ${t}${v.value}`}let B=i(()=>{let e=s.selectionColor||s.color;return"q-slider__selection absolute"+(void 0!==e?` text-${e}`:"")}),F=i(()=>j("markers")+" absolute overflow-hidden"),$=i(()=>j("track-container")),V=i(()=>D("pin")),U=i(()=>D("label")),H=i(()=>D("text-container")),W=i(()=>D("marker-labels-container")+(void 0!==s.markerLabelsClass?` ${s.markerLabelsClass}`:"")),G=i(()=>"q-slider__track relative-position no-outline"+(void 0!==s.trackColor?` bg-${s.trackColor}`:"")),Y=i(()=>{let e={[N.value]:s.trackSize};return void 0!==s.trackImg&&(e.backgroundImage=`url(${s.trackImg}) !important`),e}),Q=i(()=>"q-slider__inner absolute"+(void 0!==s.innerTrackColor?` bg-${s.innerTrackColor}`:"")),Z=i(()=>{let e=L.value-M.value,t={[R.value]:100*M.value+"%",[z.value]:0===e?"2px":100*e+"%"};return void 0!==s.innerTrackImg&&(t.backgroundImage=`url(${s.innerTrackImg}) !important`),t});function J(e){return 0===E.value?0:(e-s.min)/E.value}let X=i(()=>!0===$e(s.markers)?s.markers:T.value),ee=i(()=>{let e=[],t=X.value,n=s.max,a=s.min;do{e.push(a),a+=t}while(a{let e=` ${Yi}${v.value}-`;return Yi+`${e}${!0===s.switchMarkerLabelsSide?"switched":"standard"}${e}${!0===y.value?"rtl":"ltr"}`}),ne=i(()=>!1===s.markerLabels?null:function(e){if(!1===e)return null;if(!0===e)return ee.value.map(Qi);if("function"==typeof e)return ee.value.map(t=>{let n=e(t);return!0===je(n)?{...n,value:t}:{value:t,label:n}});let t=({value:e})=>e>=s.min&&e<=s.max;return!0===Array.isArray(e)?e.map(e=>!0===je(e)?e:{value:e}).filter(t):Object.keys(e).map(t=>{let n=e[t],a=Number(t);return!0===je(n)?{...n,value:a}:{value:a,label:n}}).filter(t)}(s.markerLabels).map((e,t)=>({index:t,value:e.value,label:e.label||e.value,classes:te.value+(void 0!==e.classes?" "+e.classes:""),style:{...oe(e.value),...e.style||{}}}))),ae=i(()=>({markerList:ne.value,markerMap:re.value,classes:te.value,getStyle:oe})),ie=i(()=>{let e=0===A.value?"2px":100*X.value/A.value;return{...Z.value,backgroundSize:!0===s.vertical?`2px ${e}%`:`${e}% 2px`}});function oe(e){return{[R.value]:100*(e-s.min)/E.value+"%"}}let re=i(()=>{if(!1===s.markerLabels)return null;let e={};return ne.value.forEach(t=>{e[t.value]=t}),e});let se=i(()=>[[Ki,le,void 0,{[O.value]:!0,prevent:!0,stop:!0,mouse:!0,mouseAllDir:!0}]]);function le(n){!0===n.isFinal?(void 0!==_.value&&(t(n.evt),!0===n.touch&&e(!0),_.value=void 0,l("pan","end")),p.value=!1,m.value=!1):!0===n.isFirst?(_.value=o(n.evt),t(n.evt),e(),p.value=!0,l("pan","start")):(t(n.evt),e())}function ue(){m.value=!1}function ce(){f.value=!1,p.value=!1,e(!0),ue(),document.removeEventListener("mouseup",ce,!0)}return g(()=>{document.removeEventListener("mouseup",ce,!0)}),{state:{active:p,focus:m,preventFocus:f,dragging:_,editable:S,classes:q,tabindex:P,attributes:I,roundValueFn:C,keyStep:T,trackLen:E,innerMin:w,innerMinRatio:M,innerMax:x,innerMaxRatio:L,positionProp:R,sizeProp:z,isReversed:y},methods:{onActivate:function(n){t(n,o(n)),e(),f.value=!0,p.value=!0,document.addEventListener("mouseup",ce,!0)},onMobileClick:function(n){t(n,o(n)),e(!0)},onBlur:ue,onKeyup:function(t){Ji.includes(t.keyCode)&&e(!0)},getContent:function(e,t,a,i){let o=[];"transparent"!==s.innerTrackColor&&o.push(n("div",{key:"inner",class:Q.value,style:Z.value})),"transparent"!==s.selectionColor&&o.push(n("div",{key:"selection",class:B.value,style:e.value})),!1!==s.markers&&o.push(n("div",{key:"marker",class:F.value,style:ie.value})),i(o);let r=[mt("div",{key:"trackC",class:$.value,tabindex:t.value,...a.value},[n("div",{class:G.value,style:Y.value},o)],"slide",S.value,()=>se.value)];if(!1!==s.markerLabels){r[!0===s.switchMarkerLabelsSide?"unshift":"push"](n("div",{key:"markerL",class:W.value},function(){if(void 0!==u["marker-label-group"])return u["marker-label-group"](ae.value);let e=u["marker-label"]||Zi;return ne.value.map(t=>e({marker:t,...ae.value}))}()))}return r},getThumbRenderFn:function(e){let t=i(()=>!1!==f.value||m.value!==e.focusValue&&"both"!==m.value?"":" q-slider--focus"),a=i(()=>`q-slider__thumb q-slider__thumb${v.value} q-slider__thumb${v.value}-${!0===y.value?"rtl":"ltr"} absolute non-selectable`+t.value+(void 0!==e.thumbColor.value?` text-${e.thumbColor.value}`:"")),o=i(()=>({width:s.thumbSize,height:s.thumbSize,[R.value]:100*e.ratio.value+"%",zIndex:m.value===e.focusValue?2:void 0})),r=i(()=>void 0!==e.labelColor.value?` text-${e.labelColor.value}`:""),l=i(()=>function(e){if(!0===s.vertical)return null;let t=c.lang.rtl!==s.reverse?1-e:e;return{transform:`translateX(calc(${2*t-1} * ${s.thumbSize} / 2 + ${50-100*t}%))`}}(e.ratio.value)),u=i(()=>"q-slider__text"+(void 0!==e.labelTextColor.value?` text-${e.labelTextColor.value}`:""));return()=>{let t=[n("svg",{class:"q-slider__thumb-shape absolute-full",viewBox:"0 0 20 20","aria-hidden":"true"},[n("path",{d:s.thumbPath})]),n("div",{class:"q-slider__focus-ring fit"})];return(!0===s.label||!0===s.labelAlways)&&(t.push(n("div",{class:V.value+" absolute fit no-pointer-events"+r.value},[n("div",{class:U.value,style:{minWidth:s.thumbSize}},[n("div",{class:H.value,style:l.value},[n("span",{class:u.value},e.label.value)])])])),void 0!==s.name&&!0!==s.disable&&h(t,"push")),n("div",{class:a.value,style:o.value,...e.getNodeData()},t)}},convertRatioToModel:function(e){let{min:t,max:n,step:a}=s,i=t+e*(n-t);if(a>0){let e=(i-w.value)%a;i+=(Math.abs(e)>=a/2?(e<0?-1:1)*a:0)-e}return i=C.value(i),Je(i,w.value,x.value)},convertModelToRatio:J,getDraggingRatio:function(e,t){let n=K(e),a=!0===s.vertical?Je((n.top-t.top)/t.height,0,1):Je((n.left-t.left)/t.width,0,1);return Je(!0===y.value?1-a:a,M.value,L.value)}}}}var no=()=>({}),ao=$({name:"QSlider",props:{...Xi,modelValue:{required:!0,default:null,validator:e=>"number"==typeof e||null===e},labelValue:[String,Number]},emits:eo,setup(e,{emit:t}){let{proxy:{$q:r}}=k(),{state:s,methods:l}=to({updateValue:v,updatePosition:function(t,n=s.dragging.value){let a=l.getDraggingRatio(t,n);d.value=l.convertRatioToModel(a),c.value=!0!==e.snap||0===e.step?a:l.convertModelToRatio(d.value)},getDragging:function(){return u.value.getBoundingClientRect()},formAttrs:ii(e)}),u=a(null),c=a(0),d=a(0);function h(){d.value=null===e.modelValue?s.innerMin.value:Je(e.modelValue,s.innerMin.value,s.innerMax.value)}o(()=>`${e.modelValue}|${s.innerMin.value}|${s.innerMax.value}`,h),h();let p=i(()=>l.convertModelToRatio(d.value)),f=i(()=>!0===s.active.value?c.value:p.value),m=i(()=>{let t={[s.positionProp.value]:100*s.innerMinRatio.value+"%",[s.sizeProp.value]:100*(f.value-s.innerMinRatio.value)+"%"};return void 0!==e.selectionImg&&(t.backgroundImage=`url(${e.selectionImg}) !important`),t}),g=l.getThumbRenderFn({focusValue:!0,getNodeData:no,ratio:f,label:i(()=>void 0!==e.labelValue?e.labelValue:d.value),thumbColor:i(()=>e.thumbColor||e.color),labelColor:i(()=>e.labelColor),labelTextColor:i(()=>e.labelTextColor)}),_=i(()=>!0!==s.editable.value?{}:!0===r.platform.is.mobile?{onClick:l.onMobileClick}:{onMousedown:l.onActivate,onFocus:b,onBlur:l.onBlur,onKeydown:y,onKeyup:l.onKeyup});function v(n){d.value!==e.modelValue&&t("update:modelValue",d.value),!0===n&&t("change",d.value)}function b(){s.focus.value=!0}function y(t){if(!1===Ji.includes(t.keyCode))return;J(t);let n=([34,33].includes(t.keyCode)?10:1)*s.keyStep.value,a=([34,37,40].includes(t.keyCode)?-1:1)*(!0===s.isReversed.value?-1:1)*(!0===e.vertical?-1:1)*n;d.value=Je(s.roundValueFn.value(d.value+a),s.innerMin.value,s.innerMax.value),v()}return()=>{let t=l.getContent(m,s.tabindex,_,e=>{e.push(g())});return n("div",{ref:u,class:s.classes.value+(null===e.modelValue?" q-slider--no-value":""),...s.attributes.value,"aria-valuenow":e.modelValue},t)}}});function io(){let e=a(!I.value);return!1===e.value&&m(()=>{e.value=!0}),{isHydrated:e}}var oo,ro=typeof ResizeObserver<"u",so=!0===ro?{}:{style:"display:block;position:absolute;top:0;left:0;right:0;bottom:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1;",url:"about:blank"},lo=$({name:"QResizeObserver",props:{debounce:{type:[String,Number],default:100}},emits:["resize"],setup(e,{emit:t}){let a,i=null,o={width:-1,height:-1};function r(t){!0===t||0===e.debounce||"0"===e.debounce?s():null===i&&(i=setTimeout(s,e.debounce))}function s(){if(null!==i&&(clearTimeout(i),i=null),a){let{offsetWidth:e,offsetHeight:n}=a;(e!==o.width||n!==o.height)&&(o={width:e,height:n},t("resize",o))}}let{proxy:l}=k();if(l.trigger=r,!0===ro){let e,t=n=>{a=l.$el.parentNode,a?(e=new ResizeObserver(r),e.observe(a),s()):!0!==n&&d(()=>{t(!0)})};return m(()=>{t()}),g(()=>{null!==i&&clearTimeout(i),void 0!==e&&(void 0!==e.disconnect?e.disconnect():a&&e.unobserve(a))}),W}{let e,t=function(){null!==i&&(clearTimeout(i),i=null),void 0!==e&&(void 0!==e.removeEventListener&&e.removeEventListener("resize",r,H.passive),e=void 0)},o=function(){t(),a?.contentDocument&&(e=a.contentDocument.defaultView,e.addEventListener("resize",r,H.passive),s())},{isHydrated:u}=io();return m(()=>{d(()=>{a=l.$el,a&&o()})}),g(t),()=>{if(!0===u.value)return n("object",{class:"q--avoid-card-border",style:so.style,tabindex:-1,type:"text/html",data:so.url,"aria-hidden":"true",onLoad:o})}}}});{let e=document.createElement("div");e.setAttribute("dir","rtl"),Object.assign(e.style,{width:"1px",height:"1px",overflow:"auto"});let t=document.createElement("div");Object.assign(t.style,{width:"1000px",height:"1px"}),document.body.appendChild(e),e.appendChild(t),e.scrollLeft=-1e3,oo=e.scrollLeft>=0,e.remove()}function uo(e,t,n){let a=!0===n?["left","right"]:["top","bottom"];return`absolute-${!0===t?a[0]:a[1]}${e?` text-${e}`:""}`}var co=["left","center","right","justify"],ho=$({name:"QTabs",props:{modelValue:[Number,String],align:{type:String,default:"center",validator:e=>co.includes(e)},breakpoint:{type:[String,Number],default:600},vertical:Boolean,shrink:Boolean,stretch:Boolean,activeClass:String,activeColor:String,activeBgColor:String,indicatorColor:String,leftIcon:String,rightIcon:String,outsideArrows:Boolean,mobileArrows:Boolean,switchIndicator:Boolean,narrowIndicator:Boolean,inlineLabel:Boolean,noCaps:Boolean,dense:Boolean,contentClass:String,"onUpdate:modelValue":[Function,Array]},setup(e,{slots:t,emit:r}){let s,{proxy:l}=k(),{$q:u}=l,{registerTick:c}=na(),{registerTick:d}=na(),{registerTick:f}=na(),{registerTimeout:m,removeTimeout:_}=aa(),{registerTimeout:v,removeTimeout:b}=aa(),y=a(null),x=a(null),S=a(e.modelValue),C=a(!1),T=a(!0),P=a(!1),E=a(!1),A=[],M=a(0),L=a(!1),R=null,z=null,N=i(()=>({activeClass:e.activeClass,activeColor:e.activeColor,activeBgColor:e.activeBgColor,indicatorClass:uo(e.indicatorColor,e.switchIndicator,e.vertical),narrowIndicator:e.narrowIndicator,inlineLabel:e.inlineLabel,noCaps:e.noCaps})),O=i(()=>{let e=M.value,t=S.value;for(let n=0;n`q-tabs__content--align-${!0===C.value?"left":!0===E.value?"justify":e.align}`),q=i(()=>`q-tabs row no-wrap items-center q-tabs--${!0===C.value?"":"not-"}scrollable q-tabs--${!0===e.vertical?"vertical":"horizontal"} q-tabs__arrows--${!0===e.outsideArrows?"outside":"inside"} q-tabs--mobile-with${!0===e.mobileArrows?"":"out"}-arrows`+(!0===e.dense?" q-tabs--dense":"")+(!0===e.shrink?" col-shrink":"")+(!0===e.stretch?" self-stretch":"")),D=i(()=>"q-tabs__content scroll--mobile row no-wrap items-center self-stretch hide-scrollbar relative-position "+I.value+(void 0!==e.contentClass?` ${e.contentClass}`:"")),j=i(()=>!0===e.vertical?{container:"height",content:"offsetHeight",scroll:"scrollHeight"}:{container:"width",content:"offsetWidth",scroll:"scrollWidth"}),B=i(()=>!0!==e.vertical&&!0===u.lang.rtl),F=i(()=>!1===oo&&!0===B.value);function $({name:t,setCurrent:n,skipEmit:a}){S.value!==t&&(!0!==a&&void 0!==e["onUpdate:modelValue"]&&r("update:modelValue",t),(!0===n||void 0===e["onUpdate:modelValue"])&&(function(t,n){let a=null!=t&&""!==t?A.find(e=>e.name.value===t):null,i=null!=n&&""!==n?A.find(e=>e.name.value===n):null;if(!0===oe)oe=!1;else if(a&&i){let t=a.tabIndicatorRef.value,n=i.tabIndicatorRef.value;null!==R&&(clearTimeout(R),R=null),t.style.transition="none",t.style.transform="none",n.style.transition="none",n.style.transform="none";let o=t.getBoundingClientRect(),r=n.getBoundingClientRect();n.style.transform=!0===e.vertical?`translate3d(0,${o.top-r.top}px,0) scale3d(1,${r.height?o.height/r.height:1},1)`:`translate3d(${o.left-r.left}px,0,0) scale3d(${r.width?o.width/r.width:1},1,1)`,f(()=>{R=setTimeout(()=>{R=null,n.style.transition="transform .25s cubic-bezier(.4, 0, .2, 1)",n.style.transform="none"},70)})}i&&!0===C.value&&H(i.rootRef.value)}(S.value,t),S.value=t))}function V(){c(()=>{y.value&&U({width:y.value.offsetWidth,height:y.value.offsetHeight})})}function U(t){if(void 0===j.value||null===x.value)return;let n=t[j.value.container],a=Math.min(x.value[j.value.scroll],Array.prototype.reduce.call(x.value.children,(e,t)=>e+(t[j.value.content]||0),0)),i=n>0&&a>n;C.value=i,!0===i&&d(W),E.value=n0&&(x.value[!0===e.vertical?"scrollTop":"scrollLeft"]+=Math.ceil(s),W())}function W(){let t=x.value;if(null===t)return;let n=t.getBoundingClientRect(),a=!0===e.vertical?t.scrollTop:Math.abs(t.scrollLeft);!0===B.value?(T.value=Math.ceil(a+n.width)0):(T.value=a>0,P.value=!0===e.vertical?Math.ceil(a+n.height){!0===function(e){let t=x.value,{get:n,set:a}=Z.value,i=!1,o=n(t),r=e=e)&&(i=!0,o=e),a(t,o),W(),i}(e)&&Q()},5)}function K(){G(!0===F.value?Number.MAX_SAFE_INTEGER:0)}function Y(){G(!0===F.value?0:Number.MAX_SAFE_INTEGER)}function Q(){null!==z&&(clearInterval(z),z=null)}o(B,W),o(()=>e.modelValue,e=>{$({name:e,setCurrent:!0,skipEmit:!0})}),o(()=>e.outsideArrows,V);let Z=i(()=>!0===F.value?{get:e=>Math.abs(e.scrollLeft),set:(e,t)=>{e.scrollLeft=-t}}:!0===e.vertical?{get:e=>e.scrollTop,set:(e,t)=>{e.scrollTop=t}}:{get:e=>e.scrollLeft,set:(e,t)=>{e.scrollLeft=t}});function J(e,t){for(let n in e)if(e[n]!==t[n])return!1;return!0}function X(){let e=null,t={matchedLen:0,queryDiff:9999,hrefLen:0},n=A.filter(e=>!0===e.routeData?.hasRouterLink.value),{hash:a,query:i}=l.$route,o=Object.keys(i).length;for(let r of n){let n=!0===r.routeData.exact.value;if(!0!==r.routeData[!0===n?"linkIsExactActive":"linkIsActive"].value)continue;let{hash:s,query:l,matched:u,href:c}=r.routeData.resolvedLink.value,d=Object.keys(l).length;if(!0===n){if(s!==a||d!==o||!1===J(i,l))continue;e=r.name.value;break}if(""!==s&&s!==a||0!==d&&!1===J(l,i))continue;let h={matchedLen:u.length,queryDiff:o-d,hrefLen:c.length-s.length};if(h.matchedLen>t.matchedLen)e=r.name.value,t=h;else if(h.matchedLen===t.matchedLen){if(h.queryDifft.hrefLen&&(e=r.name.value,t=h)}}null!==e||!0!==A.some(e=>void 0===e.routeData&&e.name.value===S.value)?$({name:e,setCurrent:!0}):oe=!1}function ee(e){if(_(),!0!==L.value&&null!==y.value&&e.target&&"function"==typeof e.target.closest){let t=e.target.closest(".q-tab");t&&!0===y.value.contains(t)&&(L.value=!0,!0===C.value&&H(t))}}function te(){m(()=>{L.value=!1},30)}function ne(){!1===re.avoidRouteWatcher?v(X):b()}function ae(){if(void 0===s){let e=o(()=>l.$route.fullPath,ne);s=()=>{e(),s=void 0}}}let ie,oe,re={currentModel:S,tabProps:N,hasFocus:L,hasActiveTab:O,registerTab:function(e){A.push(e),M.value++,V(),void 0===e.routeData||void 0===l.$route?v(()=>{if(!0===C.value){let e=S.value,t=null!=e&&""!==e?A.find(t=>t.name.value===e):null;t&&H(t.rootRef.value)}}):(ae(),!0===e.routeData.hasRouterLink.value&&ne())},unregisterTab:function(e){A.splice(A.indexOf(e),1),M.value--,V(),void 0!==s&&void 0!==e.routeData&&(!0===A.every(e=>void 0===e.routeData)&&s(),ne())},verifyRouteModel:ne,updateModel:$,onKbdNavigate:function(t,n){let a=Array.prototype.filter.call(x.value.children,e=>e===n||e.matches&&!0===e.matches(".q-tab.q-focusable")),i=a.length;if(0===i)return;if(36===t)return H(a[0]),a[0].focus(),!0;if(35===t)return H(a[i-1]),a[i-1].focus(),!0;let o=t===(!0===e.vertical?38:37),r=t===(!0===e.vertical?40:39),s=!0===o?-1:!0===r?1:void 0;if(void 0!==s){let e=!0===B.value?-1:1,t=a.indexOf(n)+s*e;return t>=0&&t{ie=void 0!==s,se()}),h(()=>{!0===ie&&(ae(),oe=!0,ne()),V()}),()=>n("div",{ref:y,class:q.value,role:"tablist",onFocusin:ee,onFocusout:te},[n(lo,{onResize:U}),n("div",{ref:x,class:D.value,onScroll:W},dt(t.default)),n(Mt,{class:"q-tabs__arrow q-tabs__arrow--left absolute q-tab__icon"+(!0===T.value?"":" q-tabs__arrow--faded"),name:e.leftIcon||u.iconSet.tabs[!0===e.vertical?"up":"left"],onMousedownPassive:K,onTouchstartPassive:K,onMouseupPassive:Q,onMouseleavePassive:Q,onTouchendPassive:Q}),n(Mt,{class:"q-tabs__arrow q-tabs__arrow--right absolute q-tab__icon"+(!0===P.value?"":" q-tabs__arrow--faded"),name:e.rightIcon||u.iconSet.tabs[!0===e.vertical?"down":"right"],onMousedownPassive:Y,onTouchstartPassive:Y,onMouseupPassive:Q,onMouseleavePassive:Q,onTouchendPassive:Q})])}}),po=0,fo=["click","keydown"],mo={icon:String,label:[Number,String],alert:[Boolean,String],alertIcon:String,name:{type:[Number,String],default:()=>"t_"+po++},noCaps:Boolean,tabindex:[String,Number],disable:Boolean,contentClass:String,ripple:{type:[Boolean,Object],default:!0}};function go(e,t,o,r){let s=y(ze,Oe);if(s===Oe)return console.error("QTab/QRouteTab component needs to be child of QTabs"),Oe;let{proxy:l}=k(),u=a(null),c=a(null),d=a(null),h=i(()=>!0!==e.disable&&!1!==e.ripple&&Object.assign({keyCodes:[13,32],early:!0},!0===e.ripple?{}:e.ripple)),p=i(()=>s.currentModel.value===e.name),f=i(()=>"q-tab relative-position self-stretch flex flex-center text-center"+(!0===p.value?" q-tab--active"+(s.tabProps.value.activeClass?" "+s.tabProps.value.activeClass:"")+(s.tabProps.value.activeColor?` text-${s.tabProps.value.activeColor}`:"")+(s.tabProps.value.activeBgColor?` bg-${s.tabProps.value.activeBgColor}`:""):" q-tab--inactive")+(e.icon&&e.label&&!1===s.tabProps.value.inlineLabel?" q-tab--full":"")+(!0===e.noCaps||!0===s.tabProps.value.noCaps?" q-tab--no-caps":"")+(!0===e.disable?" disabled":" q-focusable q-hoverable cursor-pointer")+(void 0!==r?r.linkClass.value:"")),_=i(()=>"q-tab__content self-stretch flex-center relative-position q-anchor--skip non-selectable "+(!0===s.tabProps.value.inlineLabel?"row no-wrap q-tab__content--inline":"column")+(void 0!==e.contentClass?` ${e.contentClass}`:"")),v=i(()=>!0===e.disable||!0===s.hasFocus.value||!1===p.value&&!0===s.hasActiveTab.value?-1:e.tabindex||0);function b(t,n){if(!0!==n&&!0!==t?.qAvoidFocus&&u.value?.focus(),!0!==e.disable){if(void 0===r)return s.updateModel({name:e.name}),void o("click",t);if(!0===r.hasRouterLink.value){let n=(n={})=>{let a,i=void 0===n.to||!0===De(n.to,e.to)?s.avoidRouteWatcher=Ja():null;return r.navigateToRouterLink(t,{...n,returnRouterError:!0}).catch(e=>{a=e}).then(t=>{if(i===s.avoidRouteWatcher&&(s.avoidRouteWatcher=!1,void 0===a&&(void 0===t||!0===t.message?.startsWith("Avoided redundant navigation"))&&s.updateModel({name:e.name})),!0===n.returnRouterError)return void 0!==a?Promise.reject(a):t})};return o("click",t,n),void(!0!==t.defaultPrevented&&n())}o("click",t)}else!0===r?.hasRouterLink.value&&J(t)}function w(e){pe(e,[13,32])?b(e,!0):!0!==he(e)&&e.keyCode>=35&&e.keyCode<=40&&!0!==e.altKey&&!0!==e.metaKey&&!0===s.onKbdNavigate(e.keyCode,l.$el)&&J(e),o("keydown",e)}let x={name:i(()=>e.name),rootRef:c,tabIndicatorRef:d,routeData:r};return g(()=>{s.unregisterTab(x)}),m(()=>{s.registerTab(x)}),{renderTab:function(a,i){let o={ref:c,class:f.value,tabindex:v.value,role:"tab","aria-selected":!0===p.value?"true":"false","aria-disabled":!0===e.disable?"true":void 0,onClick:b,onKeydown:w,...i};return A(n(a,o,function(){let a=s.tabProps.value.narrowIndicator,i=[],o=n("div",{ref:d,class:["q-tab__indicator",s.tabProps.value.indicatorClass]});void 0!==e.icon&&i.push(n(Mt,{class:"q-tab__icon",name:e.icon})),void 0!==e.label&&i.push(n("div",{class:"q-tab__label"},e.label)),!1!==e.alert&&i.push(void 0!==e.alertIcon?n(Mt,{class:"q-tab__alert-icon",color:!0!==e.alert?e.alert:void 0,name:e.alertIcon}):n("div",{class:"q-tab__alert"+(!0!==e.alert?` text-${e.alert}`:"")})),!0===a&&i.push(o);let r=[n("div",{class:"q-focus-helper",tabindex:-1,ref:u}),n("div",{class:_.value},pt(t.default,i))];return!1===a&&r.push(o),r}()),[[mn,h.value]])},$tabs:s}}var _o=$({name:"QTab",props:mo,emits:fo,setup(e,{slots:t,emit:n}){let{renderTab:a}=go(e,t,n);return()=>a("div")}}),vo=$({name:"QTabPanels",props:{...wi,...Nt},emits:ki,setup(e,{slots:t}){let n=k(),a=Ot(e,n.proxy.$q),{updatePanelsList:o,getPanelContent:r,panelDirectives:s}=xi(),l=i(()=>"q-tab-panels q-panel-parent"+(!0===a.value?" q-tab-panels--dark q-dark":""));return()=>(o(t),mt("div",{class:l.value},r(),"pan",e.swipeable,()=>s.value))}}),bo=$({name:"QTabPanel",props:bi,setup:(e,{slots:t})=>()=>n("div",{class:"q-tab-panel",role:"tabpanel"},dt(t.default))}),yo=/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/,wo=/^#[0-9a-fA-F]{4}([0-9a-fA-F]{4})?$/,ko=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,xo=/^rgb\(((0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),){2}(0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5])\)$/,So=/^rgba\(((0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),){2}(0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),(0|0\.[0-9]+[1-9]|0\.[1-9]+|1)\)$/,Co={date:e=>/^-?[\d]+\/[0-1]\d\/[0-3]\d$/.test(e),time:e=>/^([0-1]?\d|2[0-3]):[0-5]\d$/.test(e),fulltime:e=>/^([0-1]?\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(e),timeOrFulltime:e=>/^([0-1]?\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/.test(e),email:e=>/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(e),hexColor:e=>yo.test(e),hexaColor:e=>wo.test(e),hexOrHexaColor:e=>ko.test(e),rgbColor:e=>xo.test(e),rgbaColor:e=>So.test(e),rgbOrRgbaColor:e=>xo.test(e)||So.test(e),hexOrRgbColor:e=>yo.test(e)||xo.test(e),hexaOrRgbaColor:e=>wo.test(e)||So.test(e),anyColor:e=>ko.test(e)||xo.test(e)||So.test(e)},To={testPattern:Co},Po=/^rgb(a)?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?([01]?\.?\d*?)?\)$/;function Eo({r:e,g:t,b:n,a:a}){let i=void 0!==a;if(e=Math.round(e),t=Math.round(t),n=Math.round(n),e>255||t>255||n>255||i&&a>100)throw new TypeError("Expected 3 numbers below 256 (and optionally one below 100)");return a=i?(256|Math.round(255*a/100)).toString(16).slice(1):"","#"+(n|t<<8|e<<16|1<<24).toString(16).slice(1)+a}function Ao({r:e,g:t,b:n,a:a}){return`rgb${void 0!==a?"a":""}(${e},${t},${n}${void 0!==a?","+a/100:""})`}function Mo(e){if("string"!=typeof e)throw new TypeError("Expected a string");3===(e=e.replace(/^#/,"")).length?e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]:4===e.length&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);let t=parseInt(e,16);return e.length>6?{r:t>>24&255,g:t>>16&255,b:t>>8&255,a:Math.round((255&t)/2.55)}:{r:t>>16,g:t>>8&255,b:255&t}}function Lo({h:e,s:t,v:n,a:a}){let i,o,r;t/=100,n/=100,e/=360;let s=Math.floor(6*e),l=6*e-s,u=n*(1-t),c=n*(1-l*t),d=n*(1-(1-l)*t);switch(s%6){case 0:i=n,o=d,r=u;break;case 1:i=c,o=n,r=u;break;case 2:i=u,o=n,r=d;break;case 3:i=u,o=c,r=n;break;case 4:i=d,o=u,r=n;break;case 5:i=n,o=u,r=c}return{r:Math.round(255*i),g:Math.round(255*o),b:Math.round(255*r),a:a}}function Ro({r:e,g:t,b:n,a:a}){let i,o=Math.max(e,t,n),r=Math.min(e,t,n),s=o-r,l=0===o?0:s/o,u=o/255;switch(o){case r:i=0;break;case e:i=t-n+s*(t1)throw new TypeError("Expected offset to be between -1 and 1");let{r:n,g:a,b:i,a:o}=zo(e),r=void 0!==o?o/100:0;return Eo({r:n,g:a,b:i,a:Math.round(100*Math.min(1,Math.max(0,r+t)))})},getPaletteColor:function(e){if("string"!=typeof e)throw new TypeError("Expected a string as color");let t=document.createElement("div");t.className=`text-${e} invisible fixed no-pointer-events`,document.body.appendChild(t);let n=getComputedStyle(t).getPropertyValue("color");return t.remove(),Eo(zo(n))}},Io=["rgb(255,204,204)","rgb(255,230,204)","rgb(255,255,204)","rgb(204,255,204)","rgb(204,255,230)","rgb(204,255,255)","rgb(204,230,255)","rgb(204,204,255)","rgb(230,204,255)","rgb(255,204,255)","rgb(255,153,153)","rgb(255,204,153)","rgb(255,255,153)","rgb(153,255,153)","rgb(153,255,204)","rgb(153,255,255)","rgb(153,204,255)","rgb(153,153,255)","rgb(204,153,255)","rgb(255,153,255)","rgb(255,102,102)","rgb(255,179,102)","rgb(255,255,102)","rgb(102,255,102)","rgb(102,255,179)","rgb(102,255,255)","rgb(102,179,255)","rgb(102,102,255)","rgb(179,102,255)","rgb(255,102,255)","rgb(255,51,51)","rgb(255,153,51)","rgb(255,255,51)","rgb(51,255,51)","rgb(51,255,153)","rgb(51,255,255)","rgb(51,153,255)","rgb(51,51,255)","rgb(153,51,255)","rgb(255,51,255)","rgb(255,0,0)","rgb(255,128,0)","rgb(255,255,0)","rgb(0,255,0)","rgb(0,255,128)","rgb(0,255,255)","rgb(0,128,255)","rgb(0,0,255)","rgb(128,0,255)","rgb(255,0,255)","rgb(245,0,0)","rgb(245,123,0)","rgb(245,245,0)","rgb(0,245,0)","rgb(0,245,123)","rgb(0,245,245)","rgb(0,123,245)","rgb(0,0,245)","rgb(123,0,245)","rgb(245,0,245)","rgb(214,0,0)","rgb(214,108,0)","rgb(214,214,0)","rgb(0,214,0)","rgb(0,214,108)","rgb(0,214,214)","rgb(0,108,214)","rgb(0,0,214)","rgb(108,0,214)","rgb(214,0,214)","rgb(163,0,0)","rgb(163,82,0)","rgb(163,163,0)","rgb(0,163,0)","rgb(0,163,82)","rgb(0,163,163)","rgb(0,82,163)","rgb(0,0,163)","rgb(82,0,163)","rgb(163,0,163)","rgb(92,0,0)","rgb(92,46,0)","rgb(92,92,0)","rgb(0,92,0)","rgb(0,92,46)","rgb(0,92,92)","rgb(0,46,92)","rgb(0,0,92)","rgb(46,0,92)","rgb(92,0,92)","rgb(255,255,255)","rgb(205,205,205)","rgb(178,178,178)","rgb(153,153,153)","rgb(127,127,127)","rgb(102,102,102)","rgb(76,76,76)","rgb(51,51,51)","rgb(25,25,25)","rgb(0,0,0)"],qo="M5 5 h10 v10 h-10 v-10 z",Do=$({name:"QColor",props:{...Nt,...ai,modelValue:String,defaultValue:String,defaultView:{type:String,default:"spectrum",validator:e=>["spectrum","tune","palette"].includes(e)},formatModel:{type:String,default:"auto",validator:e=>["auto","hex","rgb","hexa","rgba"].includes(e)},palette:Array,noHeader:Boolean,noHeaderTabs:Boolean,noFooter:Boolean,square:Boolean,flat:Boolean,bordered:Boolean,disable:Boolean,readonly:Boolean},emits:["update:modelValue","change"],setup(e,{emit:t}){let{proxy:r}=k(),{$q:s}=r,l=Ot(e,s),{getCache:u}=vi(),c=a(null),h=a(null),p=i(()=>"auto"===e.formatModel?null:-1!==e.formatModel.indexOf("hex")),f=i(()=>"auto"===e.formatModel?null:-1!==e.formatModel.indexOf("a")),m=a("auto"===e.formatModel?void 0===e.modelValue||null===e.modelValue||""===e.modelValue||e.modelValue.startsWith("#")?"hex":"rgb":e.formatModel.startsWith("hex")?"hex":"rgb"),g=a(e.defaultView),_=a(z(e.modelValue||e.defaultValue)),v=i(()=>!0!==e.disable&&!0!==e.readonly),b=i(()=>void 0===e.modelValue||null===e.modelValue||""===e.modelValue||e.modelValue.startsWith("#")),y=i(()=>null!==p.value?p.value:b.value),w=oi(i(()=>({type:"hidden",name:e.name,value:_.value[!0===y.value?"hex":"rgb"]}))),x=i(()=>null!==f.value?f.value:void 0!==_.value.a),S=i(()=>({backgroundColor:_.value.rgb||"#000"})),C=i(()=>"q-color-picker__header-content q-color-picker__header-content--"+(void 0!==_.value.a&&_.value.a<65||No(_.value)>.4?"light":"dark")),T=i(()=>({background:`hsl(${_.value.h},100%,50%)`})),P=i(()=>({top:100-_.value.v+"%",[!0===s.lang.rtl?"right":"left"]:`${_.value.s}%`})),E=i(()=>void 0!==e.palette&&0!==e.palette.length?e.palette:Io),A=i(()=>"q-color-picker"+(!0===e.bordered?" q-color-picker--bordered":"")+(!0===e.square?" q-color-picker--square no-border-radius":"")+(!0===e.flat?" q-color-picker--flat no-shadow":"")+(!0===e.disable?" disabled":"")+(!0===l.value?" q-color-picker--dark q-dark":"")),M=i(()=>!0===e.disable?{"aria-disabled":"true"}:{}),L=i(()=>[[Ki,j,void 0,{prevent:!0,stop:!0,mouse:!0}]]);function R(e,n){_.value.hex=Eo(e),_.value.rgb=Ao(e),_.value.r=e.r,_.value.g=e.g,_.value.b=e.b,_.value.a=e.a;let a=_.value[!0===y.value?"hex":"rgb"];t("update:modelValue",a),!0===n&&t("change",a)}function z(t){let n=void 0!==f.value?f.value:"auto"===e.formatModel?null:-1!==e.formatModel.indexOf("a");if("string"!=typeof t||0===t.length||!0!==Co.anyColor(t.replace(/ /g,"")))return{h:0,s:0,v:0,r:0,g:0,b:0,a:!0===n?100:void 0,hex:void 0,rgb:void 0};let a=zo(t);return!0===n&&void 0===a.a&&(a.a=100),a.hex=Eo(a),a.rgb=Ao(a),Object.assign(a,Ro(a))}function N(e,t,n){let a=c.value;if(null===a)return;let i=a.clientWidth,o=a.clientHeight,r=a.getBoundingClientRect(),l=Math.min(i,Math.max(0,e-r.left));!0===s.lang.rtl&&(l=i-l);let u=Math.min(o,Math.max(0,t-r.top)),d=Math.round(100*l/i),h=Math.round(100*Math.max(0,Math.min(1,-u/o+1))),p=Lo({h:_.value.h,s:d,v:h,a:!0===x.value?_.value.a:void 0});_.value.s=d,_.value.v=h,R(p,n)}function O(e,t){let n=Math.round(e),a=Lo({h:n,s:_.value.s,v:_.value.v,a:!0===x.value?_.value.a:void 0});_.value.h=n,R(a,t)}function I(e){O(e,!0)}function q(e,t,n,a,i){if(void 0!==a&&Q(a),!/^[0-9]+$/.test(e))return void(!0===i&&r.$forceUpdate());let o=Math.floor(Number(e));if(o<0||o>n)return void(!0===i&&r.$forceUpdate());let s={r:"r"===t?o:_.value.r,g:"g"===t?o:_.value.g,b:"b"===t?o:_.value.b,a:!0===x.value?"a"===t?o:_.value.a:void 0};if("a"!==t){let e=Ro(s);_.value.h=e.h,_.value.s=e.s,_.value.v=e.v}if(R(s,i),!0!==i&&void 0!==a?.target.selectionEnd){let e=a.target.selectionEnd;d(()=>{a.target.setSelectionRange(e,e)})}}function D(e,t){let n,a=e.target.value;if(Q(e),"hex"===m.value){if(a.length!==(!0===x.value?9:7)||!/^#[0-9A-Fa-f]+$/.test(a))return!0;n=Mo(a)}else{let e;if(!a.endsWith(")"))return!0;if(!0!==x.value&&a.startsWith("rgb(")){if(e=a.substring(4,a.length-1).split(",").map(e=>parseInt(e,10)),3!==e.length||!/^rgb\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3}\)$/.test(a))return!0}else{if(!0!==x.value||!a.startsWith("rgba("))return!0;{if(e=a.substring(5,a.length-1).split(","),4!==e.length||!/^rgba\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},(0|0\.[0-9]+[1-9]|0\.[1-9]+|1)\)$/.test(a))return!0;for(let t=0;t<3;t++){let n=parseInt(e[t],10);if(n<0||n>255)return!0;e[t]=n}let t=parseFloat(e[3]);if(t<0||t>1)return!0;e[3]=t}}if(e[0]<0||e[0]>255||e[1]<0||e[1]>255||e[2]<0||e[2]>255||!0===x.value&&(e[3]<0||e[3]>1))return!0;n={r:e[0],g:e[1],b:e[2],a:!0===x.value?100*e[3]:void 0}}let i=Ro(n);if(_.value.h=i.h,_.value.s=i.s,_.value.v=i.v,R(n,t),!0!==t){let t=e.target.selectionEnd;d(()=>{e.target.setSelectionRange(t,t)})}}function j(e){e.isFinal?N(e.position.left,e.position.top,!0):B(e)}o(()=>e.modelValue,t=>{let n=z(t||e.defaultValue);n.hex!==_.value.hex&&(_.value=n)}),o(()=>e.defaultValue,t=>{if(!e.modelValue&&t){let e=z(t);e.hex!==_.value.hex&&(_.value=e)}});let B=hn(e=>{N(e.position.left,e.position.top)},20);function F(e){N(e.pageX-window.pageXOffset,e.pageY-window.pageYOffset,!0)}function $(e){N(e.pageX-window.pageXOffset,e.pageY-window.pageYOffset)}function V(e){null!==h.value&&(h.value.$el.style.opacity=e?1:0)}function U(e){m.value=e}function H(e){g.value=e}function W(){let e={ref:c,class:"q-color-picker__spectrum non-selectable relative-position cursor-pointer"+(!0!==v.value?" readonly":""),style:T.value,...!0===v.value?{onClick:F,onMousedown:$}:{}},t=[n("div",{style:{paddingBottom:"100%"}}),n("div",{class:"q-color-picker__spectrum-white absolute-full"}),n("div",{class:"q-color-picker__spectrum-black absolute-full"}),n("div",{class:"absolute",style:P.value},[void 0!==_.value.hex?n("div",{class:"q-color-picker__spectrum-circle"}):null])],a=[n(ao,{class:"q-color-picker__hue non-selectable",modelValue:_.value.h,min:0,max:360,trackSize:"8px",innerTrackColor:"transparent",selectionColor:"transparent",readonly:!0!==v.value,thumbPath:qo,"onUpdate:modelValue":O,onChange:I})];return!0===x.value&&a.push(n(ao,{class:"q-color-picker__alpha non-selectable",modelValue:_.value.a,min:0,max:100,trackSize:"8px",trackColor:"white",innerTrackColor:"transparent",selectionColor:"transparent",trackImg:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAH0lEQVQoU2NkYGAwZkAFZ5G5jPRRgOYEVDeB3EBjBQBOZwTVugIGyAAAAABJRU5ErkJggg==",readonly:!0!==v.value,hideSelection:!0,thumbPath:qo,...u("alphaSlide",{"onUpdate:modelValue":e=>q(e,"a",100),onChange:e=>q(e,"a",100,void 0,!0)})})),[mt("div",e,t,"spec",v.value,()=>L.value),n("div",{class:"q-color-picker__sliders"},a)]}function G(){return[n("div",{class:"row items-center no-wrap"},[n("div","R"),n(ao,{modelValue:_.value.r,min:0,max:255,color:"red",dark:l.value,readonly:!0!==v.value,...u("rSlide",{"onUpdate:modelValue":e=>q(e,"r",255),onChange:e=>q(e,"r",255,void 0,!0)})}),n("input",{value:_.value.r,maxlength:3,readonly:!0!==v.value,onChange:Q,...u("rIn",{onInput:e=>q(e.target.value,"r",255,e),onBlur:e=>q(e.target.value,"r",255,e,!0)})})]),n("div",{class:"row items-center no-wrap"},[n("div","G"),n(ao,{modelValue:_.value.g,min:0,max:255,color:"green",dark:l.value,readonly:!0!==v.value,...u("gSlide",{"onUpdate:modelValue":e=>q(e,"g",255),onChange:e=>q(e,"g",255,void 0,!0)})}),n("input",{value:_.value.g,maxlength:3,readonly:!0!==v.value,onChange:Q,...u("gIn",{onInput:e=>q(e.target.value,"g",255,e),onBlur:e=>q(e.target.value,"g",255,e,!0)})})]),n("div",{class:"row items-center no-wrap"},[n("div","B"),n(ao,{modelValue:_.value.b,min:0,max:255,color:"blue",readonly:!0!==v.value,dark:l.value,...u("bSlide",{"onUpdate:modelValue":e=>q(e,"b",255),onChange:e=>q(e,"b",255,void 0,!0)})}),n("input",{value:_.value.b,maxlength:3,readonly:!0!==v.value,onChange:Q,...u("bIn",{onInput:e=>q(e.target.value,"b",255,e),onBlur:e=>q(e.target.value,"b",255,e,!0)})})]),!0===x.value?n("div",{class:"row items-center no-wrap"},[n("div","A"),n(ao,{modelValue:_.value.a,color:"grey",readonly:!0!==v.value,dark:l.value,...u("aSlide",{"onUpdate:modelValue":e=>q(e,"a",100),onChange:e=>q(e,"a",100,void 0,!0)})}),n("input",{value:_.value.a,maxlength:3,readonly:!0!==v.value,onChange:Q,...u("aIn",{onInput:e=>q(e.target.value,"a",100,e),onBlur:e=>q(e.target.value,"a",100,e,!0)})})]):null]}function K(){return[n("div",{class:"row items-center q-color-picker__palette-rows"+(!0===v.value?" q-color-picker__palette-rows--editable":"")},E.value.map(e=>n("div",{class:"q-color-picker__cube col-auto",style:{backgroundColor:e},...!0===v.value?u("palette#"+e,{onClick:()=>{!function(e){let t=z(e),n={r:t.r,g:t.g,b:t.b,a:t.a};void 0===n.a&&(n.a=_.value.a),_.value.h=t.h,_.value.s=t.s,_.value.v=t.v,R(n,!0)}(e)}}):{}})))]}return()=>{let t=[n(vo,{modelValue:g.value,animated:!0},()=>[n(bo,{class:"q-color-picker__spectrum-tab overflow-hidden",name:"spectrum"},W),n(bo,{class:"q-pa-md q-color-picker__tune-tab",name:"tune"},G),n(bo,{class:"q-color-picker__palette-tab",name:"palette"},K)])];return void 0!==e.name&&!0!==e.disable&&w(t,"push"),!0!==e.noHeader&&t.unshift(function(){let t=[];return!0!==e.noHeaderTabs&&t.push(n(ho,{class:"q-color-picker__header-tabs",modelValue:m.value,dense:!0,align:"justify","onUpdate:modelValue":U},()=>[n(_o,{label:"HEX"+(!0===x.value?"A":""),name:"hex",ripple:!1}),n(_o,{label:"RGB"+(!0===x.value?"A":""),name:"rgb",ripple:!1})])),t.push(n("div",{class:"q-color-picker__header-banner row flex-center no-wrap"},[n("input",{class:"fit",value:_.value[m.value],...!0!==v.value?{readonly:!0}:{},...u("topIn",{onInput:e=>{V(!0===D(e))},onChange:Q,onBlur:e=>{!0===D(e,!0)&&r.$forceUpdate(),V(!1)}})}),n(Mt,{ref:h,class:"q-color-picker__error-icon absolute no-pointer-events",name:s.iconSet.type.negative})])),n("div",{class:"q-color-picker__header relative-position overflow-hidden"},[n("div",{class:"q-color-picker__header-bg absolute-full"}),n("div",{class:C.value,style:S.value},t)])}()),!0!==e.noFooter&&t.push(n("div",{class:"q-color-picker__footer relative-position overflow-hidden"},[n(ho,{class:"absolute-full",modelValue:g.value,dense:!0,align:"justify","onUpdate:modelValue":H},()=>[n(_o,{icon:s.iconSet.colorPicker.spectrum,name:"spectrum",ripple:!1}),n(_o,{icon:s.iconSet.colorPicker.tune,name:"tune",ripple:!1}),n(_o,{icon:s.iconSet.colorPicker.palette,name:"palette",ripple:!1})])])),n("div",{class:A.value,...M.value},t)}}}),jo=[-61,9,38,199,426,686,756,818,1111,1181,1210,1635,2060,2097,2192,2262,2324,2394,2456,3178];function Bo(e,t,n){return"[object Date]"===Object.prototype.toString.call(e)&&(n=e.getDate(),t=e.getMonth()+1,e=e.getFullYear()),function(e){let t,n,a,i=Wo(e).gy,o=i-621,r=Uo(o,!1),s=Ho(i,3,r.march);if(a=e-s,a>=0){if(a<=185)return n=1+Go(a,31),t=Ko(a,31)+1,{jy:o,jm:n,jd:t};a-=186}else o-=1,a+=179,1===r.leap&&(a+=1);return n=7+Go(a,30),t=Ko(a,30)+1,{jy:o,jm:n,jd:t}}(Ho(e,t,n))}function Fo(e,t,n){return Wo(function(e,t,n){let a=Uo(e,!0);return Ho(a.gy,3,a.march)+31*(t-1)-Go(t,7)*(t-7)+n-1}(e,t,n))}function $o(e){return 0===function(e){let t,n,a,i,o,r=jo.length,s=jo[0];if(e=jo[r-1])throw new Error("Invalid Jalaali year "+e);for(o=1;o=jo[s-1])throw new Error("Invalid Jalaali year "+e);for(r=1;rYo.includes(e),default:"gregorian"},landscape:Boolean,color:String,textColor:String,square:Boolean,flat:Boolean,bordered:Boolean,readonly:Boolean,disable:Boolean},Zo=["update:modelValue"];function Jo(e){return e.year+"/"+et(e.month)+"/"+et(e.day)}function Xo(e,t){let n=i(()=>!0!==e.disable&&!0!==e.readonly),a=i(()=>!0===n.value?0:-1),o=i(()=>{let t=[];return void 0!==e.color&&t.push(`bg-${e.color}`),void 0!==e.textColor&&t.push(`text-${e.textColor}`),t.join(" ")});return{editable:n,tabindex:a,headerClass:o,getLocale:function(){return void 0!==e.locale?{...t.lang.date,...e.locale}:t.lang.date},getCurrentDate:function(t){let n=new Date,a=!0===t?null:0;if("persian"===e.calendar){let e=Bo(n);return{year:e.jy,month:e.jm,day:e.jd}}return{year:n.getFullYear(),month:n.getMonth()+1,day:n.getDate(),hour:a,minute:a,second:a,millisecond:a}}}}var er=864e5,tr=6e4,nr="YYYY-MM-DDTHH:mm:ss.SSSZ",ar=/\[((?:[^\]\\]|\\]|\\)*)\]|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]/g,ir=/(\[[^\]]*\])|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]|([.*+:?^,\s${}()|\\]+)/g,or={};function rr(e,t){return void 0!==e?e:void 0!==t?t.date:ye.date}function sr(e,t=""){let n=e>0?"-":"+",a=Math.abs(e),i=a%60;return n+et(Math.floor(a/60))+t+et(i)}function lr(e,t,n){let a=ur(t),i=new Date(e),o=void 0!==a.year||void 0!==a.month||void 0!==a.date?function(e,t,n){let a=e.getFullYear(),i=e.getMonth(),o=e.getDate();return void 0!==t.year&&(a+=n*t.year,delete t.year),void 0!==t.month&&(i+=n*t.month,delete t.month),e.setDate(1),e.setMonth(2),e.setFullYear(a),e.setMonth(i),e.setDate(Math.min(o,vr(e))),void 0!==t.date&&(e.setDate(e.getDate()+n*t.date),delete t.date),e}(i,a,n):i;for(let e in a){let t=Ze(e);o[`set${t}`](o[`get${t}`]()+n*a[e])}return o}function ur(e){let t={...e};return void 0!==e.years&&(t.year=e.years,delete t.years),void 0!==e.months&&(t.month=e.months,delete t.months),void 0!==e.days&&(t.date=e.days,delete t.days),void 0!==e.day&&(t.date=e.day,delete t.day),void 0!==e.hour&&(t.hours=e.hour,delete t.hour),void 0!==e.minute&&(t.minutes=e.minute,delete t.minute),void 0!==e.second&&(t.seconds=e.second,delete t.second),void 0!==e.millisecond&&(t.milliseconds=e.millisecond,delete t.millisecond),t}function cr(e,t,n){let a=ur(t),i=!0===n?"UTC":"",o=new Date(e),r=void 0!==a.year||void 0!==a.month||void 0!==a.date?function(e,t,n){let a=void 0!==t.year?t.year:e[`get${n}FullYear`](),i=void 0!==t.month?t.month-1:e[`get${n}Month`](),o=new Date(a,i+1,0).getDate(),r=Math.min(o,void 0!==t.date?t.date:e[`get${n}Date`]());return e[`set${n}Date`](1),e[`set${n}Month`](2),e[`set${n}FullYear`](a),e[`set${n}Month`](i),e[`set${n}Date`](r),delete t.year,delete t.month,delete t.date,e}(o,a,i):o;for(let e in a){r[`set${i}${e.charAt(0).toUpperCase()+e.slice(1)}`](a[e])}return r}function dr(e,t,n,a,i){let o={year:null,month:null,day:null,hour:null,minute:null,second:null,millisecond:null,timezoneOffset:null,dateHash:null,timeHash:null};if(void 0!==i&&Object.assign(o,i),null==e||""===e||"string"!=typeof e)return o;void 0===t&&(t=nr);let r=rr(n,xe.props),s=r.months,l=r.monthsShort,{regex:u,map:c}=function(e,t){let n="("+t.days.join("|")+")",a=e+n;if(void 0!==or[a])return or[a];let i="("+t.daysShort.join("|")+")",o="("+t.months.join("|")+")",r="("+t.monthsShort.join("|")+")",s={},l=0,u=e.replace(ir,e=>{switch(l++,e){case"YY":return s.YY=l,"(-?\\d{1,2})";case"YYYY":return s.YYYY=l,"(-?\\d{1,4})";case"M":return s.M=l,"(\\d{1,2})";case"Mo":return s.M=l++,"(\\d{1,2}(st|nd|rd|th))";case"MM":return s.M=l,"(\\d{2})";case"MMM":return s.MMM=l,r;case"MMMM":return s.MMMM=l,o;case"D":return s.D=l,"(\\d{1,2})";case"Do":return s.D=l++,"(\\d{1,2}(st|nd|rd|th))";case"DD":return s.D=l,"(\\d{2})";case"H":return s.H=l,"(\\d{1,2})";case"HH":return s.H=l,"(\\d{2})";case"h":return s.h=l,"(\\d{1,2})";case"hh":return s.h=l,"(\\d{2})";case"m":return s.m=l,"(\\d{1,2})";case"mm":return s.m=l,"(\\d{2})";case"s":return s.s=l,"(\\d{1,2})";case"ss":return s.s=l,"(\\d{2})";case"S":return s.S=l,"(\\d{1})";case"SS":return s.S=l,"(\\d{2})";case"SSS":return s.S=l,"(\\d{3})";case"A":return s.A=l,"(AM|PM)";case"a":return s.a=l,"(am|pm)";case"aa":return s.aa=l,"(a\\.m\\.|p\\.m\\.)";case"ddd":return i;case"dddd":return n;case"Q":case"d":case"E":return"(\\d{1})";case"do":return l++,"(\\d{1}(st|nd|rd|th))";case"Qo":return"(1st|2nd|3rd|4th)";case"DDD":case"DDDD":return"(\\d{1,3})";case"DDDo":return l++,"(\\d{1,3}(st|nd|rd|th))";case"w":return"(\\d{1,2})";case"wo":return l++,"(\\d{1,2}(st|nd|rd|th))";case"ww":return"(\\d{2})";case"Z":return s.Z=l,"(Z|[+-]\\d{2}:\\d{2})";case"ZZ":return s.ZZ=l,"(Z|[+-]\\d{2}\\d{2})";case"X":return s.X=l,"(-?\\d+)";case"x":return s.x=l,"(-?\\d{4,})";default:return l--,"["===e[0]&&(e=e.substring(1,e.length-1)),e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}}),c={map:s,regex:new RegExp("^"+u)};return or[a]=c,c}(t,r),d=e.match(u);if(null===d)return o;let h="";if(void 0!==c.X||void 0!==c.x){let e=parseInt(d[void 0!==c.X?c.X:c.x],10);if(!0===isNaN(e)||e<0)return o;let t=new Date(e*(void 0!==c.X?1e3:1));o.year=t.getFullYear(),o.month=t.getMonth()+1,o.day=t.getDate(),o.hour=t.getHours(),o.minute=t.getMinutes(),o.second=t.getSeconds(),o.millisecond=t.getMilliseconds()}else{if(void 0!==c.YYYY)o.year=parseInt(d[c.YYYY],10);else if(void 0!==c.YY){let e=parseInt(d[c.YY],10);o.year=e<0?e:2e3+e}if(void 0!==c.M){if(o.month=parseInt(d[c.M],10),o.month<1||o.month>12)return o}else void 0!==c.MMM?o.month=l.indexOf(d[c.MMM])+1:void 0!==c.MMMM&&(o.month=s.indexOf(d[c.MMMM])+1);if(void 0!==c.D){if(o.day=parseInt(d[c.D],10),null===o.year||null===o.month||o.day<1)return o;let e="persian"!==a?new Date(o.year,o.month,0).getDate():Vo(o.year,o.month);if(o.day>e)return o}void 0!==c.H?o.hour=parseInt(d[c.H],10)%24:void 0!==c.h&&(o.hour=parseInt(d[c.h],10)%12,(c.A&&"PM"===d[c.A]||c.a&&"pm"===d[c.a]||c.aa&&"p.m."===d[c.aa])&&(o.hour+=12),o.hour=o.hour%24),void 0!==c.m&&(o.minute=parseInt(d[c.m],10)%60),void 0!==c.s&&(o.second=parseInt(d[c.s],10)%60),void 0!==c.S&&(o.millisecond=parseInt(d[c.S],10)*10**(3-d[c.S].length)),(void 0!==c.Z||void 0!==c.ZZ)&&(h=void 0!==c.Z?d[c.Z].replace(":",""):d[c.ZZ],o.timezoneOffset=("+"===h[0]?-1:1)*(60*h.slice(1,3)+1*h.slice(3,5)))}return o.dateHash=et(o.year,4)+"/"+et(o.month)+"/"+et(o.day),o.timeHash=et(o.hour)+":"+et(o.minute)+":"+et(o.second)+h,o}function hr(e){let t=new Date(e.getFullYear(),e.getMonth(),e.getDate());t.setDate(t.getDate()-(t.getDay()+6)%7+3);let n=new Date(t.getFullYear(),0,4);n.setDate(n.getDate()-(n.getDay()+6)%7+3);let a=t.getTimezoneOffset()-n.getTimezoneOffset();t.setHours(t.getHours()-a);let i=(t-n)/(7*er);return 1+Math.floor(i)}function pr(e,t){let n=new Date(e);return!0===t?function(e){return 1e4*e.getFullYear()+100*e.getMonth()+e.getDate()}(n):n.getTime()}function fr(e,t,n){let a=new Date(e),i="set"+(!0===n?"UTC":"");switch(t){case"year":case"years":a[`${i}Month`](0);case"month":case"months":a[`${i}Date`](1);case"day":case"days":case"date":a[`${i}Hours`](0);case"hour":case"hours":a[`${i}Minutes`](0);case"minute":case"minutes":a[`${i}Seconds`](0);case"second":case"seconds":a[`${i}Milliseconds`](0)}return a}function mr(e,t,n){return(e.getTime()-e.getTimezoneOffset()*tr-(t.getTime()-t.getTimezoneOffset()*tr))/n}function gr(e,t,n="days"){let a=new Date(e),i=new Date(t);switch(n){case"years":case"year":return a.getFullYear()-i.getFullYear();case"months":case"month":return 12*(a.getFullYear()-i.getFullYear())+a.getMonth()-i.getMonth();case"days":case"day":case"date":return mr(fr(a,"day"),fr(i,"day"),er);case"hours":case"hour":return mr(fr(a,"hour"),fr(i,"hour"),36e5);case"minutes":case"minute":return mr(fr(a,"minute"),fr(i,"minute"),tr);case"seconds":case"second":return mr(fr(a,"second"),fr(i,"second"),1e3)}}function _r(e){return gr(e,fr(e,"year"),"days")+1}function vr(e){return new Date(e.getFullYear(),e.getMonth()+1,0).getDate()}function br(e){if(e>=11&&e<=13)return`${e}th`;switch(e%10){case 1:return`${e}st`;case 2:return`${e}nd`;case 3:return`${e}rd`}return`${e}th`}var yr={YY(e,t,n){let a=this.YYYY(e,t,n)%100;return a>=0?et(a):"-"+et(Math.abs(a))},YYYY:(e,t,n)=>n??e.getFullYear(),M:e=>e.getMonth()+1,Mo:e=>br(e.getMonth()+1),MM:e=>et(e.getMonth()+1),MMM:(e,t)=>t.monthsShort[e.getMonth()],MMMM:(e,t)=>t.months[e.getMonth()],Q:e=>Math.ceil((e.getMonth()+1)/3),Qo(e){return br(this.Q(e))},D:e=>e.getDate(),Do:e=>br(e.getDate()),DD:e=>et(e.getDate()),DDD:e=>_r(e),DDDo:e=>br(_r(e)),DDDD:e=>et(_r(e),3),d:e=>e.getDay(),do:e=>br(e.getDay()),dd:(e,t)=>t.days[e.getDay()].slice(0,2),ddd:(e,t)=>t.daysShort[e.getDay()],dddd:(e,t)=>t.days[e.getDay()],E:e=>e.getDay()||7,w:e=>hr(e),wo:e=>br(hr(e)),ww:e=>et(hr(e)),H:e=>e.getHours(),HH:e=>et(e.getHours()),h(e){let t=e.getHours();return 0===t?12:t>12?t%12:t},hh(e){return et(this.h(e))},m:e=>e.getMinutes(),mm:e=>et(e.getMinutes()),s:e=>e.getSeconds(),ss:e=>et(e.getSeconds()),S:e=>Math.floor(e.getMilliseconds()/100),SS:e=>et(Math.floor(e.getMilliseconds()/10)),SSS:e=>et(e.getMilliseconds(),3),A:e=>e.getHours()<12?"AM":"PM",a:e=>e.getHours()<12?"am":"pm",aa:e=>e.getHours()<12?"a.m.":"p.m.",Z:(e,t,n,a)=>sr(a??e.getTimezoneOffset(),":"),ZZ:(e,t,n,a)=>sr(a??e.getTimezoneOffset()),X:e=>Math.floor(e.getTime()/1e3),x:e=>e.getTime()};function wr(e,t,n,a,i){if(0!==e&&!e||e===1/0||e===-1/0)return;let o=new Date(e);if(isNaN(o))return;void 0===t&&(t=nr);let r=rr(n,xe.props);return t.replace(ar,(e,t)=>e in yr?yr[e](o,r,a,i):void 0===t?e:t.split("\\]").join("]"))}var kr={isValid:function(e){return"number"==typeof e||!1===isNaN(Date.parse(e))},extractDate:function(e,t,n){let a=dr(e,t,n),i=new Date(a.year,null===a.month?null:a.month-1,null===a.day?1:a.day,a.hour,a.minute,a.second,a.millisecond),o=i.getTimezoneOffset();return null===a.timezoneOffset||a.timezoneOffset===o?i:lr(i,{minutes:a.timezoneOffset-o},1)},buildDate:function(e,t){return cr(new Date,e,t)},getDayOfWeek:function(e){let t=new Date(e).getDay();return 0===t?7:t},getWeekOfYear:hr,isBetweenDates:function(e,t,n,a={}){let i=pr(t,a.onlyDate),o=pr(n,a.onlyDate),r=pr(e,a.onlyDate);return(r>i||!0===a.inclusiveFrom&&r===i)&&(r{t=Math.max(t,new Date(e))}),t},getMinDate:function(e){let t=new Date(e);return Array.prototype.slice.call(arguments,1).forEach(e=>{t=Math.min(t,new Date(e))}),t},getDateDiff:gr,getDayOfYear:_r,inferDateFormat:function(e){return!0===Be(e)?"date":"number"==typeof e?"number":"string"},getDateBetween:function(e,t,n){let a=new Date(e);if(t){let e=new Date(t);if(ae)return e}return a},isSameDate:function(e,t,n){let a=new Date(e),i=new Date(t);if(void 0===n)return a.getTime()===i.getTime();switch(n){case"second":case"seconds":if(a.getSeconds()!==i.getSeconds())return!1;case"minute":case"minutes":if(a.getMinutes()!==i.getMinutes())return!1;case"hour":case"hours":if(a.getHours()!==i.getHours())return!1;case"day":case"days":case"date":if(a.getDate()!==i.getDate())return!1;case"month":case"months":if(a.getMonth()!==i.getMonth())return!1;case"year":case"years":if(a.getFullYear()!==i.getFullYear())return!1;break;default:throw new Error(`date isSameDate unknown unit ${n}`)}return!0},daysInMonth:vr,formatDate:wr,clone:function(e){return!0===Be(e)?new Date(e.getTime()):e}},xr=20,Sr=["Calendar","Years","Months"],Cr=e=>Sr.includes(e),Tr=e=>/^-?[\d]+\/[0-1]\d$/.test(e),Pr=" — ";function Er(e){return e.year+"/"+et(e.month)}var Ar=$({name:"QDate",props:{...Qo,...ai,...Nt,modelValue:{required:!0,validator:e=>"string"==typeof e||!0===Array.isArray(e)||Object(e)===e||null===e},multiple:Boolean,range:Boolean,title:String,subtitle:String,mask:{...Qo.mask,default:"YYYY/MM/DD"},defaultYearMonth:{type:String,validator:Tr},yearsInMonthView:Boolean,events:[Array,Function],eventColor:[String,Function],emitImmediately:Boolean,options:[Array,Function],navigationMinYearMonth:{type:String,validator:Tr},navigationMaxYearMonth:{type:String,validator:Tr},noUnset:Boolean,firstDayOfWeek:[String,Number],todayBtn:Boolean,minimal:Boolean,defaultView:{type:String,default:"Calendar",validator:Cr}},emits:[...Zo,"rangeStart","rangeEnd","navigation"],setup(e,{slots:t,emit:r}){let s,{proxy:l}=k(),{$q:u}=l,c=Ot(e,u),{getCache:h}=vi(),{tabindex:p,headerClass:f,getLocale:m,getCurrentDate:g}=Xo(e,u),_=oi(ii(e)),v=a(null),b=a(fe()),y=a(m()),w=i(()=>fe()),x=i(()=>m()),C=i(()=>g()),T=a(ge(b.value,y.value)),P=a(e.defaultView),E=i(()=>!0===u.lang.rtl?"right":"left"),A=a(E.value),M=a(E.value),L=T.value.year,R=a(L-L%xr-(L<0?xr:0)),z=a(null),N=i(()=>{let t=!0===e.landscape?"landscape":"portrait";return`q-date q-date--${t} q-date--${t}-${!0===e.minimal?"minimal":"standard"}`+(!0===c.value?" q-date--dark q-dark":"")+(!0===e.bordered?" q-date--bordered":"")+(!0===e.square?" q-date--square no-border-radius":"")+(!0===e.flat?" q-date--flat no-shadow":"")+(!0===e.disable?" disabled":!0===e.readonly?" q-date--readonly":"")}),O=i(()=>e.color||"primary"),I=i(()=>e.textColor||"white"),q=i(()=>!0===e.emitImmediately&&!0!==e.multiple&&!0!==e.range),D=i(()=>!0===Array.isArray(e.modelValue)?e.modelValue:null!==e.modelValue&&void 0!==e.modelValue?[e.modelValue]:[]),j=i(()=>D.value.filter(e=>"string"==typeof e).map(e=>me(e,b.value,y.value)).filter(e=>null!==e.dateHash&&null!==e.day&&null!==e.month&&null!==e.year)),B=i(()=>{let e=e=>me(e,b.value,y.value);return D.value.filter(e=>!0===je(e)&&void 0!==e.from&&void 0!==e.to).map(t=>({from:e(t.from),to:e(t.to)})).filter(e=>null!==e.from.dateHash&&null!==e.to.dateHash&&e.from.dateHash"persian"!==e.calendar?e=>new Date(e.year,e.month-1,e.day):e=>{let t=Fo(e.year,e.month,e.day);return new Date(t.gy,t.gm-1,t.gd)}),$=i(()=>"persian"===e.calendar?Jo:(e,t,n)=>wr(new Date(e.year,e.month-1,e.day,e.hour,e.minute,e.second,e.millisecond),void 0===t?b.value:t,void 0===n?y.value:n,e.year,e.timezoneOffset)),V=i(()=>j.value.length+B.value.reduce((e,t)=>e+1+gr(F.value(t.to),F.value(t.from)),0)),U=i(()=>{if(void 0!==e.title&&null!==e.title&&0!==e.title.length)return e.title;if(null!==z.value){let e=z.value.init,t=F.value(e);return y.value.daysShort[t.getDay()]+", "+y.value.monthsShort[e.month-1]+" "+e.day+Pr+"?"}if(0===V.value)return Pr;if(V.value>1)return`${V.value} ${y.value.pluralDay}`;let t=j.value[0],n=F.value(t);return!0===isNaN(n.valueOf())?Pr:void 0!==y.value.headerTitle?y.value.headerTitle(n,t):y.value.daysShort[n.getDay()]+", "+y.value.monthsShort[t.month-1]+" "+t.day}),H=i(()=>j.value.concat(B.value.map(e=>e.from)).sort((e,t)=>e.year-t.year||e.month-t.month)[0]),W=i(()=>j.value.concat(B.value.map(e=>e.to)).sort((e,t)=>t.year-e.year||t.month-e.month)[0]),G=i(()=>{if(void 0!==e.subtitle&&null!==e.subtitle&&0!==e.subtitle.length)return e.subtitle;if(0===V.value)return Pr;if(V.value>1){let e=H.value,t=W.value,n=y.value.monthsShort;return n[e.month-1]+(e.year!==t.year?" "+e.year+Pr+n[t.month-1]+" ":e.month!==t.month?Pr+n[t.month-1]:"")+" "+t.year}return j.value[0].year}),K=i(()=>{let e=[u.iconSet.datetime.arrowLeft,u.iconSet.datetime.arrowRight];return!0===u.lang.rtl?e.reverse():e}),Y=i(()=>void 0!==e.firstDayOfWeek?Number(e.firstDayOfWeek):y.value.firstDayOfWeek),Q=i(()=>{let e=y.value.daysShort,t=Y.value;return t>0?e.slice(t,7).concat(e.slice(0,t)):e}),Z=i(()=>{let t=T.value;return"persian"!==e.calendar?new Date(t.year,t.month,0).getDate():Vo(t.year,t.month)}),J=i(()=>"function"==typeof e.eventColor?e.eventColor:()=>e.eventColor),X=i(()=>{if(void 0===e.navigationMinYearMonth)return null;let t=e.navigationMinYearMonth.split("/");return{year:parseInt(t[0],10),month:parseInt(t[1],10)}}),ee=i(()=>{if(void 0===e.navigationMaxYearMonth)return null;let t=e.navigationMaxYearMonth.split("/");return{year:parseInt(t[0],10),month:parseInt(t[1],10)}}),te=i(()=>{let e={month:{prev:!0,next:!0},year:{prev:!0,next:!0}};return null!==X.value&&X.value.year>=T.value.year&&(e.year.prev=!1,X.value.year===T.value.year&&X.value.month>=T.value.month&&(e.month.prev=!1)),null!==ee.value&&ee.value.year<=T.value.year&&(e.year.next=!1,ee.value.year===T.value.year&&ee.value.month<=T.value.month&&(e.month.next=!1)),e}),ne=i(()=>{let e={};return j.value.forEach(t=>{let n=Er(t);void 0===e[n]&&(e[n]=[]),e[n].push(t.day)}),e}),ae=i(()=>{let e={};return B.value.forEach(t=>{let n=Er(t.from),a=Er(t.to);if(void 0===e[n]&&(e[n]=[]),e[n].push({from:t.from.day,to:n===a?t.to.day:void 0,range:t}),n12&&(r.year++,r.month=1)}}),e}),ie=i(()=>{if(null===z.value)return;let{init:e,initHash:t,final:n,finalHash:a}=z.value,[i,o]=t<=a?[e,n]:[n,e],r=Er(i),s=Er(o);if(r!==oe.value&&s!==oe.value)return;let l={};return r===oe.value?(l.from=i.day,l.includeFrom=!0):l.from=1,s===oe.value?(l.to=o.day,l.includeTo=!0):l.to=Z.value,l}),oe=i(()=>Er(T.value)),re=i(()=>{let t={};if(void 0===e.options){for(let e=1;e<=Z.value;e++)t[e]=!0;return t}let n="function"==typeof e.options?e.options:t=>e.options.includes(t);for(let e=1;e<=Z.value;e++){let a=oe.value+"/"+et(e);t[e]=n(a)}return t}),se=i(()=>{let t={};if(void 0===e.events)for(let e=1;e<=Z.value;e++)t[e]=!1;else{let n="function"==typeof e.events?e.events:t=>e.events.includes(t);for(let e=1;e<=Z.value;e++){let a=oe.value+"/"+et(e);t[e]=!0===n(a)&&J.value(a)}}return t}),le=i(()=>{let t,n,{year:a,month:i}=T.value;if("persian"!==e.calendar)t=new Date(a,i-1,1),n=new Date(a,i-1,0).getDate();else{let e=Fo(a,i,1);t=new Date(e.gy,e.gm-1,e.gd);let o=i-1,r=a;0===o&&(o=12,r--),n=Vo(r,o)}return{days:t.getDay()-Y.value-1,endDay:n}}),ue=i(()=>{let e=[],{days:t,endDay:n}=le.value,a=t<0?t+7:t;if(a<6)for(let t=n-a;t<=n;t++)e.push({i:t,fill:!0});let i=e.length;for(let t=1;t<=Z.value;t++){let n={i:t,event:se.value[t],classes:[]};!0===re.value[t]&&(n.in=!0,n.flat=!0),e.push(n)}if(void 0!==ne.value[oe.value]&&ne.value[oe.value].forEach(t=>{let n=i+t-1;Object.assign(e[n],{selected:!0,unelevated:!0,flat:!1,color:O.value,textColor:I.value})}),void 0!==ae.value[oe.value]&&ae.value[oe.value].forEach(t=>{if(void 0!==t.from){let n=i+t.from-1,a=i+(t.to||Z.value)-1;for(let i=n;i<=a;i++)Object.assign(e[i],{range:t.range,unelevated:!0,color:O.value,textColor:I.value});Object.assign(e[n],{rangeFrom:!0,flat:!1}),void 0!==t.to&&Object.assign(e[a],{rangeTo:!0,flat:!1})}else if(void 0!==t.to){let n=i+t.to-1;for(let a=i;a<=n;a++)Object.assign(e[a],{range:t.range,unelevated:!0,color:O.value,textColor:I.value});Object.assign(e[n],{flat:!1,rangeTo:!0})}else{let n=i+Z.value-1;for(let a=i;a<=n;a++)Object.assign(e[a],{range:t.range,unelevated:!0,color:O.value,textColor:I.value})}}),void 0!==ie.value){let t=i+ie.value.from-1,n=i+ie.value.to-1;for(let a=t;a<=n;a++)e[a].color=O.value,e[a].editRange=!0;!0===ie.value.includeFrom&&(e[t].editRangeFrom=!0),!0===ie.value.includeTo&&(e[n].editRangeTo=!0)}T.value.year===C.value.year&&T.value.month===C.value.month&&(e[i+C.value.day-1].today=!0);let o=e.length%7;if(o>0){let t=7-o;for(let n=1;n<=t;n++)e.push({i:n,fill:!0})}return e.forEach(e=>{let t="q-date__calendar-item ";!0===e.fill?t+="q-date__calendar-item--fill":(t+="q-date__calendar-item--"+(!0===e.in?"in":"out"),void 0!==e.range&&(t+=" q-date__range"+(!0===e.rangeTo?"-to":!0===e.rangeFrom?"-from":"")),!0===e.editRange&&(t+=` q-date__edit-range${!0===e.editRangeFrom?"-from":""}${!0===e.editRangeTo?"-to":""}`),(void 0!==e.range||!0===e.editRange)&&(t+=` text-${e.color}`)),e.classes=t}),e}),ce=i(()=>!0===e.disable?{"aria-disabled":"true"}:{});function de(e){s=JSON.stringify(e)}function he(){let{year:e,month:t,day:n}=C.value,a={...T.value,year:e,month:t,day:n},i=ne.value[Er(a)];(void 0===i||!1===i.includes(a.day))&&Pe(a),pe(a.year,a.month)}function pe(e,t){P.value="Calendar",ke(e,t)}function fe(){return"persian"===e.calendar?"YYYY/MM/DD":e.mask}function me(t,n,a){return dr(t,n,a,e.calendar,{hour:0,minute:0,second:0,millisecond:0})}function ge(t,n){let a=!0===Array.isArray(e.modelValue)?e.modelValue:e.modelValue?[e.modelValue]:[];if(0===a.length)return _e();let i=a[a.length-1],o=me(void 0!==i.from?i.from:i,t,n);return null===o.dateHash?_e():o}function _e(){let t,n;if(void 0!==e.defaultYearMonth){let a=e.defaultYearMonth.split("/");t=parseInt(a[0],10),n=parseInt(a[1],10)}else{let e=void 0!==C.value?C.value:g();t=e.year,n=e.month}return{year:t,month:n,day:1,hour:0,minute:0,second:0,millisecond:0,dateHash:t+"/"+et(n)+"/01"}}function ve(e){let t=T.value.year,n=Number(T.value.month)+e;13===n?(n=1,t++):0===n&&(n=12,t--),ke(t,n),!0===q.value&&Se("month")}function be(e){ke(Number(T.value.year)+e,T.value.month),!0===q.value&&Se("year")}function ye(t){ke(t,T.value.month),P.value="Years"===e.defaultView?"Months":"Calendar",!0===q.value&&Se("year")}function we(e){return{year:e.year,month:e.month,day:e.day}}function ke(e,t,n){if(null!==X.value&&e<=X.value.year&&((t=ee.value.year&&((t>ee.value.month||e>ee.value.year)&&(t=ee.value.month),e=ee.value.year),void 0!==n){let{hour:e,minute:t,second:a,millisecond:i,timezoneOffset:o,timeHash:r}=n;Object.assign(T.value,{hour:e,minute:t,second:a,millisecond:i,timezoneOffset:o,timeHash:r})}let a=e+"/"+et(t)+"/01";a!==T.value.dateHash&&(A.value=T.value.dateHash{R.value=e-e%xr-(e<0?xr:0),Object.assign(T.value,{year:e,month:t,day:1,dateHash:a})}))}function xe(t,n,a){let i=null!==t&&1===t.length&&!1===e.multiple?t[0]:t,{reason:o,details:s}=Ce(n,a);de(i),r("update:modelValue",i,o,s)}function Se(t){let n=void 0!==j.value[0]&&null!==j.value[0].dateHash?{...j.value[0]}:{...T.value};d(()=>{n.year=T.value.year,n.month=T.value.month;let a="persian"!==e.calendar?new Date(n.year,n.month,0).getDate():Vo(n.year,n.month);n.day=Math.min(Math.max(1,n.day),a);let i=Te(n),{details:o}=Ce("",n);de(i),r("update:modelValue",i,t,o)})}function Ce(e,t){return void 0!==t.from?{reason:`${e}-range`,details:{...we(t.target),from:we(t.from),to:we(t.to)}}:{reason:`${e}-day`,details:we(t)}}function Te(e,t,n){return void 0!==e.from?{from:$.value(e.from,t,n),to:$.value(e.to,t,n)}:$.value(e,t,n)}function Pe(t){let n;if(!0===e.multiple)if(void 0!==t.from){let e=Jo(t.from),a=Jo(t.to),i=j.value.filter(t=>t.dateHasha),o=B.value.filter(({from:t,to:n})=>n.dateHasha);n=i.concat(o).concat(t).map(e=>Te(e))}else{let e=D.value.slice();e.push(Te(t)),n=e}else n=Te(t);xe(n,"add",t)}function Ee(t){if(!0===e.noUnset)return;let n=null;if(!0===e.multiple&&!0===Array.isArray(e.modelValue)){let a=Te(t);n=void 0!==t.from?e.modelValue.filter(e=>void 0===e.from||e.from!==a.from&&e.to!==a.to):e.modelValue.filter(e=>e!==a),0===n.length&&(n=null)}xe(n,"remove",t)}function Ae(t,n,a){let i=j.value.concat(B.value).map(e=>Te(e,t,n)).filter(e=>void 0!==e.from?null!==e.from.dateHash&&null!==e.to.dateHash:null!==e.dateHash),o=(!0===e.multiple?i:i[0])||null;de(o),r("update:modelValue",o,a)}function Me(){if(!0!==e.minimal)return n("div",{class:"q-date__header "+f.value},[n("div",{class:"relative-position"},[n(S,{name:"q-transition--fade"},()=>n("div",{key:"h-yr-"+G.value,class:"q-date__header-subtitle q-date__header-link "+("Years"===P.value?"q-date__header-link--active":"cursor-pointer"),tabindex:p.value,...h("vY",{onClick(){P.value="Years"},onKeyup(e){13===e.keyCode&&(P.value="Years")}})},[G.value]))]),n("div",{class:"q-date__header-title relative-position flex no-wrap"},[n("div",{class:"relative-position col"},[n(S,{name:"q-transition--fade"},()=>n("div",{key:"h-sub"+U.value,class:"q-date__header-title-label q-date__header-link "+("Calendar"===P.value?"q-date__header-link--active":"cursor-pointer"),tabindex:p.value,...h("vC",{onClick(){P.value="Calendar"},onKeyup(e){13===e.keyCode&&(P.value="Calendar")}})},[U.value]))]),!0===e.todayBtn?n(An,{class:"q-date__header-today self-start",icon:u.iconSet.datetime.today,"aria-label":u.lang.date.today,flat:!0,size:"sm",round:!0,tabindex:p.value,onClick:he}):null])])}function Le({label:e,type:t,key:a,dir:i,goTo:o,boundaries:r,cls:s}){return[n("div",{class:"row items-center q-date__arrow"},[n(An,{round:!0,dense:!0,size:"sm",flat:!0,icon:K.value[0],"aria-label":"Years"===t?u.lang.date.prevYear:u.lang.date.prevMonth,tabindex:p.value,disable:!1===r.prev,...h("go-#"+t,{onClick(){o(-1)}})})]),n("div",{class:"relative-position overflow-hidden flex flex-center"+s},[n(S,{name:"q-transition--jump-"+i},()=>n("div",{key:a},[n(An,{flat:!0,dense:!0,noCaps:!0,label:e,tabindex:p.value,...h("view#"+t,{onClick:()=>{P.value=t}})})]))]),n("div",{class:"row items-center q-date__arrow"},[n(An,{round:!0,dense:!0,size:"sm",flat:!0,icon:K.value[1],"aria-label":"Years"===t?u.lang.date.nextYear:u.lang.date.nextMonth,tabindex:p.value,disable:!1===r.next,...h("go+#"+t,{onClick(){o(1)}})})])]}o(()=>e.modelValue,e=>{if(s===JSON.stringify(e))s=0;else{let e=ge(b.value,y.value);ke(e.year,e.month,e)}}),o(P,()=>{null!==v.value&&!0===l.$el.contains(document.activeElement)&&v.value.focus()}),o(()=>T.value.year+"|"+T.value.month,()=>{r("navigation",{year:T.value.year,month:T.value.month})}),o(w,e=>{Ae(e,y.value,"mask"),b.value=e}),o(x,e=>{Ae(b.value,e,"locale"),y.value=e});let Re={Calendar:()=>[n("div",{key:"calendar-view",class:"q-date__view q-date__calendar"},[n("div",{class:"q-date__navigation row items-center no-wrap"},Le({label:y.value.months[T.value.month-1],type:"Months",key:T.value.month,dir:A.value,goTo:ve,boundaries:te.value.month,cls:" col"}).concat(Le({label:T.value.year,type:"Years",key:T.value.year,dir:M.value,goTo:be,boundaries:te.value.year,cls:""}))),n("div",{class:"q-date__calendar-weekdays row items-center no-wrap"},Q.value.map(e=>n("div",{class:"q-date__calendar-item"},[n("div",e)]))),n("div",{class:"q-date__calendar-days-container relative-position overflow-hidden"},[n(S,{name:"q-transition--slide-"+A.value},()=>n("div",{key:oe.value,class:"q-date__calendar-days fit"},ue.value.map(t=>n("div",{class:t.classes},[!0===t.in?n(An,{class:!0===t.today?"q-date__today":"",dense:!0,flat:t.flat,unelevated:t.unelevated,color:t.color,textColor:t.textColor,label:t.i,tabindex:p.value,...h("day#"+t.i,{onClick:()=>{!function(t){let n={...T.value,day:t};if(!1===e.range)return void function(e,t){(!0===ne.value[t]?.includes(e.day)?Ee:Pe)(e)}(n,oe.value);if(null===z.value){let a=ue.value.find(e=>!0!==e.fill&&e.i===t);if(!0!==e.noUnset&&void 0!==a.range)return void Ee({target:n,from:a.range.from,to:a.range.to});if(!0===a.selected)return void Ee(n);let i=Jo(n);z.value={init:n,initHash:i,final:n,finalHash:i},r("rangeStart",we(n))}else{let e=z.value.initHash,t=Jo(n),a=e<=t?{from:z.value.init,to:n}:{from:n,to:z.value.init};z.value=null,Pe(e===t?n:{target:n,...a}),r("rangeEnd",{from:we(a.from),to:we(a.to)})}}(t.i)},onMouseover:()=>{!function(e){if(null!==z.value){let t={...T.value,day:e};Object.assign(z.value,{final:t,finalHash:Jo(t)})}}(t.i)}})},!1!==t.event?()=>n("div",{class:"q-date__event bg-"+t.event}):null):n("div",""+t.i)]))))])])],Months(){let t=T.value.year===C.value.year,a=e=>null!==X.value&&T.value.year===X.value.year&&X.value.month>e||null!==ee.value&&T.value.year===ee.value.year&&ee.value.month{let o=T.value.month===i+1;return n("div",{class:"q-date__months-item flex flex-center"},[n(An,{class:!0===t&&C.value.month===i+1?"q-date__today":null,flat:!0!==o,label:e,unelevated:o,color:!0===o?O.value:null,textColor:!0===o?I.value:null,tabindex:p.value,disable:a(i+1),...h("month#"+i,{onClick:()=>{!function(e){ke(T.value.year,e),P.value="Calendar",!0===q.value&&Se("month")}(i+1)}})})])});return!0===e.yearsInMonthView&&i.unshift(n("div",{class:"row no-wrap full-width"},[Le({label:T.value.year,type:"Years",key:T.value.year,dir:M.value,goTo:be,boundaries:te.value.year,cls:" col"})])),n("div",{key:"months-view",class:"q-date__view q-date__months flex flex-center"},i)},Years(){let e=R.value,t=e+xr,a=[],i=e=>null!==X.value&&X.value.year>e||null!==ee.value&&ee.value.year{ye(o)}})})]))}return n("div",{class:"q-date__view q-date__years flex flex-center"},[n("div",{class:"col-auto"},[n(An,{round:!0,dense:!0,flat:!0,icon:K.value[0],"aria-label":u.lang.date.prevRangeYears(xr),tabindex:p.value,disable:i(e),...h("y-",{onClick:()=>{R.value-=xr}})})]),n("div",{class:"q-date__years-content col self-stretch row items-center"},a),n("div",{class:"col-auto"},[n(An,{round:!0,dense:!0,flat:!0,icon:K.value[1],"aria-label":u.lang.date.nextRangeYears(xr),tabindex:p.value,disable:i(t),...h("y+",{onClick:()=>{R.value+=xr}})})])])}};return Object.assign(l,{setToday:he,setView:function(e){!0===Cr(e)&&(P.value=e)},offsetCalendar:function(e,t){["month","year"].includes(e)&&("month"===e?ve:be)(!0===t?-1:1)},setCalendarTo:pe,setEditingRange:function(t,n){if(!1===e.range||!t)return void(z.value=null);let a=Object.assign({...T.value},t),i=void 0!==n?Object.assign({...T.value},n):a;z.value={init:a,initHash:Jo(a),final:i,finalHash:Jo(i)},pe(a.year,a.month)}}),()=>{let a=[n("div",{class:"q-date__content col relative-position"},[n(S,{name:"q-transition--fade"},Re[P.value])])],i=dt(t.default);return void 0!==i&&a.push(n("div",{class:"q-date__actions"},i)),void 0!==e.name&&!0!==e.disable&&_(a,"push"),n("div",{class:N.value,...ce.value},[Me(),n("div",{ref:v,class:"q-date__main col column",tabindex:-1},a)])}}});function Mr(e,t,n){let a;function i(){void 0!==a&&(be.remove(a),a=void 0)}return g(()=>{!0===e.value&&i()}),{removeFromHistory:i,addToHistory(){a={condition:()=>!0===n.value,handler:t},be.add(a)}}}var Lr,Rr,zr,Nr,Or,Ir,qr=0,Dr=!1,jr=null;function Br(e){(function(e){if(e.target===document.body||e.target.classList.contains("q-layout__backdrop"))return!0;let t=Y(e),n=e.shiftKey&&!e.deltaX,a=!n&&Math.abs(e.deltaX)<=Math.abs(e.deltaY),i=n||a?e.deltaY:e.deltaX;for(let e=0;e0&&n.scrollTop+n.clientHeight===n.scrollHeight:i<0&&0===n.scrollLeft||i>0&&n.scrollLeft+n.clientWidth===n.scrollWidth}return!0})(e)&&J(e)}function Fr(e){e.target===document&&(document.scrollingElement.scrollTop=document.scrollingElement.scrollTop)}function $r(e){!0!==Dr&&(Dr=!0,requestAnimationFrame(()=>{Dr=!1;let{height:t}=e.target,{clientHeight:n,scrollTop:a}=document.scrollingElement;(void 0===zr||t!==window.innerHeight)&&(zr=n-t,document.scrollingElement.scrollTop=a),a>zr&&(document.scrollingElement.scrollTop-=Math.ceil((a-zr)/8))}))}function Vr(e){let t=document.body,n=void 0!==window.visualViewport;if("add"===e){let{overflowY:e,overflowX:a}=window.getComputedStyle(t);Lr=ca(window),Rr=ua(window),Nr=t.style.left,Or=t.style.top,Ir=window.location.href,t.style.left=`-${Lr}px`,t.style.top=`-${Rr}px`,"hidden"!==a&&("scroll"===a||t.scrollWidth>window.innerWidth)&&t.classList.add("q-body--force-scrollbar-x"),"hidden"!==e&&("scroll"===e||t.scrollHeight>window.innerHeight)&&t.classList.add("q-body--force-scrollbar-y"),t.classList.add("q-body--prevent-scroll"),document.qScrollPrevented=!0,!0===j.is.ios&&(!0===n?(window.scrollTo(0,0),window.visualViewport.addEventListener("resize",$r,H.passiveCapture),window.visualViewport.addEventListener("scroll",$r,H.passiveCapture),window.scrollTo(0,0)):window.addEventListener("scroll",Fr,H.passiveCapture))}!0===j.is.desktop&&!0===j.is.mac&&window[`${e}EventListener`]("wheel",Br,H.notPassive),"remove"===e&&(!0===j.is.ios&&(!0===n?(window.visualViewport.removeEventListener("resize",$r,H.passiveCapture),window.visualViewport.removeEventListener("scroll",$r,H.passiveCapture)):window.removeEventListener("scroll",Fr,H.passiveCapture)),t.classList.remove("q-body--prevent-scroll"),t.classList.remove("q-body--force-scrollbar-x"),t.classList.remove("q-body--force-scrollbar-y"),document.qScrollPrevented=!1,t.style.left=Nr,t.style.top=Or,window.location.href===Ir&&window.scrollTo(Lr,Rr),zr=void 0)}function Ur(e){let t="add";if(!0===e){if(qr++,null!==jr)return clearTimeout(jr),void(jr=null);if(qr>1)return}else{if(0===qr||--qr>0)return;if(t="remove",!0===j.is.ios&&!0===j.is.nativeMobile)return null!==jr&&clearTimeout(jr),void(jr=setTimeout(()=>{Vr(t),jr=null},100))}Vr(t)}function Hr(){let e;return{preventBodyScroll(t){t!==e&&(void 0!==e||!0===t)&&(e=t,Ur(t))}}}var Wr=0,Gr={standard:"fixed-full flex-center",top:"fixed-top justify-center",bottom:"fixed-bottom justify-center",right:"fixed-right items-center",left:"fixed-left items-center"},Kr={standard:["scale","scale"],top:["slide-down","slide-up"],bottom:["slide-up","slide-down"],right:["slide-left","slide-right"],left:["slide-right","slide-left"]},Yr=$({name:"QDialog",inheritAttrs:!1,props:{...In,...ea,transitionShow:String,transitionHide:String,persistent:Boolean,autoClose:Boolean,allowFocusOutside:Boolean,noEscDismiss:Boolean,noBackdropDismiss:Boolean,noRouteDismiss:Boolean,noRefocus:Boolean,noFocus:Boolean,noShake:Boolean,seamless:Boolean,maximized:Boolean,fullWidth:Boolean,fullHeight:Boolean,square:Boolean,backdropFilter:String,position:{type:String,default:"standard",validator:e=>["standard","top","bottom","left","right"].includes(e)}},emits:[...qn,"shake","click","escapeKey"],setup(e,{slots:t,emit:r,attrs:s}){let l,u,c=k(),d=a(null),h=a(!1),p=a(!1),f=null,m=null,_=i(()=>!0!==e.persistent&&!0!==e.noRouteDismiss&&!0!==e.seamless),{preventBodyScroll:v}=Hr(),{registerTimeout:b}=aa(),{registerTick:y,removeTick:w}=na(),{transitionProps:x,transitionStyle:C}=ta(e,()=>Kr[e.position][0],()=>Kr[e.position][1]),T=i(()=>C.value+(void 0!==e.backdropFilter?`;backdrop-filter:${e.backdropFilter};-webkit-backdrop-filter:${e.backdropFilter}`:"")),{showPortal:P,hidePortal:E,portalIsAccessible:A,renderPortal:M}=Xn(c,d,function(){return n("div",{role:"dialog","aria-modal":!0===O.value?"true":"false",...s,class:q.value},[n(S,{name:"q-transition--fade",appear:!0},()=>!0===O.value?n("div",{class:"q-dialog__backdrop fixed-full",style:T.value,"aria-hidden":"true",tabindex:-1,onClick:U}):null),n(S,x.value,()=>!0===h.value?n("div",{ref:d,class:N.value,style:C.value,tabindex:-1,...I.value},dt(t.default)):null)])},"dialog"),{hide:L}=Dn({showing:h,hideOnRouteChange:_,handleShow:function(t){R(),m=!1===e.noRefocus&&null!==document.activeElement?document.activeElement:null,$(e.maximized),P(),p.value=!0,!0!==e.noFocus?(document.activeElement?.blur(),y(D)):w(),b(()=>{if(!0===c.proxy.$q.platform.is.ios){if(!0!==e.seamless&&document.activeElement){let{top:e,bottom:t}=document.activeElement.getBoundingClientRect(),{innerHeight:n}=window,a=void 0!==window.visualViewport?window.visualViewport.height:n;e>0&&t>a/2&&(document.scrollingElement.scrollTop=Math.min(document.scrollingElement.scrollHeight-a,t>=n?1/0:Math.ceil(document.scrollingElement.scrollTop+t-a/2))),document.activeElement.scrollIntoView()}u=!0,d.value.click(),u=!1}P(!0),p.value=!1,r("show",t)},e.transitionDuration)},handleHide:function(t){w(),z(),F(!0),p.value=!0,E(),null!==m&&(((0===t?.type.indexOf("key")?m.closest('[tabindex]:not([tabindex^="-"])'):void 0)||m).focus(),m=null),b(()=>{E(!0),p.value=!1,r("hide",t)},e.transitionDuration)},processOnMount:!0}),{addToHistory:R,removeFromHistory:z}=Mr(h,L,_),N=i(()=>`q-dialog__inner flex no-pointer-events q-dialog__inner--${!0===e.maximized?"maximized":"minimized"} q-dialog__inner--${e.position} ${Gr[e.position]}`+(!0===p.value?" q-dialog__inner--animating":"")+(!0===e.fullWidth?" q-dialog__inner--fullwidth":"")+(!0===e.fullHeight?" q-dialog__inner--fullheight":"")+(!0===e.square?" q-dialog__inner--square":"")),O=i(()=>!0===h.value&&!0!==e.seamless),I=i(()=>!0===e.autoClose?{onClick:V}:{}),q=i(()=>["q-dialog fullscreen no-pointer-events q-dialog--"+(!0===O.value?"modal":"seamless"),s.class]);function D(e){Vn(()=>{let t=d.value;if(null!==t){if(void 0!==e){let n=t.querySelector(e);if(null!==n)return void n.focus({preventScroll:!0})}!0!==t.contains(document.activeElement)&&(t=t.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||t.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||t.querySelector("[autofocus], [data-autofocus]")||t,t.focus({preventScroll:!0}))}})}function j(e){e&&"function"==typeof e.focus?e.focus({preventScroll:!0}):D(),r("shake");let t=d.value;null!==t&&(t.classList.remove("q-animate--scale"),t.classList.add("q-animate--scale"),null!==f&&clearTimeout(f),f=setTimeout(()=>{f=null,null!==d.value&&(t.classList.remove("q-animate--scale"),D())},170))}function B(){!0!==e.seamless&&(!0===e.persistent||!0===e.noEscDismiss?!0!==e.maximized&&!0!==e.noShake&&j():(r("escapeKey"),L()))}function F(t){null!==f&&(clearTimeout(f),f=null),(!0===t||!0===h.value)&&($(!1),!0!==e.seamless&&(v(!1),La(H),Pa(B))),!0!==t&&(m=null)}function $(e){!0===e?!0!==l&&(Wr<1&&document.body.classList.add("q-body--dialog"),Wr++,l=!0):!0===l&&(Wr<2&&document.body.classList.remove("q-body--dialog"),Wr--,l=!1)}function V(e){!0!==u&&(L(e),r("click",e))}function U(t){!0!==e.persistent&&!0!==e.noBackdropDismiss?L(t):!0!==e.noShake&&j()}function H(t){!0!==e.allowFocusOutside&&!0===A.value&&!0!==cn(d.value,t.target)&&D('[tabindex]:not([tabindex="-1"])')}return o(()=>e.maximized,e=>{!0===h.value&&$(e)}),o(O,e=>{v(e),!0===e?(Ma(H),Ta(B)):(La(H),Pa(B))}),Object.assign(c.proxy,{focus:D,shake:j,__updateRefocusTarget(e){m=e||null}}),g(F),M}}),Qr=$({name:"QDrawer",inheritAttrs:!1,props:{...In,...Nt,side:{type:String,default:"left",validator:e=>["left","right"].includes(e)},width:{type:Number,default:300},mini:Boolean,miniToOverlay:Boolean,miniWidth:{type:Number,default:57},noMiniAnimation:Boolean,breakpoint:{type:Number,default:1023},showIfAbove:Boolean,behavior:{type:String,validator:e=>["default","desktop","mobile"].includes(e),default:"default"},bordered:Boolean,elevated:Boolean,overlay:Boolean,persistent:Boolean,noSwipeOpen:Boolean,noSwipeClose:Boolean,noSwipeBackdrop:Boolean},emits:[...qn,"onLayout","miniState"],setup(e,{slots:t,emit:r,attrs:s}){let l=k(),{proxy:{$q:u}}=l,c=Ot(e,u),{preventBodyScroll:h}=Hr(),{registerTimeout:p,removeTimeout:f}=aa(),_=y(Ae,Oe);if(_===Oe)return console.error("QDrawer needs to be child of QLayout"),Oe;let v,b,w=null,x=a("mobile"===e.behavior||"desktop"!==e.behavior&&_.totalWidth.value<=e.breakpoint),S=i(()=>!0===e.mini&&!0!==x.value),C=i(()=>!0===S.value?e.miniWidth:e.width),T=a(!0===e.showIfAbove&&!1===x.value||!0===e.modelValue),P=i(()=>!0!==e.persistent&&(!0===x.value||!0===W.value));function E(e,t){if(z(),!1!==e&&_.animate(),oe(0),!0===x.value){let e=_.instances[$.value];!0===e?.belowBreakpoint&&e.hide(!1),re(1),!0!==_.isContainer.value&&h(!0)}else re(0),!1!==e&&se(!1);p(()=>{!1!==e&&se(!0),!0!==t&&r("show",e)},150)}function M(e,t){N(),!1!==e&&_.animate(),re(0),oe(q.value*C.value),ce(),!0!==t?p(()=>{r("hide",e)},150):f()}let{show:L,hide:R}=Dn({showing:T,hideOnRouteChange:P,handleShow:E,handleHide:M}),{addToHistory:z,removeFromHistory:N}=Mr(T,R,P),O={belowBreakpoint:x,hide:R},I=i(()=>"right"===e.side),q=i(()=>(!0===u.lang.rtl?-1:1)*(!0===I.value?1:-1)),D=a(0),j=a(!1),B=a(!1),F=a(C.value*q.value),$=i(()=>!0===I.value?"left":"right"),V=i(()=>!0===T.value&&!1===x.value&&!1===e.overlay?!0===e.miniToOverlay?e.miniWidth:C.value:0),U=i(()=>!0===e.overlay||!0===e.miniToOverlay||-1!==_.view.value.indexOf(I.value?"R":"L")||!0===u.platform.is.ios&&!0===_.isContainer.value),H=i(()=>!1===e.overlay&&!0===T.value&&!1===x.value),W=i(()=>!0===e.overlay&&!0===T.value&&!1===x.value),G=i(()=>"fullscreen q-drawer__backdrop"+(!1===T.value&&!1===j.value?" hidden":"")),K=i(()=>({backgroundColor:`rgba(0,0,0,${.4*D.value})`})),Y=i(()=>!0===I.value?"r"===_.rows.value.top[2]:"l"===_.rows.value.top[0]),Q=i(()=>!0===I.value?"r"===_.rows.value.bottom[2]:"l"===_.rows.value.bottom[0]),Z=i(()=>{let e={};return!0===_.header.space&&!1===Y.value&&(!0===U.value?e.top=`${_.header.offset}px`:!0===_.header.space&&(e.top=`${_.header.size}px`)),!0===_.footer.space&&!1===Q.value&&(!0===U.value?e.bottom=`${_.footer.offset}px`:!0===_.footer.space&&(e.bottom=`${_.footer.size}px`)),e}),J=i(()=>{let e={width:`${C.value}px`,transform:`translateX(${F.value}px)`};return!0===x.value?e:Object.assign(e,Z.value)}),X=i(()=>"q-drawer__content fit "+(!0!==_.isContainer.value?"scroll":"overflow-auto")),ee=i(()=>`q-drawer q-drawer--${e.side}`+(!0===B.value?" q-drawer--mini-animate":"")+(!0===e.bordered?" q-drawer--bordered":"")+(!0===c.value?" q-drawer--dark q-dark":"")+(!0===j.value?" no-transition":!0===T.value?"":" q-layout--prevent-focus")+(!0===x.value?" fixed q-drawer--on-top q-drawer--mobile q-drawer--top-padding":" q-drawer--"+(!0===S.value?"mini":"standard")+(!0===U.value||!0!==H.value?" fixed":"")+(!0===e.overlay||!0===e.miniToOverlay?" q-drawer--on-top":"")+(!0===Y.value?" q-drawer--top-padding":""))),te=i(()=>{let t=!0===u.lang.rtl?e.side:$.value;return[[Ki,le,void 0,{[t]:!0,mouse:!0}]]}),ne=i(()=>{let t=!0===u.lang.rtl?$.value:e.side;return[[Ki,ue,void 0,{[t]:!0,mouse:!0}]]}),ae=i(()=>{let t=!0===u.lang.rtl?$.value:e.side;return[[Ki,ue,void 0,{[t]:!0,mouse:!0,mouseAllDir:!0}]]});function ie(){var t,n;t=x,n="mobile"===e.behavior||"desktop"!==e.behavior&&_.totalWidth.value<=e.breakpoint,t.value!==n&&(t.value=n)}function oe(e){void 0===e?d(()=>{e=!0===T.value?0:C.value,oe(q.value*e)}):(!0===_.isContainer.value&&!0===I.value&&(!0===x.value||Math.abs(e)===C.value)&&(e+=q.value*_.scrollbarWidth.value),F.value=e)}function re(e){D.value=e}function se(e){let t=!0===e?"remove":!0!==_.isContainer.value?"add":"";""!==t&&document.body.classList[t]("q-body--drawer-toggle")}function le(e){if(!1!==T.value)return;let t=C.value,n=Je(e.distance.x,0,t);if(!0===e.isFinal)return n>=Math.min(75,t)==!0?L():(_.animate(),re(0),oe(q.value*t)),void(j.value=!1);oe((!0===u.lang.rtl?!0!==I.value:I.value)?Math.max(t-n,0):Math.min(0,n-t)),re(Je(n/t,0,1)),!0===e.isFirst&&(j.value=!0)}function ue(t){if(!0!==T.value)return;let n=C.value,a=t.direction===e.side,i=(!0===u.lang.rtl?!0!==a:a)?Je(t.distance.x,0,n):0;if(!0===t.isFinal)return Math.abs(i){!0===t?(v=T.value,!0===T.value&&R(!1)):!1===e.overlay&&"mobile"!==e.behavior&&!1!==v&&(!0===T.value?(oe(0),re(0),ce()):L(!1))}),o(()=>e.side,(e,t)=>{_.instances[t]===O&&(_.instances[t]=void 0,_[t].space=!1,_[t].offset=0),_.instances[e]=O,_[e].size=C.value,_[e].space=H.value,_[e].offset=V.value}),o(_.totalWidth,()=>{(!0===_.isContainer.value||!0!==document.qScrollPrevented)&&ie()}),o(()=>e.behavior+e.breakpoint,ie),o(_.isContainer,e=>{!0===T.value&&h(!0!==e),!0===e&&ie()}),o(_.scrollbarWidth,()=>{oe(!0===T.value?0:void 0)}),o(V,e=>{de("offset",e)}),o(H,e=>{r("onLayout",e),de("space",e)}),o(I,()=>{oe()}),o(C,t=>{oe(),he(e.miniToOverlay,t)}),o(()=>e.miniToOverlay,e=>{he(e,C.value)}),o(()=>u.lang.rtl,()=>{oe()}),o(()=>e.mini,()=>{e.noMiniAnimation||!0===e.modelValue&&(null!==w&&clearTimeout(w),l.proxy&&l.proxy.$el&&l.proxy.$el.classList.add("q-drawer--mini-animate"),B.value=!0,w=setTimeout(()=>{w=null,B.value=!1,l?.proxy?.$el?.classList.remove("q-drawer--mini-animate")},150),_.animate())}),o(S,e=>{r("miniState",e)}),_.instances[e.side]=O,he(e.miniToOverlay,C.value),de("space",H.value),de("offset",V.value),!0===e.showIfAbove&&!0!==e.modelValue&&!0===T.value&&void 0!==e["onUpdate:modelValue"]&&r("update:modelValue",!0),m(()=>{r("onLayout",H.value),r("miniState",S.value),v=!0===e.showIfAbove;let t=()=>{(!0===T.value?E:M)(!1,!0)};0===_.totalWidth.value?b=o(_.totalWidth,()=>{b(),b=void 0,!1===T.value&&!0===e.showIfAbove&&!1===x.value?L(!1):t()}):d(t)}),g(()=>{b?.(),null!==w&&(clearTimeout(w),w=null),!0===T.value&&ce(),_.instances[e.side]===O&&(_.instances[e.side]=void 0,de("size",0),de("offset",0),de("space",!1))}),()=>{let a=[];!0===x.value&&(!1===e.noSwipeOpen&&a.push(A(n("div",{key:"open",class:`q-drawer__opener fixed-${e.side}`,"aria-hidden":"true"}),te.value)),a.push(mt("div",{ref:"backdrop",class:G.value,style:K.value,"aria-hidden":"true",onClick:R},void 0,"backdrop",!0!==e.noSwipeBackdrop&&!0===T.value,()=>ae.value)));let i=!0===S.value&&void 0!==t.mini,o=[n("div",{...s,key:""+i,class:[X.value,s.class]},!0===i?t.mini():dt(t.default))];return!0===e.elevated&&!0===T.value&&o.push(n("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),a.push(mt("aside",{ref:"content",class:ee.value,style:J.value},o,"contentclose",!0!==e.noSwipeClose&&!0===x.value,()=>ne.value)),n("div",{class:"q-drawer-container"},a)}}});function Zr(e,t){if(t&&e===t)return null;let n=e.nodeName.toLowerCase();if(!0===["div","li","ul","ol","blockquote"].includes(n))return e;let a=(window.getComputedStyle?window.getComputedStyle(e):e.currentStyle).display;return"block"===a||"table"===a?e:Zr(e.parentNode)}function Jr(e,t,n){return!(!e||e===document.body)&&(!0===n&&e===t||(t===document?document.body:t).contains(e.parentNode))}function Xr(e,t,n){if(n||((n=document.createRange()).selectNode(e),n.setStart(e,0)),0===t.count)n.setEnd(e,t.count);else if(t.count>0)if(e.nodeType===Node.TEXT_NODE)e.textContent.length0&&this.savedPos\n \n \n Print - ${document.title}\n \n \n
${this.el.innerHTML}
\n \n \n `),e.print(),void e.close()}if("link"===e){let e=this.getParentAttribute("href");if(null===e){let e=this.selectWord(this.selection),t=e?e.toString():"";if(!(t.length||this.range&&this.range.cloneContents().querySelector("img")))return;this.eVm.editLinkUrl.value=es.test(t)?t:"https://",document.execCommand("createLink",!1,this.eVm.editLinkUrl.value),this.save(e.getRangeAt(0))}else this.eVm.editLinkUrl.value=e,this.range.selectNodeContents(this.parent),this.save();return}if("fullscreen"===e)return this.eVm.toggleFullscreen(),void n();if("viewsource"===e)return this.eVm.isViewingSource.value=!1===this.eVm.isViewingSource.value,this.eVm.setContent(this.eVm.props.modelValue),void n()}document.execCommand(e,!1,t),n()}selectWord(e){if(null===e||!0!==e.isCollapsed||void 0===e.modify)return e;let t=document.createRange();t.setStart(e.anchorNode,e.anchorOffset),t.setEnd(e.focusNode,e.focusOffset);let n=t.collapsed?["backward","forward"]:["forward","backward"];t.detach();let a=e.focusNode,i=e.focusOffset;return e.collapse(e.anchorNode,e.anchorOffset),e.modify("move",n[0],"character"),e.modify("move",n[1],"word"),e.extend(a,i),e.modify("extend",n[1],"character"),e.modify("extend",n[0],"word"),e}},ns=$({name:"QTooltip",inheritAttrs:!1,props:{...Rn,...In,...ea,maxHeight:{type:String,default:null},maxWidth:{type:String,default:null},transitionShow:{...ea.transitionShow,default:"jump-down"},transitionHide:{...ea.transitionHide,default:"jump-up"},anchor:{type:String,default:"bottom middle",validator:Ba},self:{type:String,default:"top middle",validator:Ba},offset:{type:Array,default:()=>[14,14],validator:Fa},scrollTarget:oa,delay:{type:Number,default:0},hideDelay:{type:Number,default:0},persistent:Boolean},emits:[...qn],setup(e,{slots:t,emit:r,attrs:s}){let l,u,c=k(),{proxy:{$q:d}}=c,h=a(null),p=a(!1),f=i(()=>Va(e.anchor,d.lang.rtl)),m=i(()=>Va(e.self,d.lang.rtl)),_=i(()=>!0!==e.persistent),{registerTick:v,removeTick:b}=na(),{registerTimeout:y}=aa(),{transitionProps:w,transitionStyle:x}=ta(e),{localScrollTarget:C,changeScrollEvent:T,unconfigureScrollTarget:P}=On(e,D),{anchorEl:E,canShow:A,anchorEvents:M}=Nn({showing:p,configureAnchorEl:function(){if(!0===e.noParentEvent||null===E.value)return;let t=!0===d.platform.is.mobile?[[E.value,"touchstart","delayShow","passive"]]:[[E.value,"mouseenter","delayShow","passive"],[E.value,"mouseleave","delayHide","passive"]];ee(M,"anchor",t)}}),{show:L,hide:R}=Dn({showing:p,canShow:A,handleShow:function(t){z(),v(()=>{u=new MutationObserver(()=>q()),u.observe(h.value,{attributes:!1,childList:!0,characterData:!0,subtree:!0}),q(),D()}),void 0===l&&(l=o(()=>d.screen.width+"|"+d.screen.height+"|"+e.self+"|"+e.anchor+"|"+d.lang.rtl,q)),y(()=>{z(!0),r("show",t)},e.transitionDuration)},handleHide:function(t){b(),N(),I(),y(()=>{N(!0),r("hide",t)},e.transitionDuration)},hideOnRouteChange:_,processOnMount:!0});Object.assign(M,{delayShow:function(t){if(!0===d.platform.is.mobile){Ln(),document.body.classList.add("non-selectable");let e=E.value,t=["touchmove","touchcancel","touchend","click"].map(t=>[e,t,"delayHide","passiveCapture"]);ee(M,"tooltipTemp",t)}y(()=>{L(t)},e.delay)},delayHide:function(t){!0===d.platform.is.mobile&&(te(M,"tooltipTemp"),Ln(),setTimeout(()=>{document.body.classList.remove("non-selectable")},10)),y(()=>{R(t)},e.hideDelay)}});let{showPortal:z,hidePortal:N,renderPortal:O}=Xn(c,h,function(){return n(S,w.value,j)},"tooltip");if(!0===d.platform.is.mobile){let t={anchorEl:E,innerRef:h,onClickOutside:e=>(R(e),e.target.classList.contains("q-dialog__backdrop")&&J(e),!0)},n=i(()=>null===e.modelValue&&!0!==e.persistent&&!0===p.value);o(n,e=>{(!0===e?Da:ja)(t)}),g(()=>{ja(t)})}function I(){void 0!==u&&(u.disconnect(),u=void 0),void 0!==l&&(l(),l=void 0),P(),te(M,"tooltipTemp")}function q(){Ha({targetEl:h.value,offset:e.offset,anchorEl:E.value,anchorOrigin:f.value,selfOrigin:m.value,maxHeight:e.maxHeight,maxWidth:e.maxWidth})}function D(){if(null!==E.value||void 0!==e.scrollTarget){C.value=sa(E.value,e.scrollTarget);let t=!0===e.noParentEvent?q:R;T(C.value,t)}}function j(){return!0===p.value?n("div",{...s,ref:h,class:["q-tooltip q-tooltip--style q-position-engine no-pointer-events",s.class],style:[s.style,x.value],role:"tooltip"},dt(t.default)):null}return g(I),Object.assign(c.proxy,{updatePosition:q}),O}}),as=$({name:"QItem",props:{...Nt,...en,tag:{type:String,default:"div"},active:{type:Boolean,default:null},clickable:Boolean,dense:Boolean,insetLevel:Number,tabindex:[String,Number],focused:Boolean,manualFocus:Boolean},emits:["click","keyup"],setup(e,{slots:t,emit:o}){let{proxy:{$q:r}}=k(),s=Ot(e,r),{hasLink:l,linkAttrs:u,linkClass:c,linkTag:d,navigateOnClick:h}=tn(),p=a(null),f=a(null),m=i(()=>!0===e.clickable||!0===l.value||"label"===e.tag),g=i(()=>!0!==e.disable&&!0===m.value),_=i(()=>"q-item q-item-type row no-wrap"+(!0===e.dense?" q-item--dense":"")+(!0===s.value?" q-item--dark":"")+(!0===l.value&&null===e.active?c.value:!0===e.active?" q-item--active"+(void 0!==e.activeClass?` ${e.activeClass}`:""):"")+(!0===e.disable?" disabled":"")+(!0===g.value?" q-item--clickable q-link cursor-pointer "+(!0===e.manualFocus?"q-manual-focusable":"q-focusable q-hoverable")+(!0===e.focused?" q-manual-focusable--focused":""):"")),v=i(()=>void 0===e.insetLevel?null:{["padding"+(!0===r.lang.rtl?"Right":"Left")]:16+56*e.insetLevel+"px"});function b(e){!0===g.value&&(null!==f.value&&!0!==e.qAvoidFocus&&(!0!==e.qKeyEvent&&document.activeElement===p.value?f.value.focus():document.activeElement===f.value&&p.value.focus()),h(e))}function y(e){if(!0===g.value&&!0===pe(e,[13,32])){J(e),e.qKeyEvent=!0;let t=new MouseEvent("click",e);t.qKeyEvent=!0,p.value.dispatchEvent(t)}o("keyup",e)}return()=>{let a={ref:p,class:_.value,style:v.value,role:"listitem",onClick:b,onKeyup:y};return!0===g.value?(a.tabindex=e.tabindex||"0",Object.assign(a,u.value)):!0===m.value&&(a["aria-disabled"]="true"),n(d.value,a,function(){let e=ht(t.default,[]);return!0===g.value&&e.unshift(n("div",{class:"q-focus-helper",tabindex:-1,ref:f})),e}())}}}),is=$({name:"QItemSection",props:{avatar:Boolean,thumbnail:Boolean,side:Boolean,top:Boolean,noWrap:Boolean},setup(e,{slots:t}){let a=i(()=>"q-item__section column q-item__section--"+(!0===e.avatar||!0===e.side||!0===e.thumbnail?"side":"main")+(!0===e.top?" q-item__section--top justify-start":" justify-center")+(!0===e.avatar?" q-item__section--avatar":"")+(!0===e.thumbnail?" q-item__section--thumbnail":"")+(!0===e.noWrap?" q-item__section--nowrap":""));return()=>n("div",{class:a.value},dt(t.default))}});function os(e,t,n){t.handler?t.handler(e,n,n.caret):n.runCmd(t.cmd,t.param)}function rs(e){return n("div",{class:"q-editor__toolbar-group"},e)}function ss(e,t,a,i=!1){let o=i||"toggle"===t.type&&(t.toggled?t.toggled(e):t.cmd&&e.caret.is(t.cmd,t.param)),r=[];if(e.$q.platform.is.desktop&&(t.tip||t.htmlTip)){let e=t.key?n("div",[n("small",`(CTRL + ${String.fromCharCode(t.key)})`)]):null;r.push(n(ns,{delay:1e3},()=>[n("div",t.htmlTip?{innerHTML:t.htmlTip}:t.tip),e]))}return n(An,{...e.buttonProps.value,icon:null!==t.icon?t.icon:void 0,color:o?t.toggleColor||e.props.toolbarToggleColor:t.color||e.props.toolbarColor,textColor:o&&!e.props.toolbarPush?null:t.textColor||e.props.toolbarTextColor,label:t.label,"aria-label":null==t.label?t.tip:void 0,disable:!!t.disable&&("function"!=typeof t.disable||t.disable(e)),size:"sm",onClick(n){a?.(),os(n,t,e)}},()=>r)}function ls(e){if(e.caret)return e.buttons.value.filter(t=>!e.isViewingSource.value||t.find(e=>"viewsource"===e.cmd)).map(t=>rs(t.map(t=>(!e.isViewingSource.value||"viewsource"===t.cmd)&&("slot"===t.type?dt(e.slots[t.slot]):"dropdown"===t.type?function(e,t){let a,i,o="only-icons"===t.list,r=t.label,s=null!==t.icon?t.icon:void 0;function l(){c.component.proxy.hide()}if(o)i=t.options.map(t=>{let n=void 0===t.type&&e.caret.is(t.cmd,t.param);return n&&(r=t.tip,s=null!==t.icon?t.icon:void 0),ss(e,t,l,n)}),a=e.toolbarBackgroundClass.value,i=[rs(i)];else{let o=void 0!==e.props.toolbarToggleColor?`text-${e.props.toolbarToggleColor}`:null,u=void 0!==e.props.toolbarTextColor?`text-${e.props.toolbarTextColor}`:null,c="no-icons"===t.list;i=t.options.map(t=>{let a=!!t.disable&&t.disable(e),i=void 0===t.type&&e.caret.is(t.cmd,t.param);i&&(r=t.tip,s=null!==t.icon?t.icon:void 0);let d=t.htmlTip;return n(as,{active:i,activeClass:o,clickable:!0,disable:a,dense:!0,onClick(n){l(),!0!==n?.qAvoidFocus&&e.contentRef.value?.focus(),e.caret.restore(),os(n,t,e)}},()=>[!0===c?null:n(is,{class:i?o:u,side:!0},()=>n(Mt,{name:null!==t.icon?t.icon:void 0})),n(is,d?()=>n("div",{class:"text-no-wrap",innerHTML:t.htmlTip}):t.tip?()=>n("div",{class:"text-no-wrap"},t.tip):void 0)])}),a=[e.toolbarBackgroundClass.value,u]}let u=t.highlight&&r!==t.label,c=n(ni,{...e.buttonProps.value,noCaps:!0,noWrap:!0,color:u?e.props.toolbarToggleColor:e.props.toolbarColor,textColor:u&&!e.props.toolbarPush?null:e.props.toolbarTextColor,label:t.fixedLabel?t.label:r,icon:t.fixedIcon?null!==t.icon?t.icon:void 0:s,contentClass:a,onShow:t=>e.emit("dropdownShow",t),onHide:t=>e.emit("dropdownHide",t),onBeforeShow:t=>e.emit("dropdownBeforeShow",t),onBeforeHide:t=>e.emit("dropdownBeforeHide",t)},()=>i);return c}(e,t):ss(e,t)))))}var us=/^on[A-Z]/;function cs(){let{attrs:e,vnode:t}=k(),n={listeners:a({}),attributes:a({})};function i(){let a={},i={};for(let t in e)"class"!==t&&"style"!==t&&!1===us.test(t)&&(a[t]=e[t]);for(let e in t.props)!0===us.test(e)&&(i[e]=t.props[e]);n.attributes.value=a,n.listeners.value=i}return v(i),i(),n}var ds=Object.prototype.toString,hs=Object.prototype.hasOwnProperty,ps=new Set(["Boolean","Number","String","Function","Array","Date","RegExp"].map(e=>"[object "+e+"]"));function fs(e){if(e!==Object(e)||!0===ps.has(ds.call(e))||e.constructor&&!1===hs.call(e,"constructor")&&!1===hs.call(e.constructor.prototype,"isPrototypeOf"))return!1;let t;for(t in e);return void 0===t||hs.call(e,t)}function ms(){let e,t,n,a,i,o,r=arguments[0]||{},s=1,l=!1,u=arguments.length;for("boolean"==typeof r&&(l=r,r=arguments[1]||{},s=2),Object(r)!==r&&"function"!=typeof r&&(r={}),u===s&&(r=this,s--);s0===e.length||e.every(e=>e.length),default:()=>[["left","center","right","justify"],["bold","italic","underline","strike"],["undo","redo"]]},toolbarColor:String,toolbarBg:String,toolbarTextColor:String,toolbarToggleColor:{type:String,default:"primary"},toolbarOutline:Boolean,toolbarPush:Boolean,toolbarRounded:Boolean,paragraphTag:{type:String,validator:e=>["div","p"].includes(e),default:"div"},contentStyle:Object,contentClass:[Object,Array,String],square:Boolean,flat:Boolean,dense:Boolean},emits:[...Ti,"update:modelValue","keydown","click","focus","blur","dropdownShow","dropdownHide","dropdownBeforeShow","dropdownBeforeHide","linkShow","linkHide"],setup(e,{slots:t,emit:r}){let s,l,{proxy:u}=k(),{$q:c}=u,h=Ot(e,c),{inFullscreen:p,toggleFullscreen:f}=Pi(),_=cs(),v=a(null),b=a(null),y=a(null),w=a(!1),x=i(()=>!e.readonly&&!e.disable),S=e.modelValue;document.execCommand("defaultParagraphSeparator",!1,e.paragraphTag),s=window.getComputedStyle(document.body).fontFamily;let C=i(()=>e.toolbarBg?` bg-${e.toolbarBg}`:""),T=i(()=>({type:"a",flat:!0!==e.toolbarOutline&&!0!==e.toolbarPush,noWrap:!0,outline:e.toolbarOutline,push:e.toolbarPush,rounded:e.toolbarRounded,dense:!0,color:e.toolbarColor,disable:!x.value,size:"sm"})),P=i(()=>{let t=c.lang.editor,n=c.iconSet.editor;return{bold:{cmd:"bold",icon:n.bold,tip:t.bold,key:66},italic:{cmd:"italic",icon:n.italic,tip:t.italic,key:73},strike:{cmd:"strikeThrough",icon:n.strikethrough,tip:t.strikethrough,key:83},underline:{cmd:"underline",icon:n.underline,tip:t.underline,key:85},unordered:{cmd:"insertUnorderedList",icon:n.unorderedList,tip:t.unorderedList},ordered:{cmd:"insertOrderedList",icon:n.orderedList,tip:t.orderedList},subscript:{cmd:"subscript",icon:n.subscript,tip:t.subscript,htmlTip:"x2"},superscript:{cmd:"superscript",icon:n.superscript,tip:t.superscript,htmlTip:"x2"},link:{cmd:"link",disable:e=>e.caret&&!e.caret.can("link"),icon:n.hyperlink,tip:t.hyperlink,key:76},fullscreen:{cmd:"fullscreen",icon:n.toggleFullscreen,tip:t.toggleFullscreen,key:70},viewsource:{cmd:"viewsource",icon:n.viewSource,tip:t.viewSource},quote:{cmd:"formatBlock",param:"BLOCKQUOTE",icon:n.quote,tip:t.quote,key:81},left:{cmd:"justifyLeft",icon:n.left,tip:t.left},center:{cmd:"justifyCenter",icon:n.center,tip:t.center},right:{cmd:"justifyRight",icon:n.right,tip:t.right},justify:{cmd:"justifyFull",icon:n.justify,tip:t.justify},print:{type:"no-state",cmd:"print",icon:n.print,tip:t.print,key:80},outdent:{type:"no-state",disable:e=>e.caret&&!e.caret.can("outdent"),cmd:"outdent",icon:n.outdent,tip:t.outdent},indent:{type:"no-state",disable:e=>e.caret&&!e.caret.can("indent"),cmd:"indent",icon:n.indent,tip:t.indent},removeFormat:{type:"no-state",cmd:"removeFormat",icon:n.removeFormat,tip:t.removeFormat},hr:{type:"no-state",cmd:"insertHorizontalRule",icon:n.hr,tip:t.hr},undo:{type:"no-state",cmd:"undo",icon:n.undo,tip:t.undo,key:90},redo:{type:"no-state",cmd:"redo",icon:n.redo,tip:t.redo,key:89},h1:{cmd:"formatBlock",param:"H1",icon:n.heading1||n.heading,tip:t.heading1,htmlTip:`

${t.heading1}

`},h2:{cmd:"formatBlock",param:"H2",icon:n.heading2||n.heading,tip:t.heading2,htmlTip:`

${t.heading2}

`},h3:{cmd:"formatBlock",param:"H3",icon:n.heading3||n.heading,tip:t.heading3,htmlTip:`

${t.heading3}

`},h4:{cmd:"formatBlock",param:"H4",icon:n.heading4||n.heading,tip:t.heading4,htmlTip:`

${t.heading4}

`},h5:{cmd:"formatBlock",param:"H5",icon:n.heading5||n.heading,tip:t.heading5,htmlTip:`
${t.heading5}
`},h6:{cmd:"formatBlock",param:"H6",icon:n.heading6||n.heading,tip:t.heading6,htmlTip:`
${t.heading6}
`},p:{cmd:"formatBlock",param:e.paragraphTag,icon:n.heading,tip:t.paragraph},code:{cmd:"formatBlock",param:"PRE",icon:n.code,htmlTip:`${t.code}`},"size-1":{cmd:"fontSize",param:"1",icon:n.size1||n.size,tip:t.size1,htmlTip:`${t.size1}`},"size-2":{cmd:"fontSize",param:"2",icon:n.size2||n.size,tip:t.size2,htmlTip:`${t.size2}`},"size-3":{cmd:"fontSize",param:"3",icon:n.size3||n.size,tip:t.size3,htmlTip:`${t.size3}`},"size-4":{cmd:"fontSize",param:"4",icon:n.size4||n.size,tip:t.size4,htmlTip:`${t.size4}`},"size-5":{cmd:"fontSize",param:"5",icon:n.size5||n.size,tip:t.size5,htmlTip:`${t.size5}`},"size-6":{cmd:"fontSize",param:"6",icon:n.size6||n.size,tip:t.size6,htmlTip:`${t.size6}`},"size-7":{cmd:"fontSize",param:"7",icon:n.size7||n.size,tip:t.size7,htmlTip:`${t.size7}`}}}),E=i(()=>{let t=e.definitions||{},n=e.definitions||e.fonts?ms(!0,{},P.value,t,function(e,t,n,a={}){let i=Object.keys(a);if(0===i.length)return{};let o={default_font:{cmd:"fontName",param:e,icon:n,tip:t}};return i.forEach(e=>{let t=a[e];o[e]={cmd:"fontName",param:t,icon:n,tip:t,htmlTip:`${t}`}}),o}(s,c.lang.editor.defaultFont,c.iconSet.editor.font,e.fonts)):P.value;return e.toolbar.map(e=>e.map(e=>{if(e.options)return{type:"dropdown",icon:e.icon,label:e.label,size:"sm",dense:!0,fixedLabel:e.fixedLabel,fixedIcon:e.fixedIcon,highlight:e.highlight,list:e.list,options:e.options.map(e=>n[e])};let a=n[e];return a?"no-state"===a.type||t[e]&&(void 0===a.cmd||P.value[a.cmd]&&"no-state"===P.value[a.cmd].type)?a:Object.assign({type:"toggle"},a):{type:"slot",slot:e}}))}),A={$q:c,props:e,slots:t,emit:r,inFullscreen:p,toggleFullscreen:f,runCmd:W,isViewingSource:w,editLinkUrl:y,toolbarBackgroundClass:C,buttonProps:T,contentRef:b,buttons:E,setContent:H};o(()=>e.modelValue,e=>{S!==e&&(S=e,H(e,!0))}),o(y,e=>{r("link"+(e?"Show":"Hide"))});let M=i(()=>e.toolbar&&0!==e.toolbar.length),L=i(()=>{let e={},t=t=>{t.key&&(e[t.key]={cmd:t.cmd,param:t.param})};return E.value.forEach(e=>{e.forEach(e=>{e.options?e.options.forEach(t):t(e)})}),e}),R=i(()=>p.value?e.contentStyle:[{minHeight:e.minHeight,height:e.height,maxHeight:e.maxHeight},e.contentStyle]),z=i(()=>"q-editor q-editor--"+(!0===w.value?"source":"default")+(!0===e.disable?" disabled":"")+(!0===p.value?" fullscreen column":"")+(!0===e.square?" q-editor--square no-border-radius":"")+(!0===e.flat?" q-editor--flat":"")+(!0===e.dense?" q-editor--dense":"")+(!0===h.value?" q-editor--dark q-dark":"")),N=i(()=>[e.contentClass,"q-editor__content",{col:p.value,"overflow-auto":p.value||e.maxHeight}]),O=i(()=>!0===e.disable?{"aria-disabled":"true"}:{});function I(){if(null!==b.value){let t="inner"+(!0===w.value?"Text":"HTML"),n=b.value[t];n!==e.modelValue&&(S=n,r("update:modelValue",n))}}function q(e){if(r("keydown",e),!0!==e.ctrlKey||!0===he(e))return void G();let t=e.keyCode,n=L.value[t];if(void 0!==n){let{cmd:t,param:a}=n;J(e),W(t,a,!1)}}function D(e){G(),r("click",e)}function j(e){if(null!==b.value){let{scrollTop:e,scrollHeight:t}=b.value;l=t-e}A.caret.save(),r("blur",e)}function B(e){d(()=>{null!==b.value&&void 0!==l&&(b.value.scrollTop=b.value.scrollHeight-l)}),r("focus",e)}function F(e){let t=v.value;if(null!==t&&!0===t.contains(e.target)&&(null===e.relatedTarget||!0!==t.contains(e.relatedTarget))){let e="inner"+(!0===w.value?"Text":"HTML");A.caret.restorePosition(b.value[e].length),G()}}function $(e){let t=v.value;null!==t&&!0===t.contains(e.target)&&(null===e.relatedTarget||!0!==t.contains(e.relatedTarget))&&(A.caret.savePosition(),G())}function V(){l=void 0}function U(e){A.caret.save()}function H(e,t){if(null!==b.value){!0===t&&A.caret.savePosition();let n="inner"+(!0===w.value?"Text":"HTML");b.value[n]=e,!0===t&&(A.caret.restorePosition(b.value[n].length),G())}}function W(e,t,n=!0){K(),A.caret.restore(),A.caret.apply(e,t,()=>{K(),A.caret.save(),n&&G()})}function G(){setTimeout(()=>{y.value=null,u.$forceUpdate()},1)}function K(){Vn(()=>{b.value?.focus({preventScroll:!0})})}return m(()=>{A.caret=u.caret=new ts(b.value,A),H(e.modelValue),G(),document.addEventListener("selectionchange",U)}),g(()=>{document.removeEventListener("selectionchange",U)}),Object.assign(u,{runCmd:W,refreshToolbar:G,focus:K,getContentEl:function(){return b.value}}),()=>{let t;if(M.value){let e=[n("div",{key:"qedt_top",class:"q-editor__toolbar row no-wrap scroll-x"+C.value},ls(A))];null!==y.value&&e.push(n("div",{key:"qedt_btm",class:"q-editor__toolbar row no-wrap items-center scroll-x"+C.value},function(e){if(e.caret){let t=e.props.toolbarColor||e.props.toolbarTextColor,a=e.editLinkUrl.value,i=()=>{e.caret.restore(),a!==e.editLinkUrl.value&&document.execCommand("createLink",!1,""===a?" ":a),e.editLinkUrl.value=null};return[n("div",{class:`q-mx-xs text-${t}`},`${e.$q.lang.editor.url}: `),n("input",{key:"qedt_btm_input",class:"col q-editor__link-input",value:a,onInput:e=>{Q(e),a=e.target.value},onKeydown:t=>{if(!0!==he(t))switch(t.keyCode){case 13:return Z(t),i();case 27:Z(t),e.caret.restore(),(!e.editLinkUrl.value||"https://"===e.editLinkUrl.value)&&document.execCommand("unlink"),e.editLinkUrl.value=null}}}),rs([n(An,{key:"qedt_btm_rem",...e.buttonProps.value,label:e.$q.lang.label.remove,noCaps:!0,onClick:()=>{e.caret.restore(),document.execCommand("unlink"),e.editLinkUrl.value=null}}),n(An,{key:"qedt_btm_upd",...e.buttonProps.value,label:e.$q.lang.label.update,noCaps:!0,onClick:i})])]}}(A))),t=n("div",{key:"toolbar_ctainer",class:"q-editor__toolbars-container"},e)}return n("div",{ref:v,class:z.value,style:{height:!0===p.value?"100%":null},...O.value,onFocusin:F,onFocusout:$},[t,n("div",{ref:b,style:R.value,class:N.value,contenteditable:x.value,placeholder:e.placeholder,..._.listeners.value,onInput:I,onKeydown:q,onClick:D,onBlur:j,onFocus:B,onMousedown:V,onTouchstartPassive:V})])}}}),_s=$({name:"QItemLabel",props:{overline:Boolean,caption:Boolean,header:Boolean,lines:[Number,String]},setup(e,{slots:t}){let a=i(()=>parseInt(e.lines,10)),o=i(()=>"q-item__label"+(!0===e.overline?" q-item__label--overline text-overline":"")+(!0===e.caption?" q-item__label--caption text-caption":"")+(!0===e.header?" q-item__label--header":"")+(1===a.value?" ellipsis":"")),r=i(()=>void 0!==e.lines&&a.value>1?{overflow:"hidden",display:"-webkit-box","-webkit-box-orient":"vertical","-webkit-line-clamp":a.value}:null);return()=>n("div",{style:r.value,class:o.value},dt(t.default))}}),vs=$({name:"QSlideTransition",props:{appear:Boolean,duration:{type:Number,default:300}},emits:["show","hide"],setup(e,{slots:t,emit:a}){let i,o,r,s,l=!1,u=null,c=null;function d(){i?.(),i=null,l=!1,null!==u&&(clearTimeout(u),u=null),null!==c&&(clearTimeout(c),c=null),o?.removeEventListener("transitionend",r),r=null}function h(t,n,a){void 0!==n&&(t.style.height=`${n}px`),t.style.transition=`height ${e.duration}ms cubic-bezier(.25, .8, .50, 1)`,l=!0,i=a}function p(e,t){e.style.overflowY=null,e.style.height=null,e.style.transition=null,d(),t!==s&&a(t)}function f(t,n){let a=0;o=t,!0===l?(d(),a=t.offsetHeight===t.scrollHeight?0:void 0):(s="hide",t.style.overflowY="hidden"),h(t,a,n),u=setTimeout(()=>{u=null,t.style.height=`${t.scrollHeight}px`,r=e=>{c=null,(Object(e)!==e||e.target===t)&&p(t,"show")},t.addEventListener("transitionend",r),c=setTimeout(r,1.1*e.duration)},100)}function m(t,n){let a;o=t,!0===l?d():(s="show",t.style.overflowY="hidden",a=t.scrollHeight),h(t,a,n),u=setTimeout(()=>{u=null,t.style.height=0,r=e=>{c=null,(Object(e)!==e||e.target===t)&&p(t,"hide")},t.addEventListener("transitionend",r),c=setTimeout(r,1.1*e.duration)},100)}return g(()=>{!0===l&&d()}),()=>n(S,{css:!1,appear:e.appear,onEnter:f,onLeave:m},t.default)}}),bs={true:"inset",item:"item-inset","item-thumbnail":"item-thumbnail-inset"},ys={xs:2,sm:4,md:8,lg:16,xl:24},ws=$({name:"QSeparator",props:{...Nt,spaced:[Boolean,String],inset:[Boolean,String],vertical:Boolean,color:String,size:String},setup(e){let t=k(),a=Ot(e,t.proxy.$q),o=i(()=>!0===e.vertical?"vertical":"horizontal"),r=i(()=>` q-separator--${o.value}`),s=i(()=>!1!==e.inset?`${r.value}-${bs[e.inset]}`:""),l=i(()=>`q-separator${r.value}${s.value}`+(void 0!==e.color?` bg-${e.color}`:"")+(!0===a.value?" q-separator--dark":"")),u=i(()=>{let t={};if(void 0!==e.size&&(t[!0===e.vertical?"width":"height"]=e.size),!1!==e.spaced){let n=!0===e.spaced?`${ys.md}px`:e.spaced in ys?`${ys[e.spaced]}px`:e.spaced,a=!0===e.vertical?["Left","Right"]:["Top","Bottom"];t[`margin${a[0]}`]=t[`margin${a[1]}`]=n}return t});return()=>n("hr",{class:l.value,style:u.value,"aria-orientation":o.value})}}),ks=c({}),xs=Object.keys(en),Ss=$({name:"QExpansionItem",props:{...en,...In,...Nt,icon:String,label:String,labelLines:[Number,String],caption:String,captionLines:[Number,String],dense:Boolean,toggleAriaLabel:String,expandIcon:String,expandedIcon:String,expandIconClass:[Array,String,Object],duration:{},headerInsetLevel:Number,contentInsetLevel:Number,expandSeparator:Boolean,defaultOpened:Boolean,hideExpandIcon:Boolean,expandIconToggle:Boolean,switchToggleSide:Boolean,denseToggle:Boolean,group:String,popup:Boolean,headerStyle:[Array,String,Object],headerClass:[Array,String,Object]},emits:[...qn,"click","afterShow","afterHide"],setup(e,{slots:t,emit:r}){let s,l,{proxy:{$q:u}}=k(),c=Ot(e,u),d=a(null!==e.modelValue?e.modelValue:e.defaultOpened),h=a(null),p=ei(),{show:f,hide:m,toggle:_}=Dn({showing:d}),v=i(()=>`q-expansion-item q-item-type q-expansion-item--${!0===d.value?"expanded":"collapsed"} q-expansion-item--${!0===e.popup?"popup":"standard"}`),b=i(()=>void 0===e.contentInsetLevel?null:{["padding"+(!0===u.lang.rtl?"Right":"Left")]:56*e.contentInsetLevel+"px"}),y=i(()=>!0!==e.disable&&(void 0!==e.href||void 0!==e.to&&null!==e.to&&""!==e.to)),w=i(()=>{let t={};return xs.forEach(n=>{t[n]=e[n]}),t}),x=i(()=>!0===y.value||!0!==e.expandIconToggle),S=i(()=>void 0!==e.expandedIcon&&!0===d.value?e.expandedIcon:e.expandIcon||u.iconSet.expansionItem[!0===e.denseToggle?"denseIcon":"icon"]),C=i(()=>!0!==e.disable&&(!0===y.value||!0===e.expandIconToggle)),T=i(()=>({expanded:!0===d.value,detailsId:p.value,toggle:_,show:f,hide:m})),P=i(()=>{let t=void 0!==e.toggleAriaLabel?e.toggleAriaLabel:u.lang.label[!0===d.value?"collapse":"expand"](e.label);return{role:"button","aria-expanded":!0===d.value?"true":"false","aria-controls":p.value,"aria-label":t}});function E(e){!0!==y.value&&_(e),r("click",e)}function L(e){13===e.keyCode&&R(e,!0)}function R(e,t){!0!==t&&!0!==e.qAvoidFocus&&h.value?.focus(),_(e),J(e)}function z(){r("afterShow")}function N(){r("afterHide")}function O(){void 0===s&&(s=Ja()),!0===d.value&&(ks[e.group]=s);let t=o(d,t=>{!0===t?ks[e.group]=s:ks[e.group]===s&&delete ks[e.group]}),n=o(()=>ks[e.group],(e,t)=>{t===s&&void 0!==e&&e!==s&&m()});l=()=>{t(),n(),ks[e.group]===s&&delete ks[e.group],l=void 0}}function I(){let a;return void 0!==t.header?a=[].concat(t.header(T.value)):(a=[n(is,()=>[n(_s,{lines:e.labelLines},()=>e.label||""),e.caption?n(_s,{lines:e.captionLines,caption:!0},()=>e.caption):null])],e.icon&&a[!0===e.switchToggleSide?"push":"unshift"](n(is,{side:!0===e.switchToggleSide,avatar:!0!==e.switchToggleSide},()=>n(Mt,{name:e.icon})))),!0!==e.disable&&!0!==e.hideExpandIcon&&a[!0===e.switchToggleSide?"unshift":"push"](function(){let t={class:["q-focusable relative-position cursor-pointer"+(!0===e.denseToggle&&!0===e.switchToggleSide?" items-end":""),e.expandIconClass],side:!0!==e.switchToggleSide,avatar:e.switchToggleSide},a=[n(Mt,{class:"q-expansion-item__toggle-icon"+(void 0===e.expandedIcon&&!0===d.value?" q-expansion-item__toggle-icon--rotated":""),name:S.value})];return!0===C.value&&(Object.assign(t,{tabindex:0,...P.value,onClick:R,onKeyup:L}),a.unshift(n("div",{ref:h,class:"q-expansion-item__toggle-focus q-icon q-focus-helper q-focus-helper--rounded",tabindex:-1}))),n(is,t,()=>a)}()),a}function q(){let t={ref:"item",style:e.headerStyle,class:e.headerClass,dark:c.value,disable:e.disable,dense:e.dense,insetLevel:e.headerInsetLevel};return!0===x.value&&(t.clickable=!0,t.onClick=E,Object.assign(t,!0===y.value?w.value:P.value)),n(as,t,I)}function D(){return A(n("div",{key:"e-content",class:"q-expansion-item__content relative-position",style:b.value,id:p.value},dt(t.default)),[[M,d.value]])}function j(){let t=[q(),n(vs,{duration:e.duration,onShow:z,onHide:N},D)];return!0===e.expandSeparator&&t.push(n(ws,{class:"q-expansion-item__border q-expansion-item__border--top absolute-top",dark:c.value}),n(ws,{class:"q-expansion-item__border q-expansion-item__border--bottom absolute-bottom",dark:c.value})),t}return o(()=>e.group,e=>{l?.(),void 0!==e&&O()}),void 0!==e.group&&O(),g(()=>{l?.()}),()=>n("div",{class:v.value},[n("div",{class:"q-expansion-item__container relative-position"},j())])}}),Cs=["top","right","bottom","left"],Ts={type:{type:String,default:"a"},outline:Boolean,push:Boolean,flat:Boolean,unelevated:Boolean,color:String,textColor:String,glossy:Boolean,square:Boolean,padding:String,label:{type:[String,Number],default:""},labelPosition:{type:String,default:"right",validator:e=>Cs.includes(e)},externalLabel:Boolean,hideLabel:{type:Boolean},labelClass:[Array,String,Object],labelStyle:[Array,String,Object],disable:Boolean,tabindex:[Number,String]};function Ps(e,t){return{formClass:i(()=>"q-fab--form-"+(!0===e.square?"square":"rounded")),stacked:i(()=>!1===e.externalLabel&&["top","bottom"].includes(e.labelPosition)),labelProps:i(()=>{if(!0===e.externalLabel){let n=null===e.hideLabel?!1===t.value:e.hideLabel;return{action:"push",data:{class:[e.labelClass,`q-fab__label q-tooltip--style q-fab__label--external q-fab__label--external-${e.labelPosition}`+(!0===n?" q-fab__label--external-hidden":"")],style:e.labelStyle}}}return{action:["left","top"].includes(e.labelPosition)?"unshift":"push",data:{class:[e.labelClass,`q-fab__label q-fab__label--internal q-fab__label--internal-${e.labelPosition}`+(!0===e.hideLabel?" q-fab__label--internal-hidden":"")],style:e.labelStyle}}})}}var Es=["up","right","down","left"],As=["left","center","right"],Ms=$({name:"QFab",props:{...Ts,...In,icon:String,activeIcon:String,hideIcon:Boolean,hideLabel:{...Ts.hideLabel,default:null},direction:{type:String,default:"right",validator:e=>Es.includes(e)},persistent:Boolean,verticalActionsAlign:{type:String,default:"center",validator:e=>As.includes(e)}},emits:qn,setup(e,{slots:t}){let o=a(null),r=a(!0===e.modelValue),s=ei(),{proxy:{$q:l}}=k(),{formClass:u,labelProps:c}=Ps(e,r),d=i(()=>!0!==e.persistent),{hide:h,toggle:p}=Dn({showing:r,hideOnRouteChange:d}),f=i(()=>({opened:r.value})),m=i(()=>`q-fab z-fab row inline justify-center q-fab--align-${e.verticalActionsAlign} ${u.value}`+(!0===r.value?" q-fab--opened":" q-fab--closed")),g=i(()=>`q-fab__actions flex no-wrap inline q-fab__actions--${e.direction} q-fab__actions--${!0===r.value?"opened":"closed"}`),_=i(()=>{let e={id:s.value,role:"menu"};return!0!==r.value&&(e["aria-hidden"]="true"),e}),v=i(()=>"q-fab__icon-holder q-fab__icon-holder--"+(!0===r.value?"opened":"closed"));function b(a,i){let o=t[a],r=`q-fab__${a} absolute-full`;return void 0===o?n(Mt,{class:r,name:e[i]||l.iconSet.fab[i]}):n("div",{class:r},o(f.value))}function y(){let a=[];return!0!==e.hideIcon&&a.push(n("div",{class:v.value},[b("icon","icon"),b("active-icon","activeIcon")])),(""!==e.label||void 0!==t.label)&&a[c.value.action](n("div",c.value.data,void 0!==t.label?t.label(f.value):[e.label])),pt(t.tooltip,a)}return w(Le,{showing:r,onChildClick(e){h(e),!0!==e?.qAvoidFocus&&o.value?.$el.focus()}}),()=>n("div",{class:m.value},[n(An,{ref:o,class:u.value,...e,noWrap:!0,stack:e.stacked,align:void 0,icon:void 0,label:void 0,noCaps:!0,fab:!0,"aria-expanded":!0===r.value?"true":"false","aria-haspopup":"true","aria-controls":s.value,onClick:p},y),n("div",{class:g.value,..._.value},dt(t.default))])}}),Ls={start:"self-end",center:"self-center",end:"self-start"},Rs=Object.keys(Ls),zs=$({name:"QFabAction",props:{...Ts,icon:{type:String,default:""},anchor:{type:String,validator:e=>Rs.includes(e)},to:[String,Object],replace:Boolean},emits:["click"],setup(e,{slots:t,emit:a}){let o=y(Le,()=>({showing:{value:!0},onChildClick:W})),{formClass:r,labelProps:s}=Ps(e,o.showing),l=i(()=>{let t=Ls[e.anchor];return r.value+(void 0!==t?` ${t}`:"")}),u=i(()=>!0===e.disable||!0!==o.showing.value);function c(e){o.onChildClick(e),a("click",e)}function d(){let a=[];return void 0!==t.icon?a.push(t.icon()):""!==e.icon&&a.push(n(Mt,{name:e.icon})),(""!==e.label||void 0!==t.label)&&a[s.value.action](n("div",s.value.data,void 0!==t.label?t.label():[e.label])),pt(t.default,a)}let h=k();return Object.assign(h.proxy,{click:c}),()=>n(An,{class:l.value,...e,noWrap:!0,stack:e.stacked,icon:void 0,label:void 0,noCaps:!0,fabMini:!0,disable:u.value,onClick:c},d)}});function Ns({validate:e,resetValidation:t,requiresQForm:n}){let a=y(Re,!1);if(!1!==a){let{props:n,proxy:i}=k();Object.assign(i,{validate:e,resetValidation:t}),o(()=>n.disable,e=>{!0===e?("function"==typeof t&&t(),a.unbindComponent(i)):a.bindComponent(i)}),m(()=>{!0!==n.disable&&a.bindComponent(i)}),g(()=>{!0!==n.disable&&a.unbindComponent(i)})}else!0===n&&console.error("Parent QForm not found on useFormChild()!")}var Os=[!0,!1,"ondemand"],Is={modelValue:{},error:{type:Boolean,default:null},errorMessage:String,noErrorIcon:Boolean,rules:Array,reactiveRules:Boolean,lazyRules:{type:[Boolean,String],default:!1,validator:e=>Os.includes(e)}};function qs(e){return null!=e&&0!==(""+e).length}var Ds={...Nt,...Is,label:String,stackLabel:Boolean,hint:String,hideHint:Boolean,prefix:String,suffix:String,labelColor:String,color:String,bgColor:String,filled:Boolean,outlined:Boolean,borderless:Boolean,standout:[Boolean,String],square:Boolean,loading:Boolean,labelSlot:Boolean,bottomSlots:Boolean,hideBottomSpace:Boolean,rounded:Boolean,dense:Boolean,itemAligned:Boolean,counter:Boolean,clearable:Boolean,clearIcon:String,disable:Boolean,readonly:Boolean,autofocus:Boolean,for:String},js={...Ds,maxlength:[Number,String]},Bs=["update:modelValue","clear","focus","blur"];function Fs({requiredForAttr:e=!0,tagProp:t,changeEvent:n=!1}={}){let{props:o,proxy:r}=k(),s=Ot(o,r.$q),l=ei({required:e,getValue:()=>o.for});return{requiredForAttr:e,changeEvent:n,tag:!0===t?i(()=>o.tag):{value:"label"},isDark:s,editable:i(()=>!0!==o.disable&&!0!==o.readonly),innerLoading:a(!1),focused:a(!1),hasPopupOpen:!1,splitAttrs:cs(),targetUid:l,rootRef:a(null),targetRef:a(null),controlRef:a(null)}}function $s(e){let{props:t,emit:r,slots:s,attrs:l,proxy:u}=k(),{$q:c}=u,f=null;void 0===e.hasValue&&(e.hasValue=i(()=>qs(t.modelValue))),void 0===e.emitValue&&(e.emitValue=e=>{r("update:modelValue",e)}),void 0===e.controlEvents&&(e.controlEvents={onFocusin:I,onFocusout:q}),Object.assign(e,{clearValue:D,onControlFocusin:I,onControlFocusout:q,focus:O}),void 0===e.computedCounter&&(e.computedCounter=i(()=>{if(!1!==t.counter){let e="string"==typeof t.modelValue||"number"==typeof t.modelValue?(""+t.modelValue).length:!0===Array.isArray(t.modelValue)?t.modelValue.length:0,n=void 0!==t.maxlength?t.maxlength:t.maxValues;return e+(void 0!==n?" / "+n:"")}}));let{isDirtyModel:_,hasRules:v,hasError:b,errorMessage:y,resetValidation:w}=function(e,t){let{props:n,proxy:r}=k(),s=a(!1),l=a(null),u=a(!1);Ns({validate:b,resetValidation:v});let c,d=0,h=i(()=>void 0!==n.rules&&null!==n.rules&&0!==n.rules.length),p=i(()=>!0!==n.disable&&!0===h.value&&!1===t.value),f=i(()=>!0===n.error||!0===s.value),m=i(()=>"string"==typeof n.errorMessage&&0!==n.errorMessage.length?n.errorMessage:l.value);function _(){"ondemand"!==n.lazyRules&&!0===p.value&&!0===u.value&&y()}function v(){d++,t.value=!1,u.value=!1,s.value=!1,l.value=null,y.cancel()}function b(e=n.modelValue){if(!0===n.disable||!1===h.value)return!0;let a=++d,i=!0!==t.value?()=>{u.value=!0}:()=>{},o=(e,n)=>{!0===e&&i(),s.value=e,l.value=n||null,t.value=!1},r=[];for(let t=0;t{if(void 0===e||!1===Array.isArray(e)||0===e.length)return a===d&&o(!1),!0;let t=e.find(e=>!1===e||"string"==typeof e);return a===d&&o(void 0!==t,t),void 0===t},e=>(a===d&&(console.error(e),o(!0)),!1)))}o(()=>n.modelValue,()=>{u.value=!0,!0===p.value&&!1===n.lazyRules&&y()}),o(()=>n.reactiveRules,e=>{!0===e?void 0===c&&(c=o(()=>n.rules,_,{immediate:!0,deep:!0})):void 0!==c&&(c(),c=void 0)},{immediate:!0}),o(()=>n.lazyRules,_),o(e,e=>{!0===e?u.value=!0:!0===p.value&&"ondemand"!==n.lazyRules&&y()});let y=ae(b,0);return g(()=>{c?.(),y.cancel()}),Object.assign(r,{resetValidation:v,validate:b}),z(r,"hasError",()=>f.value),{isDirtyModel:u,hasRules:h,hasError:f,errorMessage:m,validate:b,resetValidation:v}}(e.focused,e.innerLoading),x=void 0!==e.floatingLabel?i(()=>!0===t.stackLabel||!0===e.focused.value||!0===e.floatingLabel.value):i(()=>!0===t.stackLabel||!0===e.focused.value||!0===e.hasValue.value),C=i(()=>!0===t.bottomSlots||void 0!==t.hint||!0===v.value||!0===t.counter||null!==t.error),T=i(()=>!0===t.filled?"filled":!0===t.outlined?"outlined":!0===t.borderless?"borderless":t.standout?"standout":"standard"),P=i(()=>`q-field row no-wrap items-start q-field--${T.value}`+(void 0!==e.fieldClass?` ${e.fieldClass.value}`:"")+(!0===t.rounded?" q-field--rounded":"")+(!0===t.square?" q-field--square":"")+(!0===x.value?" q-field--float":"")+(!0===A.value?" q-field--labeled":"")+(!0===t.dense?" q-field--dense":"")+(!0===t.itemAligned?" q-field--item-aligned q-item-type":"")+(!0===e.isDark.value?" q-field--dark":"")+(void 0===e.getControl?" q-field--auto-height":"")+(!0===e.focused.value?" q-field--focused":"")+(!0===b.value?" q-field--error":"")+(!0===b.value||!0===e.focused.value?" q-field--highlighted":"")+(!0!==t.hideBottomSpace&&!0===C.value?" q-field--with-bottom":"")+(!0===t.disable?" q-field--disabled":!0===t.readonly?" q-field--readonly":"")),E=i(()=>"q-field__control relative-position row no-wrap"+(void 0!==t.bgColor?` bg-${t.bgColor}`:"")+(!0===b.value?" text-negative":"string"==typeof t.standout&&0!==t.standout.length&&!0===e.focused.value?` ${t.standout}`:void 0!==t.color?` text-${t.color}`:"")),A=i(()=>!0===t.labelSlot||void 0!==t.label),M=i(()=>"q-field__label no-pointer-events absolute ellipsis"+(void 0!==t.labelColor&&!0!==b.value?` text-${t.labelColor}`:"")),L=i(()=>({id:e.targetUid.value,editable:e.editable.value,focused:e.focused.value,floatingLabel:x.value,modelValue:t.modelValue,emitValue:e.emitValue})),R=i(()=>{let n={};return e.targetUid.value&&(n.for=e.targetUid.value),!0===t.disable&&(n["aria-disabled"]="true"),n});function N(){let t=document.activeElement,n=e.targetRef?.value;n&&(null===t||t.id!==e.targetUid.value)&&(!0===n.hasAttribute("tabindex")||(n=n.querySelector("[tabindex]")),n!==t&&n?.focus({preventScroll:!0}))}function O(){Vn(N)}function I(t){null!==f&&(clearTimeout(f),f=null),!0===e.editable.value&&!1===e.focused.value&&(e.focused.value=!0,r("focus",t))}function q(t,n){null!==f&&clearTimeout(f),f=setTimeout(()=>{f=null,(!0!==document.hasFocus()||!0!==e.hasPopupOpen&&void 0!==e.controlRef&&null!==e.controlRef.value&&!1===e.controlRef.value.contains(document.activeElement))&&(!0===e.focused.value&&(e.focused.value=!1,r("blur",t)),n?.())})}function D(n){J(n),!0!==c.platform.is.mobile?(e.targetRef?.value||e.rootRef.value).focus():!0===e.rootRef.value.contains(document.activeElement)&&document.activeElement.blur(),"file"===t.type&&(e.inputRef.value.value=null),r("update:modelValue",null),!0===e.changeEvent&&r("change",null),r("clear",t.modelValue),d(()=>{let e=_.value;w(),_.value=e})}function j(e){[13,32].includes(e.keyCode)&&D(e)}function B(){let a=[];return void 0!==s.prepend&&a.push(n("div",{class:"q-field__prepend q-field__marginal row no-wrap items-center",key:"prepend",onClick:Z},s.prepend())),a.push(n("div",{class:"q-field__control-container col relative-position row no-wrap q-anchor--skip"},function(){let a=[];return void 0!==t.prefix&&null!==t.prefix&&a.push(n("div",{class:"q-field__prefix no-pointer-events row items-center"},t.prefix)),void 0!==e.getShadowControl&&!0===e.hasShadow.value&&a.push(e.getShadowControl()),!0===A.value&&a.push(n("div",{class:M.value},dt(s.label,t.label))),void 0!==e.getControl?a.push(e.getControl()):void 0!==s.rawControl?a.push(s.rawControl()):void 0!==s.control&&a.push(n("div",{ref:e.targetRef,class:"q-field__native row",tabindex:-1,...e.splitAttrs.attributes.value,"data-autofocus":!0===t.autofocus||void 0},s.control(L.value))),void 0!==t.suffix&&null!==t.suffix&&a.push(n("div",{class:"q-field__suffix no-pointer-events row items-center"},t.suffix)),a.concat(dt(s.default))}())),!0===b.value&&!1===t.noErrorIcon&&a.push($("error",[n(Mt,{name:c.iconSet.field.error,color:"negative"})])),!0===t.loading||!0===e.innerLoading.value?a.push($("inner-loading-append",void 0!==s.loading?s.loading():[n(rn,{color:t.color})])):!0===t.clearable&&!0===e.hasValue.value&&!0===e.editable.value&&a.push($("inner-clearable-append",[n(Mt,{class:"q-field__focusable-action",name:t.clearIcon||c.iconSet.field.clear,tabindex:0,role:"button","aria-hidden":"false","aria-label":c.lang.label.clear,onKeyup:j,onClick:D})])),void 0!==s.append&&a.push(n("div",{class:"q-field__append q-field__marginal row no-wrap items-center",key:"append",onClick:Z},s.append())),void 0!==e.getInnerAppend&&a.push($("inner-append",e.getInnerAppend())),void 0!==e.getControlChild&&a.push(e.getControlChild()),a}function F(){let a,i;!0===b.value?null!==y.value?(a=[n("div",{role:"alert"},y.value)],i=`q--slot-error-${y.value}`):(a=dt(s.error),i="q--slot-error"):(!0!==t.hideHint||!0===e.focused.value)&&(void 0!==t.hint?(a=[n("div",t.hint)],i=`q--slot-hint-${t.hint}`):(a=dt(s.hint),i="q--slot-hint"));let o=!0===t.counter||void 0!==s.counter;if(!0===t.hideBottomSpace&&!1===o&&void 0===a)return;let r=n("div",{key:i,class:"q-field__messages col"},a);return n("div",{class:"q-field__bottom row items-start q-field__bottom--"+(!0!==t.hideBottomSpace?"animated":"stale"),onClick:Z},[!0===t.hideBottomSpace?r:n(S,{name:"q-transition--field-message"},()=>r),!0===o?n("div",{class:"q-field__counter"},void 0!==s.counter?s.counter():e.computedCounter.value):null])}function $(e,t){return null===t?null:n("div",{key:e,class:"q-field__append q-field__marginal row no-wrap items-center q-anchor--skip"},t)}let V=!1;return p(()=>{V=!0}),h(()=>{!0===V&&!0===t.autofocus&&u.focus()}),!0===t.autofocus&&m(()=>{u.focus()}),g(()=>{null!==f&&clearTimeout(f)}),Object.assign(u,{focus:O,blur:function(){!function(e){jn=jn.filter(t=>t!==e)}(N);let t=document.activeElement;null!==t&&e.rootRef.value.contains(t)&&t.blur()}}),function(){let a=void 0===e.getControl&&void 0===s.control?{...e.splitAttrs.attributes.value,"data-autofocus":!0===t.autofocus||void 0,...R.value}:R.value;return n(e.tag.value,{ref:e.rootRef,class:[P.value,l.class],style:l.style,...a},[void 0!==s.before?n("div",{class:"q-field__before q-field__marginal row no-wrap items-center",onClick:Z},s.before()):null,n("div",{class:"q-field__inner relative-position col self-stretch"},[n("div",{ref:e.controlRef,class:E.value,tabindex:-1,...e.controlEvents},B()),!0===C.value?F():null]),void 0!==s.after?n("div",{class:"q-field__after q-field__marginal row no-wrap items-center",onClick:Z},s.after()):null])}}var Vs=$({name:"QField",inheritAttrs:!1,props:{...js,tag:{type:String,default:"label"}},emits:Bs,setup:()=>$s(Fs({tagProp:!0}))});function Us(e,t,n,a){let i=[];return e.forEach(e=>{!0===a(e)?i.push(e):t.push({failedPropValidation:n,file:e})}),i}function Hs(e){e?.dataTransfer&&(e.dataTransfer.dropEffect="copy"),J(e)}var Ws={multiple:Boolean,accept:String,capture:String,maxFileSize:[Number,String],maxTotalSize:[Number,String],maxFiles:[Number,String],filter:Function},Gs=["rejected"];function Ks({editable:e,dnd:t,getFileInput:o,addFilesToQueue:r}){let{props:s,emit:l,proxy:u}=k(),c=a(null),d=i(()=>void 0!==s.accept?s.accept.split(",").map(e=>"*"===(e=e.trim())?"*/":(e.endsWith("/*")&&(e=e.slice(0,e.length-1)),e.toUpperCase())):null),h=i(()=>parseInt(s.maxFiles,10)),p=i(()=>parseInt(s.maxTotalSize,10));function f(t){if(e.value)if(t!==Object(t)&&(t={target:null}),!0===t.target?.matches('input[type="file"]'))0===t.clientX&&0===t.clientY&&Q(t);else{let e=o();e!==t.target&&e?.click(t)}}function m(t){e.value&&t&&r(null,t)}function g(e){J(e),!0==(null!==e.relatedTarget||!0!==j.is.safari?e.relatedTarget!==c.value:!1===document.elementsFromPoint(e.clientX,e.clientY).includes(c.value))&&(t.value=!1)}function _(e){Hs(e);let n=e.dataTransfer.files;0!==n.length&&r(null,n),t.value=!1}return Object.assign(u,{pickFiles:f,addFiles:m}),{pickFiles:f,addFiles:m,onDragover:function(e){Hs(e),!0!==t.value&&(t.value=!0)},onDragleave:g,processFiles:function(e,t,n,a){let i=Array.from(t||e.target.files),o=[],r=()=>{0!==o.length&&l("rejected",o)};if(void 0!==s.accept&&-1===d.value.indexOf("*/")&&(i=Us(i,o,"accept",e=>d.value.some(t=>e.type.toUpperCase().startsWith(t)||e.name.toUpperCase().endsWith(t))),0===i.length))return r();if(void 0!==s.maxFileSize){let e=parseInt(s.maxFileSize,10);if(i=Us(i,o,"max-file-size",t=>t.size<=e),0===i.length)return r()}if(!0!==s.multiple&&0!==i.length&&(i=[i[0]]),i.forEach(e=>{e.__key=e.webkitRelativePath+e.lastModified+e.name+e.size}),!0===a){let e=n.map(e=>e.__key);i=Us(i,o,"duplicate",t=>!1===e.includes(t.__key))}if(0===i.length)return r();if(void 0!==s.maxTotalSize){let e=!0===a?n.reduce((e,t)=>e+t.size,0):0;if(i=Us(i,o,"max-total-size",t=>(e+=t.size,e<=p.value)),0===i.length)return r()}if("function"==typeof s.filter){let e=s.filter(i);i=Us(i,o,"filter",t=>e.includes(t))}if(void 0!==s.maxFiles){let e=!0===a?n.length:0;if(i=Us(i,o,"max-files",()=>(e++,e<=h.value)),0===i.length)return r()}return r(),0!==i.length?i:void 0},getDndNode:function(e){if(!0===t.value)return n("div",{ref:c,class:`q-${e}__dnd absolute-full`,onDragenter:Hs,onDragover:Hs,onDragleave:g,onDrop:_})},maxFilesNumber:h,maxTotalSizeNumber:p}}function Ys(e,t){function n(){let t=e.modelValue;try{let e="DataTransfer"in window?new DataTransfer:"ClipboardEvent"in window?new ClipboardEvent("").clipboardData:void 0;return Object(t)===t&&("length"in t?Array.from(t):[t]).forEach(t=>{e.items.add(t)}),{files:e.files}}catch{return{files:void 0}}}return i(!0===t?()=>{if("file"===e.type)return n()}:n)}var Qs=$({name:"QFile",inheritAttrs:!1,props:{...Ds,...ai,...Ws,modelValue:[File,FileList,Array],append:Boolean,useChips:Boolean,displayValue:[String,Number],tabindex:{type:[String,Number],default:0},counterLabel:Function,inputClass:[Array,String,Object],inputStyle:[Array,String,Object]},emits:[...Bs,...Gs],setup(e,{slots:t,emit:o,attrs:r}){let{proxy:s}=k(),l=Fs(),u=a(null),c=a(!1),d=ri(e),{pickFiles:h,onDragover:p,onDragleave:f,processFiles:m,getDndNode:g}=Ks({editable:l.editable,dnd:c,getFileInput:L,addFilesToQueue:R}),_=Ys(e),v=i(()=>Object(e.modelValue)===e.modelValue?"length"in e.modelValue?Array.from(e.modelValue):[e.modelValue]:[]),b=i(()=>qs(v.value)),y=i(()=>v.value.map(e=>e.name).join(", ")),w=i(()=>Qe(v.value.reduce((e,t)=>e+t.size,0))),x=i(()=>({totalSize:w.value,filesNumber:v.value.length,maxFiles:e.maxFiles})),S=i(()=>({tabindex:-1,type:"file",title:"",accept:e.accept,capture:e.capture,name:d.value,...r,id:l.targetUid.value,disabled:!0!==l.editable.value})),C=i(()=>"q-file q-field--auto-height"+(!0===c.value?" q-file--dnd":"")),T=i(()=>!0===e.multiple&&!0===e.append);function P(e){let t=v.value.slice();t.splice(e,1),E(t)}function E(t){o("update:modelValue",!0===e.multiple?t:t[0])}function A(e){13===e.keyCode&&Z(e)}function M(e){(13===e.keyCode||32===e.keyCode)&&h(e)}function L(){return u.value}function R(t,n){let a=m(t,n,v.value,T.value),i=L();null!=i&&(i.value=""),void 0!==a&&((!0===e.multiple?e.modelValue&&a.every(e=>v.value.includes(e)):e.modelValue===a[0])||E(!0===T.value?v.value.concat(a):a))}function N(){return[n("input",{class:[e.inputClass,"q-file__filler"],style:e.inputStyle})]}function O(){let t={ref:u,...S.value,..._.value,class:"q-field__input fit absolute-full cursor-pointer",onChange:R};return!0===e.multiple&&(t.multiple=!0),n("input",t)}return Object.assign(l,{fieldClass:C,emitValue:E,hasValue:b,inputRef:u,innerValue:v,floatingLabel:i(()=>!0===b.value||qs(e.displayValue)),computedCounter:i(()=>{if(void 0!==e.counterLabel)return e.counterLabel(x.value);let t=e.maxFiles;return`${v.value.length}${void 0!==t?" / "+t:""} (${w.value})`}),getControlChild:()=>g("file"),getControl:()=>{let a={ref:l.targetRef,class:"q-field__native row items-center cursor-pointer",tabindex:e.tabindex};return!0===l.editable.value&&Object.assign(a,{onDragover:p,onDragleave:f,onKeydown:A,onKeyup:M}),n("div",a,[O()].concat(function(){if(void 0!==t.file)return 0===v.value.length?N():v.value.map((e,n)=>t.file({index:n,file:e,ref:this}));if(void 0!==t.selected)return 0===v.value.length?N():t.selected({files:v.value,ref:this});if(!0===e.useChips)return 0===v.value.length?N():v.value.map((t,a)=>n(Fi,{key:"file-"+a,removable:l.editable.value,dense:!0,textColor:e.color,tabindex:e.tabindex,onRemove:()=>{P(a)}},()=>n("span",{class:"ellipsis",textContent:t.name})));let a=void 0!==e.displayValue?e.displayValue:y.value;return 0!==a.length?[n("div",{class:e.inputClass,style:e.inputStyle,textContent:a})]:N()}()))}}),Object.assign(s,{removeAtIndex:P,removeFile:function(e){let t=v.value.indexOf(e);-1!==t&&P(t)},getNativeElement:()=>u.value}),z(s,"nativeEl",()=>u.value),$s(l)}}),Zs=$({name:"QFooter",props:{modelValue:{type:Boolean,default:!0},reveal:Boolean,bordered:Boolean,elevated:Boolean,heightHint:{type:[String,Number],default:50}},emits:["reveal","focusin"],setup(e,{slots:t,emit:r}){let{proxy:{$q:s}}=k(),l=y(Ae,Oe);if(l===Oe)return console.error("QFooter needs to be child of QLayout"),Oe;let u=a(parseInt(e.heightHint,10)),c=a(!0),d=a(!0===I.value||!0===l.isContainer.value?0:window.innerHeight),h=i(()=>!0===e.reveal||-1!==l.view.value.indexOf("F")||s.platform.is.ios&&!0===l.isContainer.value),p=i(()=>!0===l.isContainer.value?l.containerHeight.value:d.value),f=i(()=>{if(!0!==e.modelValue)return 0;if(!0===h.value)return!0===c.value?u.value:0;let t=l.scroll.value.position+p.value+u.value-l.height.value;return t>0?t:0}),m=i(()=>!0!==e.modelValue||!0===h.value&&!0!==c.value),_=i(()=>!0===e.modelValue&&!0===m.value&&!0===e.reveal),v=i(()=>"q-footer q-layout__section--marginal "+(!0===h.value?"fixed":"absolute")+"-bottom"+(!0===e.bordered?" q-footer--bordered":"")+(!0===m.value?" q-footer--hidden":"")+(!0!==e.modelValue?" q-layout--prevent-focus"+(!0!==h.value?" hidden":""):"")),b=i(()=>{let e=l.rows.value.bottom,t={};return"l"===e[0]&&!0===l.left.space&&(t[!0===s.lang.rtl?"right":"left"]=`${l.left.size}px`),"r"===e[2]&&!0===l.right.space&&(t[!0===s.lang.rtl?"left":"right"]=`${l.right.size}px`),t});function w(e,t){l.update("footer",e,t)}function x(e,t){e.value!==t&&(e.value=t)}function S({height:e}){x(u,e),w("size",e)}function C(e){!0===_.value&&x(c,!0),r("focusin",e)}o(()=>e.modelValue,e=>{w("space",e),x(c,!0),l.animate()}),o(f,e=>{w("offset",e)}),o(()=>e.reveal,t=>{!1===t&&x(c,e.modelValue)}),o(c,e=>{l.animate(),r("reveal",e)}),o([u,l.scroll,l.height],function(){if(!0!==e.reveal)return;let{direction:t,position:n,inflectionPoint:a}=l.scroll.value;x(c,"up"===t||n-a<100||l.height.value-p.value-n-u.value<300)}),o(()=>s.screen.height,e=>{!0!==l.isContainer.value&&x(d,e)});let T={};return l.instances.footer=T,!0===e.modelValue&&w("size",u.value),w("space",e.modelValue),w("offset",f.value),g(()=>{l.instances.footer===T&&(l.instances.footer=void 0,w("size",0),w("offset",0),w("space",!1))}),()=>{let a=pt(t.default,[n(lo,{debounce:0,onResize:S})]);return!0===e.elevated&&a.push(n("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),n("footer",{class:v.value,style:b.value,onFocusin:C},a)}}}),Js=$({name:"QForm",props:{autofocus:Boolean,noErrorFocus:Boolean,noResetFocus:Boolean,greedy:Boolean,onSubmit:Function},emits:["reset","validationSuccess","validationError"],setup(e,{slots:t,emit:i}){let o=k(),r=a(null),s=0,l=[];function u(t){let n="boolean"==typeof t?t:!0!==e.noErrorFocus,a=++s,o=(e,t)=>{i("validation"+(!0===e?"Success":"Error"),t)},r=e=>{let t=e.validate();return"function"==typeof t.then?t.then(t=>({valid:t,comp:e}),t=>({valid:!1,comp:e,err:t})):Promise.resolve({valid:t,comp:e})};return(!0===e.greedy?Promise.all(l.map(r)).then(e=>e.filter(e=>!0!==e.valid)):l.reduce((e,t)=>e.then(()=>r(t).then(e=>{if(!1===e.valid)return Promise.reject(e)})),Promise.resolve()).catch(e=>[e])).then(e=>{if(void 0===e||0===e.length)return a===s&&o(!0),!0;if(a===s){let{comp:t,err:a}=e[0];if(void 0!==a&&console.error(a),o(!1,t),!0===n){let t=e.find(({comp:e})=>"function"==typeof e.focus&&!1===Wt(e.$));void 0!==t&&t.comp.focus()}}return!1})}function c(){s++,l.forEach(e=>{"function"==typeof e.resetValidation&&e.resetValidation()})}function f(t){void 0!==t&&J(t);let n=s+1;u().then(a=>{n===s&&!0===a&&(void 0!==e.onSubmit?i("submit",t):void 0!==t?.target&&"function"==typeof t.target.submit&&t.target.submit())})}function g(t){void 0!==t&&J(t),i("reset"),d(()=>{c(),!0===e.autofocus&&!0!==e.noResetFocus&&_()})}function _(){Vn(()=>{null!==r.value&&(r.value.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||r.value.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||r.value.querySelector("[autofocus], [data-autofocus]")||Array.prototype.find.call(r.value.querySelectorAll("[tabindex]"),e=>-1!==e.tabIndex))?.focus({preventScroll:!0})})}w(Re,{bindComponent(e){l.push(e)},unbindComponent(e){let t=l.indexOf(e);-1!==t&&l.splice(t,1)}});let v=!1;return p(()=>{v=!0}),h(()=>{!0===v&&!0===e.autofocus&&_()}),m(()=>{!0===e.autofocus&&_()}),Object.assign(o.proxy,{validate:u,resetValidation:c,submit:f,reset:g,focus:_,getValidationComponents:()=>l}),()=>n("form",{class:"q-form",ref:r,onSubmit:f,onReset:g},dt(t.default))}}),Xs={inject:{[Re]:{default:W}},watch:{disable(e){let t=this.$.provides[Re];void 0!==t&&(!0===e?(this.resetValidation(),t.unbindComponent(this)):t.bindComponent(this))}},methods:{validate(){},resetValidation(){}},mounted(){!0!==this.disable&&this.$.provides[Re]?.bindComponent(this)},beforeUnmount(){!0!==this.disable&&this.$.provides[Re]?.unbindComponent(this)}},el=$({name:"QHeader",props:{modelValue:{type:Boolean,default:!0},reveal:Boolean,revealOffset:{type:Number,default:250},bordered:Boolean,elevated:Boolean,heightHint:{type:[String,Number],default:50}},emits:["reveal","focusin"],setup(e,{slots:t,emit:r}){let{proxy:{$q:s}}=k(),l=y(Ae,Oe);if(l===Oe)return console.error("QHeader needs to be child of QLayout"),Oe;let u=a(parseInt(e.heightHint,10)),c=a(!0),d=i(()=>!0===e.reveal||-1!==l.view.value.indexOf("H")||s.platform.is.ios&&!0===l.isContainer.value),h=i(()=>{if(!0!==e.modelValue)return 0;if(!0===d.value)return!0===c.value?u.value:0;let t=u.value-l.scroll.value.position;return t>0?t:0}),p=i(()=>!0!==e.modelValue||!0===d.value&&!0!==c.value),f=i(()=>!0===e.modelValue&&!0===p.value&&!0===e.reveal),m=i(()=>"q-header q-layout__section--marginal "+(!0===d.value?"fixed":"absolute")+"-top"+(!0===e.bordered?" q-header--bordered":"")+(!0===p.value?" q-header--hidden":"")+(!0!==e.modelValue?" q-layout--prevent-focus":"")),_=i(()=>{let e=l.rows.value.top,t={};return"l"===e[0]&&!0===l.left.space&&(t[!0===s.lang.rtl?"right":"left"]=`${l.left.size}px`),"r"===e[2]&&!0===l.right.space&&(t[!0===s.lang.rtl?"left":"right"]=`${l.right.size}px`),t});function v(e,t){l.update("header",e,t)}function b(e,t){e.value!==t&&(e.value=t)}function w({height:e}){b(u,e),v("size",e)}function x(e){!0===f.value&&b(c,!0),r("focusin",e)}o(()=>e.modelValue,e=>{v("space",e),b(c,!0),l.animate()}),o(h,e=>{v("offset",e)}),o(()=>e.reveal,t=>{!1===t&&b(c,e.modelValue)}),o(c,e=>{l.animate(),r("reveal",e)}),o(l.scroll,t=>{!0===e.reveal&&b(c,"up"===t.direction||t.position<=e.revealOffset||t.position-t.inflectionPoint<100)});let S={};return l.instances.header=S,!0===e.modelValue&&v("size",u.value),v("space",e.modelValue),v("offset",h.value),g(()=>{l.instances.header===S&&(l.instances.header=void 0,v("size",0),v("offset",0),v("space",!1))}),()=>{let a=ht(t.default,[]);return!0===e.elevated&&a.push(n("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),a.push(n(lo,{debounce:0,onResize:w})),n("header",{class:m.value,style:_.value,onFocusin:x},a)}}}),tl={ratio:[String,Number]};function nl(e,t){return i(()=>{let n=Number(e.ratio||(void 0!==t?t.value:void 0));return!0!==isNaN(n)&&n>0?{paddingBottom:100/n+"%"}:null})}var al=$({name:"QImg",props:{...tl,src:String,srcset:String,sizes:String,alt:String,crossorigin:String,decoding:String,referrerpolicy:String,draggable:Boolean,loading:{type:String,default:"lazy"},loadingShowDelay:{type:[Number,String],default:0},fetchpriority:{type:String,default:"auto"},width:String,height:String,initialRatio:{type:[Number,String],default:1.7778},placeholderSrc:String,errorSrc:String,fit:{type:String,default:"cover"},position:{type:String,default:"50% 50%"},imgClass:String,imgStyle:Object,noSpinner:Boolean,noNativeMenu:Boolean,noTransition:Boolean,spinnerColor:String,spinnerSize:String},emits:["load","error"],setup(e,{slots:t,emit:r}){let s=a(e.initialRatio),l=nl(e,s),u=k(),{registerTimeout:c,removeTimeout:d}=aa(),{registerTimeout:h,removeTimeout:p}=aa(),f=i(()=>void 0!==e.placeholderSrc?{src:e.placeholderSrc}:null),g=i(()=>void 0!==e.errorSrc?{src:e.errorSrc,__qerror:!0}:null),_=[a(null),a(f.value)],v=a(0),b=a(!1),y=a(!1),w=i(()=>`q-img q-img--${!0===e.noNativeMenu?"no-":""}menu`),x=i(()=>({width:e.width,height:e.height})),C=i(()=>`q-img__image ${void 0!==e.imgClass?e.imgClass+" ":""}q-img__image--with${!0===e.noTransition?"out":""}-transition q-img__image--`),T=i(()=>({...e.imgStyle,objectFit:e.fit,objectPosition:e.position}));function P(){p(),b.value=!1}function E({target:e}){!1===Wt(u)&&(d(),s.value=0===e.naturalHeight?.5:e.naturalWidth/e.naturalHeight,A(e,1))}function A(e,t){1e3===t||!0===Wt(u)||(!0===e.complete?function(e){!0!==Wt(u)&&(v.value=1^v.value,_[v.value].value=null,P(),"true"!==e.getAttribute("__qerror")&&(y.value=!1),r("load",e.currentSrc||e.src))}(e):c(()=>{A(e,t+1)},50))}function M(e){d(),P(),y.value=!0,_[v.value].value=g.value,_[1^v.value].value=f.value,r("error",e)}function L(t){let a=_[t].value,i={key:"img_"+t,class:C.value,style:T.value,alt:e.alt,crossorigin:e.crossorigin,decoding:e.decoding,referrerpolicy:e.referrerpolicy,height:e.height,width:e.width,loading:e.loading,fetchpriority:e.fetchpriority,"aria-hidden":"true",draggable:e.draggable,...a};return v.value===t?Object.assign(i,{class:i.class+"current",onLoad:E,onError:M}):i.class+="loaded",n("div",{class:"q-img__container absolute-full",key:"img"+t},n("img",i))}function R(){return!1===b.value?n("div",{key:"content",class:"q-img__content absolute-full q-anchor--skip"},dt(t[!0===y.value?"error":"default"])):n("div",{key:"loading",class:"q-img__loading absolute-full flex flex-center"},void 0!==t.loading?t.loading():!0===e.noSpinner?void 0:[n(rn,{color:e.spinnerColor,size:e.spinnerSize})])}{let t=function(){o(()=>e.src||e.srcset||e.sizes?{src:e.src,srcset:e.srcset,sizes:e.sizes}:null,t=>{d(),y.value=!1,null===t?(P(),_[1^v.value].value=f.value):(p(),0!==e.loadingShowDelay?h(()=>{b.value=!0},e.loadingShowDelay):b.value=!0),_[v.value].value=t},{immediate:!0})};!0===I.value?m(t):t()}return()=>{let t=[];return null!==l.value&&t.push(n("div",{key:"filler",style:l.value})),null!==_[0].value&&t.push(L(0)),null!==_[1].value&&t.push(L(1)),t.push(n(S,{name:"q-transition--fade"},R)),n("div",{key:"main",class:w.value,style:x.value,role:"img","aria-label":e.alt},t)}}}),{passive:il}=H,ol=$({name:"QInfiniteScroll",props:{offset:{type:Number,default:500},debounce:{type:[String,Number],default:100},scrollTarget:oa,initialIndex:{type:Number,default:0},disable:Boolean,reverse:Boolean},emits:["load"],setup(e,{slots:t,emit:r}){let s,l,u=a(!1),c=a(!0),f=a(null),_=a(null),v=e.initialIndex,b=i(()=>"q-infinite-scroll__loading"+(!0===u.value?"":" invisible"));function y(){if(!0===e.disable||!0===u.value||!1===c.value)return;let t=la(s),n=ua(s),a=ln(s);!1===e.reverse?Math.round(n+a+e.offset)>=Math.round(t)&&w():Math.round(n)<=e.offset&&w()}function w(){if(!0===e.disable||!0===u.value||!1===c.value)return;v++,u.value=!0;let t=la(s);r("load",v,n=>{!0===c.value&&(u.value=!1,d(()=>{if(!0===e.reverse){let e=la(s),n=ua(s);ma(s,n+(e-t))}!0===n?S():f.value&&f.value.closest("body")&&l()}))})}function x(){!1===c.value&&(c.value=!0,s.addEventListener("scroll",l,il)),y()}function S(){!0===c.value&&(c.value=!1,u.value=!1,s.removeEventListener("scroll",l,il),l?.cancel?.())}function C(){if(s&&!0===c.value&&s.removeEventListener("scroll",l,il),s=sa(f.value,e.scrollTarget),!0===c.value){if(s.addEventListener("scroll",l,il),!0===e.reverse){let e=la(s),t=ln(s);ma(s,e-t)}y()}}function T(e){e=parseInt(e,10);let t=l;l=e<=0?y:ae(y,!0===isNaN(e)?100:e),s&&!0===c.value&&(void 0!==t&&s.removeEventListener("scroll",t,il),s.addEventListener("scroll",l,il))}function P(e){if(!0===E.value){if(null===_.value)return void(!0!==e&&d(()=>{P(!0)}));let t=(!0===u.value?"un":"")+"pauseAnimations";Array.from(_.value.getElementsByTagName("svg")).forEach(e=>{e[t]()})}}let E=i(()=>!0!==e.disable&&!0===c.value);o([u,E],()=>{P()}),o(()=>e.disable,e=>{!0===e?S():x()}),o(()=>e.reverse,()=>{!1===u.value&&!0===c.value&&y()}),o(()=>e.scrollTarget,C),o(()=>e.debounce,T);let A=!1;h(()=>{!1!==A&&s&&ma(s,A)}),p(()=>{A=!!s&&ua(s)}),g(()=>{!0===c.value&&s.removeEventListener("scroll",l,il)}),m(()=>{T(e.debounce),C(),!1===u.value&&P()});let M=k();return Object.assign(M.proxy,{poll:()=>{l?.()},trigger:w,stop:S,reset:function(){v=0},resume:x,setIndex:function(e){v=e},updateScrollTarget:C}),()=>{let a=ht(t.default,[]);return!0===E.value&&a[!1===e.reverse?"push":"unshift"](n("div",{ref:_,class:b.value},dt(t.loading))),n("div",{class:"q-infinite-scroll",ref:f},a)}}}),rl=$({name:"QInnerLoading",props:{...Nt,...ea,showing:Boolean,color:String,size:{type:[String,Number],default:"42px"},label:String,labelClass:String,labelStyle:[String,Array,Object]},setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q),{transitionProps:r,transitionStyle:s}=ta(e),l=i(()=>"q-inner-loading q--avoid-card-border absolute-full column flex-center"+(!0===o.value?" q-inner-loading--dark":"")),u=i(()=>"q-inner-loading__label"+(void 0!==e.labelClass?` ${e.labelClass}`:""));function c(){return!0===e.showing?n("div",{class:l.value,style:s.value},void 0!==t.default?t.default():function(){let t=[n(rn,{size:e.size,color:e.color})];return void 0!==e.label&&t.push(n("div",{class:u.value,style:e.labelStyle},[e.label])),t}()):null}return()=>n(S,r.value,c)}}),sl={date:"####/##/##",datetime:"####/##/## ##:##",time:"##:##",fulltime:"##:##:##",phone:"(###) ### - ####",card:"#### #### #### ####"},{tokenMap:ll,tokenKeys:ul}=cl({"#":{pattern:"[\\d]",negate:"[^\\d]"},S:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]"},N:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]"},A:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]",transform:e=>e.toLocaleUpperCase()},a:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]",transform:e=>e.toLocaleLowerCase()},X:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]",transform:e=>e.toLocaleUpperCase()},x:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]",transform:e=>e.toLocaleLowerCase()}});function cl(e){let t=Object.keys(e),n={};return t.forEach(t=>{let a=e[t];n[t]={...a,regex:new RegExp(a.pattern)}}),{tokenMap:n,tokenKeys:t}}function dl(e){return new RegExp("\\\\([^.*+?^${}()|([\\]])|([.*+?^${}()|[\\]])|(["+e.join("")+"])|(.)","g")}var hl=/[.*+?^${}()|[\]\\]/g,pl=dl(ul),fl="",ml={mask:String,reverseFillMask:Boolean,fillMask:[Boolean,String],unmaskedValue:Boolean,maskTokens:Object};function gl(e,t,n,r){let s,l,u,c,h,p,f=i(()=>{if(void 0===e.maskTokens||null===e.maskTokens)return{tokenMap:ll,tokenRegexMask:pl};let{tokenMap:t}=cl(e.maskTokens),n={...ll,...t};return{tokenMap:n,tokenRegexMask:dl(Object.keys(n))}}),m=a(null),g=a(function(){if(v(),!0===m.value){let t=w(k(e.modelValue));return!1!==e.fillMask?x(t):t}return e.modelValue}());function _(e){if(e0;a--)t+=fl;n=n.slice(0,a)+t+n.slice(a)}return n}function v(){if(m.value=void 0!==e.mask&&0!==e.mask.length&&(!0===e.autogrow||["textarea","text","search","url","tel","password"].includes(e.type)),!1===m.value)return c=void 0,s="",void(l="");let t=void 0===sl[e.mask]?e.mask:sl[e.mask],n="string"==typeof e.fillMask&&0!==e.fillMask.length?e.fillMask.slice(0,1):"_",a=n.replace(hl,"\\$&"),i=[],o=[],r=[],d=!0===e.reverseFillMask,h="",p="";t.replace(f.value.tokenRegexMask,(e,t,n,a,s)=>{if(void 0!==a){let e=f.value.tokenMap[a];r.push(e),p=e.negate,!0===d&&(o.push("(?:"+p+"+)?("+e.pattern+"+)?(?:"+p+"+)?("+e.pattern+"+)?"),d=!1),o.push("(?:"+p+"+)?("+e.pattern+")?")}else if(void 0!==n)h="\\"+("\\"===n?"":n),r.push(n),i.push("([^"+h+"]+)?"+h+"?");else{let e=void 0!==t?t:s;h="\\"===e?"\\\\\\\\":e.replace(hl,"\\\\$&"),r.push(e),i.push("([^"+h+"]+)?"+h+"?")}});let g=new RegExp("^"+i.join("")+"("+(""===h?".":"[^"+h+"]")+"+)?"+(""===h?"":"["+h+"]*")+"$"),_=o.length-1,v=o.map((t,n)=>0===n&&!0===e.reverseFillMask?new RegExp("^"+a+"*"+t):n===_?new RegExp("^"+t+"("+(""===p?".":p)+"+)?"+(!0===e.reverseFillMask?"$":a+"*")):new RegExp("^"+t));u=r,c=t=>{let n=g.exec(!0===e.reverseFillMask?t:t.slice(0,r.length+1));null!==n&&(t=n.slice(1).join(""));let a=[],i=v.length;for(let e=0,n=t;e"string"==typeof e?e:fl).join(""),l=s.split(fl).join(n)}function b(t,a,i){let o=r.value,u=o.selectionEnd,c=o.value.length-u,p=k(t);!0===a&&v();let f=w(p,a),m=!1!==e.fillMask?x(f):f,_=g.value!==m;o.value!==m&&(o.value=m),!0===_&&(g.value=m),document.activeElement===o&&d(()=>{if(m===l){let t=!0===e.reverseFillMask?l.length:0;return void o.setSelectionRange(t,t,"forward")}if("insertFromPaste"===i&&!0!==e.reverseFillMask){let e=o.selectionEnd,t=u-1;for(let n=h;n<=t&&nf.length?1:0:Math.max(0,m.length-(m===l?0:Math.min(f.length,c)+1))+1:u;return void o.setSelectionRange(t,t,"forward")}if(!0===e.reverseFillMask)if(!0===_){let e=Math.max(0,m.length-(m===l?0:Math.min(f.length,c+1)));1===e&&1===u?o.setSelectionRange(e,e,"forward"):y.rightReverse(o,e)}else{let e=m.length-c;o.setSelectionRange(e,e,"backward")}else if(!0===_){let e=Math.max(0,s.indexOf(fl),Math.min(f.length,u)-1);y.right(o,e)}else{let e=u-1;y.right(o,e)}});let b=!0===e.unmaskedValue?k(m):m;String(e.modelValue)!==b&&(null!==e.modelValue||""!==b)&&n(b,!0)}o(()=>e.type+e.autogrow,v),o(()=>e.mask,n=>{if(void 0!==n)b(g.value,!0);else{let n=k(g.value);v(),e.modelValue!==n&&t("update:modelValue",n)}}),o(()=>e.fillMask+e.reverseFillMask,()=>{!0===m.value&&b(g.value,!0)}),o(()=>e.unmaskedValue,()=>{!0===m.value&&b(g.value)});let y={left(e,t){let n=-1===s.slice(t-1).indexOf(fl),a=Math.max(0,t-1);for(;a>=0;a--)if(s[a]===fl){t=a,!0===n&&t++;break}if(a<0&&void 0!==s[t]&&s[t]!==fl)return y.right(e,0);t>=0&&e.setSelectionRange(t,t,"backward")},right(e,t){let n=e.value.length,a=Math.min(n,t+1);for(;a<=n;a++){if(s[a]===fl){t=a;break}s[a-1]===fl&&(t=a)}if(a>n&&void 0!==s[t-1]&&s[t-1]!==fl)return y.left(e,n);e.setSelectionRange(t,t,"forward")},leftReverse(e,t){let n=_(e.value.length),a=Math.max(0,t-1);for(;a>=0;a--){if(n[a-1]===fl){t=a;break}if(n[a]===fl&&(t=a,0===a))break}if(a<0&&void 0!==n[t]&&n[t]!==fl)return y.rightReverse(e,0);t>=0&&e.setSelectionRange(t,t,"backward")},rightReverse(e,t){let n=e.value.length,a=_(n),i=-1===a.slice(0,t+1).indexOf(fl),o=Math.min(n,t+1);for(;o<=n;o++)if(a[o-1]===fl){(t=o)>0&&!0===i&&t--;break}if(o>n&&void 0!==a[t-1]&&a[t-1]!==fl)return y.leftReverse(e,n);e.setSelectionRange(t,t,"forward")}};function w(t,n){if(null==t||""===t)return"";if(!0===e.reverseFillMask)return function(e,t){let n=u,a=s.indexOf(fl),i=e.length-1,o="";for(let r=n.length-1;r>=0&&-1!==i;r--){let s=n[r],l=e[i];if("string"==typeof s)o=s+o,!0===t&&l===s&&i--;else{if(void 0===l||!s.regex.test(l))return o;do{o=(void 0!==s.transform?s.transform(l):l)+o,i--,l=e[i]}while(a===r&&void 0!==l&&s.regex.test(l))}}return o}(t,n);let a=u,i=0,o="";for(let e=0;eqs(y.value)),A=wl(q),M=Fs({changeEvent:!0}),L=i(()=>"textarea"===e.type||!0===e.autogrow),R=i(()=>!0===L.value||["text","search","url","tel","password"].includes(e.type)),N=i(()=>{let t={...M.splitAttrs.listeners.value,onInput:q,onPaste:I,onChange:F,onBlur:$,onFocus:Q};return t.onCompositionstart=t.onCompositionupdate=t.onCompositionend=A,!0===w.value&&(t.onKeydown=C,t.onClick=T),!0===e.autogrow&&(t.onAnimationend=D),t}),O=i(()=>{let t={tabindex:0,"data-autofocus":!0===e.autofocus||void 0,rows:"textarea"===e.type?6:void 0,"aria-label":e.label,name:b.value,...M.splitAttrs.attributes.value,id:M.targetUid.value,maxlength:e.maxlength,disabled:!0===e.disable,readonly:!0===e.readonly};return!1===L.value&&(t.type=e.type),!0===e.autogrow&&(t.rows=1),t});function I(n){if(!0===w.value&&!0!==e.reverseFillMask){let e=n.target;x(e,e.selectionStart,e.selectionEnd)}t("paste",n)}function q(n){if(!n||!n.target)return;if("file"===e.type)return void t("update:modelValue",n.target.files);let a=n.target.value;if(!0!==n.target.qComposing){if(!0===w.value)S(a,!1,n.inputType);else if(j(a),!0===R.value&&n.target===document.activeElement){let{selectionStart:e,selectionEnd:t}=n.target;void 0!==e&&void 0!==t&&d(()=>{n.target===document.activeElement&&0===a.indexOf(n.target.value)&&n.target.setSelectionRange(e,t)})}!0===e.autogrow&&B()}else p.value=a}function D(e){t("animationend",e),B()}function j(n,a){u=()=>{_=null,"number"!==e.type&&!0===p.hasOwnProperty("value")&&delete p.value,e.modelValue!==n&&f!==n&&(f=n,!0===a&&(l=!0),t("update:modelValue",n),d(()=>{f===n&&(f=NaN)})),u=void 0},"number"===e.type&&(s=!0,p.value=n),void 0!==e.debounce?(null!==_&&clearTimeout(_),p.value=n,_=setTimeout(u,e.debounce)):u()}function B(){requestAnimationFrame(()=>{let e=v.value;if(null!==e){let t=e.parentNode.style,{scrollTop:n}=e,{overflowY:a,maxHeight:i}=!0===h.platform.is.firefox?{}:window.getComputedStyle(e),o=void 0!==a&&"scroll"!==a;!0===o&&(e.style.overflowY="hidden"),t.marginBottom=e.scrollHeight-1+"px",e.style.height="1px",e.style.height=e.scrollHeight+"px",!0===o&&(e.style.overflowY=parseInt(i,10){null!==v.value&&(v.value.value=void 0!==y.value?y.value:"")})}function V(){return!0===p.hasOwnProperty("value")?p.value:void 0!==y.value?y.value:""}o(()=>e.type,()=>{v.value&&(v.value.value=e.modelValue)}),o(()=>e.modelValue,t=>{if(!0===w.value){if(!0===l&&(l=!1,String(t)===f))return;S(t)}else y.value!==t&&(y.value=t,"number"===e.type&&!0===p.hasOwnProperty("value")&&(!0===s?s=!1:delete p.value));!0===e.autogrow&&d(B)}),o(()=>e.autogrow,e=>{!0===e?d(B):null!==v.value&&r.rows>0&&(v.value.style.height="auto")}),o(()=>e.dense,()=>{!0===e.autogrow&&d(B)}),g(()=>{$()}),m(()=>{!0===e.autogrow&&B()}),Object.assign(M,{innerValue:y,fieldClass:i(()=>"q-"+(!0===L.value?"textarea":"input")+(!0===e.autogrow?" q-textarea--autogrow":"")),hasShadow:i(()=>"file"!==e.type&&"string"==typeof e.shadowText&&0!==e.shadowText.length),inputRef:v,emitValue:j,hasValue:E,floatingLabel:i(()=>!0===E.value&&("number"!==e.type||!1===isNaN(y.value))||qs(e.displayValue)),getControl:()=>n(!0===L.value?"textarea":"input",{ref:v,class:["q-field__native q-placeholder",e.inputClass],style:e.inputStyle,...O.value,...N.value,..."file"!==e.type?{value:V()}:P.value}),getShadowControl:()=>n("div",{class:"q-field__native q-field__shadow absolute-bottom no-pointer-events"+(!0===L.value?"":" text-no-wrap")},[n("span",{class:"invisible"},V()),n("span",e.shadowText)])});let U=$s(M);return Object.assign(c,{focus:function(){Vn(()=>{let e=document.activeElement;null!==v.value&&v.value!==e&&(null===e||e.id!==M.targetUid.value)&&v.value.focus({preventScroll:!0})})},select:function(){v.value?.select()},getNativeElement:()=>v.value}),z(c,"nativeEl",()=>v.value),U}}),xl={threshold:0,root:null,rootMargin:"0px"};function Sl(e,t,n){let a,i,o;"function"==typeof n?(a=n,i=xl,o=void 0===t.cfg):(a=n.handler,i=Object.assign({},xl,n.cfg),o=void 0===t.cfg||!1===De(t.cfg,i)),t.handler!==a&&(t.handler=a),!0===o&&(t.cfg=i,t.observer?.unobserve(e),t.observer=new IntersectionObserver(([n])=>{if("function"==typeof t.handler){if(null===n.rootBounds&&!0===document.body.contains(e))return t.observer.unobserve(e),void t.observer.observe(e);(!1===t.handler(n,t.observer)||!0===t.once&&!0===n.isIntersecting)&&Cl(e)}},i),t.observer.observe(e))}function Cl(e){let t=e.__qvisible;void 0!==t&&(t.observer?.unobserve(e),delete e.__qvisible)}var Tl=V({name:"intersection",mounted(e,{modifiers:t,value:n}){let a={once:!0===t.once};Sl(e,a,n),e.__qvisible=a},updated(e,t){let n=e.__qvisible;void 0!==n&&Sl(e,n,t.value)},beforeUnmount:Cl}),Pl=$({name:"QIntersection",props:{tag:{type:String,default:"div"},once:Boolean,transition:String,transitionDuration:{type:[String,Number],default:300},ssrPrerender:Boolean,margin:String,threshold:[Number,Array],root:{default:null},disable:Boolean,onVisibility:Function},setup(e,{slots:t,emit:o}){let r=a(!0===I.value&&e.ssrPrerender),s=i(()=>void 0!==e.root||void 0!==e.margin||void 0!==e.threshold?{handler:d,cfg:{root:e.root,rootMargin:e.margin,threshold:e.threshold}}:d),l=i(()=>!0!==e.disable&&(!0!==I.value||!0!==e.once||!0!==e.ssrPrerender)),u=i(()=>[[Tl,s.value,void 0,{once:e.once}]]),c=i(()=>`--q-transition-duration: ${e.transitionDuration}ms`);function d(t){r.value!==t.isIntersecting&&(r.value=t.isIntersecting,void 0!==e.onVisibility&&o("visibility",r.value))}function h(){return!0===r.value?[n("div",{key:"content",style:c.value},dt(t.default))]:void 0!==t.hidden?[n("div",{key:"hidden",style:c.value},t.hidden())]:void 0}return()=>{let t=e.transition?[n(S,{name:"q-transition--"+e.transition},h)]:h();return mt(e.tag,{class:"q-intersection"},t,"main",l.value,()=>u.value)}}}),El=["ul","ol"],Al=$({name:"QList",props:{...Nt,bordered:Boolean,dense:Boolean,separator:Boolean,padding:Boolean,tag:{type:String,default:"div"}},setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q),r=i(()=>El.includes(e.tag)?null:"list"),s=i(()=>"q-list"+(!0===e.bordered?" q-list--bordered":"")+(!0===e.dense?" q-list--dense":"")+(!0===e.separator?" q-list--separator":"")+(!0===o.value?" q-list--dark":"")+(!0===e.padding?" q-list--padding":""));return()=>n(e.tag,{class:s.value,role:r.value},dt(t.default))}}),Ml=[34,37,40,33,39,38],Ll=Object.keys($i),Rl=$({name:"QKnob",props:{...ai,...$i,modelValue:{type:Number,required:!0},innerMin:Number,innerMax:Number,step:{type:Number,default:1,validator:e=>e>=0},tabindex:{type:[Number,String],default:0},disable:Boolean,readonly:Boolean},emits:["update:modelValue","change","dragValue"],setup(e,{slots:t,emit:r}){let s,{proxy:l}=k(),{$q:u}=l,c=a(e.modelValue),d=a(!1),h=i(()=>!0===isNaN(e.innerMin)||e.innerMin!0===isNaN(e.innerMax)||e.innerMax>e.max?e.max:e.innerMax);function f(){c.value=null===e.modelValue?h.value:Je(e.modelValue,h.value,p.value),R(!0)}o(()=>`${e.modelValue}|${h.value}|${p.value}`,f),f();let m=i(()=>!1===e.disable&&!1===e.readonly),g=i(()=>"q-knob non-selectable"+(!0===m.value?" q-knob--editable":!0===e.disable?" disabled":"")),_=i(()=>(String(e.step).trim().split(".")[1]||"").length),v=i(()=>0===e.step?1:e.step),b=i(()=>!0===e.instantFeedback||!0===d.value),y=!0===u.platform.is.mobile?i(()=>!0===m.value?{onClick:E}:{}):i(()=>!0===m.value?{onMousedown:P,onClick:E,onKeydown:A,onKeyup:L}:{}),w=i(()=>!0===m.value?{tabindex:e.tabindex}:{["aria-"+(!0===e.disable?"disabled":"readonly")]:"true"}),x=i(()=>{let t={};return Ll.forEach(n=>{t[n]=e[n]}),t});function S(e){e.isFinal?(M(e.evt,!0),d.value=!1):(e.isFirst&&(T(),d.value=!0),M(e.evt))}let C=i(()=>[[Ki,S,void 0,{prevent:!0,stop:!0,mouse:!0}]]);function T(){let{top:e,left:t,width:n,height:a}=l.$el.getBoundingClientRect();s={top:e+a/2,left:t+n/2}}function P(e){T(),M(e)}function E(e){T(),M(e,!0)}function A(e){if(!1===Ml.includes(e.keyCode))return;J(e);let t=([34,33].includes(e.keyCode)?10:1)*v.value,n=[34,37,40].includes(e.keyCode)?-t:t;c.value=Je(parseFloat((c.value+n).toFixed(_.value)),h.value,p.value),R()}function M(t,n){let a=K(t),i=Math.abs(a.top-s.top),o=Math.sqrt(i**2+Math.abs(a.left-s.left)**2),l=Math.asin(i/o)*(180/Math.PI);l=a.top=v.value/2?(e<0?-1:1)*v.value:0),d=parseFloat(d.toFixed(_.value))}d=Je(d,h.value,p.value),r("dragValue",d),c.value!==d&&(c.value=d),R(n)}function L(e){Ml.includes(e.keyCode)&&R(!0)}function R(t){e.modelValue!==c.value&&r("update:modelValue",c.value),!0===t&&r("change",c.value)}let z=ii(e);function N(){return n("input",z.value)}return()=>{let n={class:g.value,role:"slider","aria-valuemin":h.value,"aria-valuemax":p.value,"aria-valuenow":e.modelValue,...w.value,...x.value,value:c.value,instantFeedback:b.value,...y.value},a={default:t.default};return!0===m.value&&void 0!==e.name&&(a.internal=N),mt(Hi,n,a,"knob",m.value,()=>C.value)}}}),{passive:zl}=H,Nl=["both","horizontal","vertical"],Ol=$({name:"QScrollObserver",props:{axis:{type:String,validator:e=>Nl.includes(e),default:"vertical"},debounce:[String,Number],scrollTarget:oa},emits:["scroll"],setup(e,{emit:t}){let n,a,i={position:{top:0,left:0},direction:"down",directionChanged:!1,delta:{top:0,left:0},inflectionPoint:{top:0,left:0}},r=null;function s(){r?.();let a=Math.max(0,ua(n)),o=ca(n),s={top:a-i.position.top,left:o-i.position.left};if("vertical"===e.axis&&0===s.top||"horizontal"===e.axis&&0===s.left)return;let l=Math.abs(s.top)>=Math.abs(s.left)?s.top<0?"up":"down":s.left<0?"left":"right";i.position={top:a,left:o},i.directionChanged=i.direction!==l,i.delta=s,!0===i.directionChanged&&(i.direction=l,i.inflectionPoint=i.position),t("scroll",{...i})}function l(){n=sa(a,e.scrollTarget),n.addEventListener("scroll",c,zl),c(!0)}function u(){void 0!==n&&(n.removeEventListener("scroll",c,zl),n=void 0)}function c(t){if(!0===t||0===e.debounce||"0"===e.debounce)s();else if(null===r){let[t,n]=e.debounce?[setTimeout(s,e.debounce),clearTimeout]:[requestAnimationFrame(s),cancelAnimationFrame];r=()=>{n(t),r=null}}}o(()=>e.scrollTarget,()=>{u(),l()});let{proxy:d}=k();return o(()=>d.$q.lang.rtl,s),m(()=>{a=d.$el.parentNode,l()}),g(()=>{r?.(),u()}),Object.assign(d,{trigger:c,getPosition:()=>i}),W}}),Il=$({name:"QLayout",props:{container:Boolean,view:{type:String,default:"hhh lpr fff",validator:e=>/^(h|l)h(h|r) lpr (f|l)f(f|r)$/.test(e.toLowerCase())},onScroll:Function,onScrollHeight:Function,onResize:Function},setup(e,{slots:t,emit:r}){let{proxy:{$q:s}}=k(),l=a(null),c=a(s.screen.height),d=a(!0===e.container?0:s.screen.width),h=a({position:0,direction:"down",inflectionPoint:0}),p=a(0),f=a(!0===I.value?0:_a()),m=i(()=>"q-layout q-layout--"+(!0===e.container?"containerized":"standard")),g=i(()=>!1===e.container?{minHeight:s.screen.height+"px"}:null),v=i(()=>0!==f.value?{[!0===s.lang.rtl?"left":"right"]:`${f.value}px`}:null),b=i(()=>0!==f.value?{[!0===s.lang.rtl?"right":"left"]:0,[!0===s.lang.rtl?"left":"right"]:`-${f.value}px`,width:`calc(100% + ${f.value}px)`}:null);function y(t){if(!0===e.container||!0!==document.qScrollPrevented){let n={position:t.position.top,direction:t.direction,directionChanged:t.directionChanged,inflectionPoint:t.inflectionPoint.top,delta:t.delta.top};h.value=n,void 0!==e.onScroll&&r("scroll",n)}}function x(t){let{height:n,width:a}=t,i=!1;c.value!==n&&(i=!0,c.value=n,void 0!==e.onScrollHeight&&r("scrollHeight",n),C()),d.value!==a&&(i=!0,d.value=a),!0===i&&void 0!==e.onResize&&r("resize",t)}function S({height:e}){p.value!==e&&(p.value=e,C())}function C(){if(!0===e.container){let e=c.value>p.value?_a():0;f.value!==e&&(f.value=e)}}let T=null,P={instances:{},view:i(()=>e.view),isContainer:i(()=>e.container),rootRef:l,height:c,containerHeight:p,scrollbarWidth:f,totalWidth:i(()=>d.value+f.value),rows:i(()=>{let t=e.view.toLowerCase().split(" ");return{top:t[0].split(""),middle:t[1].split(""),bottom:t[2].split("")}}),header:u({size:0,offset:0,space:!1}),right:u({size:300,offset:0,space:!1}),footer:u({size:0,offset:0,space:!1}),left:u({size:300,offset:0,space:!1}),scroll:h,animate(){null!==T?clearTimeout(T):document.body.classList.add("q-body--layout-animate"),T=setTimeout(()=>{T=null,document.body.classList.remove("q-body--layout-animate")},155)},update(e,t,n){P[e][t]=n}};if(w(Ae,P),_a()>0){let t=function(){i=null,r.classList.remove("hide-scrollbar")},n=function(){if(null===i){if(r.scrollHeight>s.screen.height)return;r.classList.add("hide-scrollbar")}else clearTimeout(i);i=setTimeout(t,300)},a=function(e){null!==i&&"remove"===e&&(clearTimeout(i),t()),window[`${e}EventListener`]("resize",n)},i=null,r=document.body;o(()=>!0!==e.container?"add":"remove",a),!0!==e.container&&a("add"),_(()=>{a("remove")})}return()=>{let a=pt(t.default,[n(Ol,{onScroll:y}),n(lo,{onResize:x})]),i=n("div",{class:m.value,style:g.value,ref:!0===e.container?void 0:l,tabindex:-1},a);return!0===e.container?n("div",{class:"q-layout-container overflow-hidden",ref:l},[n(lo,{onResize:S}),n("div",{class:"absolute-full",style:v.value},[n("div",{class:"scroll",style:b.value},[i])])]):i}}}),ql=["horizontal","vertical","cell","none"],Dl=$({name:"QMarkupTable",props:{...Nt,dense:Boolean,flat:Boolean,bordered:Boolean,square:Boolean,wrapCells:Boolean,separator:{type:String,default:"horizontal",validator:e=>ql.includes(e)}},setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q),r=i(()=>`q-markup-table q-table__container q-table__card q-table--${e.separator}-separator`+(!0===o.value?" q-table--dark q-table__card--dark q-dark":"")+(!0===e.dense?" q-table--dense":"")+(!0===e.flat?" q-table--flat":"")+(!0===e.bordered?" q-table--bordered":"")+(!0===e.square?" q-table--square":"")+(!1===e.wrapCells?" q-table--no-wrap":""));return()=>n("div",{class:r.value},[n("table",{class:"q-table"},dt(t.default))])}}),jl=$({name:"QNoSsr",props:{tag:{type:String,default:"div"},placeholder:String},setup(e,{slots:t}){let{isHydrated:a}=io();return()=>{if(!0===a.value){let a=dt(t.default);return void 0===a?a:a.length>1?n(e.tag,{},a):a[0]}let i={class:"q-no-ssr-placeholder"},o=dt(t.placeholder);return void 0!==o?o.length>1?n(e.tag,i,o):o[0]:void 0!==e.placeholder?n(e.tag,i,e.placeholder):void 0}}}),Bl=$({name:"QRadio",props:{...Nt,...ut,...ai,modelValue:{required:!0},val:{required:!0},label:String,leftLabel:Boolean,checkedIcon:String,uncheckedIcon:String,color:String,keepColor:Boolean,dense:Boolean,disable:Boolean,tabindex:[String,Number]},emits:["update:modelValue"],setup(e,{slots:t,emit:o}){let{proxy:r}=k(),l=Ot(e,r.$q),u=ct(e,Oi),c=a(null),{refocusTargetEl:d,refocusTarget:h}=Ni(e,c),p=i(()=>s(e.modelValue)===s(e.val)),f=i(()=>"q-radio cursor-pointer no-outline row inline no-wrap items-center"+(!0===e.disable?" disabled":"")+(!0===l.value?" q-radio--dark":"")+(!0===e.dense?" q-radio--dense":"")+(!0===e.leftLabel?" reverse":"")),m=i(()=>{let t=void 0===e.color||!0!==e.keepColor&&!0!==p.value?"":` text-${e.color}`;return`q-radio__inner relative-position q-radio__inner--${!0===p.value?"truthy":"falsy"}${t}`}),g=i(()=>(!0===p.value?e.checkedIcon:e.uncheckedIcon)||null),_=i(()=>!0===e.disable?-1:e.tabindex||0),v=oi(i(()=>{let t={type:"radio"};return void 0!==e.name&&Object.assign(t,{".checked":!0===p.value,"^checked":!0===p.value?"checked":void 0,name:e.name,value:e.val}),t}));function b(t){void 0!==t&&(J(t),h(t)),!0!==e.disable&&!0!==p.value&&o("update:modelValue",e.val,t)}function y(e){(13===e.keyCode||32===e.keyCode)&&J(e)}function w(e){(13===e.keyCode||32===e.keyCode)&&b(e)}Object.assign(r,{set:b});let x=n("svg",{key:"svg",class:"q-radio__bg absolute non-selectable",viewBox:"0 0 24 24"},[n("path",{d:"M12,22a10,10 0 0 1 -10,-10a10,10 0 0 1 10,-10a10,10 0 0 1 10,10a10,10 0 0 1 -10,10m0,-22a12,12 0 0 0 -12,12a12,12 0 0 0 12,12a12,12 0 0 0 12,-12a12,12 0 0 0 -12,-12"}),n("path",{class:"q-radio__check",d:"M12,6a6,6 0 0 0 -6,6a6,6 0 0 0 6,6a6,6 0 0 0 6,-6a6,6 0 0 0 -6,-6"})]);return()=>{let a=null!==g.value?[n("div",{key:"icon",class:"q-radio__icon-container absolute-full flex flex-center no-wrap"},[n(Mt,{class:"q-radio__icon",name:g.value})])]:[x];!0!==e.disable&&v(a,"unshift"," q-radio__native q-ma-none q-pa-none");let i=[n("div",{class:m.value,style:u.value,"aria-hidden":"true"},a)];null!==d.value&&i.push(d.value);let o=void 0!==e.label?pt(t.default,[e.label]):dt(t.default);return void 0!==o&&i.push(n("div",{class:"q-radio__label q-anchor--skip"},o)),n("div",{ref:c,class:f.value,tabindex:_.value,role:"radio","aria-label":e.label,"aria-checked":!0===p.value?"true":"false","aria-disabled":!0===e.disable?"true":void 0,onClick:b,onKeydown:y,onKeyup:w},i)}}}),Fl=$({name:"QToggle",props:{...Ii,icon:String,iconColor:String},emits:qi,setup:e=>Di("toggle",function(t,a){let o=i(()=>(!0===t.value?e.checkedIcon:!0===a.value?e.indeterminateIcon:e.uncheckedIcon)||e.icon),r=i(()=>!0===t.value?e.iconColor:null);return()=>[n("div",{class:"q-toggle__track"}),n("div",{class:"q-toggle__thumb absolute flex flex-center no-wrap"},void 0!==o.value?[n(Mt,{name:o.value,color:r.value})]:void 0)]})}),$l={radio:Bl,checkbox:ji,toggle:Fl},Vl=Object.keys($l);function Ul(e,t){if("function"==typeof e)return e;let n=void 0!==e?e:t;return e=>e[n]}var Hl=$({name:"QOptionGroup",props:{...Nt,modelValue:{required:!0},options:{type:Array,validator:e=>e.every(je),default:()=>[]},optionValue:[Function,String],optionLabel:[Function,String],optionDisable:[Function,String],name:String,type:{type:String,default:"radio",validator:e=>Vl.includes(e)},color:String,keepColor:Boolean,dense:Boolean,size:String,leftLabel:Boolean,inline:Boolean,disable:Boolean},emits:["update:modelValue"],setup(e,{emit:t,slots:a}){let{proxy:{$q:o}}=k(),r=Array.isArray(e.modelValue);"radio"===e.type?!0===r&&console.error("q-option-group: model should not be array"):!1===r&&console.error("q-option-group: model should be array in your case");let s=Ot(e,o),l=i(()=>$l[e.type]),u=i(()=>Ul(e.optionValue,"value")),c=i(()=>Ul(e.optionLabel,"label")),d=i(()=>Ul(e.optionDisable,"disable")),h=i(()=>e.options.map(t=>({val:u.value(t),name:void 0===t.name?e.name:t.name,disable:e.disable||d.value(t),leftLabel:void 0===t.leftLabel?e.leftLabel:t.leftLabel,color:void 0===t.color?e.color:t.color,checkedIcon:t.checkedIcon,uncheckedIcon:t.uncheckedIcon,dark:void 0===t.dark?s.value:t.dark,size:void 0===t.size?e.size:t.size,dense:e.dense,keepColor:void 0===t.keepColor?e.keepColor:t.keepColor}))),p=i(()=>"q-option-group q-gutter-x-sm"+(!0===e.inline?" q-option-group--inline":"")),f=i(()=>{let t={role:"group"};return"radio"===e.type&&(t.role="radiogroup",!0===e.disable&&(t["aria-disabled"]="true")),t});function m(e){t("update:modelValue",e)}return()=>n("div",{class:p.value,...f.value},e.options.map((t,i)=>{let o=void 0!==a["label-"+i]?()=>a["label-"+i](t):void 0!==a.label?()=>a.label(t):void 0;return n("div",[n(l.value,{label:void 0===o?c.value(t):null,modelValue:e.modelValue,"onUpdate:modelValue":m,...h.value[i]},o)])}))}}),Wl=$({name:"QPage",props:{padding:Boolean,styleFn:Function},setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=y(Ae,Oe);if(o===Oe)return console.error("QPage needs to be a deep child of QLayout"),Oe;if(y(Me,Oe)===Oe)return console.error("QPage needs to be child of QPageContainer"),Oe;let r=i(()=>{let t=(!0===o.header.space?o.header.size:0)+(!0===o.footer.space?o.footer.size:0);if("function"==typeof e.styleFn){let n=!0===o.isContainer.value?o.containerHeight.value:a.screen.height;return e.styleFn(t,n)}return{minHeight:!0===o.isContainer.value?o.containerHeight.value-t+"px":0===a.screen.height?0!==t?`calc(100vh - ${t}px)`:"100vh":a.screen.height-t+"px"}}),s=i(()=>"q-page"+(!0===e.padding?" q-layout-padding":""));return()=>n("main",{class:s.value,style:r.value},dt(t.default))}}),Gl=$({name:"QPageContainer",setup(e,{slots:t}){let{proxy:{$q:a}}=k(),o=y(Ae,Oe);if(o===Oe)return console.error("QPageContainer needs to be child of QLayout"),Oe;w(Me,!0);let r=i(()=>{let e={};return!0===o.header.space&&(e.paddingTop=`${o.header.size}px`),!0===o.right.space&&(e["padding"+(!0===a.lang.rtl?"Left":"Right")]=`${o.right.size}px`),!0===o.footer.space&&(e.paddingBottom=`${o.footer.size}px`),!0===o.left.space&&(e["padding"+(!0===a.lang.rtl?"Right":"Left")]=`${o.left.size}px`),e});return()=>n("div",{class:"q-page-container",style:r.value},dt(t.default))}}),Kl={position:{type:String,default:"bottom-right",validator:e=>["top-right","top-left","bottom-right","bottom-left","top","right","bottom","left"].includes(e)},offset:{type:Array,validator:e=>2===e.length},expand:Boolean};function Yl(){let{props:e,proxy:{$q:t}}=k(),a=y(Ae,Oe);if(a===Oe)return console.error("QPageSticky needs to be child of QLayout"),Oe;let o=i(()=>{let t=e.position;return{top:-1!==t.indexOf("top"),right:-1!==t.indexOf("right"),bottom:-1!==t.indexOf("bottom"),left:-1!==t.indexOf("left"),vertical:"top"===t||"bottom"===t,horizontal:"left"===t||"right"===t}}),r=i(()=>a.header.offset),s=i(()=>a.right.offset),l=i(()=>a.footer.offset),u=i(()=>a.left.offset),c=i(()=>{let n=0,a=0,i=o.value,c=!0===t.lang.rtl?-1:1;!0===i.top&&0!==r.value?a=`${r.value}px`:!0===i.bottom&&0!==l.value&&(a=-l.value+"px"),!0===i.left&&0!==u.value?n=c*u.value+"px":!0===i.right&&0!==s.value&&(n=-c*s.value+"px");let d={transform:`translate(${n}, ${a})`};return e.offset&&(d.margin=`${e.offset[1]}px ${e.offset[0]}px`),!0===i.vertical?(0!==u.value&&(d[!0===t.lang.rtl?"right":"left"]=`${u.value}px`),0!==s.value&&(d[!0===t.lang.rtl?"left":"right"]=`${s.value}px`)):!0===i.horizontal&&(0!==r.value&&(d.top=`${r.value}px`),0!==l.value&&(d.bottom=`${l.value}px`)),d}),d=i(()=>`q-page-sticky row flex-center fixed-${e.position} q-page-sticky--${!0===e.expand?"expand":"shrink"}`);return{$layout:a,getStickyContent:function(t){let a=dt(t.default);return n("div",{class:d.value,style:c.value},!0===e.expand?a:[n("div",a)])}}}var Ql=$({name:"QPageScroller",props:{...Kl,scrollOffset:{type:Number,default:1e3},reverse:Boolean,duration:{type:Number,default:300},offset:{...Kl.offset,default:()=>[18,18]}},emits:["click"],setup(e,{slots:t,emit:r}){let s,{proxy:{$q:l}}=k(),{$layout:u,getStickyContent:c}=Yl(),d=a(null),h=i(()=>u.height.value-(!0===u.isContainer.value?u.containerHeight.value:l.screen.height));function p(){return!0===e.reverse?h.value-u.scroll.value.position>e.scrollOffset:u.scroll.value.position>e.scrollOffset}let f=a(p());function m(){let e=p();f.value!==e&&(f.value=e)}function _(){!0===e.reverse?void 0===s&&(s=o(h,m)):v()}function v(){void 0!==s&&(s(),s=void 0)}function b(t){ma(sa(!0===u.isContainer.value?d.value:u.rootRef.value),!0===e.reverse?u.height.value:0,e.duration),r("click",t)}function y(){return!0===f.value?n("div",{ref:d,class:"q-page-scroller",onClick:b},c(t)):null}return o(u.scroll,m),o(()=>e.reverse,_),_(),g(v),()=>n(S,{name:"q-transition--fade"},y)}}),Zl=$({name:"QPageSticky",props:Kl,setup(e,{slots:t}){let{getStickyContent:n}=Yl();return()=>n(t)}});function Jl(e,t){return[!0,!1].includes(e)?e:t}var Xl=$({name:"QPagination",props:{...Nt,modelValue:{type:Number,required:!0},min:{type:[Number,String],default:1},max:{type:[Number,String],required:!0},maxPages:{type:[Number,String],default:0,validator:e=>("string"==typeof e?parseInt(e,10):e)>=0},inputStyle:[Array,String,Object],inputClass:[Array,String,Object],size:String,disable:Boolean,input:Boolean,iconPrev:String,iconNext:String,iconFirst:String,iconLast:String,toFn:Function,boundaryLinks:{type:Boolean,default:null},boundaryNumbers:{type:Boolean,default:null},directionLinks:{type:Boolean,default:null},ellipses:{type:Boolean,default:null},ripple:{type:[Boolean,Object],default:null},round:Boolean,rounded:Boolean,flat:Boolean,outline:Boolean,unelevated:Boolean,push:Boolean,glossy:Boolean,color:{type:String,default:"primary"},textColor:String,activeDesign:{type:String,default:"",values:e=>""===e||yn.includes(e)},activeColor:String,activeTextColor:String,gutter:String,padding:{type:String,default:"3px 2px"}},emits:["update:modelValue"],setup(e,{emit:t}){let{proxy:r}=k(),{$q:s}=r,l=Ot(e,s),u=i(()=>parseInt(e.min,10)),c=i(()=>parseInt(e.max,10)),d=i(()=>parseInt(e.maxPages,10)),h=i(()=>v.value+" / "+c.value),p=i(()=>Jl(e.boundaryLinks,e.input)),f=i(()=>Jl(e.boundaryNumbers,!e.input)),m=i(()=>Jl(e.directionLinks,e.input)),g=i(()=>Jl(e.ellipses,!e.input)),_=a(null),v=i({get:()=>e.modelValue,set:n=>{if(n=parseInt(n,10),e.disable||isNaN(n))return;let a=Je(n,u.value,c.value);e.modelValue!==a&&t("update:modelValue",a)}});o(()=>`${u.value}|${c.value}`,()=>{v.value=e.modelValue});let b=i(()=>"q-pagination row no-wrap items-center"+(!0===e.disable?" disabled":"")),y=i(()=>e.gutter in gn?`${gn[e.gutter]}px`:e.gutter||null),w=i(()=>null!==y.value?`--q-pagination-gutter-parent:-${y.value};--q-pagination-gutter-child:${y.value}`:null),x=i(()=>{let t=[e.iconFirst||s.iconSet.pagination.first,e.iconPrev||s.iconSet.pagination.prev,e.iconNext||s.iconSet.pagination.next,e.iconLast||s.iconSet.pagination.last];return!0===s.lang.rtl?t.reverse():t}),S=i(()=>({"aria-disabled":!0===e.disable?"true":"false",role:"navigation"})),C=i(()=>wn(e,"flat")),T=i(()=>({[C.value]:!0,round:e.round,rounded:e.rounded,padding:e.padding,color:e.color,textColor:e.textColor,size:e.size,ripple:null===e.ripple||e.ripple})),P=i(()=>{let t={[C.value]:!1};return""!==e.activeDesign&&(t[e.activeDesign]=!0),t}),E=i(()=>({...P.value,color:e.activeColor||e.color,textColor:e.activeTextColor||e.textColor})),A=i(()=>{let t=Math.max(d.value,1+(g.value?2:0)+(f.value?2:0)),n={pgFrom:u.value,pgTo:c.value,ellipsesStart:!1,ellipsesEnd:!1,boundaryStart:!1,boundaryEnd:!1,marginalStyle:{minWidth:`${Math.max(2,String(c.value).length)}em`}};return d.value&&tu.value+(f.value?1:0)&&(n.ellipsesStart=!0,n.pgFrom++),f.value&&(n.boundaryEnd=!0,n.pgTo--),g.value&&n.pgTo{M(a)}),n(An,o)}return Object.assign(r,{set:M,setByOffset:function(e){v.value=v.value+e}}),()=>{let t,a=[],i=[];if(!0===p.value&&(a.push(N({key:"bls",disable:e.disable||e.modelValue<=u.value,icon:x.value[0],"aria-label":s.lang.pagination.first},u.value)),i.unshift(N({key:"ble",disable:e.disable||e.modelValue>=c.value,icon:x.value[3],"aria-label":s.lang.pagination.last},c.value))),!0===m.value&&(a.push(N({key:"bdp",disable:e.disable||e.modelValue<=u.value,icon:x.value[1],"aria-label":s.lang.pagination.prev},e.modelValue-1)),i.unshift(N({key:"bdn",disable:e.disable||e.modelValue>=c.value,icon:x.value[2],"aria-label":s.lang.pagination.next},e.modelValue+1))),!0!==e.input){t=[];let{pgFrom:n,pgTo:o,marginalStyle:r}=A.value;if(!0===A.value.boundaryStart){let t=u.value===e.modelValue;a.push(N({key:"bns",style:r,disable:e.disable,label:u.value},u.value,t))}if(!0===A.value.boundaryEnd){let t=c.value===e.modelValue;i.unshift(N({key:"bne",style:r,disable:e.disable,label:c.value},c.value,t))}!0===A.value.ellipsesStart&&a.push(N({key:"bes",style:r,disable:e.disable,label:"…",ripple:!1},n-1)),!0===A.value.ellipsesEnd&&i.unshift(N({key:"bee",style:r,disable:e.disable,label:"…",ripple:!1},o+1));for(let a=n;a<=o;a++)t.push(N({key:`bpg${a}`,style:r,disable:e.disable,label:a},a,a===e.modelValue))}return n("div",{class:b.value,...S.value},[n("div",{class:"q-pagination__content row no-wrap items-center",style:w.value},[...a,!0===e.input?n(kl,{class:"inline",style:{width:h.value.length/1.5+"em"},type:"number",dense:!0,value:_.value,disable:e.disable,dark:l.value,borderless:!0,inputClass:e.inputClass,inputStyle:e.inputStyle,placeholder:h.value,min:u.value,max:c.value,"onUpdate:modelValue":R,onKeyup:z,onBlur:L}):n("div",{class:"q-pagination__middle row justify-center"},t),...i])])}}});function eu(e){let t,n,a=!1;function i(){n=arguments,!0!==a&&(a=!0,t=window.requestAnimationFrame(()=>{e.apply(this,n),n=void 0,a=!1}))}return i.cancel=()=>{window.cancelAnimationFrame(t),a=!1},i}var{passive:tu}=H,nu=$({name:"QParallax",props:{src:String,height:{type:Number,default:500},speed:{type:Number,default:1,validator:e=>e>=0&&e<=1},scrollTarget:oa,onScroll:Function},setup(e,{slots:t,emit:i}){let r,s,l,u,c,d,h=a(0),p=a(null),f=a(null),_=a(null);o(()=>e.height,()=>{!0===r&&b()}),o(()=>e.scrollTarget,()=>{!0===r&&(x(),k())});let v=t=>{h.value=t,void 0!==e.onScroll&&i("scroll",t)};function b(){let t,n,a;d===window?(t=0,a=n=window.innerHeight):(t=sn(d).top,n=ln(d),a=t+n);let i=sn(p.value).top,o=i+e.height;if(void 0!==c||o>t&&i{s.style.transform=`translate3d(-50%,${Math.round(e)}px,0)`};function w(){l=s.naturalHeight||s.videoHeight||ln(s),!0===r&&b()}function k(){r=!0,d=sa(p.value,e.scrollTarget),d.addEventListener("scroll",b,tu),window.addEventListener("resize",u,tu),b()}function x(){!0===r&&(r=!1,d.removeEventListener("scroll",b,tu),window.removeEventListener("resize",u,tu),d=void 0,y.cancel(),v.cancel(),u.cancel())}return m(()=>{y=eu(y),v=eu(v),u=eu(w),s=void 0!==t.media?f.value.children[0]:_.value,s.onload=s.onloadstart=s.loadedmetadata=w,w(),s.style.display="initial",void 0!==window.IntersectionObserver?(c=new IntersectionObserver(e=>{(!0===e[0].isIntersecting?k:x)()}),c.observe(p.value)):k()}),g(()=>{x(),c?.disconnect(),s.onload=s.onloadstart=s.loadedmetadata=null}),()=>n("div",{ref:p,class:"q-parallax",style:{height:`${e.height}px`}},[n("div",{ref:f,class:"q-parallax__media absolute-full"},void 0!==t.media?t.media():[n("img",{ref:_,src:e.src})]),n("div",{class:"q-parallax__content absolute-full column flex-center"},void 0!==t.content?t.content({percentScrolled:h.value}):dt(t.default))])}});function au(e,t=new WeakMap){if(Object(e)!==e)return e;if(t.has(e))return t.get(e);let n=e instanceof Date?new Date(e):e instanceof RegExp?new RegExp(e.source,e.flags):e instanceof Set?new Set:e instanceof Map?new Map:"function"!=typeof e.constructor?Object.create(null):void 0!==e.prototype&&"function"==typeof e.prototype.constructor?e:new e.constructor;if("function"==typeof e.constructor&&"function"==typeof e.valueOf){let n=e.valueOf();if(Object(n)!==n){let a=new e.constructor(n);return t.set(e,a),a}}return t.set(e,n),e instanceof Set?e.forEach(e=>{n.add(au(e,t))}):e instanceof Map&&e.forEach((e,a)=>{n.set(a,au(e,t))}),Object.assign(n,...Object.keys(e).map(n=>({[n]:au(e[n],t)})))}var iu=$({name:"QPopupEdit",props:{modelValue:{required:!0},title:String,buttons:Boolean,labelSet:String,labelCancel:String,color:{type:String,default:"primary"},validate:{type:Function,default:()=>!0},autoSave:Boolean,cover:{type:Boolean,default:!0},disable:Boolean},emits:["update:modelValue","save","cancel","beforeShow","show","beforeHide","hide"],setup(e,{slots:t,emit:o}){let{proxy:r}=k(),{$q:s}=r,l=a(null),u=a(""),c=a(""),h=!1,p=i(()=>z({initialValue:u.value,validate:e.validate,set:f,cancel:m,updatePosition:g},"value",()=>c.value,e=>{c.value=e}));function f(){!1!==e.validate(c.value)&&(!0===_()&&(o("save",c.value,u.value),o("update:modelValue",c.value)),v())}function m(){!0===_()&&o("cancel",c.value,u.value),v()}function g(){d(()=>{l.value.updatePosition()})}function _(){return!1===De(c.value,u.value)}function v(){h=!0,l.value.hide()}function b(){h=!1,u.value=au(e.modelValue),c.value=au(e.modelValue),o("beforeShow")}function y(){o("show")}function w(){!1===h&&!0===_()&&(!0===e.autoSave&&!0===e.validate(c.value)?(o("save",c.value,u.value),o("update:modelValue",c.value)):o("cancel",c.value,u.value)),o("beforeHide")}function x(){o("hide")}function S(){let a=void 0!==t.default?[].concat(t.default(p.value)):[];return e.title&&a.unshift(n("div",{class:"q-dialog__title q-mt-sm q-mb-sm"},e.title)),!0===e.buttons&&a.push(n("div",{class:"q-popup-edit__buttons row justify-center no-wrap"},[n(An,{flat:!0,color:e.color,label:e.labelCancel||s.lang.label.cancel,onClick:m}),n(An,{flat:!0,color:e.color,label:e.labelSet||s.lang.label.set,onClick:f})])),a}return Object.assign(r,{set:f,cancel:m,show(e){l.value?.show(e)},hide(e){l.value?.hide(e)},updatePosition:g}),()=>{if(!0!==e.disable)return n(Ka,{ref:l,class:"q-popup-edit",cover:e.cover,onBeforeShow:b,onShow:y,onBeforeHide:w,onHide:x,onEscapeKey:m},S)}}}),ou=$({name:"QPopupProxy",props:{...zn,breakpoint:{type:[String,Number],default:450}},emits:["show","hide"],setup(e,{slots:t,emit:r,attrs:s}){let{proxy:l}=k(),{$q:u}=l,c=a(!1),d=a(null),h=i(()=>parseInt(e.breakpoint,10)),{canShow:p}=Nn({showing:c});function f(){return u.screen.width"menu"===m.value?{maxHeight:"99vh"}:{});function _(e){c.value=!0,r("show",e)}function v(e){c.value=!1,m.value=f(),r("hide",e)}return o(()=>f(),e=>{!0!==c.value&&(m.value=e)}),Object.assign(l,{show(e){!0===p(e)&&d.value.show(e)},hide(e){d.value.hide(e)},toggle(e){d.value.toggle(e)}}),z(l,"currentComponent",()=>({type:m.value,ref:d.value})),()=>{let a,i={ref:d,...g.value,...s,onShow:_,onHide:v};return"dialog"===m.value?a=Yr:(a=Ka,Object.assign(i,{target:e.target,contextMenu:e.contextMenu,noParentEvent:!0,separateClosePopup:!0})),n(a,i,t.default)}}}),ru={xs:2,sm:4,md:6,lg:10,xl:14};function su(e,t,n){return{transform:!0===t?`translateX(${!0===n.lang.rtl?"-":""}100%) scale3d(${-e},1,1)`:`scale3d(${e},1,1)`}}var lu=$({name:"QLinearProgress",props:{...Nt,...ut,value:{type:Number,default:0},buffer:Number,color:String,trackColor:String,reverse:Boolean,stripe:Boolean,indeterminate:Boolean,query:Boolean,rounded:Boolean,animationSpeed:{type:[String,Number],default:2100},instantFeedback:Boolean},setup(e,{slots:t}){let{proxy:a}=k(),o=Ot(e,a.$q),r=ct(e,ru),s=i(()=>!0===e.indeterminate||!0===e.query),l=i(()=>e.reverse!==e.query),u=i(()=>({...null!==r.value?r.value:{},"--q-linear-progress-speed":`${e.animationSpeed}ms`})),c=i(()=>"q-linear-progress"+(void 0!==e.color?` text-${e.color}`:"")+(!0===e.reverse||!0===e.query?" q-linear-progress--reverse":"")+(!0===e.rounded?" rounded-borders":"")),d=i(()=>su(void 0!==e.buffer?e.buffer:1,l.value,a.$q)),h=i(()=>`with${!0===e.instantFeedback?"out":""}-transition`),p=i(()=>`q-linear-progress__track absolute-full q-linear-progress__track--${h.value} q-linear-progress__track--${!0===o.value?"dark":"light"}`+(void 0!==e.trackColor?` bg-${e.trackColor}`:"")),f=i(()=>su(!0===s.value?1:e.value,l.value,a.$q)),m=i(()=>`q-linear-progress__model absolute-full q-linear-progress__model--${h.value} q-linear-progress__model--${!0===s.value?"in":""}determinate`),g=i(()=>({width:100*e.value+"%"})),_=i(()=>`q-linear-progress__stripe absolute-${!0===e.reverse?"right":"left"} q-linear-progress__stripe--${h.value}`);return()=>{let a=[n("div",{class:p.value,style:d.value}),n("div",{class:m.value,style:f.value})];return!0===e.stripe&&!1===s.value&&a.push(n("div",{class:_.value,style:g.value})),n("div",{class:c.value,style:u.value,role:"progressbar","aria-valuemin":0,"aria-valuemax":1,"aria-valuenow":!0===e.indeterminate?void 0:e.value},pt(t.default,a))}}}),uu=40,cu=$({name:"QPullToRefresh",props:{color:String,bgColor:String,icon:String,noMouse:Boolean,disable:Boolean,scrollTarget:oa},emits:["refresh"],setup(e,{slots:t,emit:r}){let{proxy:s}=k(),{$q:l}=s,u=a("pull"),c=a(0),d=a(!1),h=a(-40),p=a(!1),f=a({}),_=i(()=>({opacity:c.value,transform:`translateY(${h.value}px) rotate(${360*c.value}deg)`})),v=i(()=>"q-pull-to-refresh__puller row flex-center"+(!0===p.value?" q-pull-to-refresh__puller--animating":"")+(void 0!==e.bgColor?` bg-${e.bgColor}`:""));function b(e){if(!0===e.isFinal)return void(!0===d.value&&(d.value=!1,"pulled"===u.value?(u.value="refreshing",T({pos:20}),x()):"pull"===u.value&&T({pos:-40,ratio:0})));if(!0===p.value||"refreshing"===u.value)return!1;if(!0===e.isFirst){if(0!==ua(S)||"down"!==e.direction)return!0===d.value&&(d.value=!1,u.value="pull",T({pos:-40,ratio:0})),!1;d.value=!0;let{top:t,left:n}=s.$el.getBoundingClientRect();f.value={top:t+"px",left:n+"px",width:window.getComputedStyle(s.$el).getPropertyValue("width")}}Z(e.evt);let t=Math.min(140,Math.max(0,e.distance.y));h.value=t-uu,c.value=Je(t/60,0,1);let n=h.value>20?"pulled":"pull";u.value!==n&&(u.value=n)}let y=i(()=>{let t={down:!0};return!0!==e.noMouse&&(t.mouse=!0),[[Ki,b,void 0,t]]}),w=i(()=>"q-pull-to-refresh__content"+(!0===d.value?" no-pointer-events":""));function x(){r("refresh",()=>{T({pos:-40,ratio:0},()=>{u.value="pull"})})}let S,C=null;function T({pos:e,ratio:t},n){p.value=!0,h.value=e,void 0!==t&&(c.value=t),null!==C&&clearTimeout(C),C=setTimeout(()=>{C=null,p.value=!1,n?.()},300)}function P(){S=sa(s.$el,e.scrollTarget)}return o(()=>e.scrollTarget,P),m(P),g(()=>{null!==C&&clearTimeout(C)}),Object.assign(s,{trigger:x,updateScrollTarget:P}),()=>mt("div",{class:"q-pull-to-refresh"},[n("div",{class:w.value},dt(t.default)),n("div",{class:"q-pull-to-refresh__puller-container fixed row flex-center no-pointer-events z-top",style:f.value},[n("div",{class:v.value,style:_.value},["refreshing"!==u.value?n(Mt,{name:e.icon||l.iconSet.pullToRefresh.icon,color:e.color,size:"32px"}):n(rn,{size:"24px",color:e.color})])])],"main",!1===e.disable,()=>y.value)}}),du=0,hu=1,pu=2,fu=$({name:"QRange",props:{...Xi,modelValue:{type:Object,default:()=>({min:null,max:null}),validator:e=>"min"in e&&"max"in e},dragRange:Boolean,dragOnlyRange:Boolean,leftLabelColor:String,leftLabelTextColor:String,rightLabelColor:String,rightLabelTextColor:String,leftLabelValue:[String,Number],rightLabelValue:[String,Number],leftThumbColor:String,rightThumbColor:String},emits:eo,setup(e,{emit:t}){let{proxy:{$q:r}}=k(),{state:s,methods:l}=to({updateValue:A,updatePosition:function(t,n=s.dragging.value){let a,i=l.getDraggingRatio(t,n),o=l.convertRatioToModel(i);switch(n.type){case du:i<=n.ratioMax?(a={minR:i,maxR:n.ratioMax,min:o,max:n.valueMax},s.focus.value="min"):(a={minR:n.ratioMax,maxR:i,min:n.valueMax,max:o},s.focus.value="max");break;case pu:i>=n.ratioMin?(a={minR:n.ratioMin,maxR:i,min:n.valueMin,max:o},s.focus.value="max"):(a={minR:i,maxR:n.ratioMin,min:o,max:n.valueMin},s.focus.value="min");break;case hu:let e=i-n.offsetRatio,t=Je(n.ratioMin+e,s.innerMinRatio.value,s.innerMaxRatio.value-n.rangeRatio),r=o-n.offsetModel,l=Je(n.valueMin+r,s.innerMin.value,s.innerMax.value-n.rangeValue);a={minR:t,maxR:t+n.rangeRatio,min:s.roundValueFn.value(l),max:s.roundValueFn.value(l+n.rangeValue)},s.focus.value="both"}h.value=null===h.value.min||null===h.value.max?{min:a.min||e.min,max:a.max||e.max}:{min:a.min,max:a.max},!0!==e.snap||0===e.step?(c.value=a.minR,d.value=a.maxR):(c.value=l.convertModelToRatio(h.value.min),d.value=l.convertModelToRatio(h.value.max))},getDragging:function(t){let{left:n,top:a,width:i,height:o}=u.value.getBoundingClientRect(),r=!0===e.dragOnlyRange?0:!0===e.vertical?S.value.offsetHeight/(2*o):S.value.offsetWidth/(2*i),s={left:n,top:a,width:i,height:o,valueMin:h.value.min,valueMax:h.value.max,ratioMin:f.value,ratioMax:m.value},c=l.getDraggingRatio(t,s);return!0!==e.dragOnlyRange&&c({type:"hidden",name:e.name,value:`${e.modelValue.min}|${e.modelValue.max}`}))}),u=a(null),c=a(0),d=a(0),h=a({min:0,max:0});function p(){h.value.min=null===e.modelValue.min?s.innerMin.value:Je(e.modelValue.min,s.innerMin.value,s.innerMax.value),h.value.max=null===e.modelValue.max?s.innerMax.value:Je(e.modelValue.max,s.innerMin.value,s.innerMax.value)}o(()=>`${e.modelValue.min}|${e.modelValue.max}|${s.innerMin.value}|${s.innerMax.value}`,p),p();let f=i(()=>l.convertModelToRatio(h.value.min)),m=i(()=>l.convertModelToRatio(h.value.max)),g=i(()=>!0===s.active.value?c.value:f.value),_=i(()=>!0===s.active.value?d.value:m.value),v=i(()=>{let t={[s.positionProp.value]:100*g.value+"%",[s.sizeProp.value]:100*(_.value-g.value)+"%"};return void 0!==e.selectionImg&&(t.backgroundImage=`url(${e.selectionImg}) !important`),t}),b=i(()=>{if(!0!==s.editable.value)return{};if(!0===r.platform.is.mobile)return{onClick:l.onMobileClick};let t={onMousedown:l.onActivate};return(!0===e.dragRange||!0===e.dragOnlyRange)&&Object.assign(t,{onFocus:()=>{s.focus.value="both"},onBlur:l.onBlur,onKeydown:M,onKeyup:l.onKeyup}),t});function y(t){return!0!==r.platform.is.mobile&&!0===s.editable.value&&!0!==e.dragOnlyRange?{onFocus:()=>{s.focus.value=t},onBlur:l.onBlur,onKeydown:M,onKeyup:l.onKeyup}:{}}let w=i(()=>!0!==e.dragOnlyRange?s.tabindex.value:null),x=i(()=>!0===r.platform.is.mobile||!e.dragRange&&!0!==e.dragOnlyRange?null:s.tabindex.value),S=a(null),C=i(()=>y("min")),T=l.getThumbRenderFn({focusValue:"min",getNodeData:()=>({ref:S,key:"tmin",...C.value,tabindex:w.value}),ratio:g,label:i(()=>void 0!==e.leftLabelValue?e.leftLabelValue:h.value.min),thumbColor:i(()=>e.leftThumbColor||e.thumbColor||e.color),labelColor:i(()=>e.leftLabelColor||e.labelColor),labelTextColor:i(()=>e.leftLabelTextColor||e.labelTextColor)}),P=i(()=>y("max")),E=l.getThumbRenderFn({focusValue:"max",getNodeData:()=>({...P.value,key:"tmax",tabindex:w.value}),ratio:_,label:i(()=>void 0!==e.rightLabelValue?e.rightLabelValue:h.value.max),thumbColor:i(()=>e.rightThumbColor||e.thumbColor||e.color),labelColor:i(()=>e.rightLabelColor||e.labelColor),labelTextColor:i(()=>e.rightLabelTextColor||e.labelTextColor)});function A(n){(h.value.min!==e.modelValue.min||h.value.max!==e.modelValue.max)&&t("update:modelValue",{...h.value}),!0===n&&t("change",{...h.value})}function M(t){if(!1===Ji.includes(t.keyCode))return;J(t);let n=([34,33].includes(t.keyCode)?10:1)*s.keyStep.value,a=([34,37,40].includes(t.keyCode)?-1:1)*(!0===s.isReversed.value?-1:1)*(!0===e.vertical?-1:1)*n;if("both"===s.focus.value){let e=h.value.max-h.value.min,t=Je(s.roundValueFn.value(h.value.min+a),s.innerMin.value,s.innerMax.value-e);h.value={min:t,max:s.roundValueFn.value(t+e)}}else{if(!1===s.focus.value)return;{let e=s.focus.value;h.value={...h.value,[e]:Je(s.roundValueFn.value(h.value[e]+a),"min"===e?s.innerMin.value:h.value.min,"max"===e?s.innerMax.value:h.value.max)}}}A()}return()=>{let t=l.getContent(v,x,b,e=>{e.push(T(),E())});return n("div",{ref:u,class:"q-range "+s.classes.value+(null===e.modelValue.min||null===e.modelValue.max?" q-slider--no-value":""),...s.attributes.value,"aria-valuenow":e.modelValue.min+"|"+e.modelValue.max},t)}}}),mu=$({name:"QRating",props:{...ut,...ai,modelValue:{type:Number,required:!0},max:{type:[String,Number],default:5},icon:[String,Array],iconHalf:[String,Array],iconSelected:[String,Array],iconAriaLabel:[String,Array],color:[String,Array],colorHalf:[String,Array],colorSelected:[String,Array],noReset:Boolean,noDimming:Boolean,readonly:Boolean,disable:Boolean},emits:["update:modelValue"],setup(e,{slots:t,emit:o}){let{proxy:{$q:r}}=k(),s=ct(e),l=oi(ii(e)),u=a(0),c={},d=i(()=>!0!==e.readonly&&!0!==e.disable),h=i(()=>`q-rating row inline items-center q-rating--${!0===d.value?"":"non-"}editable`+(!0===e.noDimming?" q-rating--no-dimming":"")+(!0===e.disable?" disabled":"")+(void 0!==e.color&&!1===Array.isArray(e.color)?` text-${e.color}`:"")),p=i(()=>{let t=!0===Array.isArray(e.icon)?e.icon.length:0,n=!0===Array.isArray(e.iconSelected)?e.iconSelected.length:0,a=!0===Array.isArray(e.iconHalf)?e.iconHalf.length:0,i=!0===Array.isArray(e.color)?e.color.length:0,o=!0===Array.isArray(e.colorSelected)?e.colorSelected.length:0,r=!0===Array.isArray(e.colorHalf)?e.colorHalf.length:0;return{iconLen:t,icon:t>0?e.icon[t-1]:e.icon,selIconLen:n,selIcon:n>0?e.iconSelected[n-1]:e.iconSelected,halfIconLen:a,halfIcon:a>0?e.iconHalf[n-1]:e.iconHalf,colorLen:i,color:i>0?e.color[i-1]:e.color,selColorLen:o,selColor:o>0?e.colorSelected[o-1]:e.colorSelected,halfColorLen:r,halfColor:r>0?e.colorHalf[r-1]:e.colorHalf}}),f=i(()=>{if("string"==typeof e.iconAriaLabel){let t=0!==e.iconAriaLabel.length?`${e.iconAriaLabel} `:"";return e=>`${t}${e}`}if(!0===Array.isArray(e.iconAriaLabel)){let t=e.iconAriaLabel.length;if(t>0)return n=>e.iconAriaLabel[Math.min(n,t)-1]}return(e,t)=>`${t} ${e}`}),m=i(()=>{let t=[],n=p.value,a=Math.ceil(e.modelValue),i=!0===d.value?0:null,o=void 0===e.iconHalf||a===e.modelValue?-1:a;for(let s=1;s<=e.max;s++){let l=0===u.value&&e.modelValue>=s||u.value>0&&u.value>=s,c=o===s&&u.value0&&(!0===c?a:e.modelValue)>=s&&u.value{let t={role:"radiogroup"};return!0===e.disable&&(t["aria-disabled"]="true"),!0===e.readonly&&(t["aria-readonly"]="true"),t});function _(t){if(!0===d.value){let n=Je(parseInt(t,10),1,parseInt(e.max,10)),a=!0!==e.noReset&&e.modelValue===n?0:n;a!==e.modelValue&&o("update:modelValue",a),u.value=0}}function b(e){!0===d.value&&(u.value=e)}function y(){u.value=0}return v(()=>{c={}}),()=>{let a=[];return m.value.forEach(({iconClass:e,name:i,attrs:o},r)=>{let s=r+1;a.push(n("div",{key:s,ref:e=>{c[`rt${s}`]=e},class:"q-rating__icon-container flex flex-center",...o,onClick(){_(s)},onMouseover(){b(s)},onMouseout:y,onFocus(){b(s)},onBlur:y,onKeyup(e){!function(e,t){switch(e.keyCode){case 13:case 32:return _(t),J(e);case 37:case 40:return c["rt"+(t-1)]&&c["rt"+(t-1)].focus(),J(e);case 39:case 38:c[`rt${t+1}`]&&c[`rt${t+1}`].focus(),J(e)}}(e,s)}},pt(t[`tip-${s}`],[n(Mt,{class:e,name:i})])))}),void 0!==e.name&&!0!==e.disable&&l(a,"push"),n("div",{class:h.value,style:s.value,...g.value},a)}}}),gu=$({name:"QResponsive",props:tl,setup(e,{slots:t}){let a=nl(e);return()=>n("div",{class:"q-responsive"},[n("div",{class:"q-responsive__filler overflow-hidden"},[n("div",{style:a.value})]),n("div",{class:"q-responsive__content absolute-full fit"},dt(t.default))])}}),_u=$({props:["store","barStyle","verticalBarStyle","horizontalBarStyle"],setup:e=>()=>[n("div",{class:e.store.scroll.vertical.barClass.value,style:[e.barStyle,e.verticalBarStyle],"aria-hidden":"true",onMousedown:e.store.onVerticalMousedown}),n("div",{class:e.store.scroll.horizontal.barClass.value,style:[e.barStyle,e.horizontalBarStyle],"aria-hidden":"true",onMousedown:e.store.onHorizontalMousedown}),A(n("div",{ref:e.store.scroll.vertical.ref,class:e.store.scroll.vertical.thumbClass.value,style:e.store.scroll.vertical.style.value,"aria-hidden":"true"}),e.store.thumbVertDir),A(n("div",{ref:e.store.scroll.horizontal.ref,class:e.store.scroll.horizontal.thumbClass.value,style:e.store.scroll.horizontal.style.value,"aria-hidden":"true"}),e.store.thumbHorizDir)]}),vu=["vertical","horizontal"],bu={vertical:{offset:"offsetY",scroll:"scrollTop",dir:"down",dist:"y"},horizontal:{offset:"offsetX",scroll:"scrollLeft",dir:"right",dist:"x"}},yu={prevent:!0,mouse:!0,mouseAllDir:!0},wu=e=>e>=250?50:Math.ceil(e/5),ku=$({name:"QScrollArea",props:{...Nt,thumbStyle:Object,verticalThumbStyle:Object,horizontalThumbStyle:Object,barStyle:[Array,String,Object],verticalBarStyle:[Array,String,Object],horizontalBarStyle:[Array,String,Object],verticalOffset:{type:Array,default:[0,0]},horizontalOffset:{type:Array,default:[0,0]},contentStyle:[Array,String,Object],contentActiveStyle:[Array,String,Object],delay:{type:[String,Number],default:1e3},visible:{type:Boolean,default:null},tabindex:[String,Number],onScroll:Function},setup(e,{slots:t,emit:r}){let s,l=a(!1),u=a(!1),c=a(!1),d={vertical:a(0),horizontal:a(0)},f={vertical:{ref:a(null),position:a(0),size:a(0)},horizontal:{ref:a(null),position:a(0),size:a(0)}},{proxy:m}=k(),_=Ot(e,m.$q),v=null,b=a(null),y=i(()=>"q-scrollarea"+(!0===_.value?" q-scrollarea--dark":""));Object.assign(d,{verticalInner:i(()=>d.vertical.value-e.verticalOffset[0]-e.verticalOffset[1]),horizontalInner:i(()=>d.horizontal.value-e.horizontalOffset[0]-e.horizontalOffset[1])}),f.vertical.percentage=i(()=>{let e=f.vertical.size.value-d.vertical.value;if(e<=0)return 0;let t=Je(f.vertical.position.value/e,0,1);return Math.round(1e4*t)/1e4}),f.vertical.thumbHidden=i(()=>!0!==(null===e.visible?c.value:e.visible)&&!1===l.value&&!1===u.value||f.vertical.size.value<=d.vertical.value+1),f.vertical.thumbStart=i(()=>e.verticalOffset[0]+f.vertical.percentage.value*(d.verticalInner.value-f.vertical.thumbSize.value)),f.vertical.thumbSize=i(()=>Math.round(Je(d.verticalInner.value*d.verticalInner.value/f.vertical.size.value,wu(d.verticalInner.value),d.verticalInner.value))),f.vertical.style=i(()=>({...e.thumbStyle,...e.verticalThumbStyle,top:`${f.vertical.thumbStart.value}px`,height:`${f.vertical.thumbSize.value}px`,right:`${e.horizontalOffset[1]}px`})),f.vertical.thumbClass=i(()=>"q-scrollarea__thumb q-scrollarea__thumb--v absolute-right"+(!0===f.vertical.thumbHidden.value?" q-scrollarea__thumb--invisible":"")),f.vertical.barClass=i(()=>"q-scrollarea__bar q-scrollarea__bar--v absolute-right"+(!0===f.vertical.thumbHidden.value?" q-scrollarea__bar--invisible":"")),f.horizontal.percentage=i(()=>{let e=f.horizontal.size.value-d.horizontal.value;if(e<=0)return 0;let t=Je(Math.abs(f.horizontal.position.value)/e,0,1);return Math.round(1e4*t)/1e4}),f.horizontal.thumbHidden=i(()=>!0!==(null===e.visible?c.value:e.visible)&&!1===l.value&&!1===u.value||f.horizontal.size.value<=d.horizontal.value+1),f.horizontal.thumbStart=i(()=>e.horizontalOffset[0]+f.horizontal.percentage.value*(d.horizontalInner.value-f.horizontal.thumbSize.value)),f.horizontal.thumbSize=i(()=>Math.round(Je(d.horizontalInner.value*d.horizontalInner.value/f.horizontal.size.value,wu(d.horizontalInner.value),d.horizontalInner.value))),f.horizontal.style=i(()=>({...e.thumbStyle,...e.horizontalThumbStyle,[!0===m.$q.lang.rtl?"right":"left"]:`${f.horizontal.thumbStart.value}px`,width:`${f.horizontal.thumbSize.value}px`,bottom:`${e.verticalOffset[1]}px`})),f.horizontal.thumbClass=i(()=>"q-scrollarea__thumb q-scrollarea__thumb--h absolute-bottom"+(!0===f.horizontal.thumbHidden.value?" q-scrollarea__thumb--invisible":"")),f.horizontal.barClass=i(()=>"q-scrollarea__bar q-scrollarea__bar--h absolute-bottom"+(!0===f.horizontal.thumbHidden.value?" q-scrollarea__bar--invisible":""));let w=i(()=>!0===f.vertical.thumbHidden.value&&!0===f.horizontal.thumbHidden.value?e.contentStyle:e.contentActiveStyle);function x(){let e={};return vu.forEach(t=>{let n=f[t];Object.assign(e,{[t+"Position"]:n.position.value,[t+"Percentage"]:n.percentage.value,[t+"Size"]:n.size.value,[t+"ContainerSize"]:d[t].value,[t+"ContainerInnerSize"]:d[t+"Inner"].value})}),e}let S=ae(()=>{let e=x();e.ref=m,r("scroll",e)},0);function C(e,t,n){!1!==vu.includes(e)?("vertical"===e?ma:ga)(b.value,t,n):console.error("[QScrollArea]: wrong first param of setScrollPosition (vertical/horizontal)")}function T({height:e,width:t}){let n=!1;d.vertical.value!==e&&(d.vertical.value=e,n=!0),d.horizontal.value!==t&&(d.horizontal.value=t,n=!0),!0===n&&L()}function P({position:e}){let t=!1;f.vertical.position.value!==e.top&&(f.vertical.position.value=e.top,t=!0),f.horizontal.position.value!==e.left&&(f.horizontal.position.value=e.left,t=!0),!0===t&&L()}function E({height:e,width:t}){f.horizontal.size.value!==t&&(f.horizontal.size.value=t,L()),f.vertical.size.value!==e&&(f.vertical.size.value=e,L())}function A(e,t){let n=f[t];if(!0===e.isFirst){if(!0===n.thumbHidden.value)return;s=n.position.value,u.value=!0}else if(!0!==u.value)return;!0===e.isFinal&&(u.value=!1);let a=bu[t],i=(n.size.value-d[t].value)/(d[t+"Inner"].value-n.thumbSize.value),o=e.distance[a.dist];R(s+(e.direction===a.dir?1:-1)*o*i,t)}function M(t,n){let a=f[n];if(!0!==a.thumbHidden.value){let i="vertical"===n?e.verticalOffset[0]:e.horizontalOffset[0],o=t[bu[n].offset]-i,r=a.thumbStart.value-i;if(or+a.thumbSize.value){R(Je((o-a.thumbSize.value/2)/(d[n+"Inner"].value-a.thumbSize.value),0,1)*Math.max(0,a.size.value-d[n].value),n)}null!==a.ref.value&&a.ref.value.dispatchEvent(new MouseEvent(t.type,t))}}function L(){l.value=!0,null!==v&&clearTimeout(v),v=setTimeout(()=>{v=null,l.value=!1},e.delay),void 0!==e.onScroll&&S()}function R(e,t){b.value[bu[t].scroll]=e}let z=null;function N(){null!==z&&clearTimeout(z),z=setTimeout(()=>{z=null,c.value=!0},m.$q.platform.is.ios?50:0)}function O(){null!==z&&(clearTimeout(z),z=null),c.value=!1}let I=null;o(()=>m.$q.lang.rtl,e=>{null!==b.value&&ga(b.value,Math.abs(f.horizontal.position.value)*(!0===e?-1:1))}),p(()=>{I={top:f.vertical.position.value,left:f.horizontal.position.value}}),h(()=>{if(null===I)return;let e=b.value;null!==e&&(ga(e,I.left),ma(e,I.top))}),g(S.cancel),Object.assign(m,{getScrollTarget:()=>b.value,getScroll:x,getScrollPosition:()=>({top:f.vertical.position.value,left:f.horizontal.position.value}),getScrollPercentage:()=>({top:f.vertical.percentage.value,left:f.horizontal.percentage.value}),setScrollPosition:C,setScrollPercentage(e,t,n){C(e,t*(f[e].size.value-d[e].value)*("horizontal"===e&&!0===m.$q.lang.rtl?-1:1),n)}});let q={scroll:f,thumbVertDir:[[Ki,e=>{A(e,"vertical")},void 0,{vertical:!0,...yu}]],thumbHorizDir:[[Ki,e=>{A(e,"horizontal")},void 0,{horizontal:!0,...yu}]],onVerticalMousedown(e){M(e,"vertical")},onHorizontalMousedown(e){M(e,"horizontal")}};return()=>n("div",{class:y.value,onMouseenter:N,onMouseleave:O},[n("div",{ref:b,class:"q-scrollarea__container scroll relative-position fit hide-scrollbar",tabindex:void 0!==e.tabindex?e.tabindex:void 0},[n("div",{class:"q-scrollarea__content absolute",style:w.value},pt(t.default,[n(lo,{debounce:0,onResize:E})])),n(Ol,{axis:"both",onScroll:P})]),n(lo,{debounce:0,onResize:T}),n(_u,{store:q,barStyle:e.barStyle,verticalBarStyle:e.verticalBarStyle,horizontalBarStyle:e.horizontalBarStyle})])}}),xu=1e3,Su=["start","center","end","start-force","center-force","end-force"],Cu=Array.prototype.filter,Tu=void 0===window.getComputedStyle(document.body).overflowAnchor?W:function(e,t){null!==e&&(void 0!==e._qOverflowAnimationFrame&&cancelAnimationFrame(e._qOverflowAnimationFrame),e._qOverflowAnimationFrame=requestAnimationFrame(()=>{if(null===e)return;e._qOverflowAnimationFrame=void 0;let n=e.children||[];Cu.call(n,e=>e.dataset&&void 0!==e.dataset.qVsAnchor).forEach(e=>{delete e.dataset.qVsAnchor});let a=n[t];a?.dataset&&(a.dataset.qVsAnchor="")}))};function Pu(e,t){return e+t}function Eu(e,t,n,a,i,o,r,s){let l=e===window?document.scrollingElement||document.documentElement:e,u=!0===i?"offsetWidth":"offsetHeight",c={scrollStart:0,scrollViewSize:-r-s,scrollMaxSize:0,offsetStart:-r,offsetEnd:-s};if(!0===i?(e===window?(c.scrollStart=window.pageXOffset||window.scrollX||document.body.scrollLeft||0,c.scrollViewSize+=document.documentElement.clientWidth):(c.scrollStart=l.scrollLeft,c.scrollViewSize+=l.clientWidth),c.scrollMaxSize=l.scrollWidth,!0===o&&(c.scrollStart=(!0===oo?c.scrollMaxSize-c.scrollViewSize:0)-c.scrollStart)):(e===window?(c.scrollStart=window.pageYOffset||window.scrollY||document.body.scrollTop||0,c.scrollViewSize+=document.documentElement.clientHeight):(c.scrollStart=l.scrollTop,c.scrollViewSize+=l.clientHeight),c.scrollMaxSize=l.scrollHeight),null!==n)for(let e=n.previousElementSibling;null!==e;e=e.previousElementSibling)!1===e.classList.contains("q-virtual-scroll--skip")&&(c.offsetStart+=e[u]);if(null!==a)for(let e=a.nextElementSibling;null!==e;e=e.nextElementSibling)!1===e.classList.contains("q-virtual-scroll--skip")&&(c.offsetEnd+=e[u]);if(t!==e){let n=l.getBoundingClientRect(),a=t.getBoundingClientRect();!0===i?(c.offsetStart+=a.left-n.left,c.offsetEnd-=a.width):(c.offsetStart+=a.top-n.top,c.offsetEnd-=a.height),e!==window&&(c.offsetStart+=c.scrollStart),c.offsetEnd+=c.scrollMaxSize-c.offsetStart}return c}function Au(e,t,n,a){"end"===t&&(t=(e===window?document.body:e)[!0===n?"scrollWidth":"scrollHeight"]),e===window?!0===n?(!0===a&&(t=(!0===oo?document.body.scrollWidth-document.documentElement.clientWidth:0)-t),window.scrollTo(t,window.pageYOffset||window.scrollY||document.body.scrollTop||0)):window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,t):!0===n?(!0===a&&(t=(!0===oo?e.scrollWidth-e.offsetWidth:0)-t),e.scrollLeft=t):e.scrollTop=t}function Mu(e,t,n,a){if(n>=a)return 0;let i=t.length,o=Math.floor(n/xu),r=Math.floor((a-1)/xu)+1,s=e.slice(o,r).reduce(Pu,0);return n%xu!==0&&(s-=t.slice(o*xu,n).reduce(Pu,0)),a%xu!==0&&a!==i&&(s-=t.slice(a,r*xu).reduce(Pu,0)),s}var Lu={virtualScrollSliceSize:{type:[Number,String],default:10},virtualScrollSliceRatioBefore:{type:[Number,String],default:1},virtualScrollSliceRatioAfter:{type:[Number,String],default:1},virtualScrollItemSize:{type:[Number,String],default:24},virtualScrollStickySizeStart:{type:[Number,String],default:0},virtualScrollStickySizeEnd:{type:[Number,String],default:0},tableColspan:[Number,String]},Ru=Object.keys(Lu),zu={virtualScrollHorizontal:Boolean,onVirtualScroll:Function,...Lu};function Nu({virtualScrollLength:e,getVirtualScrollTarget:t,getVirtualScrollEl:r,virtualScrollItemSizeComputed:s}){let l,u,c,m,_=k(),{props:v,emit:b,proxy:y}=_,{$q:w}=y,x=[],S=a(0),C=a(0),T=a({}),P=a(null),E=a(null),A=a(null),M=a({from:0,to:0}),L=i(()=>void 0!==v.tableColspan?v.tableColspan:100);void 0===s&&(s=i(()=>v.virtualScrollItemSize));let R=i(()=>s.value+";"+v.virtualScrollHorizontal),z=i(()=>R.value+";"+v.virtualScrollSliceRatioBefore+";"+v.virtualScrollSliceRatioAfter);function N(){B(u,!0)}function O(e){B(void 0===e?u:e)}function I(n,a){let i=t();if(null==i||8===i.nodeType)return;let o=Eu(i,r(),P.value,E.value,v.virtualScrollHorizontal,w.lang.rtl,v.virtualScrollStickySizeStart,v.virtualScrollStickySizeEnd);c!==o.scrollViewSize&&F(o.scrollViewSize),q(i,o,Math.min(e.value-1,Math.max(0,parseInt(n,10)||0)),0,-1!==Su.indexOf(a)?a:-1!==u&&n>u?"end":"start")}function q(t,n,a,i,o){let r="string"==typeof o&&-1!==o.indexOf("-force"),s=!0===r?o.replace("-force",""):o,u=void 0!==s?s:"start",c=Math.max(0,a-T.value[u]),d=c+T.value.total;d>e.value&&(d=e.value,c=Math.max(0,d-T.value.total)),l=n.scrollStart;let h=c!==M.value.from||d!==M.value.to;if(!1===h&&void 0===s)return void $(a);let{activeElement:p}=document,f=A.value;!0===h&&null!==f&&f!==p&&!0===f.contains(p)&&(f.addEventListener("focusout",j),setTimeout(()=>{f?.removeEventListener("focusout",j)})),Tu(f,a-c);let g=void 0!==s?m.slice(c,a).reduce(Pu,0):0;if(!0===h){let t=d>=M.value.from&&c<=M.value.to?M.value.to:d;M.value={from:c,to:t},S.value=Mu(x,m,0,c),C.value=Mu(x,m,d,e.value),requestAnimationFrame(()=>{M.value.to!==d&&l===n.scrollStart&&(M.value={from:M.value.from,to:d},C.value=Mu(x,m,d,e.value))})}requestAnimationFrame(()=>{if(l!==n.scrollStart)return;!0===h&&D(c);let e=m.slice(c,a).reduce(Pu,0),o=e+n.offsetStart+S.value,u=o+m[a],d=o+i;if(void 0!==s){let t=e-g,i=n.scrollStart+t;d=!0!==r&&ie.classList&&!1===e.classList.contains("q-virtual-scroll--skip")),o=i.length,r=!0===v.virtualScrollHorizontal?e=>e.getBoundingClientRect().width:e=>e.offsetHeight,s=e;for(let e=0;e=i;t--)m[t]=a;let o=Math.floor((e.value-1)/xu);x=[];for(let t=0;t<=o;t++){let n=0,a=Math.min((t+1)*xu,e.value);for(let e=t*xu;e=0?(D(M.value.from),d(()=>{I(t)})):V()}function F(e){if(void 0===e&&typeof window<"u"){let n=t();null!=n&&8!==n.nodeType&&(e=Eu(n,r(),P.value,E.value,v.virtualScrollHorizontal,w.lang.rtl,v.virtualScrollStickySizeStart,v.virtualScrollStickySizeEnd).scrollViewSize)}c=e;let n=parseFloat(v.virtualScrollSliceRatioBefore)||0,a=1+n+(parseFloat(v.virtualScrollSliceRatioAfter)||0),i=void 0===e||e<=0?1:Math.ceil(e/s.value),o=Math.max(1,i,Math.ceil((v.virtualScrollSliceSize>0?v.virtualScrollSliceSize:10)/a));T.value={total:Math.ceil(o*a),start:Math.ceil(o*n),center:Math.ceil(o*(.5+n)),end:Math.ceil(o*(1+n)),view:i}}function $(e){u!==e&&(void 0!==v.onVirtualScroll&&b("virtualScroll",{index:e,from:M.value.from,to:M.value.to-1,direction:e{F()}),o(R,N),F();let V=ae(function(){let n=t();if(null==n||8===n.nodeType)return;let a=Eu(n,r(),P.value,E.value,v.virtualScrollHorizontal,w.lang.rtl,v.virtualScrollStickySizeStart,v.virtualScrollStickySizeEnd),i=e.value-1,o=a.scrollMaxSize-a.offsetStart-a.offsetEnd-C.value;if(l===a.scrollStart)return;if(a.scrollMaxSize<=0)return void q(n,a,0,0);c!==a.scrollViewSize&&F(a.scrollViewSize),D(M.value.from);let s=Math.floor(a.scrollMaxSize-Math.max(a.scrollViewSize,a.offsetEnd)-Math.min(m[i],a.scrollViewSize/2));if(s>0&&Math.ceil(a.scrollStart)>=s)return void q(n,a,i,a.scrollMaxSize-a.offsetEnd-x.reduce(Pu,0));let u=0,d=a.scrollStart-a.offsetStart,h=d;if(d<=o&&d+a.scrollViewSize>=S.value)d-=S.value,u=M.value.from,h=d;else for(let e=0;d>=x[e]&&u0&&u-a.scrollViewSize?(u++,h=d):h=m[u]+d;q(n,a,u,h)},!0===w.platform.is.ios?120:35);f(()=>{F()});let U=!1;return p(()=>{U=!0}),h(()=>{if(!0!==U)return;let e=t();void 0!==l&&null!=e&&8!==e.nodeType?Au(e,l,v.virtualScrollHorizontal,w.lang.rtl):I(u)}),g(()=>{V.cancel()}),Object.assign(y,{scrollTo:I,reset:N,refresh:O}),{virtualScrollSliceRange:M,virtualScrollSliceSizeComputed:T,setVirtualScrollSize:F,onVirtualScrollEvt:V,localResetVirtualScroll:B,padVirtualScroll:function(e,t){let a=!0===v.virtualScrollHorizontal?"width":"height",i={["--q-virtual-scroll-item-"+a]:s.value+"px"};return["tbody"===e?n(e,{class:"q-virtual-scroll__padding",key:"before",ref:P},[n("tr",[n("td",{style:{[a]:`${S.value}px`,...i},colspan:L.value})])]):n(e,{class:"q-virtual-scroll__padding",key:"before",ref:P,style:{[a]:`${S.value}px`,...i}}),n(e,{class:"q-virtual-scroll__content",key:"content",ref:A,tabindex:-1},t.flat()),"tbody"===e?n(e,{class:"q-virtual-scroll__padding",key:"after",ref:E},[n("tr",[n("td",{style:{[a]:`${C.value}px`,...i},colspan:L.value})])]):n(e,{class:"q-virtual-scroll__padding",key:"after",ref:E,style:{[a]:`${C.value}px`,...i}})]},scrollTo:I,reset:N,refresh:O}}var Ou=e=>["add","add-unique","toggle"].includes(e),Iu=Object.keys(js);function qu(e,t){if("function"==typeof e)return e;let n=void 0!==e?e:t;return e=>null!==e&&"object"==typeof e&&n in e?e[n]:e}var Du=$({name:"QSelect",inheritAttrs:!1,props:{...zu,...ai,...js,modelValue:{required:!0},multiple:Boolean,displayValue:[String,Number],displayValueHtml:Boolean,dropdownIcon:String,options:{type:Array,default:()=>[]},optionValue:[Function,String],optionLabel:[Function,String],optionDisable:[Function,String],hideSelected:Boolean,hideDropdownIcon:Boolean,fillInput:Boolean,maxValues:[Number,String],optionsDense:Boolean,optionsDark:{type:Boolean,default:null},optionsSelectedClass:String,optionsHtml:Boolean,optionsCover:Boolean,menuShrink:Boolean,menuAnchor:String,menuSelf:String,menuOffset:Array,popupContentClass:String,popupContentStyle:[String,Array,Object],popupNoRouteDismiss:Boolean,useInput:Boolean,useChips:Boolean,newValueMode:{type:String,validator:Ou},mapOptions:Boolean,emitValue:Boolean,disableTabSelection:Boolean,inputDebounce:{type:[Number,String],default:500},inputClass:[Array,String,Object],inputStyle:[Array,String,Object],tabindex:{type:[String,Number],default:0},autocomplete:String,transitionShow:{},transitionHide:{},transitionDuration:{},behavior:{type:String,validator:e=>["default","menu","dialog"].includes(e),default:"default"},virtualScrollItemSize:zu.virtualScrollItemSize.type,onNewValue:Function,onFilter:Function},emits:[...Bs,"add","remove","inputValue","keyup","keypress","keydown","popupShow","popupHide","filterAbort"],setup(e,{slots:t,emit:r}){let s,l,u,c,h,p,f,{proxy:m}=k(),{$q:_}=m,y=a(!1),w=a(!1),x=a(-1),S=a(""),C=a(!1),T=a(!1),P=null,E=null,A=null,M=a(null),L=a(null),R=a(null),z=a(null),N=a(null),O=ri(e),I=wl(qe),q=i(()=>Array.isArray(e.options)?e.options.length:0),D=i(()=>void 0===e.virtualScrollItemSize?!0===e.optionsDense?24:48:e.virtualScrollItemSize),{virtualScrollSliceRange:j,virtualScrollSliceSizeComputed:B,localResetVirtualScroll:F,padVirtualScroll:$,onVirtualScrollEvt:V,scrollTo:U,setVirtualScrollSize:H}=Nu({virtualScrollLength:q,getVirtualScrollTarget:function(){return Oe()},getVirtualScrollEl:Oe,virtualScrollItemSizeComputed:D}),W=Fs(),G=i(()=>{let t=!0===e.mapOptions&&!0!==e.multiple,n=void 0===e.modelValue||null===e.modelValue&&!0!==t?[]:!0===e.multiple&&Array.isArray(e.modelValue)?e.modelValue:[e.modelValue];if(!0===e.mapOptions&&!0===Array.isArray(e.options)){let a=!0===e.mapOptions&&void 0!==s?s:[],i=n.map(t=>function(t,n){let a=e=>De(_e.value(e),t);return e.options.find(a)||n.find(a)||t}(t,a));return null===e.modelValue&&!0===t?i.filter(e=>null!==e):i}return n}),K=i(()=>{let t={};return Iu.forEach(n=>{let a=e[n];void 0!==a&&(t[n]=a)}),t}),Y=i(()=>null===e.optionsDark?W.isDark.value:e.optionsDark),X=i(()=>qs(G.value)),ee=i(()=>{let t="q-field__input q-placeholder col";return!0===e.hideSelected||0===G.value.length?[t,e.inputClass]:(t+=" q-field__input--padding",void 0===e.inputClass?t:[t,e.inputClass])}),te=i(()=>(!0===e.virtualScrollHorizontal?"q-virtual-scroll--horizontal":"")+(e.popupContentClass?" "+e.popupContentClass:"")),ne=i(()=>0===q.value),ae=i(()=>G.value.map(e=>ve.value(e)).join(", ")),ie=i(()=>void 0!==e.displayValue?e.displayValue:ae.value),oe=i(()=>!0===e.optionsHtml?()=>!0:e=>!0===e?.html),re=i(()=>!0===e.displayValueHtml||void 0===e.displayValue&&(!0===e.optionsHtml||G.value.some(oe.value))),se=i(()=>!0===W.focused.value?e.tabindex:-1),le=i(()=>{let t={tabindex:e.tabindex,role:"combobox","aria-label":e.label,"aria-readonly":!0===e.readonly?"true":"false","aria-autocomplete":!0===e.useInput?"list":"none","aria-expanded":!0===y.value?"true":"false","aria-controls":`${W.targetUid.value}_lb`};return x.value>=0&&(t["aria-activedescendant"]=`${W.targetUid.value}_${x.value}`),t}),ue=i(()=>({id:`${W.targetUid.value}_lb`,role:"listbox","aria-multiselectable":!0===e.multiple?"true":"false"})),ce=i(()=>G.value.map((e,t)=>({index:t,opt:e,html:oe.value(e),selected:!0,removeAtIndex:Se,toggleOption:Te,tabindex:se.value}))),de=i(()=>{if(0===q.value)return[];let{from:t,to:n}=j.value;return e.options.slice(t,n).map((n,a)=>{let i=!0===be.value(n),o=!0===Ae(n),r=t+a,s={clickable:!0,active:o,activeClass:ge.value,manualFocus:!0,focused:!1,disable:i,tabindex:-1,dense:e.optionsDense,dark:Y.value,role:"option","aria-selected":!0===o?"true":"false",id:`${W.targetUid.value}_${r}`,onClick:()=>{Te(n)}};return!0!==i&&(x.value===r&&(s.focused=!0),!0===_.platform.is.desktop&&(s.onMousemove=()=>{!0===y.value&&Pe(r)})),{index:r,opt:n,html:oe.value(n),label:ve.value(n),selected:s.active,focused:s.focused,toggleOption:Te,setOptionIndex:Pe,itemProps:s}})}),fe=i(()=>void 0!==e.dropdownIcon?e.dropdownIcon:_.iconSet.arrow.dropdown),me=i(()=>!1===e.optionsCover&&!0!==e.outlined&&!0!==e.standout&&!0!==e.borderless&&!0!==e.rounded),ge=i(()=>void 0!==e.optionsSelectedClass?e.optionsSelectedClass:void 0!==e.color?`text-${e.color}`:""),_e=i(()=>qu(e.optionValue,"value")),ve=i(()=>qu(e.optionLabel,"label")),be=i(()=>qu(e.optionDisable,"disable")),ye=i(()=>G.value.map(_e.value)),we=i(()=>{let e={onInput:qe,onChange:I,onKeydown:Ne,onKeyup:Re,onKeypress:ze,onFocus:Me,onClick(e){!0===l&&Q(e)}};return e.onCompositionstart=e.onCompositionupdate=e.onCompositionend=I,e});function ke(t){return!0===e.emitValue?_e.value(t):t}function xe(t){if(-1!==t&&t=e.maxValues)return;let i=e.modelValue.slice();r("add",{index:i.length,value:a}),i.push(a),r("update:modelValue",i)}function Te(t,n){if(!0!==W.editable.value||void 0===t||!0===be.value(t))return;let a=_e.value(t);if(!0!==e.multiple)return!0!==n&&(Be(!0===e.fillInput?ve.value(t):"",!0,!0),Ze()),L.value?.focus(),void((0===G.value.length||!0!==De(_e.value(G.value[0]),a))&&r("update:modelValue",!0===e.emitValue?a:t));if((!0!==l||!0===C.value)&&W.focus(),Me(),0===G.value.length){let n=!0===e.emitValue?a:t;return r("add",{index:0,value:n}),void r("update:modelValue",!0===e.multiple?[n]:n)}let i=e.modelValue.slice(),o=ye.value.findIndex(e=>De(e,a));if(-1!==o)r("remove",{index:o,value:i.splice(o,1)[0]});else{if(void 0!==e.maxValues&&i.length>=e.maxValues)return;let n=!0===e.emitValue?a:t;r("add",{index:i.length,value:n}),i.push(n)}r("update:modelValue",i)}function Pe(e){if(!0!==_.platform.is.desktop)return;let t=-1!==e&&e=0?ve.value(e.options[a]):c,!0))}}function Ae(e){let t=_e.value(e);return void 0!==ye.value.find(e=>De(e,t))}function Me(t){!0===e.useInput&&null!==L.value&&(void 0===t||L.value===t.target&&t.target.value===ae.value)&&L.value.select()}function Le(e){!0===pe(e,27)&&!0===y.value&&(Q(e),Ze(),Je()),r("keyup",e)}function Re(t){let{value:n}=t.target;if(void 0===t.keyCode)if(t.target.value="",null!==P&&(clearTimeout(P),P=null),null!==E&&(clearTimeout(E),E=null),Je(),"string"==typeof n&&0!==n.length){let t=n.toLocaleLowerCase(),a=n=>{let a=e.options.find(e=>String(n.value(e)).toLocaleLowerCase()===t);return void 0!==a&&(-1===G.value.indexOf(a)?Te(a):Ze(),!0)},i=e=>{!0!==a(_e)&&!0!==e&&!0!==a(ve)&&Fe(n,!0,()=>i(!0))};i()}else W.clearValue(t);else Le(t)}function ze(e){r("keypress",e)}function Ne(t){if(r("keydown",t),!0===he(t))return;let n=0!==S.value.length&&(void 0!==e.newValueMode||void 0!==e.onNewValue),a=!0!==t.shiftKey&&!0!==e.disableTabSelection&&!0!==e.multiple&&(-1!==x.value||!0===n);if(27===t.keyCode)return void Z(t);if(9===t.keyCode&&!1===a)return void Ye();if(void 0===t.target||t.target.id!==W.targetUid.value||!0!==W.editable.value)return;if(40===t.keyCode&&!0!==W.innerLoading.value&&!1===y.value)return J(t),void Qe();if(8===t.keyCode&&(!0===e.useChips||!0===e.clearable)&&!0!==e.hideSelected&&0===S.value.length)return void(!0===e.multiple&&!0===Array.isArray(e.modelValue)?xe(e.modelValue.length-1):!0!==e.multiple&&null!==e.modelValue&&r("update:modelValue",null));(35===t.keyCode||36===t.keyCode)&&("string"!=typeof S.value||0===S.value.length)&&(J(t),x.value=-1,Ee(36===t.keyCode?1:-1,e.multiple)),(33===t.keyCode||34===t.keyCode)&&void 0!==B.value&&(J(t),x.value=Math.max(-1,Math.min(q.value,x.value+(33===t.keyCode?-1:1)*B.value.view)),Ee(33===t.keyCode?1:-1,e.multiple)),(38===t.keyCode||40===t.keyCode)&&(J(t),Ee(38===t.keyCode?-1:1,e.multiple));let i=q.value;if((void 0===p||f0&&!0!==e.useInput&&void 0!==t.key&&1===t.key.length&&!1===t.altKey&&!1===t.ctrlKey&&!1===t.metaKey&&(32!==t.keyCode||0!==p.length)){!0!==y.value&&Qe(t);let n=t.key.toLocaleLowerCase(),a=1===p.length&&p[0]===n;f=Date.now()+1500,!1===a&&(J(t),p+=n);let o=new RegExp("^"+p.split("").map(e=>-1!==".*+?^${}()|[]\\".indexOf(e)?"\\"+e:e).join(".*"),"i"),r=x.value;if(!0===a||r<0||!0!==o.test(ve.value(e.options[r])))do{r=Xe(r+1,-1,i-1)}while(r!==x.value&&(!0===be.value(e.options[r])||!0!==o.test(ve.value(e.options[r]))));return void(x.value!==r&&d(()=>{Pe(r),U(r),r>=0&&!0===e.useInput&&!0===e.fillInput&&je(ve.value(e.options[r]),!0)}))}if(13===t.keyCode||32===t.keyCode&&!0!==e.useInput&&""===p||9===t.keyCode&&!1!==a){if(9!==t.keyCode&&J(t),-1!==x.value&&x.value{if(n){if(!0!==Ou(n))return}else n=e.newValueMode;Be("",!0!==e.multiple,!0),null!=t&&(("toggle"===n?Te:Ce)(t,"add-unique"===n),!0!==e.multiple&&(L.value?.focus(),Ze()))};if(void 0!==e.onNewValue?r("newValue",S.value,t):t(S.value),!0!==e.multiple)return}!0===y.value?Ye():!0!==W.innerLoading.value&&Qe()}}function Oe(){return!0===l?N.value:null!==R.value&&null!==R.value.contentEl?R.value.contentEl:void 0}function Ie(){if(!0===ne.value)return void 0!==t["no-option"]?t["no-option"]({inputValue:S.value}):void 0;let e=void 0!==t.option?t.option:e=>n(as,{key:e.index,...e.itemProps},()=>n(is,()=>n(_s,()=>n("span",{[!0===e.html?"innerHTML":"textContent"]:e.label})))),a=$("div",de.value.map(e));return void 0!==t["before-options"]&&(a=t["before-options"]().concat(a)),pt(t["after-options"],a)}function qe(t){null!==P&&(clearTimeout(P),P=null),null!==E&&(clearTimeout(E),E=null),(!t||!t.target||!0!==t.target.qComposing)&&(je(t.target.value||""),u=!0,c=S.value,!0!==W.focused.value&&(!0!==l||!0===C.value)&&W.focus(),void 0!==e.onFilter&&(P=setTimeout(()=>{P=null,Fe(S.value)},e.inputDebounce)))}function je(t,n){S.value!==t&&(S.value=t,!0===n||0===e.inputDebounce||"0"===e.inputDebounce?r("inputValue",t):E=setTimeout(()=>{E=null,r("inputValue",t)},e.inputDebounce))}function Be(t,n,a){u=!0!==a,!0===e.useInput&&(je(t,!0),(!0===n||!0!==a)&&(c=t),!0!==n&&Fe(t))}function Fe(t,n,a){if(void 0===e.onFilter||!0!==n&&!0!==W.focused.value)return;!0===W.innerLoading.value?r("filterAbort"):(W.innerLoading.value=!0,T.value=!0),""!==t&&!0!==e.multiple&&0!==G.value.length&&!0!==u&&t===ve.value(G.value[0])&&(t="");let i=setTimeout(()=>{!0===y.value&&(y.value=!1)},10);null!==A&&clearTimeout(A),A=i,r("filter",t,(e,t)=>{(!0===n||!0===W.focused.value)&&A===i&&(clearTimeout(A),"function"==typeof e&&e(),T.value=!1,d(()=>{W.innerLoading.value=!1,!0===W.editable.value&&(!0===n?!0===y.value&&Ze():!0===y.value?et(!0):y.value=!0),"function"==typeof t&&d(()=>{t(m)}),"function"==typeof a&&d(()=>{a(m)})}))},()=>{!0===W.focused.value&&A===i&&(clearTimeout(A),W.innerLoading.value=!1,T.value=!1),!0===y.value&&(y.value=!1)})}function $e(e){at(e),Ye()}function Ve(){H()}function Ue(e){Q(e),L.value?.focus(),C.value=!0,window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,0)}function He(e){Q(e),d(()=>{C.value=!1})}function We(e){at(e),null!==z.value&&z.value.__updateRefocusTarget(W.rootRef.value.querySelector(".q-field__native > [tabindex]:last-child")),W.focused.value=!1}function Ge(e){Ze(),!1===W.focused.value&&r("blur",e),Je()}function Ke(){let e=document.activeElement;(null===e||e.id!==W.targetUid.value)&&null!==L.value&&L.value!==e&&L.value.focus(),H()}function Ye(){!0!==w.value&&(x.value=-1,!0===y.value&&(y.value=!1),!1===W.focused.value&&(null!==A&&(clearTimeout(A),A=null),!0===W.innerLoading.value&&(r("filterAbort"),W.innerLoading.value=!1,T.value=!1)))}function Qe(n){!0===W.editable.value&&(!0===l?(W.onControlFocusin(n),w.value=!0,d(()=>{W.focus()})):W.focus(),void 0!==e.onFilter?Fe(S.value):(!0!==ne.value||void 0!==t["no-option"])&&(y.value=!0))}function Ze(){w.value=!1,Ye()}function Je(){!0===e.useInput&&Be(!0!==e.multiple&&!0===e.fillInput&&0!==G.value.length&&ve.value(G.value[0])||"",!0,!0)}function et(t){let n=-1;if(!0===t){if(0!==G.value.length){let t=_e.value(G.value[0]);n=e.options.findIndex(e=>De(_e.value(e),t))}F(n)}Pe(n)}function tt(){!1===w.value&&null!==R.value&&R.value.updatePosition()}function nt(e){void 0!==e&&Q(e),r("popupShow",e),W.hasPopupOpen=!0,W.onControlFocusin(e)}function at(e){void 0!==e&&Q(e),r("popupHide",e),W.hasPopupOpen=!1,W.onControlFocusout(e)}function it(){l=(!0===_.platform.is.mobile||"dialog"===e.behavior)&&("menu"!==e.behavior&&(!0!==e.useInput||(void 0!==t["no-option"]||void 0!==e.onFilter||!1===ne.value))),h=!0===_.platform.is.ios&&!0===l&&!0===e.useInput?"fade":e.transitionShow}return o(G,t=>{s=t,!0===e.useInput&&!0===e.fillInput&&!0!==e.multiple&&!0!==W.innerLoading.value&&(!0!==w.value&&!0!==y.value||!0!==X.value)&&(!0!==u&&Je(),(!0===w.value||!0===y.value)&&Fe(""))},{immediate:!0}),o(()=>e.fillInput,Je),o(y,et),o(q,function(e,t){!0===y.value&&!1===W.innerLoading.value&&(F(-1,!0),d(()=>{!0===y.value&&!1===W.innerLoading.value&&(e>t?F():et(!0))}))}),v(it),b(tt),it(),g(()=>{null!==P&&clearTimeout(P),null!==E&&clearTimeout(E)}),Object.assign(m,{showPopup:Qe,hidePopup:Ze,removeAtIndex:xe,add:Ce,toggleOption:Te,getOptionIndex:()=>x.value,setOptionIndex:Pe,moveOptionSelection:Ee,filter:Fe,updateMenuPosition:tt,updateInputValue:Be,isOptionSelected:Ae,getEmittingOptionValue:ke,isOptionDisabled:(...e)=>!0===be.value.apply(null,e),getOptionValue:(...e)=>_e.value.apply(null,e),getOptionLabel:(...e)=>ve.value.apply(null,e)}),Object.assign(W,{innerValue:G,fieldClass:i(()=>`q-select q-field--auto-height q-select--with${!0!==e.useInput?"out":""}-input q-select--with${!0!==e.useChips?"out":""}-chips q-select--${!0===e.multiple?"multiple":"single"}`),inputRef:M,targetRef:L,hasValue:X,showPopup:Qe,floatingLabel:i(()=>!0!==e.hideSelected&&!0===X.value||"number"==typeof S.value||0!==S.value.length||qs(e.displayValue)),getControlChild:()=>{if(!1!==W.editable.value&&(!0===w.value||!0!==ne.value||void 0!==t["no-option"]))return!0===l?function(){let a=[n(Vs,{class:`col-auto ${W.fieldClass.value}`,...K.value,for:W.targetUid.value,dark:Y.value,square:!0,loading:T.value,itemAligned:!1,filled:!0,stackLabel:0!==S.value.length,...W.splitAttrs.listeners.value,onFocus:Ue,onBlur:He},{...t,rawControl:()=>W.getControl(!0),before:void 0,after:void 0})];return!0===y.value&&a.push(n("div",{ref:N,class:te.value+" scroll",style:e.popupContentStyle,...ue.value,onClick:Z,onScrollPassive:V},Ie())),n(Yr,{ref:z,modelValue:w.value,position:!0===e.useInput?"top":void 0,transitionShow:h,transitionHide:e.transitionHide,transitionDuration:e.transitionDuration,noRouteDismiss:e.popupNoRouteDismiss,onBeforeShow:nt,onBeforeHide:We,onHide:Ge,onShow:Ke},()=>n("div",{class:"q-select__dialog"+(!0===Y.value?" q-select__dialog--dark q-dark":"")+(!0===C.value?" q-select__dialog--focused":"")},a))}():n(Ka,{ref:R,class:te.value,style:e.popupContentStyle,modelValue:y.value,fit:!0!==e.menuShrink,cover:!0===e.optionsCover&&!0!==ne.value&&!0!==e.useInput,anchor:e.menuAnchor,self:e.menuSelf,offset:e.menuOffset,dark:Y.value,noParentEvent:!0,noRefocus:!0,noFocus:!0,noRouteDismiss:e.popupNoRouteDismiss,square:me.value,transitionShow:e.transitionShow,transitionHide:e.transitionHide,transitionDuration:e.transitionDuration,separateClosePopup:!0,...ue.value,onScrollPassive:V,onBeforeShow:nt,onBeforeHide:$e,onShow:Ve},Ie);!0===W.hasPopupOpen&&(W.hasPopupOpen=!1)},controlEvents:{onFocusin(e){W.onControlFocusin(e)},onFocusout(e){W.onControlFocusout(e,()=>{Je(),Ye()})},onClick(e){if(Z(e),!0!==l&&!0===y.value)return Ye(),void L.value?.focus();Qe(e)}},getControl:a=>{let i=!0===e.hideSelected?[]:void 0!==t["selected-item"]?ce.value.map(e=>t["selected-item"](e)).slice():void 0!==t.selected?[].concat(t.selected()):!0===e.useChips?ce.value.map((t,a)=>n(Fi,{key:"option-"+a,removable:!0===W.editable.value&&!0!==be.value(t.opt),dense:!0,textColor:e.color,tabindex:se.value,onRemove(){t.removeAtIndex(a)}},()=>n("span",{class:"ellipsis",[!0===t.html?"innerHTML":"textContent"]:ve.value(t.opt)}))):[n("span",{class:"ellipsis",[!0===re.value?"innerHTML":"textContent"]:ie.value})],o=!0===a||!0!==w.value||!0!==l;if(!0===e.useInput)i.push(function(t,a){let i=!0===a?{...le.value,...W.splitAttrs.attributes.value}:void 0,o={ref:!0===a?L:void 0,key:"i_t",class:ee.value,style:e.inputStyle,value:void 0!==S.value?S.value:"",type:"search",...i,id:!0===a?W.targetUid.value:void 0,maxlength:e.maxlength,autocomplete:e.autocomplete,"data-autofocus":!0===t||!0===e.autofocus||void 0,disabled:!0===e.disable,readonly:!0===e.readonly,...we.value};return!0!==t&&!0===l&&(!0===Array.isArray(o.class)?o.class=[...o.class,"no-pointer-events"]:o.class+=" no-pointer-events"),n("input",o)}(a,o));else if(!0===W.editable.value){let t=!0===o?le.value:void 0;i.push(n("input",{ref:!0===o?L:void 0,key:"d_t",class:"q-select__focus-target",id:!0===o?W.targetUid.value:void 0,value:ie.value,readonly:!0,"data-autofocus":!0===a||!0===e.autofocus||void 0,...t,onKeydown:Ne,onKeyup:Le,onKeypress:ze})),!0===o&&"string"==typeof e.autocomplete&&0!==e.autocomplete.length&&i.push(n("input",{class:"q-select__autocomplete-input",autocomplete:e.autocomplete,tabindex:-1,onKeyup:Re}))}if(void 0!==O.value&&!0!==e.disable&&0!==ye.value.length){let t=ye.value.map(e=>n("option",{value:e,selected:!0}));i.push(n("select",{class:"hidden",name:O.value,multiple:e.multiple},t))}let r=!0===e.useInput||!0!==o?void 0:W.splitAttrs.attributes.value;return n("div",{class:"q-field__native row items-center",...r,...W.splitAttrs.listeners.value},i)},getInnerAppend:()=>!0!==e.loading&&!0!==T.value&&!0!==e.hideDropdownIcon?[n(Mt,{class:"q-select__dropdown-icon"+(!0===y.value?" rotate-180":""),name:fe.value})]:null}),$s(W)}}),ju=["text","rect","circle","QBtn","QBadge","QChip","QToolbar","QCheckbox","QRadio","QToggle","QSlider","QRange","QInput","QAvatar"],Bu=["wave","pulse","pulse-x","pulse-y","fade","blink","none"],Fu=$({name:"QSkeleton",props:{...Nt,tag:{type:String,default:"div"},type:{type:String,validator:e=>ju.includes(e),default:"rect"},animation:{type:String,validator:e=>Bu.includes(e),default:"wave"},animationSpeed:{type:[String,Number],default:1500},square:Boolean,bordered:Boolean,size:String,width:String,height:String},setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q),r=i(()=>{let t=void 0!==e.size?[e.size,e.size]:[e.width,e.height];return{"--q-skeleton-speed":`${e.animationSpeed}ms`,width:t[0],height:t[1]}}),s=i(()=>`q-skeleton q-skeleton--${!0===o.value?"dark":"light"} q-skeleton--type-${e.type}`+("none"!==e.animation?` q-skeleton--anim q-skeleton--anim-${e.animation}`:"")+(!0===e.square?" q-skeleton--square":"")+(!0===e.bordered?" q-skeleton--bordered":""));return()=>n(e.tag,{class:s.value,style:r.value},dt(t.default))}}),$u=[["left","center","start","width"],["right","center","end","width"],["top","start","center","height"],["bottom","end","center","height"]],Vu=$({name:"QSlideItem",props:{...Nt,leftColor:String,rightColor:String,topColor:String,bottomColor:String,onSlide:Function},emits:["action","top","right","bottom","left"],setup(e,{slots:t,emit:o}){let{proxy:r}=k(),{$q:s}=r,l=Ot(e,s),{getCache:u}=vi(),c=a(null),d=null,h={},p={},f={},m=i(()=>!0===s.lang.rtl?{left:"right",right:"left"}:{left:"left",right:"right"}),_=i(()=>"q-slide-item q-item-type overflow-hidden"+(!0===l.value?" q-slide-item--dark q-dark":""));function b(){c.value.style.transform="translate(0,0)"}function y(t,n,a){void 0!==e.onSlide&&o("slide",{side:t,ratio:n,isReset:a})}function w(e){let n,a,i,r=c.value;if(e.isFirst)h={dir:null,size:{left:0,right:0,top:0,bottom:0},scale:0},r.classList.add("no-transition"),$u.forEach(e=>{if(void 0!==t[e[0]]){let t=f[e[0]];t.style.transform="scale(1)",h.size[e[0]]=t.getBoundingClientRect()[e[3]]}}),h.axis="up"===e.direction||"down"===e.direction?"Y":"X";else{if(e.isFinal)return r.classList.remove("no-transition"),void(1===h.scale?(r.style.transform=`translate${h.axis}(${100*h.dir}%)`,null!==d&&clearTimeout(d),d=setTimeout(()=>{d=null,o(h.showing,{reset:b}),o("action",{side:h.showing,reset:b})},230)):(r.style.transform="translate(0,0)",y(h.showing,0,!0)));e.direction="X"===h.axis?e.offset.x<0?"left":"right":e.offset.y<0?"up":"down"}void 0===t.left&&e.direction===m.value.right||void 0===t.right&&e.direction===m.value.left||void 0===t.top&&"down"===e.direction||void 0===t.bottom&&"up"===e.direction?r.style.transform="translate(0,0)":("X"===h.axis?(a="left"===e.direction?-1:1,n=1===a?m.value.left:m.value.right,i=e.distance.x):(a="up"===e.direction?-2:2,n=2===a?"top":"bottom",i=e.distance.y),(null===h.dir||Math.abs(a)===Math.abs(h.dir))&&(h.dir!==a&&(["left","right","top","bottom"].forEach(e=>{p[e]&&(p[e].style.visibility=n===e?"visible":"hidden")}),h.showing=n,h.dir=a),h.scale=Math.max(0,Math.min(1,(i-40)/h.size[n])),r.style.transform=`translate${h.axis}(${i*a/Math.abs(a)}px)`,f[n].style.transform=`scale(${h.scale})`,y(n,h.scale,!1)))}return v(()=>{p={},f={}}),g(()=>{null!==d&&clearTimeout(d)}),Object.assign(r,{reset:b}),()=>{let a=[],i={left:void 0!==t[m.value.right],right:void 0!==t[m.value.left],up:void 0!==t.bottom,down:void 0!==t.top},o=Object.keys(i).filter(e=>!0===i[e]);$u.forEach(i=>{let o=i[0];void 0!==t[o]&&a.push(n("div",{key:o,ref:e=>{p[o]=e},class:`q-slide-item__${o} absolute-full row no-wrap items-${i[1]} justify-${i[2]}`+(void 0!==e[o+"Color"]?` bg-${e[o+"Color"]}`:"")},[n("div",{ref:e=>{f[o]=e}},t[o]())]))});let r=n("div",{key:(0===o.length?"only-":"")+" content",ref:c,class:"q-slide-item__content"},dt(t.default));return 0===o.length?a.push(r):a.push(A(r,u("dir#"+o.join(""),()=>{let e={prevent:!0,stop:!0,mouse:!0};return o.forEach(t=>{e[t]=!0}),[[Ki,w,void 0,e]]}))),n("div",{class:_.value},a)}}}),Uu=$({name:"QSpace",setup(){let e=n("div",{class:"q-space"});return()=>e}}),Hu=$({name:"QSpinnerAudio",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,fill:"currentColor",width:t.value,height:t.value,viewBox:"0 0 55 80",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Wu=$({name:"QSpinnerBall",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,stroke:"currentColor",width:t.value,height:t.value,viewBox:"0 0 57 57",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Gu=$({name:"QSpinnerBars",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,fill:"currentColor",width:t.value,height:t.value,viewBox:"0 0 135 140",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Ku=$({name:"QSpinnerBox",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Yu=$({name:"QSpinnerClock",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Qu=$({name:"QSpinnerComment",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Zu=$({name:"QSpinnerCube",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Ju=$({name:"QSpinnerDots",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,fill:"currentColor",width:t.value,height:t.value,viewBox:"0 0 120 30",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Xu=$({name:"QSpinnerFacebook",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",xmlns:"http://www.w3.org/2000/svg",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),ec=$({name:"QSpinnerGears",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),tc=$({name:"QSpinnerGrid",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,fill:"currentColor",width:t.value,height:t.value,viewBox:"0 0 105 105",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),nc=$({name:"QSpinnerHearts",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,fill:"currentColor",width:t.value,height:t.value,viewBox:"0 0 140 64",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ac=$({name:"QSpinnerHourglass",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ic=$({name:"QSpinnerInfinity",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),oc=$({name:"QSpinnerIos",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,stroke:"currentColor",fill:"currentColor",viewBox:"0 0 64 64",innerHTML:''})}}),rc=$({name:"QSpinnerOrbit",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),sc=$({name:"QSpinnerOval",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,stroke:"currentColor",width:t.value,height:t.value,viewBox:"0 0 38 38",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),lc=$({name:"QSpinnerPie",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),uc=$({name:"QSpinnerPuff",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,stroke:"currentColor",width:t.value,height:t.value,viewBox:"0 0 44 44",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),cc=$({name:"QSpinnerRadio",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),dc=$({name:"QSpinnerRings",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,stroke:"currentColor",width:t.value,height:t.value,viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),hc=$({name:"QSpinnerTail",props:an,setup(e){let{cSize:t,classes:a}=on(e);return()=>n("svg",{class:a.value,width:t.value,height:t.value,viewBox:"0 0 38 38",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),pc=$({name:"QSplitter",props:{...Nt,modelValue:{type:Number,required:!0},reverse:Boolean,unit:{type:String,default:"%",validator:e=>["%","px"].includes(e)},limits:{type:Array,validator:e=>2===e.length&&"number"==typeof e[0]&&"number"==typeof e[1]&&(e[0]>=0&&e[0]<=e[1])},emitImmediately:Boolean,horizontal:Boolean,disable:Boolean,beforeClass:[Array,String,Object],afterClass:[Array,String,Object],separatorClass:[Array,String,Object],separatorStyle:[Array,String,Object]},emits:["update:modelValue"],setup(e,{slots:t,emit:r}){let{proxy:{$q:s}}=k(),l=Ot(e,s),u=a(null),c={before:a(null),after:a(null)},h=i(()=>`q-splitter no-wrap ${!0===e.horizontal?"q-splitter--horizontal column":"q-splitter--vertical row"} q-splitter--${!0===e.disable?"disabled":"workable"}`+(!0===l.value?" q-splitter--dark":"")),p=i(()=>!0===e.horizontal?"height":"width"),f=i(()=>!0!==e.reverse?"before":"after"),m=i(()=>void 0!==e.limits?e.limits:"%"===e.unit?[10,90]:[50,1/0]);function g(t){return("%"===e.unit?t:Math.round(t))+e.unit}let _,v,b,y,w,x=i(()=>({[f.value]:{[p.value]:g(e.modelValue)}}));function S(t){if(!0===t.isFirst){let t=u.value.getBoundingClientRect()[p.value];return _=!0===e.horizontal?"up":"left",v="%"===e.unit?100:t,b=Math.min(v,m.value[1],Math.max(m.value[0],e.modelValue)),y=(!0!==e.reverse?1:-1)*(!0===e.horizontal?1:!0===s.lang.rtl?-1:1)*("%"===e.unit?0===t?0:100/t:1),void u.value.classList.add("q-splitter--active")}if(!0===t.isFinal)return w!==e.modelValue&&r("update:modelValue",w),void u.value.classList.remove("q-splitter--active");let n=b+y*(t.direction===_?-1:1)*t.distance[!0===e.horizontal?"y":"x"];w=Math.min(v,m.value[1],Math.max(m.value[0],n)),c[f.value].value.style[p.value]=g(w),!0===e.emitImmediately&&e.modelValue!==w&&r("update:modelValue",w)}let C=i(()=>[[Ki,S,void 0,{[!0===e.horizontal?"vertical":"horizontal"]:!0,prevent:!0,stop:!0,mouse:!0,mouseAllDir:!0}]]);function T(e,t){et[1]&&r("update:modelValue",t[1])}return o(()=>e.modelValue,e=>{T(e,m.value)}),o(()=>e.limits,()=>{d(()=>{T(e.modelValue,m.value)})}),()=>{let a=[n("div",{ref:c.before,class:["q-splitter__panel q-splitter__before"+(!0===e.reverse?" col":""),e.beforeClass],style:x.value.before},dt(t.before)),n("div",{class:["q-splitter__separator",e.separatorClass],style:e.separatorStyle,"aria-disabled":!0===e.disable?"true":void 0},[mt("div",{class:"q-splitter__separator-area absolute-full"},dt(t.separator),"sep",!0!==e.disable,()=>C.value)]),n("div",{ref:c.after,class:["q-splitter__panel q-splitter__after"+(!0===e.reverse?"":" col"),e.afterClass],style:x.value.after},dt(t.after))];return n("div",{class:h.value,ref:u},pt(t.default,a))}}}),fc=$({name:"StepHeader",props:{stepper:{},step:{},goToPanel:Function},setup(e,{attrs:t}){let{proxy:{$q:o}}=k(),r=a(null),s=i(()=>e.stepper.modelValue===e.step.name),l=i(()=>{let t=e.step.disable;return!0===t||""===t}),u=i(()=>{let t=e.step.error;return!0===t||""===t}),c=i(()=>{let t=e.step.done;return!1===l.value&&(!0===t||""===t)}),d=i(()=>{let t=e.step.headerNav,n=!0===t||""===t||void 0===t;return!1===l.value&&e.stepper.headerNav&&n}),h=i(()=>e.step.prefix&&(!1===s.value||"none"===e.stepper.activeIcon)&&(!1===u.value||"none"===e.stepper.errorIcon)&&(!1===c.value||"none"===e.stepper.doneIcon)),p=i(()=>{let t=e.step.icon||e.stepper.inactiveIcon;if(!0===s.value){let n=e.step.activeIcon||e.stepper.activeIcon;return"none"===n?t:n||o.iconSet.stepper.active}if(!0===u.value){let n=e.step.errorIcon||e.stepper.errorIcon;return"none"===n?t:n||o.iconSet.stepper.error}if(!1===l.value&&!0===c.value){let n=e.step.doneIcon||e.stepper.doneIcon;return"none"===n?t:n||o.iconSet.stepper.done}return t}),f=i(()=>{let t=!0===u.value?e.step.errorColor||e.stepper.errorColor:void 0;if(!0===s.value){let n=e.step.activeColor||e.stepper.activeColor||e.step.color;return void 0!==n?n:t}return void 0!==t?t:!1===l.value&&!0===c.value?e.step.doneColor||e.stepper.doneColor||e.step.color||e.stepper.inactiveColor:e.step.color||e.stepper.inactiveColor}),m=i(()=>"q-stepper__tab col-grow flex items-center no-wrap relative-position"+(void 0!==f.value?` text-${f.value}`:"")+(!0===u.value?" q-stepper__tab--error q-stepper__tab--error-with-"+(!0===h.value?"prefix":"icon"):"")+(!0===s.value?" q-stepper__tab--active":"")+(!0===c.value?" q-stepper__tab--done":"")+(!0===d.value?" q-stepper__tab--navigation q-focusable q-hoverable":"")+(!0===l.value?" q-stepper__tab--disabled":"")),g=i(()=>!0===e.stepper.headerNav&&d.value);function _(){r.value?.focus(),!1===s.value&&e.goToPanel(e.step.name)}function v(t){13===t.keyCode&&!1===s.value&&e.goToPanel(e.step.name)}return()=>{let a={class:m.value};!0===d.value&&(a.onClick=_,a.onKeyup=v,Object.assign(a,!0===l.value?{tabindex:-1,"aria-disabled":"true"}:{tabindex:t.tabindex||0}));let i=[n("div",{class:"q-focus-helper",tabindex:-1,ref:r}),n("div",{class:"q-stepper__dot row flex-center q-stepper__line relative-position"},[n("span",{class:"row flex-center"},[!0===h.value?e.step.prefix:n(Mt,{name:p.value})])])];if(void 0!==e.step.title&&null!==e.step.title){let t=[n("div",{class:"q-stepper__title"},e.step.title)];void 0!==e.step.caption&&null!==e.step.caption&&t.push(n("div",{class:"q-stepper__caption"},e.step.caption)),i.push(n("div",{class:"q-stepper__label q-stepper__line relative-position"},t))}return A(n("div",a,i),[[mn,g.value]])}}});function mc(e){return n("div",{class:"q-stepper__step-content"},[n("div",{class:"q-stepper__step-inner"},dt(e.default))])}var gc={setup:(e,{slots:t})=>()=>mc(t)},_c=$({name:"QStep",props:{...bi,icon:String,color:String,title:{type:String,required:!0},caption:String,prefix:[String,Number],doneIcon:String,doneColor:String,activeIcon:String,activeColor:String,errorIcon:String,errorColor:String,headerNav:{type:Boolean,default:!0},done:Boolean,error:Boolean,onScroll:[Function,Array]},setup(e,{slots:t,emit:o}){let{proxy:{$q:r}}=k(),s=y(Ee,Oe);if(s===Oe)return console.error("QStep needs to be a child of QStepper"),Oe;let{getCache:l}=vi(),u=a(null),c=i(()=>s.value.modelValue===e.name),d=i(()=>!0!==r.platform.is.ios&&!0===r.platform.is.chrome||!0!==c.value||!0!==s.value.vertical?{}:{onScroll(t){let{target:n}=t;n.scrollTop>0&&(n.scrollTop=0),void 0!==e.onScroll&&o("scroll",t)}}),h=i(()=>"string"==typeof e.name||"number"==typeof e.name?e.name:String(e.name));function p(){let e=s.value.vertical;return!0===e&&!0===s.value.keepAlive?n(T,s.value.keepAliveProps.value,!0===c.value?[n(!0===s.value.needsUniqueKeepAliveWrapper.value?l(h.value,()=>({...gc,name:h.value})):gc,{key:h.value},t.default)]:void 0):!0!==e||!0===c.value?mc(t):void 0}return()=>n("div",{ref:u,class:"q-stepper__step",role:"tabpanel",...d.value},!0===s.value.vertical?[n(fc,{stepper:s.value,step:e,goToPanel:s.value.goToPanel}),!0===s.value.animated?n(vs,p):p()]:[p()])}}),vc=/(-\w)/g;var bc=$({name:"QStepper",props:{...Nt,...wi,flat:Boolean,bordered:Boolean,alternativeLabels:Boolean,headerNav:Boolean,contracted:Boolean,headerClass:String,inactiveColor:String,inactiveIcon:String,doneIcon:String,doneColor:String,activeIcon:String,activeColor:String,errorIcon:String,errorColor:String},emits:ki,setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q),{updatePanelsList:r,isValidPanelName:s,updatePanelIndex:l,getPanelContent:u,getPanels:c,panelDirectives:d,goToPanel:h,keepAliveProps:p,needsUniqueKeepAliveWrapper:f}=xi();w(Ee,i(()=>({goToPanel:h,keepAliveProps:p,needsUniqueKeepAliveWrapper:f,...e})));let m=i(()=>"q-stepper q-stepper--"+(!0===e.vertical?"vertical":"horizontal")+(!0===e.flat?" q-stepper--flat":"")+(!0===e.bordered?" q-stepper--bordered":"")+(!0===o.value?" q-stepper--dark q-dark":"")),g=i(()=>`q-stepper__header row items-stretch justify-between q-stepper__header--${!0===e.alternativeLabels?"alternative":"standard"}-labels`+(!1===e.flat||!0===e.bordered?" q-stepper__header--border":"")+(!0===e.contracted?" q-stepper__header--contracted":"")+(void 0!==e.headerClass?` ${e.headerClass}`:""));function _(){let a=dt(t.message,[]);if(!0===e.vertical){s(e.modelValue)&&l();let i=n("div",{class:"q-stepper__content"},dt(t.default));return void 0===a?[i]:a.concat(i)}return[n("div",{class:g.value},c().map(t=>{let a=function(e){let t={};for(let n in e)t[n.replace(vc,e=>e[1].toUpperCase())]=e[n];return t}(t.props);return n(fc,{key:a.name,stepper:e,step:a,goToPanel:h})})),a,mt("div",{class:"q-stepper__content q-panel-parent"},u(),"cont",e.swipeable,()=>d.value)]}return()=>(r(t),n("div",{class:m.value},pt(t.navigation,_())))}}),yc=$({name:"QStepperNavigation",setup:(e,{slots:t})=>()=>n("div",{class:"q-stepper__nav"},dt(t.default))}),wc=$({name:"QTh",props:{props:Object,autoWidth:Boolean},emits:["click"],setup(e,{slots:t,emit:a}){let i=k(),{proxy:{$q:o}}=i,r=e=>{a("click",e)};return()=>{if(void 0===e.props)return n("th",{class:!0===e.autoWidth?"q-table--col-auto-width":"",onClick:r},dt(t.default));let a,s,l=i.vnode.key;if(l){if(a=e.props.colsMap[l],void 0===a)return}else a=e.props.col;if(!0===a.sortable){let e="right"===a.align?"unshift":"push";s=ht(t.default,[]),s[e](n(Mt,{class:a.__iconClass,name:o.iconSet.table.arrowUp}))}else s=dt(t.default);let u={class:a.__thClass+(!0===e.autoWidth?" q-table--col-auto-width":""),style:a.headerStyle,onClick:t=>{!0===a.sortable&&e.props.sort(a),r(t)}};return n("th",u,s)}}});function kc(e,t){return n("div",e,[n("table",{class:"q-table"},t)])}var xc={list:Al,table:Dl},Sc=["list","table","__qtable"],Cc=$({name:"QVirtualScroll",props:{...zu,type:{type:String,default:"list",validator:e=>Sc.includes(e)},items:{type:Array,default:()=>[]},itemsFn:Function,itemsSize:Number,scrollTarget:oa},setup(e,{slots:t,attrs:r}){let s,l=a(null),u=i(()=>e.itemsSize>=0&&void 0!==e.itemsFn?parseInt(e.itemsSize,10):Array.isArray(e.items)?e.items.length:0),{virtualScrollSliceRange:c,localResetVirtualScroll:d,padVirtualScroll:_,onVirtualScrollEvt:v}=Nu({virtualScrollLength:u,getVirtualScrollTarget:function(){return s},getVirtualScrollEl:k}),b=i(()=>{if(0===u.value)return[];let t=(e,t)=>({index:c.value.from+t,item:e});return void 0===e.itemsFn?e.items.slice(c.value.from,c.value.to).map(t):e.itemsFn(c.value.from,c.value.to-c.value.from).map(t)}),y=i(()=>"q-virtual-scroll q-virtual-scroll"+(!0===e.virtualScrollHorizontal?"--horizontal":"--vertical")+(void 0!==e.scrollTarget?"":" scroll")),w=i(()=>void 0!==e.scrollTarget?{}:{tabindex:0});function k(){return l.value.$el||l.value}function x(){s=sa(k(),e.scrollTarget),s.addEventListener("scroll",v,H.passive)}function S(){void 0!==s&&(s.removeEventListener("scroll",v,H.passive),s=void 0)}function C(){let n=_("list"===e.type?"div":"tbody",b.value.map(t.default));return void 0!==t.before&&(n=t.before().concat(n)),pt(t.after,n)}return o(u,()=>{d()}),o(()=>e.scrollTarget,()=>{S(),x()}),f(()=>{d()}),m(()=>{x()}),h(()=>{x()}),p(()=>{S()}),g(()=>{S()}),()=>{if(void 0!==t.default)return"__qtable"===e.type?kc({ref:l,class:"q-table__middle "+y.value},C()):n(xc[e.type],{...r,ref:l,class:[r.class,y.value],...w.value},C);console.error("QVirtualScroll: default scoped slot is required for rendering")}}});var Tc={sortMethod:Function,binaryStateSort:Boolean,columnSortOrder:{type:String,validator:e=>"ad"===e||"da"===e,default:"ad"}};function Pc(e,t,n,a){let o=i(()=>{let{sortBy:e}=t.value;return e&&n.value.find(t=>t.name===e)||null}),r=i(()=>void 0!==e.sortMethod?e.sortMethod:(e,t,a)=>{let i=n.value.find(e=>e.name===t);if(void 0===i||void 0===i.field)return e;let o=!0===a?-1:1,r="function"==typeof i.field?e=>i.field(e):e=>e[i.field];return e.sort((e,t)=>{let n=r(e),a=r(t);return void 0!==i.rawSort?i.rawSort(n,a,e,t)*o:null==n?-1*o:null==a?1*o:void 0!==i.sort?i.sort(n,a,e,t)*o:!0===$e(n)&&!0===$e(a)?(n-a)*o:!0===Be(n)&&!0===Be(a)?function(e,t){return new Date(e)-new Date(t)}(n,a)*o:"boolean"==typeof n&&"boolean"==typeof a?(n-a)*o:([n,a]=[n,a].map(e=>(e+"").toLocaleString().toLowerCase()),ne.name===i);e?.sortOrder&&(o=e.sortOrder)}let{sortBy:r,descending:s}=t.value;r!==i?(r=i,s="da"===o):!0===e.binaryStateSort?s=!s:!0===s?"ad"===o?r=null:s=!1:"ad"===o?s=!0:r=null,a({sortBy:r,descending:s,page:1})}}}var Ec={filter:[String,Object],filterMethod:Function};function Ac(e){return e.page<1&&(e.page=1),void 0!==e.rowsPerPage&&e.rowsPerPage<1&&(e.rowsPerPage=0),e}var Mc={pagination:Object,rowsPerPageOptions:{type:Array,default:()=>[5,7,10,15,20,25,50,0]},"onUpdate:pagination":[Function,Array]};var Lc={selection:{type:String,default:"none",validator:e=>["single","multiple","none"].includes(e)},selected:{type:Array,default:()=>[]}};function Rc(e){return Array.isArray(e)?e.slice():[]}var zc={expanded:Array};var Nc={visibleColumns:Array};var Oc="q-table__bottom row items-center",Ic={};Ru.forEach(e=>{Ic[e]={}});var qc=$({name:"QTable",props:{rows:{type:Array,required:!0},rowKey:{type:[String,Function],default:"id"},columns:Array,loading:Boolean,iconFirstPage:String,iconPrevPage:String,iconNextPage:String,iconLastPage:String,title:String,hideHeader:Boolean,grid:Boolean,gridHeader:Boolean,dense:Boolean,flat:Boolean,bordered:Boolean,square:Boolean,separator:{type:String,default:"horizontal",validator:e=>["horizontal","vertical","cell","none"].includes(e)},wrapCells:Boolean,virtualScroll:Boolean,virtualScrollTarget:{},...Ic,noDataLabel:String,noResultsLabel:String,loadingLabel:String,selectedRowsLabel:Function,rowsPerPageLabel:String,paginationLabel:Function,color:{type:String,default:"grey-8"},titleClass:[String,Array,Object],tableStyle:[String,Array,Object],tableClass:[String,Array,Object],tableHeaderStyle:[String,Array,Object],tableHeaderClass:[String,Array,Object],tableRowStyleFn:Function,tableRowClassFn:Function,cardContainerClass:[String,Array,Object],cardContainerStyle:[String,Array,Object],cardStyle:[String,Array,Object],cardClass:[String,Array,Object],cardStyleFn:Function,cardClassFn:Function,hideBottom:Boolean,hideSelectedBanner:Boolean,hideNoData:Boolean,hidePagination:Boolean,onRowClick:Function,onRowDblclick:Function,onRowContextmenu:Function,...Nt,...Ci,...Nc,...Ec,...Mc,...zc,...Lc,...Tc},emits:["request","virtualScroll",...Ti,"update:expanded","update:selected","selection"],setup(e,{slots:t,emit:r}){let s=k(),{proxy:{$q:l}}=s,u=Ot(e,l),{inFullscreen:c,toggleFullscreen:h}=Pi(),p=i(()=>"function"==typeof e.rowKey?e.rowKey:t=>t[e.rowKey]),f=a(null),m=a(null),g=i(()=>!0!==e.grid&&!0===e.virtualScroll),_=i(()=>" q-table__card"+(!0===u.value?" q-table__card--dark q-dark":"")+(!0===e.square?" q-table--square":"")+(!0===e.flat?" q-table--flat":"")+(!0===e.bordered?" q-table--bordered":"")),v=i(()=>`q-table__container q-table--${e.separator}-separator column no-wrap`+(!0===e.grid?" q-table--grid":_.value)+(!0===u.value?" q-table--dark":"")+(!0===e.dense?" q-table--dense":"")+(!1===e.wrapCells?" q-table--no-wrap":"")+(!0===c.value?" fullscreen scroll":"")),b=i(()=>v.value+(!0===e.loading?" q-table--loading":""));o(()=>e.tableStyle+e.tableClass+e.tableHeaderStyle+e.tableHeaderClass+v.value,()=>{!0===g.value&&m.value?.reset()});let{innerPagination:y,computedPagination:w,isServerSide:x,requestServerInteraction:S,setPagination:C}=function(e,t){let{props:n,emit:o}=e,r=a(Object.assign({sortBy:null,descending:!1,page:1,rowsPerPage:0!==n.rowsPerPageOptions.length?n.rowsPerPageOptions[0]:5},n.pagination)),s=i(()=>Ac(void 0!==n["onUpdate:pagination"]?{...r.value,...n.pagination}:r.value)),l=i(()=>void 0!==s.value.rowsNumber);function u(e){c({pagination:e,filter:n.filter})}function c(e={}){d(()=>{o("request",{pagination:e.pagination||s.value,filter:e.filter||n.filter,getCellValue:t})})}return{innerPagination:r,computedPagination:s,isServerSide:l,requestServerInteraction:c,setPagination:function(e,t){let a=Ac({...s.value,...e});!0!==function(e,t){for(let n in t)if(t[n]!==e[n])return!1;return!0}(s.value,a)?!0!==l.value?void 0!==n.pagination&&void 0!==n["onUpdate:pagination"]?o("update:pagination",a):r.value=a:u(a):!0===l.value&&!0===t&&u(a)}}}(s,_e),{computedFilterMethod:T}=function(e,t){let n=i(()=>void 0!==e.filterMethod?e.filterMethod:(e,t,n,a)=>{let i=t?t.toLowerCase():"";return e.filter(e=>n.some(t=>{let n=a(t,e)+"";return-1!==("undefined"===n||"null"===n?"":n.toLowerCase()).indexOf(i)}))});return o(()=>e.filter,()=>{d(()=>{t({page:1},!0)})},{deep:!0}),{computedFilterMethod:n}}(e,C),{isRowExpanded:P,setExpanded:E,updateExpanded:A}=function(e,t){let n=a(Rc(e.expanded));function i(a){void 0!==e.expanded?t("update:expanded",a):n.value=a}return o(()=>e.expanded,e=>{n.value=Rc(e)}),{isRowExpanded:function(e){return n.value.includes(e)},setExpanded:i,updateExpanded:function(e,t){let a=n.value.slice(),o=a.indexOf(e);!0===t?-1===o&&(a.push(e),i(a)):-1!==o&&(a.splice(o,1),i(a))}}}(e,r),M=i(()=>{let t=e.rows;if(!0===x.value||0===t.length)return t;let{sortBy:n,descending:a}=w.value;return e.filter&&(t=T.value(t,e.filter,H.value,_e)),null!==K.value&&(t=Y.value(e.rows===t?t.slice():t,n,a)),t}),L=i(()=>M.value.length),R=i(()=>{let t=M.value;if(!0===x.value)return t;let{rowsPerPage:n}=w.value;return 0!==n&&(0===Z.value&&e.rows!==t?t.length>J.value&&(t=t.slice(0,J.value)):t=t.slice(Z.value,J.value)),t}),{hasSelectionMode:O,singleSelection:I,multipleSelection:q,allRowsSelected:D,someRowsSelected:j,rowsSelectedNumber:B,isRowSelected:F,clearSelection:$,updateSelection:V}=function(e,t,n,a){let o=i(()=>{let t={};return e.selected.map(a.value).forEach(e=>{t[e]=!0}),t}),r=i(()=>"none"!==e.selection),s=i(()=>"single"===e.selection),l=i(()=>"multiple"===e.selection),u=i(()=>0!==n.value.length&&n.value.every(e=>!0===o.value[a.value(e)])),c=i(()=>!0!==u.value&&n.value.some(e=>!0===o.value[a.value(e)])),d=i(()=>e.selected.length);return{hasSelectionMode:r,singleSelection:s,multipleSelection:l,allRowsSelected:u,someRowsSelected:c,rowsSelectedNumber:d,isRowSelected:function(e){return!0===o.value[e]},clearSelection:function(){t("update:selected",[])},updateSelection:function(n,i,o,r){t("selection",{rows:i,added:o,keys:n,evt:r});let l=!0===s.value?!0===o?i:[]:!0===o?e.selected.concat(i):e.selected.filter(e=>!1===n.includes(a.value(e)));t("update:selected",l)}}}(e,r,R,p),{colList:U,computedCols:H,computedColsMap:W,computedColspan:G}=function(e,t,n){let a=i(()=>{if(void 0!==e.columns)return e.columns;let t=e.rows[0];return void 0!==t?Object.keys(t).map(e=>({name:e,label:e.toUpperCase(),field:e,align:$e(t[e])?"right":"left",sortable:!0})):[]}),o=i(()=>{let{sortBy:n,descending:i}=t.value;return(void 0!==e.visibleColumns?a.value.filter(t=>!0===t.required||!0===e.visibleColumns.includes(t.name)):a.value).map(e=>{let t=e.align||"right",a=`text-${t}`;return{...e,align:t,__iconClass:`q-table__sort-icon q-table__sort-icon--${t}`,__thClass:a+(void 0!==e.headerClasses?" "+e.headerClasses:"")+(!0===e.sortable?" sortable":"")+(e.name===n?" sorted "+(!0===i?"sort-desc":""):""),__tdStyle:void 0!==e.style?"function"!=typeof e.style?()=>e.style:e.style:()=>null,__tdClass:void 0!==e.classes?"function"!=typeof e.classes?()=>a+" "+e.classes:t=>a+" "+e.classes(t):()=>a}})}),r=i(()=>{let e={};return o.value.forEach(t=>{e[t.name]=t}),e}),s=i(()=>void 0!==e.tableColspan?e.tableColspan:o.value.length+(!0===n.value?1:0));return{colList:a,computedCols:o,computedColsMap:r,computedColspan:s}}(e,w,O),{columnToSort:K,computedSortMethod:Y,sort:Q}=Pc(e,w,U,C),{firstRowIndex:Z,lastRowIndex:J,isFirstPage:X,isLastPage:ee,pagesNumber:te,computedRowsPerPageOptions:ne,computedRowsNumber:ae,firstPage:ie,prevPage:oe,nextPage:re,lastPage:se}=function(e,t,n,a,r,s){let{props:l,emit:u,proxy:{$q:c}}=e,d=i(()=>!0===a.value?n.value.rowsNumber||0:s.value),h=i(()=>{let{page:e,rowsPerPage:t}=n.value;return(e-1)*t}),p=i(()=>{let{page:e,rowsPerPage:t}=n.value;return e*t}),f=i(()=>1===n.value.page),m=i(()=>0===n.value.rowsPerPage?1:Math.max(1,Math.ceil(d.value/n.value.rowsPerPage))),g=i(()=>0===p.value||n.value.page>=m.value),_=i(()=>(l.rowsPerPageOptions.includes(t.value.rowsPerPage)?l.rowsPerPageOptions:[t.value.rowsPerPage].concat(l.rowsPerPageOptions)).map(e=>({label:0===e?c.lang.table.allRows:""+e,value:e})));return o(m,(e,t)=>{if(e===t)return;let a=n.value.page;e&&!a?r({page:1}):e1&&r({page:e-1})},nextPage:function(){let{page:e,rowsPerPage:t}=n.value;p.value>0&&e*t0===R.value.length),ue=i(()=>{let t={};return Ru.forEach(n=>{t[n]=e[n]}),void 0===t.virtualScrollItemSize&&(t.virtualScrollItemSize=!0===e.dense?28:48),t});function ce(){if(!0===e.grid)return function(){let a=void 0!==t.item?t.item:a=>{let i=a.cols.map(e=>n("div",{class:"q-table__grid-item-row"},[n("div",{class:"q-table__grid-item-title"},[e.label]),n("div",{class:"q-table__grid-item-value"},[e.value])]));if(!0===O.value){let o=t["body-selection"],r=void 0!==o?o(a):[n(ji,{modelValue:a.selected,color:e.color,dark:u.value,dense:e.dense,"onUpdate:modelValue":(e,t)=>{V([a.key],[a.row],e,t)}})];i.unshift(n("div",{class:"q-table__grid-item-row"},r),n(ws,{dark:u.value}))}let o={class:["q-table__grid-item-card"+_.value,e.cardClass],style:e.cardStyle};if(void 0!==e.cardStyleFn&&(o.style=[o.style,e.cardStyleFn(a.row)]),void 0!==e.cardClassFn){let t=e.cardClassFn(a.row);t&&(o.class[0]+=` ${t}`)}return(void 0!==e.onRowClick||void 0!==e.onRowDblclick||void 0!==e.onRowContextmenu)&&(o.class[0]+=" cursor-pointer",void 0!==e.onRowClick&&(o.onClick=e=>{r("RowClick",e,a.row,a.pageIndex)}),void 0!==e.onRowDblclick&&(o.onDblclick=e=>{r("RowDblclick",e,a.row,a.pageIndex)}),void 0!==e.onRowContextmenu&&(o.onContextmenu=e=>{r("rowContextmenu",e,a.row,a.pageIndex)})),n("div",{class:"q-table__grid-item col-xs-12 col-sm-6 col-md-4 col-lg-3"+(!0===a.selected?" q-table__grid-item--selected":"")},[n("div",o,i)])};return n("div",{class:["q-table__grid-content row",e.cardContainerClass],style:e.cardContainerStyle},R.value.map((e,t)=>a(me({key:p.value(e),row:e,pageIndex:t}))))}();let a=!0!==e.hideHeader?we:null;if(!0===g.value){let i=t["top-row"],o=t["bottom-row"],r={default:e=>pe(e.item,t.body,e.index)};if(void 0!==i){let e=n("tbody",i({cols:H.value}));r.before=null===a?()=>e:()=>[a()].concat(e)}else null!==a&&(r.before=a);return void 0!==o&&(r.after=()=>n("tbody",o({cols:H.value}))),n(Cc,{ref:m,class:e.tableClass,style:e.tableStyle,...ue.value,scrollTarget:e.virtualScrollTarget,items:R.value,type:"__qtable",tableColspan:G.value,onVirtualScroll:de},r)}let i=[fe()];return null!==a&&i.unshift(a()),kc({class:["q-table__middle scroll",e.tableClass],style:e.tableStyle},i)}function de(e){r("virtualScroll",e)}function he(){return[n(lu,{class:"q-table__linear-progress",color:e.color,dark:u.value,indeterminate:!0,trackColor:"transparent"})]}function pe(a,i,o){let s=p.value(a),l=F(s);if(void 0!==i){let t={key:s,row:a,pageIndex:o,__trClass:l?"selected":""};if(void 0!==e.tableRowStyleFn&&(t.__trStyle=e.tableRowStyleFn(a)),void 0!==e.tableRowClassFn){let n=e.tableRowClassFn(a);n&&(t.__trClass=`${n} ${t.__trClass}`)}return i(me(t))}let c=t["body-cell"],d=H.value.map(e=>{let i=t[`body-cell-${e.name}`],r=void 0!==i?i:c;return void 0!==r?r(function(e){return ge(e),z(e,"value",()=>_e(e.col,e.row)),e}({key:s,row:a,pageIndex:o,col:e})):n("td",{class:e.__tdClass(a),style:e.__tdStyle(a)},_e(e,a))});if(!0===O.value){let i=t["body-selection"],r=void 0!==i?i(function(e){return ge(e),e}({key:s,row:a,pageIndex:o})):[n(ji,{modelValue:l,color:e.color,dark:u.value,dense:e.dense,"onUpdate:modelValue":(e,t)=>{V([s],[a],e,t)}})];d.unshift(n("td",{class:"q-table--col-auto-width"},r))}let h={key:s,class:{selected:l}};if(void 0!==e.onRowClick&&(h.class["cursor-pointer"]=!0,h.onClick=e=>{r("rowClick",e,a,o)}),void 0!==e.onRowDblclick&&(h.class["cursor-pointer"]=!0,h.onDblclick=e=>{r("rowDblclick",e,a,o)}),void 0!==e.onRowContextmenu&&(h.class["cursor-pointer"]=!0,h.onContextmenu=e=>{r("rowContextmenu",e,a,o)}),void 0!==e.tableRowStyleFn&&(h.style=e.tableRowStyleFn(a)),void 0!==e.tableRowClassFn){let t=e.tableRowClassFn(a);t&&(h.class[t]=!0)}return n("tr",h,d)}function fe(){let e=t.body,a=t["top-row"],i=t["bottom-row"],o=R.value.map((t,n)=>pe(t,e,n));return void 0!==a&&(o=a({cols:H.value}).concat(o)),void 0!==i&&(o=o.concat(i({cols:H.value}))),n("tbody",o)}function me(e){return ge(e),e.cols=e.cols.map(t=>z({...t},"value",()=>_e(t,e.row))),e}function ge(t){Object.assign(t,{cols:H.value,colsMap:W.value,sort:Q,rowIndex:Z.value+t.pageIndex,color:e.color,dark:u.value,dense:e.dense}),!0===O.value&&z(t,"selected",()=>F(t.key),(e,n)=>{V([t.key],[t.row],e,n)}),z(t,"expand",()=>P(t.key),e=>{A(t.key,e)})}function _e(e,t){let n="function"==typeof e.field?e.field(t):t[e.field];return void 0!==e.format?e.format(n,t):n}let ve=i(()=>({pagination:w.value,pagesNumber:te.value,isFirstPage:X.value,isLastPage:ee.value,firstPage:ie,prevPage:oe,nextPage:re,lastPage:se,inFullscreen:c.value,toggleFullscreen:h}));function be(){let a,i=t.top,o=t["top-left"],r=t["top-right"],s=t["top-selection"],l=!0===O.value&&void 0!==s&&B.value>0,u="q-table__top relative-position row items-center";return void 0!==i?n("div",{class:u},[i(ve.value)]):(!0===l?a=s(ve.value).slice():(a=[],void 0!==o?a.push(n("div",{class:"q-table__control"},[o(ve.value)])):e.title&&a.push(n("div",{class:"q-table__control"},[n("div",{class:["q-table__title",e.titleClass]},e.title)]))),void 0!==r&&(a.push(n("div",{class:"q-table__separator col"})),a.push(n("div",{class:"q-table__control"},[r(ve.value)]))),0!==a.length?n("div",{class:u},a):void 0)}let ye=i(()=>!0===j.value?null:D.value);function we(){let a=function(){let a=t.header,i=t["header-cell"];if(void 0!==a)return a(ke({header:!0})).slice();let o=H.value.map(e=>{let a=t[`header-cell-${e.name}`],o=void 0!==a?a:i,r=ke({col:e});return void 0!==o?o(r):n(wc,{key:e.name,props:r},()=>e.label)});if(!0===I.value&&!0!==e.grid)o.unshift(n("th",{class:"q-table--col-auto-width"}," "));else if(!0===q.value){let a=t["header-selection"],i=void 0!==a?a(ke({})):[n(ji,{color:e.color,modelValue:ye.value,dark:u.value,dense:e.dense,"onUpdate:modelValue":xe})];o.unshift(n("th",{class:"q-table--col-auto-width"},i))}return[n("tr",{class:e.tableHeaderClass,style:e.tableHeaderStyle},o)]}();return!0===e.loading&&void 0===t.loading&&a.push(n("tr",{class:"q-table__progress"},[n("th",{class:"relative-position",colspan:G.value},he())])),n("thead",a)}function ke(t){return Object.assign(t,{cols:H.value,sort:Q,colsMap:W.value,color:e.color,dark:u.value,dense:e.dense}),!0===q.value&&z(t,"selected",()=>ye.value,xe),t}function xe(e){!0===j.value&&(e=!1),V(R.value.map(p.value),R.value,e)}let Se=i(()=>{let t=[e.iconFirstPage||l.iconSet.table.firstPage,e.iconPrevPage||l.iconSet.table.prevPage,e.iconNextPage||l.iconSet.table.nextPage,e.iconLastPage||l.iconSet.table.lastPage];return!0===l.lang.rtl?t.reverse():t});function Ce(){if(!0===e.hideBottom)return;if(!0===le.value){if(!0===e.hideNoData)return;let a=!0===e.loading?e.loadingLabel||l.lang.table.loading:e.filter?e.noResultsLabel||l.lang.table.noResults:e.noDataLabel||l.lang.table.noData,i=t["no-data"],o=void 0!==i?[i({message:a,icon:l.iconSet.table.warning,filter:e.filter})]:[n(Mt,{class:"q-table__bottom-nodata-icon",name:l.iconSet.table.warning}),a];return n("div",{class:Oc+" q-table__bottom--nodata"},o)}let a=t.bottom;if(void 0!==a)return n("div",{class:Oc},[a(ve.value)]);let i=!0!==e.hideSelectedBanner&&!0===O.value&&B.value>0?[n("div",{class:"q-table__control"},[n("div",[(e.selectedRowsLabel||l.lang.table.selectedRecords)(B.value)])])]:[];return!0!==e.hidePagination?n("div",{class:Oc+" justify-end"},function(a){let i,{rowsPerPage:o}=w.value,r=e.paginationLabel||l.lang.table.pagination,s=t.pagination,c=e.rowsPerPageOptions.length>1;if(a.push(n("div",{class:"q-table__separator col"})),!0===c&&a.push(n("div",{class:"q-table__control"},[n("span",{class:"q-table__bottom-item"},[e.rowsPerPageLabel||l.lang.table.recordsPerPage]),n(Du,{class:"q-table__select inline q-table__bottom-item",color:e.color,modelValue:o,options:ne.value,displayValue:0===o?l.lang.table.allRows:o,dark:u.value,borderless:!0,dense:!0,optionsDense:!0,optionsCover:!0,"onUpdate:modelValue":Te})])),void 0!==s)i=s(ve.value);else if(i=[n("span",0!==o?{class:"q-table__bottom-item"}:{},[o?r(Z.value+1,Math.min(J.value,ae.value),ae.value):r(1,L.value,ae.value)])],0!==o&&te.value>1){let t={color:e.color,round:!0,dense:!0,flat:!0};!0===e.dense&&(t.size="sm"),te.value>2&&i.push(n(An,{key:"pgFirst",...t,icon:Se.value[0],disable:X.value,"aria-label":l.lang.pagination.first,onClick:ie})),i.push(n(An,{key:"pgPrev",...t,icon:Se.value[1],disable:X.value,"aria-label":l.lang.pagination.prev,onClick:oe}),n(An,{key:"pgNext",...t,icon:Se.value[2],disable:ee.value,"aria-label":l.lang.pagination.next,onClick:re})),te.value>2&&i.push(n(An,{key:"pgLast",...t,icon:Se.value[3],disable:ee.value,"aria-label":l.lang.pagination.last,onClick:se}))}return a.push(n("div",{class:"q-table__control"},i)),a}(i)):0!==i.length?n("div",{class:Oc},i):void 0}function Te(e){C({page:1,rowsPerPage:e.value})}return Object.assign(s.proxy,{requestServerInteraction:S,setPagination:C,firstPage:ie,prevPage:oe,nextPage:re,lastPage:se,isRowSelected:F,clearSelection:$,isRowExpanded:P,setExpanded:E,sort:Q,resetVirtualScroll:function(){!0===g.value&&m.value.reset()},scrollTo:function(t,n){if(null!==m.value)return void m.value.scrollTo(t,n);t=parseInt(t,10);let a=f.value.querySelector(`tbody tr:nth-of-type(${t+1})`);if(null!==a){let n=f.value.querySelector(".q-table__middle.scroll"),i=a.offsetTop-e.virtualScrollStickySizeStart,o=iM.value,computedRows:()=>R.value,computedRowsNumber:()=>ae.value}),()=>{let a=[be()],i={ref:f,class:b.value};return!0===e.grid?a.push(function(){let a=!0===e.gridHeader?[n("table",{class:"q-table"},[we()])]:!0===e.loading&&void 0===t.loading?he():void 0;return n("div",{class:"q-table__middle"},a)}()):Object.assign(i,{class:[i.class,e.cardClass],style:e.cardStyle}),a.push(ce(),Ce()),!0===e.loading&&void 0!==t.loading&&a.push(t.loading()),n("div",i,a)}}}),Dc=$({name:"QTr",props:{props:Object,noHover:Boolean},setup(e,{slots:t}){let a=i(()=>"q-tr"+(void 0===e.props||!0===e.props.header?"":" "+e.props.__trClass)+(!0===e.noHover?" q-tr--no-hover":""));return()=>n("tr",{style:e.props?.__trStyle,class:a.value},dt(t.default))}}),jc=$({name:"QTd",props:{props:Object,autoWidth:Boolean,noHover:Boolean},setup(e,{slots:t}){let a=k(),o=i(()=>"q-td"+(!0===e.autoWidth?" q-table--col-auto-width":"")+(!0===e.noHover?" q-td--no-hover":"")+" ");return()=>{if(void 0===e.props)return n("td",{class:o.value},dt(t.default));let i=a.vnode.key,r=(void 0!==e.props.colsMap?e.props.colsMap[i]:null)||e.props.col;if(void 0===r)return;let{row:s}=e.props;return n("td",{class:o.value+r.__tdClass(s),style:r.__tdStyle(s)},dt(t.default))}}}),Bc=$({name:"QRouteTab",props:{...en,...mo},emits:fo,setup(e,{slots:t,emit:n}){let a=tn({useDisableForRouterLinkProps:!1}),{renderTab:r,$tabs:s}=go(e,t,n,{exact:i(()=>e.exact),...a});return o(()=>`${e.name} | ${e.exact} | ${(a.resolvedLink.value||{}).href}`,s.verifyRouteModel),()=>r(a.linkTag.value,a.linkAttrs.value)}});function Fc(){let e=new Date;return{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}}var $c=$({name:"QTime",props:{...Nt,...ai,...Qo,modelValue:{required:!0,validator:e=>"string"==typeof e||null===e},mask:{...Qo.mask,default:null},format24h:{type:Boolean,default:null},defaultDate:{type:String,validator:e=>/^-?[\d]+\/[0-1]\d\/[0-3]\d$/.test(e)},options:Function,hourOptions:Array,minuteOptions:Array,secondOptions:Array,withSeconds:Boolean,nowBtn:Boolean},emits:Zo,setup(e,{slots:t,emit:r}){let s,l,u=k(),{$q:c}=u.proxy,h=Ot(e,c),{tabindex:p,headerClass:f,getLocale:m,getCurrentDate:g}=Xo(e,c),_=oi(ii(e)),v=a(null),b=i(()=>"persian"!==e.calendar&&null!==e.mask?e.mask:"HH:mm"+(!0===e.withSeconds?":ss":"")),y=i(()=>m()),w=i(()=>function(){if("string"!=typeof e.defaultDate){let e=g(!0);return e.dateHash=Jo(e),e}return dr(e.defaultDate,"YYYY/MM/DD",void 0,e.calendar)}()),x=dr(e.modelValue,b.value,y.value,e.calendar,w.value),C=a(function(e,t){if(null!==e.hour){if(null===e.minute)return"minute";if(!0===t&&null===e.second)return"second"}return"hour"}(x)),T=a(x),P=a(null===x.hour||x.hour<12),E=i(()=>"q-time q-time--"+(!0===e.landscape?"landscape":"portrait")+(!0===h.value?" q-time--dark q-dark":"")+(!0===e.disable?" disabled":!0===e.readonly?" q-time--readonly":"")+(!0===e.bordered?" q-time--bordered":"")+(!0===e.square?" q-time--square no-border-radius":"")+(!0===e.flat?" q-time--flat no-shadow":"")),M=i(()=>{let e=T.value;return{hour:null===e.hour?"--":!0===L.value?et(e.hour):String(!0===P.value?0===e.hour?12:e.hour:e.hour>12?e.hour-12:e.hour),minute:null===e.minute?"--":et(e.minute),second:null===e.second?"--":et(e.second)}}),L=i(()=>null!==e.format24h?e.format24h:c.lang.date.format24h),R=i(()=>{let e="hour"===C.value,t=!0===e?12:60,n=T.value[C.value],a=`rotate(${Math.round(n*(360/t))-180}deg) translateX(-50%)`;return!0===e&&!0===L.value&&T.value.hour>=12&&(a+=" scale(.7)"),{transform:a}}),z=i(()=>null!==T.value.hour),N=i(()=>!0===z.value&&null!==T.value.minute),O=i(()=>void 0!==e.hourOptions?t=>e.hourOptions.includes(t):void 0!==e.options?t=>e.options(t,null,null):null),I=i(()=>void 0!==e.minuteOptions?t=>e.minuteOptions.includes(t):void 0!==e.options?t=>e.options(T.value.hour,t,null):null),q=i(()=>void 0!==e.secondOptions?t=>e.secondOptions.includes(t):void 0!==e.options?t=>e.options(T.value.hour,T.value.minute,t):null),D=i(()=>{if(null===O.value)return null;let e=H(0,11,O.value),t=H(12,11,O.value);return{am:e,pm:t,values:e.values.concat(t.values)}}),j=i(()=>null!==I.value?H(0,59,I.value):null),B=i(()=>null!==q.value?H(0,59,q.value):null),F=i(()=>{switch(C.value){case"hour":return D.value;case"minute":return j.value;case"second":return B.value}}),$=i(()=>{let e,t,n=0,a=1,i=null!==F.value?F.value.values:void 0;"hour"===C.value?!0===L.value?(e=0,t=23):(e=0,t=11,!1===P.value&&(n=12)):(e=0,t=55,a=5);let o=[];for(let r=e,s=e;r<=t;r+=a,s++){let e=r+n,t=!1===i?.includes(e),a="hour"===C.value&&0===r?!0===L.value?"00":"12":r;o.push({val:e,index:s,disable:t,label:a})}return o}),V=i(()=>[[Ki,Z,void 0,{stop:!0,prevent:!0,mouse:!0}]]);function U(){let e={...g(),...Fc()};ge(e),Object.assign(T.value,e),C.value="hour"}function H(e,t,n){let a=Array.apply(null,{length:t+1}).map((t,a)=>{let i=a+e;return{index:i,val:!0===n(i)}}).filter(e=>!0===e.val).map(e=>e.index);return{min:a[0],max:a[a.length-1],values:a,threshold:t+1}}function W(e,t,n){let a=Math.abs(e-t);return Math.min(a,n-a)}function G(e,{min:t,max:n,values:a,threshold:i}){if(e===t)return t;if(en)return W(e,t,i)<=W(e,n,i)?t:n;let o=a.findIndex(t=>e<=t),r=a[o-1],s=a[o];return e-r<=s-e?r:s}function Y(){return!0===Wt(u)||null!==F.value&&(0===F.value.values.length||"hour"===C.value&&!0!==L.value&&0===D.value[!0===P.value?"am":"pm"].values.length)}function Q(){let e=v.value,{top:t,left:n,width:a}=e.getBoundingClientRect(),i=a/2;return{top:t+i,left:n+i,dist:.7*i}}function Z(e){if(!0!==Y()){if(!0===e.isFirst)return s=Q(),void(l=X(e.evt,s));l=X(e.evt,s,l),!0===e.isFinal&&(s=!1,l=null,J())}}function J(){"hour"===C.value?C.value="minute":e.withSeconds&&"minute"===C.value&&(C.value="second")}function X(e,t,n){let a,i=K(e),o=Math.abs(i.top-t.top),r=Math.sqrt(Math.pow(Math.abs(i.top-t.top),2)+Math.pow(Math.abs(i.left-t.left),2)),s=Math.asin(o/r)*(180/Math.PI);if(s=i.top=t.dist:0!==D.value.am.values.length;a=G(a+(!0===e?0:12),D.value[!0===e?"am":"pm"])}else a=Math.round(a),!0===L.value?re.modelValue,t=>{let n=dr(t,b.value,y.value,e.calendar,w.value);(n.dateHash!==T.value.dateHash||n.timeHash!==T.value.timeHash)&&(T.value=n,null===n.hour?C.value="hour":P.value=n.hour<12)}),o([b,y],()=>{d(()=>{ge()})});let ee={hour(){C.value="hour"},minute(){C.value="minute"},second(){C.value="second"}};function te(e){13===e.keyCode&&he()}function ne(e){13===e.keyCode&&pe()}function ae(e){!0!==Y()&&(!0!==c.platform.is.desktop&&X(e,Q()),J())}function ie(e){!0!==Y()&&X(e,Q())}function oe(e){if(13===e.keyCode)C.value="hour";else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==D.value){let e=!0===L.value?D.value.values:D.value[!0===P.value?"am":"pm"].values;if(0===e.length)return;if(null===T.value.hour)le(e[0]);else{let n=(e.length+e.indexOf(T.value.hour)+t)%e.length;le(e[n])}}else{let e=!0===L.value?24:12;le((!0!==L.value&&!1===P.value?12:0)+(24+(null===T.value.hour?-t:T.value.hour)+t)%e)}}}function re(e){if(13===e.keyCode)C.value="minute";else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==j.value){let e=j.value.values;if(0===e.length)return;if(null===T.value.minute)ue(e[0]);else{let n=(e.length+e.indexOf(T.value.minute)+t)%e.length;ue(e[n])}}else{ue((60+(null===T.value.minute?-t:T.value.minute)+t)%60)}}}function se(e){if(13===e.keyCode)C.value="second";else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==B.value){let e=B.value.values;if(0===e.length)return;if(null===T.value.seconds)ce(e[0]);else{let n=(e.length+e.indexOf(T.value.second)+t)%e.length;ce(e[n])}}else{ce((60+(null===T.value.second?-t:T.value.second)+t)%60)}}}function le(e){T.value.hour!==e&&(T.value.hour=e,me())}function ue(e){T.value.minute!==e&&(T.value.minute=e,me())}function ce(e){T.value.second!==e&&(T.value.second=e,me())}let de={hour:le,minute:ue,second:ce};function he(){!1===P.value&&(P.value=!0,null!==T.value.hour&&(T.value.hour-=12,me()))}function pe(){!0===P.value&&(P.value=!1,null!==T.value.hour&&(T.value.hour+=12,me()))}function fe(t){let n=e.modelValue;C.value!==t&&null!=n&&""!==n&&"string"!=typeof n&&(C.value=t)}function me(){return null!==O.value&&!0!==O.value(T.value.hour)?(T.value=dr(),void fe("hour")):null!==I.value&&!0!==I.value(T.value.minute)?(T.value.minute=null,T.value.second=null,void fe("minute")):!0===e.withSeconds&&null!==q.value&&!0!==q.value(T.value.second)?(T.value.second=null,void fe("second")):void(null===T.value.hour||null===T.value.minute||!0===e.withSeconds&&null===T.value.second||ge())}function ge(t){let n=Object.assign({...T.value},t),a="persian"===e.calendar?et(n.hour)+":"+et(n.minute)+(!0===e.withSeconds?":"+et(n.second):""):wr(new Date(n.year,null===n.month?null:n.month-1,n.day,n.hour,n.minute,n.second,n.millisecond),b.value,y.value,n.year,n.timezoneOffset);n.changed=a!==e.modelValue,r("update:modelValue",a,n)}function _e(){let t=[n("div",{class:"q-time__link "+("hour"===C.value?"q-time__link--active":"cursor-pointer"),tabindex:p.value,onClick:ee.hour,onKeyup:oe},M.value.hour),n("div",":"),n("div",!0===z.value?{class:"q-time__link "+("minute"===C.value?"q-time__link--active":"cursor-pointer"),tabindex:p.value,onKeyup:re,onClick:ee.minute}:{class:"q-time__link"},M.value.minute)];!0===e.withSeconds&&t.push(n("div",":"),n("div",!0===N.value?{class:"q-time__link "+("second"===C.value?"q-time__link--active":"cursor-pointer"),tabindex:p.value,onKeyup:se,onClick:ee.second}:{class:"q-time__link"},M.value.second));let a=[n("div",{class:"q-time__header-label row items-center no-wrap",dir:"ltr"},t)];return!1===L.value&&a.push(n("div",{class:"q-time__header-ampm column items-between no-wrap"},[n("div",{class:"q-time__link "+(!0===P.value?"q-time__link--active":"cursor-pointer"),tabindex:p.value,onClick:he,onKeyup:te},"AM"),n("div",{class:"q-time__link "+(!0!==P.value?"q-time__link--active":"cursor-pointer"),tabindex:p.value,onClick:pe,onKeyup:ne},"PM")])),n("div",{class:"q-time__header flex flex-center no-wrap "+f.value},a)}function ve(){let t=T.value[C.value];return n("div",{class:"q-time__content col relative-position"},[n(S,{name:"q-transition--scale"},()=>n("div",{key:"clock"+C.value,class:"q-time__container-parent absolute-full"},[n("div",{ref:v,class:"q-time__container-child fit overflow-hidden"},[A(n("div",{class:"q-time__clock cursor-pointer non-selectable",onClick:ae,onMousedown:ie},[n("div",{class:"q-time__clock-circle fit"},[n("div",{class:"q-time__clock-pointer"+(null===T.value[C.value]?" hidden":void 0!==e.color?` text-${e.color}`:""),style:R.value}),$.value.map(e=>n("div",{class:`q-time__clock-position row flex-center q-time__clock-pos-${e.index}`+(e.val===t?" q-time__clock-position--active "+f.value:!0===e.disable?" q-time__clock-position--disable":"")},[n("span",e.label)]))])]),V.value)])])),!0===e.nowBtn?n(An,{class:"q-time__now-button absolute",icon:c.iconSet.datetime.now,unelevated:!0,size:"sm",round:!0,color:e.color,textColor:e.textColor,tabindex:p.value,onClick:U}):null])}return u.proxy.setNow=U,()=>{let a=[ve()],i=dt(t.default);return void 0!==i&&a.push(n("div",{class:"q-time__actions"},i)),void 0!==e.name&&!0!==e.disable&&_(a,"push"),n("div",{class:E.value,tabindex:-1},[_e(),n("div",{class:"q-time__main col overflow-auto"},a)])}}}),Vc=$({name:"QTimeline",props:{...Nt,color:{type:String,default:"primary"},side:{type:String,default:"right",validator:e=>["left","right"].includes(e)},layout:{type:String,default:"dense",validator:e=>["dense","comfortable","loose"].includes(e)}},setup(e,{slots:t}){let a=k(),o=Ot(e,a.proxy.$q);w(Pe,e);let r=i(()=>`q-timeline q-timeline--${e.layout} q-timeline--${e.layout}--${e.side}`+(!0===o.value?" q-timeline--dark":""));return()=>n("ul",{class:r.value},dt(t.default))}}),Uc=$({name:"QTimelineEntry",props:{heading:Boolean,tag:{type:String,default:"h3"},side:{type:String,default:"right",validator:e=>["left","right"].includes(e)},icon:String,avatar:String,color:String,title:String,subtitle:String,body:String},setup(e,{slots:t}){let a=y(Pe,Oe);if(a===Oe)return console.error("QTimelineEntry needs to be child of QTimeline"),Oe;let o=i(()=>`q-timeline__entry q-timeline__entry--${e.side}`+(void 0!==e.icon||void 0!==e.avatar?" q-timeline__entry--icon":"")),r=i(()=>`q-timeline__dot text-${e.color||a.color}`),s=i(()=>"comfortable"===a.layout&&"left"===a.side);return()=>{let a,i=ht(t.default,[]);if(void 0!==e.body&&i.unshift(e.body),!0===e.heading){let t=[n("div"),n("div"),n(e.tag,{class:"q-timeline__heading-title"},i)];return n("div",{class:"q-timeline__heading"},!0===s.value?t.reverse():t)}void 0!==e.icon?a=[n(Mt,{class:"row items-center justify-center",name:e.icon})]:void 0!==e.avatar&&(a=[n("img",{class:"q-timeline__dot-img",src:e.avatar})]);let l=[n("div",{class:"q-timeline__subtitle"},[n("span",{},dt(t.subtitle,[e.subtitle]))]),n("div",{class:r.value},a),n("div",{class:"q-timeline__content"},[n("h6",{class:"q-timeline__title"},dt(t.title,[e.title]))].concat(i))];return n("li",{class:o.value},!0===s.value?l.reverse():l)}}}),Hc=$({name:"QToolbar",props:{inset:Boolean},setup(e,{slots:t}){let a=i(()=>"q-toolbar row no-wrap items-center"+(!0===e.inset?" q-toolbar--inset":""));return()=>n("div",{class:a.value,role:"toolbar"},dt(t.default))}}),Wc=$({name:"QToolbarTitle",props:{shrink:Boolean},setup(e,{slots:t}){let a=i(()=>"q-toolbar__title ellipsis"+(!0===e.shrink?" col-shrink":""));return()=>n("div",{class:a.value},dt(t.default))}}),Gc=["none","strict","leaf","leaf-filtered"],Kc=$({name:"QTree",props:{...Nt,nodes:{type:Array,required:!0},nodeKey:{type:String,required:!0},labelKey:{type:String,default:"label"},childrenKey:{type:String,default:"children"},dense:Boolean,color:String,controlColor:String,textColor:String,selectedColor:String,icon:String,tickStrategy:{type:String,default:"none",validator:e=>Gc.includes(e)},ticked:Array,expanded:Array,selected:{},noSelectionUnset:Boolean,defaultExpandAll:Boolean,accordion:Boolean,filter:String,filterMethod:Function,duration:{},noConnectors:Boolean,noTransition:Boolean,noNodesLabel:String,noResultsLabel:String},emits:["update:expanded","update:ticked","update:selected","lazyLoad","afterShow","afterHide"],setup(e,{slots:t,emit:r}){let{proxy:s}=k(),{$q:l}=s,u=Ot(e,l),c=a({}),h=a(e.ticked||[]),p=a(e.expanded||[]),f={};v(()=>{f={}});let m=i(()=>"q-tree q-tree--"+(!0===e.dense?"dense":"standard")+(!0===e.noConnectors?" q-tree--no-connectors":"")+(!0===u.value?" q-tree--dark":"")+(void 0!==e.color?` text-${e.color}`:"")),g=i(()=>void 0!==e.selected),_=i(()=>e.icon||l.iconSet.tree.icon),b=i(()=>e.controlColor||e.color),y=i(()=>void 0!==e.textColor?` text-${e.textColor}`:""),w=i(()=>{let t=e.selectedColor||e.color;return t?` text-${t}`:""}),x=i(()=>void 0!==e.filterMethod?e.filterMethod:(t,n)=>{let a=n.toLowerCase();return t[e.labelKey]&&-1!==t[e.labelKey].toLowerCase().indexOf(a)}),S=i(()=>{let t={},n=(a,i)=>{let o=a.tickStrategy||(i?i.tickStrategy:e.tickStrategy),r=a[e.nodeKey],s=a[e.childrenKey]&&Array.isArray(a[e.childrenKey])&&0!==a[e.childrenKey].length,l=!0!==a.disabled&&!0===g.value&&!1!==a.selectable,u=!0!==a.disabled&&!1!==a.expandable,d="none"!==o,f="strict"===o,m="leaf-filtered"===o,_="leaf"===o||"leaf-filtered"===o,v=!0!==a.disabled&&!1!==a.tickable;!0===_&&!0===v&&i&&!0!==i.tickable&&(v=!1);let b=a.lazy;!0===b&&void 0!==c.value[r]&&!0===Array.isArray(a[e.childrenKey])&&(b=c.value[r]);let y={key:r,parent:i,isParent:s,lazy:b,disabled:a.disabled,link:!0!==a.disabled&&(!0===l||!0===u&&(!0===s||!0===b)),children:[],matchesFilter:!e.filter||x.value(a,e.filter),selected:r===e.selected&&!0===l,selectable:l,expanded:!0===s&&p.value.includes(r),expandable:u,noTick:!0===a.noTick||!0!==f&&b&&"loaded"!==b,tickable:v,tickStrategy:o,hasTicking:d,strictTicking:f,leafFilteredTicking:m,leafTicking:_,ticked:(!0===f||!0!==s)&&h.value.includes(r)};if(t[r]=y,!0===s&&(y.children=a[e.childrenKey].map(e=>n(e,y)),e.filter&&(!0!==y.matchesFilter?y.matchesFilter=y.children.some(e=>e.matchesFilter):!0!==y.noTick&&!0!==y.disabled&&!0===y.tickable&&!0===m&&!0===y.children.every(e=>!0!==e.matchesFilter||!0===e.noTick||!0!==e.tickable)&&(y.tickable=!1)),!0===y.matchesFilter&&(!0!==y.noTick&&!0!==f&&!0===y.children.every(e=>e.noTick)&&(y.noTick=!0),_))){if(y.ticked=!1,y.indeterminate=y.children.some(e=>!0===e.indeterminate),y.tickable=!0===y.tickable&&y.children.some(e=>e.tickable),!0!==y.indeterminate){let e=y.children.reduce((e,t)=>!0===t.ticked?e+1:e,0);e===y.children.length?y.ticked=!0:e>0&&(y.indeterminate=!0)}!0===y.indeterminate&&(y.indeterminateNextState=y.children.every(e=>!0!==e.tickable||!0!==e.ticked))}return y};return e.nodes.forEach(e=>n(e,null)),t});function C(t){let n=[].reduce,a=(i,o)=>i||!o?i:!0===Array.isArray(o)?n.call(Object(o),a,i):o[e.nodeKey]===t?o:o[e.childrenKey]?a(null,o[e.childrenKey]):void 0;return a(null,e.nodes)}function T(){let t=[],n=a=>{a[e.childrenKey]&&0!==a[e.childrenKey].length&&!1!==a.expandable&&!0!==a.disabled&&(t.push(a[e.nodeKey]),a[e.childrenKey].forEach(n))};e.nodes.forEach(n),void 0!==e.expanded?r("update:expanded",t):p.value=t}function P(t,n,a=C(t),i=S.value[t]){if(i.lazy&&"loaded"!==i.lazy){if("loading"===i.lazy)return;c.value[t]="loading",!0!==Array.isArray(a[e.childrenKey])&&(a[e.childrenKey]=[]),r("lazyLoad",{node:a,key:t,done:n=>{c.value[t]="loaded",a[e.childrenKey]=!0===Array.isArray(n)?n:[],d(()=>{!0===S.value[t]?.isParent&&E(t,!0)})},fail:()=>{delete c.value[t],0===a[e.childrenKey].length&&delete a[e.childrenKey]}})}else!0===i.isParent&&!0===i.expandable&&E(t,n)}function E(t,n){let a=p.value,i=void 0!==e.expanded;if(!0===i&&(a=a.slice()),n){if(e.accordion&&S.value[t]){let n=[];S.value[t].parent?S.value[t].parent.children.forEach(e=>{e.key!==t&&!0===e.expandable&&n.push(e.key)}):e.nodes.forEach(a=>{let i=a[e.nodeKey];i!==t&&n.push(i)}),0!==n.length&&(a=a.filter(e=>!1===n.includes(e)))}a=a.concat([t]).filter((e,t,n)=>n.indexOf(e)===t)}else a=a.filter(e=>e!==t);!0===i?r("update:expanded",a):p.value=a}function L(t,n){let a=h.value,i=void 0!==e.ticked;!0===i&&(a=a.slice()),a=n?a.concat(t).filter((e,t,n)=>n.indexOf(e)===t):a.filter(e=>!1===t.includes(e)),!0===i&&r("update:ticked",a)}function R(a){return(e.filter?a.filter(t=>S.value[t[e.nodeKey]].matchesFilter):a).map(a=>function(a){let i=a[e.nodeKey],o=S.value[i],r=a.header&&t[`header-${a.header}`]||t["default-header"],l=!0===o.isParent?R(a[e.childrenKey]):[],c=0!==l.length||o.lazy&&"loaded"!==o.lazy,d=a.body&&t[`body-${a.body}`]||t["default-body"],h=void 0!==r||void 0!==d?function(t,n,a){let i={tree:s,node:t,key:a,color:e.color,dark:u.value};return z(i,"expanded",()=>n.expanded,e=>{e!==n.expanded&&P(a,e)}),z(i,"ticked",()=>n.ticked,e=>{e!==n.ticked&&L([a],e)}),i}(a,o,i):null;return void 0!==d&&(d=n("div",{class:"q-tree__node-body relative-position"},[n("div",{class:y.value},[d(h)])])),n("div",{key:i,class:"q-tree__node relative-position q-tree__node--"+(!0===c?"parent":"child")},[n("div",{class:"q-tree__node-header relative-position row no-wrap items-center"+(!0===o.link?" q-tree__node--link q-hoverable q-focusable":"")+(!0===o.selected?" q-tree__node--selected":"")+(!0===o.disabled?" q-tree__node--disabled":""),tabindex:!0===o.link?0:-1,ariaExpanded:l.length>0?o.expanded:null,role:"treeitem",onClick:e=>{D(a,o,e)},onKeypress(e){!0!==he(e)&&(13===e.keyCode?D(a,o,e,!0):32===e.keyCode&&j(a,o,e,!0))}},[n("div",{class:"q-focus-helper",tabindex:-1,ref:e=>{f[o.key]=e}}),"loading"===o.lazy?n(rn,{class:"q-tree__spinner",color:b.value}):!0===c?n(Mt,{class:"q-tree__arrow"+(!0===o.expanded?" q-tree__arrow--rotate":""),name:_.value,onClick(e){j(a,o,e)}}):null,!0===o.hasTicking&&!0!==o.noTick?n(ji,{class:"q-tree__tickbox",modelValue:!0===o.indeterminate?null:o.ticked,color:b.value,dark:u.value,dense:!0,keepColor:!0,disable:!0!==o.tickable,onKeydown:J,"onUpdate:modelValue":e=>{!function(e,t){if(!0===e.indeterminate&&(t=e.indeterminateNextState),e.strictTicking)L([e.key],t);else if(e.leafTicking){let n=[],a=e=>{e.isParent?(!0!==t&&!0!==e.noTick&&!0===e.tickable&&n.push(e.key),!0===e.leafTicking&&e.children.forEach(a)):!0!==e.noTick&&!0===e.tickable&&(!0!==e.leafFilteredTicking||!0===e.matchesFilter)&&n.push(e.key)};a(e),L(n,t)}}(o,e)}}):null,n("div",{class:"q-tree__node-header-content col row no-wrap items-center"+(!0===o.selected?w.value:y.value)},[r?r(h):[N(a),n("div",a[e.labelKey])]])]),!0===c?!0===e.noTransition?!0===o.expanded?n("div",{class:"q-tree__node-collapsible"+y.value,key:`${i}__q`},[d,n("div",{class:"q-tree__children"+(!0===o.disabled?" q-tree__node--disabled":""),role:"group"},l)]):null:n(vs,{duration:e.duration,onShow:O,onHide:I},()=>A(n("div",{class:"q-tree__node-collapsible"+y.value,key:`${i}__q`},[d,n("div",{class:"q-tree__children"+(!0===o.disabled?" q-tree__node--disabled":""),role:"group"},l)]),[[M,o.expanded]])):d])}(a))}function N(e){if(void 0!==e.icon)return n(Mt,{class:"q-tree__icon q-mr-sm",name:e.icon,color:e.iconColor});let t=e.img||e.avatar;return t?n("img",{class:`q-tree__${e.img?"img":"avatar"} q-mr-sm`,src:t}):void 0}function O(){r("afterShow")}function I(){r("afterHide")}function q(e){f[e]?.focus()}function D(t,n,a,i){!0!==i&&!1!==n.selectable&&q(n.key),g.value&&n.selectable?!1===e.noSelectionUnset?r("update:selected",n.key!==e.selected?n.key:null):n.key!==e.selected&&r("update:selected",void 0===n.key?null:n.key):j(t,n,a,i),"function"==typeof t.handler&&t.handler(t)}function j(e,t,n,a){void 0!==n&&J(n),!0!==a&&!1!==t.selectable&&q(t.key),P(t.key,!t.expanded,e,t)}return o(()=>e.ticked,e=>{h.value=e}),o(()=>e.expanded,e=>{p.value=e}),!0===e.defaultExpandAll&&T(),Object.assign(s,{getNodeByKey:C,getTickedNodes:function(){return h.value.map(e=>C(e))},getExpandedNodes:function(){return p.value.map(e=>C(e))},isExpanded:function(e){return!(!e||!S.value[e])&&S.value[e].expanded},collapseAll:function(){void 0!==e.expanded?r("update:expanded",[]):p.value=[]},expandAll:T,setExpanded:P,isTicked:function(e){return!(!e||!S.value[e])&&S.value[e].ticked},setTicked:L}),()=>{let t=R(e.nodes);return n("div",{class:m.value,role:"tree"},0===t.length?e.filter?e.noResultsLabel||l.lang.tree.noResults:e.noNodesLabel||l.lang.tree.noNodes:t)}}});function Yc(e){return(100*e).toFixed(2)+"%"}var Qc={...Nt,...Ws,label:String,color:String,textColor:String,square:Boolean,flat:Boolean,bordered:Boolean,noThumbnails:Boolean,thumbnailFit:{type:String,default:"cover"},autoUpload:Boolean,hideUploadBtn:Boolean,disable:Boolean,readonly:Boolean},Zc=[...Gs,"start","finish","added","removed"];var Jc=()=>!0;function Xc(e){let t={};return e.forEach(e=>{t[e]=Jc}),t}var ed=Xc(Zc),td=({name:e,props:t,emits:s,injectPlugin:l})=>$({name:e,props:{...Qc,...t},emits:!0===je(s)?{...ed,...s}:[...Zc,...s],setup:(e,{expose:t})=>function(e,t){let s=k(),{props:l,slots:u,emit:c,proxy:d}=s,{$q:h}=d,p=Ot(l,h),f=i(()=>!0!==l.disable&&!0!==l.readonly),m=a(!1),_=a(null),v=a(null),b={files:a([]),queuedFiles:a([]),uploadedFiles:a([]),uploadedSize:a(0),updateFileStatus:function(e,t,n){if(e.__status=t,"idle"===t)return e.__uploaded=0,e.__progress=0,e.__sizeLabel=Qe(e.size),void(e.__progressLabel="0.00%");"failed"!==t?(e.__uploaded="uploaded"===t?e.size:n,e.__progress="uploaded"===t?1:Math.min(.9999,e.__uploaded/e.size),e.__progressLabel=Yc(e.__progress),d.$forceUpdate()):d.$forceUpdate()},isAlive:()=>!1===Wt(s)},{pickFiles:y,addFiles:x,onDragover:S,onDragleave:C,processFiles:T,getDndNode:P,maxFilesNumber:E,maxTotalSizeNumber:A}=Ks({editable:f,dnd:m,getFileInput:W,addFilesToQueue:G});Object.assign(b,e({props:l,slots:u,emit:c,helpers:b,exposeApi:e=>{Object.assign(b,e)}})),void 0===b.isBusy&&(b.isBusy=a(!1));let M=a(0),L=i(()=>0===M.value?0:b.uploadedSize.value/M.value),R=i(()=>Yc(L.value)),O=i(()=>Qe(M.value)),I=i(()=>!0===f.value&&!0!==b.isUploading.value&&(!0===l.multiple||0===b.queuedFiles.value.length)&&(void 0===l.maxFiles||b.files.value.length!0===f.value&&!0!==b.isBusy.value&&!0!==b.isUploading.value&&0!==b.queuedFiles.value.length);w(Ne,Z);let D=i(()=>"q-uploader column no-wrap"+(!0===p.value?" q-uploader--dark q-dark":"")+(!0===l.bordered?" q-uploader--bordered":"")+(!0===l.square?" q-uploader--square no-border-radius":"")+(!0===l.flat?" q-uploader--flat no-shadow":"")+(!0===l.disable?" disabled q-uploader--disable":"")+(!0===m.value?" q-uploader--dnd":"")),j=i(()=>"q-uploader__header"+(void 0!==l.color?` bg-${l.color}`:"")+(void 0!==l.textColor?` text-${l.textColor}`:""));function B(){!1===l.disable&&(b.abort(),b.uploadedSize.value=0,M.value=0,H(),b.files.value=[],b.queuedFiles.value=[],b.uploadedFiles.value=[])}function F(){!1===l.disable&&V(["uploaded"],()=>{b.uploadedFiles.value=[]})}function $(){V(["idle","failed"],({size:e})=>{M.value-=e,b.queuedFiles.value=[]})}function V(e,t){if(!0===l.disable)return;let n={files:[],size:0},a=b.files.value.filter(t=>-1===e.indexOf(t.__status)||(n.size+=t.size,n.files.push(t),void 0!==t.__img&&window.URL.revokeObjectURL(t.__img.src),!1));0!==n.files.length&&(b.files.value=a,t(n),c("removed",n.files))}function U(e){l.disable||("uploaded"===e.__status?b.uploadedFiles.value=b.uploadedFiles.value.filter(t=>t.__key!==e.__key):"uploading"===e.__status?e.__abort():M.value-=e.size,b.files.value=b.files.value.filter(t=>t.__key!==e.__key||(void 0!==t.__img&&window.URL.revokeObjectURL(t.__img.src),!1)),b.queuedFiles.value=b.queuedFiles.value.filter(t=>t.__key!==e.__key),c("removed",[e]))}function H(){b.files.value.forEach(e=>{void 0!==e.__img&&window.URL.revokeObjectURL(e.__img.src)})}function W(){return v.value||_.value.getElementsByClassName("q-uploader__input")[0]}function G(e,t){let n=T(e,t,b.files.value,!0),a=W();null!=a&&(a.value=""),void 0!==n&&(n.forEach(e=>{if(b.updateFileStatus(e,"idle"),M.value+=e.size,!0!==l.noThumbnails&&e.type.toUpperCase().startsWith("IMAGE")){let t=new Image;t.src=window.URL.createObjectURL(e),e.__img=t}}),b.files.value=b.files.value.concat(n),b.queuedFiles.value=b.queuedFiles.value.concat(n),c("added",n),!0===l.autoUpload&&b.upload())}function K(){!0===q.value&&b.upload()}function Y(e,t,a){if(!0===e){let e,i={type:"a",key:t,icon:h.iconSet.uploader[t],flat:!0,dense:!0};return"add"===t?(i.onClick=y,e=Z):i.onClick=a,n(An,i,e)}}function Z(){return n("input",{ref:v,class:"q-uploader__input overflow-hidden absolute-full",tabindex:-1,type:"file",title:"",accept:l.accept,multiple:!0===l.multiple?"multiple":void 0,capture:l.capture,onMousedown:Q,onClick:y,onChange:G})}o(b.isUploading,(e,t)=>{!1===t&&!0===e?c("start"):!0===t&&!1===e&&c("finish")}),g(()=>{!0===b.isUploading.value&&b.abort(),0!==b.files.value.length&&H()});let J={};for(let e in b)!0===r(b[e])?z(J,e,()=>b[e].value):J[e]=b[e];return Object.assign(J,{upload:K,reset:B,removeUploadedFiles:F,removeQueuedFiles:$,removeFile:U,pickFiles:y,addFiles:x}),N(J,{canAddFiles:()=>I.value,canUpload:()=>q.value,uploadSizeLabel:()=>O.value,uploadProgressLabel:()=>R.value}),t({...b,upload:K,reset:B,removeUploadedFiles:F,removeQueuedFiles:$,removeFile:U,pickFiles:y,addFiles:x,canAddFiles:I,canUpload:q,uploadSizeLabel:O,uploadProgressLabel:R}),()=>{let e=[n("div",{class:j.value},void 0!==u.header?u.header(J):[n("div",{class:"q-uploader__header-content column"},[n("div",{class:"flex flex-center no-wrap q-gutter-xs"},[Y(0!==b.queuedFiles.value.length,"removeQueue",$),Y(0!==b.uploadedFiles.value.length,"removeUploaded",F),!0===b.isUploading.value?n(rn,{class:"q-uploader__spinner"}):null,n("div",{class:"col column justify-center"},[void 0!==l.label?n("div",{class:"q-uploader__title"},[l.label]):null,n("div",{class:"q-uploader__subtitle"},[O.value+" / "+R.value])]),Y(I.value,"add"),Y(!1===l.hideUploadBtn&&!0===q.value,"upload",b.upload),Y(b.isUploading.value,"clear",b.abort)])])]),n("div",{class:"q-uploader__list scroll"},void 0!==u.list?u.list(J):b.files.value.map(e=>n("div",{key:e.__key,class:"q-uploader__file relative-position"+(!0!==l.noThumbnails&&void 0!==e.__img?" q-uploader__file--img":"")+("failed"===e.__status?" q-uploader__file--failed":"uploaded"===e.__status?" q-uploader__file--uploaded":""),style:!0!==l.noThumbnails&&void 0!==e.__img?{backgroundImage:'url("'+e.__img.src+'")',backgroundSize:l.thumbnailFit}:null},[n("div",{class:"q-uploader__file-header row flex-center no-wrap"},["failed"===e.__status?n(Mt,{class:"q-uploader__file-status",name:h.iconSet.type.negative,color:"negative"}):null,n("div",{class:"q-uploader__file-header-content col"},[n("div",{class:"q-uploader__title"},[e.name]),n("div",{class:"q-uploader__subtitle row items-center no-wrap"},[e.__sizeLabel+" / "+e.__progressLabel])]),"uploading"===e.__status?n(Hi,{value:e.__progress,min:0,max:1,indeterminate:0===e.__progress}):n(An,{round:!0,dense:!0,flat:!0,icon:h.iconSet.uploader["uploaded"===e.__status?"done":"clear"],onClick:()=>{U(e)}})])]))),P("uploader")];!0===b.isBusy.value&&e.push(n("div",{class:"q-uploader__overlay absolute-full flex flex-center"},[n(rn)]));let t={ref:_,class:D.value};return!0===I.value&&Object.assign(t,{onDragover:S,onDragleave:C}),n("div",t,e)}}(l,t)});function nd(e){return"function"==typeof e?e:()=>e}var ad={url:[Function,String],method:{type:[Function,String],default:"POST"},fieldName:{type:[Function,String],default:()=>e=>e.name},headers:[Function,Array],formFields:[Function,Array],withCredentials:[Function,Boolean],sendRaw:[Function,Boolean],batch:[Function,Boolean],factory:Function};var id={name:"QUploader",props:ad,emits:["factoryFailed","uploaded","failed","uploading"],injectPlugin:function({props:e,emit:t,helpers:n}){let o,r=a([]),s=a([]),l=a(0),u=i(()=>({url:nd(e.url),method:nd(e.method),headers:nd(e.headers),formFields:nd(e.formFields),fieldName:nd(e.fieldName),withCredentials:nd(e.withCredentials),sendRaw:nd(e.sendRaw),batch:nd(e.batch)}));function c(a){if(l.value++,"function"!=typeof e.factory)return void d(a,{});let i=e.factory(a);if(i)if("function"==typeof i.catch&&"function"==typeof i.then){s.value.push(i);let e=e=>{!0===n.isAlive()&&(s.value=s.value.filter(e=>e!==i),0===s.value.length&&(o=!1),n.queuedFiles.value=n.queuedFiles.value.concat(a),a.forEach(e=>{n.updateFileStatus(e,"failed")}),t("factoryFailed",e,a),l.value--)};i.then(t=>{!0===o?e(new Error("Aborted")):!0===n.isAlive()&&(s.value=s.value.filter(e=>e!==i),d(a,t))}).catch(e)}else d(a,i||{});else t("factoryFailed",new Error("QUploader: factory() does not return properly"),a),l.value--}function d(e,a){let i=new FormData,o=new XMLHttpRequest,s=(e,t)=>void 0!==a[e]?nd(a[e])(t):u.value[e](t),c=s("url",e);if(!c)return console.error("q-uploader: invalid or no URL specified"),void l.value--;let d=s("formFields",e);void 0!==d&&d.forEach(e=>{i.append(e.name,e.value)});let h,p=0,f=0,m=0,g=0;o.upload.addEventListener("progress",t=>{if(!0===h)return;let a=Math.min(g,t.loaded);n.uploadedSize.value+=a-m,m=a;let i=m-f;for(let t=p;i>0&&ta.size))return void n.updateFileStatus(a,"uploading",i);i-=a.size,p++,f+=a.size,n.updateFileStatus(a,"uploading",a.size)}},!1),o.onreadystatechange=()=>{o.readyState<4||(o.status&&o.status<400?(n.uploadedFiles.value=n.uploadedFiles.value.concat(e),e.forEach(e=>{n.updateFileStatus(e,"uploaded")}),t("uploaded",{files:e,xhr:o})):(h=!0,n.uploadedSize.value-=m,n.queuedFiles.value=n.queuedFiles.value.concat(e),e.forEach(e=>{n.updateFileStatus(e,"failed")}),t("failed",{files:e,xhr:o})),l.value--,r.value=r.value.filter(e=>e!==o))},o.open(s("method",e),c),!0===s("withCredentials",e)&&(o.withCredentials=!0);let _=s("headers",e);void 0!==_&&_.forEach(e=>{o.setRequestHeader(e.name,e.value)});let v=s("sendRaw",e);e.forEach(e=>{n.updateFileStatus(e,"uploading",0),!0!==v&&i.append(s("fieldName",e),e,e.name),e.xhr=o,e.__abort=()=>{o.abort()},g+=e.size}),t("uploading",{files:e,xhr:o}),r.value.push(o),!0===v?o.send(new Blob(e)):o.send(i)}return{isUploading:i(()=>l.value>0),isBusy:i(()=>0!==s.value.length),abort:function(){r.value.forEach(e=>{e.abort()}),0!==s.value.length&&(o=!0)},upload:function(){let e=n.queuedFiles.value.slice(0);n.queuedFiles.value=[],u.value.batch(e)?c(e):e.forEach(e=>{c([e])})}}}},od=td(id),rd=$({name:"QUploaderAddTrigger",setup(){let e=y(Ne,Oe);return e===Oe&&console.error("QUploaderAddTrigger needs to be child of QUploader"),e}}),sd=$({name:"QVideo",props:{...tl,src:{type:String,required:!0},title:String,fetchpriority:{type:String,default:"auto"},loading:{type:String,default:"eager"},referrerpolicy:{type:String,default:"strict-origin-when-cross-origin"}},setup(e){let t=nl(e),a=i(()=>"q-video"+(void 0!==e.ratio?" q-video--responsive":""));return()=>n("div",{class:a.value,style:t.value},[n("iframe",{src:e.src,title:e.title,fetchpriority:e.fetchpriority,loading:e.loading,referrerpolicy:e.referrerpolicy,frameborder:"0",allowfullscreen:!0})])}}),ld={};function ud(e){if(!1===e)return 0;if(!0===e||void 0===e)return 1;let t=parseInt(e,10);return isNaN(t)?0:t}t(ld,{ClosePopup:()=>dd,Intersection:()=>Tl,Morph:()=>zd,Mutation:()=>qd,Ripple:()=>mn,Scroll:()=>$d,ScrollFire:()=>Bd,TouchHold:()=>Vd,TouchPan:()=>Ki,TouchRepeat:()=>Gd,TouchSwipe:()=>_i});var cd,dd=V({name:"close-popup",beforeMount(e,{value:t}){let n={depth:ud(t),handler(t){0!==n.depth&&setTimeout(()=>{let a=function(e){return Qn.find(t=>null!==t.contentEl&&t.contentEl.contains(e))}(e);void 0!==a&&function(e,t,n){for(;0!==n&&null!=e;){if(!0===e.__qPortal){if(n--,"QMenu"===e.$options.name){e=Zn(e,t);continue}e.hide(t)}e=$t(e)}}(a,t,n.depth)})},handlerKey(e){!0===pe(e,13)&&n.handler(e)}};e.__qclosepopup=n,e.addEventListener("click",n.handler),e.addEventListener("keyup",n.handlerKey)},updated(e,{value:t,oldValue:n}){t!==n&&(e.__qclosepopup.depth=ud(t))},beforeUnmount(e){let t=e.__qclosepopup;e.removeEventListener("click",t.handler),e.removeEventListener("keyup",t.handlerKey),delete e.__qclosepopup}}),hd=0;function pd(e,t){void 0===cd&&((cd=document.createElement("div")).style.cssText="position: absolute; left: 0; top: 0",document.body.appendChild(cd));let n=e.getBoundingClientRect(),a=cd.getBoundingClientRect(),{marginLeft:i,marginRight:o,marginTop:r,marginBottom:s}=window.getComputedStyle(e),l=parseInt(i,10)+parseInt(o,10),u=parseInt(r,10)+parseInt(s,10);return{left:n.left-a.left,top:n.top-a.top,width:n.right-n.left,height:n.bottom-n.top,widthM:n.right-n.left+(!0===t?0:l),heightM:n.bottom-n.top+(!0===t?0:u),marginH:!0===t?l:0,marginV:!0===t?u:0}}function fd(e){return{width:e.scrollWidth,height:e.scrollHeight}}var md=["Top","Right","Bottom","Left"],gd=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],_d=/-block|-inline|block-|inline-/,vd=/(-block|-inline|block-|inline-).*:/;function bd(e,t){let n=window.getComputedStyle(e),a={};for(let e=0;e!0!==vd.test(e)).join(";"):n[i]}return a}var yd=["absolute","fixed","relative","sticky"];function wd(e){let t=e,n=0;for(;null!==t&&t!==document;){let{position:a,zIndex:i}=window.getComputedStyle(t),o=Number(i);o>n&&(t===e||!0===yd.includes(a))&&(n=o),t=t.parentNode}return n}function kd(e){let t=typeof e;return"function"===t?e():"string"===t?document.querySelector(e):e}function xd(e){return e&&e.ownerDocument===document&&null!==e.parentNode}function Sd(e){let t=()=>!1,n=!1,a=!0,i=function(e){return{from:e.from,to:void 0!==e.to?e.to:e.from}}(e),o=function(e){return"number"==typeof e?e={duration:e}:"function"==typeof e&&(e={onEnd:e}),{...e,waitFor:void 0===e.waitFor?0:e.waitFor,duration:!0===isNaN(e.duration)?300:parseInt(e.duration,10),easing:"string"==typeof e.easing&&0!==e.easing.length?e.easing:"ease-in-out",delay:!0===isNaN(e.delay)?0:parseInt(e.delay,10),fill:"string"==typeof e.fill&&0!==e.fill.length?e.fill:"none",resize:!0===e.resize,useCSS:!0===e.useCSS||!0===e.usecss,hideFromClone:!0===e.hideFromClone||!0===e.hidefromclone,keepToClone:!0===e.keepToClone||!0===e.keeptoclone,tween:!0===e.tween,tweenFromOpacity:!0===isNaN(e.tweenFromOpacity)?.6:parseFloat(e.tweenFromOpacity),tweenToOpacity:!0===isNaN(e.tweenToOpacity)?.5:parseFloat(e.tweenToOpacity)}}(e),r=kd(i.from);if(!0!==xd(r))return t;"function"==typeof r.qMorphCancel&&r.qMorphCancel();let s,l,u,c,d=r.parentNode,h=r.nextElementSibling,p=pd(r,o.resize),{width:f,height:m}=fd(d),{borderWidth:g,borderStyle:_,borderColor:v,borderRadius:b,backgroundColor:y,transform:w,position:k,cssText:x}=bd(r,["borderWidth","borderStyle","borderColor","borderRadius","backgroundColor","transform","position","cssText"]),S=r.classList.toString(),C=r.style.cssText,T=r.cloneNode(!0),P=!0===o.tween?r.cloneNode(!0):void 0;void 0!==P&&(P.className=P.classList.toString().split(" ").filter(e=>!1===/^bg-/.test(e)).join(" ")),!0===o.hideFromClone&&T.classList.add("q-morph--internal"),T.setAttribute("aria-hidden","true"),T.style.transition="none",T.style.animation="none",T.style.pointerEvents="none",d.insertBefore(T,h),r.qMorphCancel=()=>{n=!0,T.remove(),P?.remove(),!0===o.hideFromClone&&T.classList.remove("q-morph--internal"),r.qMorphCancel=void 0};return"function"==typeof e.onToggle&&e.onToggle(),requestAnimationFrame(()=>{let e=kd(i.to);if(!0===n||!0!==xd(e))return void("function"==typeof r.qMorphCancel&&r.qMorphCancel());r!==e&&"function"==typeof e.qMorphCancel&&e.qMorphCancel(),!0!==o.keepToClone&&e.classList.add("q-morph--internal"),T.classList.add("q-morph--internal");let{width:h,height:E}=fd(d),{width:A,height:M}=fd(e.parentNode);!0!==o.hideFromClone&&T.classList.remove("q-morph--internal"),e.qMorphCancel=()=>{n=!0,T.remove(),P?.remove(),!0===o.hideFromClone&&T.classList.remove("q-morph--internal"),!0!==o.keepToClone&&e.classList.remove("q-morph--internal"),r.qMorphCancel=void 0,e.qMorphCancel=void 0};let L=()=>{if(!0===n)return void("function"==typeof e.qMorphCancel&&e.qMorphCancel());!0!==o.hideFromClone&&(T.classList.add("q-morph--internal"),T.innerHTML="",T.style.left=0,T.style.right="unset",T.style.top=0,T.style.bottom="unset",T.style.transform="none"),!0!==o.keepToClone&&e.classList.remove("q-morph--internal");let i=e.parentNode,{width:L,height:R}=fd(i),z=e.cloneNode(o.keepToClone);z.setAttribute("aria-hidden","true"),!0!==o.keepToClone&&(z.style.left=0,z.style.right="unset",z.style.top=0,z.style.bottom="unset",z.style.transform="none",z.style.pointerEvents="none"),z.classList.add("q-morph--internal");let N=e===r&&d===i?T:e.nextElementSibling;i.insertBefore(z,N);let{borderWidth:O,borderStyle:I,borderColor:q,borderRadius:D,backgroundColor:j,transform:B,position:F,cssText:$}=bd(e,["borderWidth","borderStyle","borderColor","borderRadius","backgroundColor","transform","position","cssText"]),V=e.classList.toString(),U=e.style.cssText;e.style.cssText=$,e.style.transform="none",e.style.animation="none",e.style.transition="none",e.className=V.split(" ").filter(e=>!1===/^bg-/.test(e)).join(" ");let H=pd(e,o.resize),W=p.left-H.left,G=p.top-H.top,K=p.width/(H.width>0?H.width:10),Y=p.height/(H.height>0?H.height:100),Q=f-h,Z=m-E,J=L-A,X=R-M,ee=Math.max(p.widthM,Q),te=Math.max(p.heightM,Z),ne=Math.max(H.widthM,J),ae=Math.max(H.heightM,X),ie=r===e&&!1===["absolute","fixed"].includes(F)&&!1===["absolute","fixed"].includes(k),oe="fixed"===F,re=i;for(;!0!==oe&&re!==document;)oe="fixed"===window.getComputedStyle(re).position,re=re.parentNode;if(!0!==o.hideFromClone&&(T.style.display="block",T.style.flex="0 0 auto",T.style.opacity=0,T.style.minWidth="unset",T.style.maxWidth="unset",T.style.minHeight="unset",T.style.maxHeight="unset",T.classList.remove("q-morph--internal")),!0!==o.keepToClone&&(z.style.display="block",z.style.flex="0 0 auto",z.style.opacity=0,z.style.minWidth="unset",z.style.maxWidth="unset",z.style.minHeight="unset",z.style.maxHeight="unset"),z.classList.remove("q-morph--internal"),"string"==typeof o.classes&&(e.className+=" "+o.classes),"string"==typeof o.style)e.style.cssText+=" "+o.style;else if(!0===je(o.style))for(let t in o.style)e.style[t]=o.style[t];let se=wd(T),le=wd(e),ue=!0===oe?document.documentElement:{scrollLeft:0,scrollTop:0};e.style.position=!0===oe?"fixed":"absolute",e.style.left=H.left-ue.scrollLeft+"px",e.style.right="unset",e.style.top=H.top-ue.scrollTop+"px",e.style.margin=0,!0===o.resize&&(e.style.minWidth="unset",e.style.maxWidth="unset",e.style.minHeight="unset",e.style.maxHeight="unset",e.style.overflow="hidden",e.style.overflowX="hidden",e.style.overflowY="hidden"),document.body.appendChild(e),void 0!==P&&(P.style.cssText=x,P.style.transform="none",P.style.animation="none",P.style.transition="none",P.style.position=e.style.position,P.style.left=p.left-ue.scrollLeft+"px",P.style.right="unset",P.style.top=p.top-ue.scrollTop+"px",P.style.margin=0,P.style.pointerEvents="none",!0===o.resize&&(P.style.minWidth="unset",P.style.maxWidth="unset",P.style.minHeight="unset",P.style.maxHeight="unset",P.style.overflow="hidden",P.style.overflowX="hidden",P.style.overflowY="hidden"),document.body.appendChild(P));let ce=n=>{r===e&&!0!==a?(e.style.cssText=C,e.className=S):(e.style.cssText=U,e.className=V),z.parentNode===i&&i.insertBefore(e,z),T.remove(),z.remove(),P?.remove(),t=()=>!1,r.qMorphCancel=void 0,e.qMorphCancel=void 0,"function"==typeof o.onEnd&&o.onEnd(!0===a?"to":"from",!0===n)};if(!0!==o.useCSS&&"function"==typeof e.animate){let i=!0===o.resize?{transform:`translate(${W}px, ${G}px)`,width:`${ee}px`,height:`${te}px`}:{transform:`translate(${W}px, ${G}px) scale(${K}, ${Y})`},d=!0===o.resize?{width:`${ne}px`,height:`${ae}px`}:{},h=!0===o.resize?{width:`${ee}px`,height:`${te}px`}:{},f=!0===o.resize?{transform:`translate(${-1*W}px, ${-1*G}px)`,width:`${ne}px`,height:`${ae}px`}:{transform:`translate(${-1*W}px, ${-1*G}px) scale(${1/K}, ${1/Y})`},m=void 0!==P?{opacity:o.tweenToOpacity}:{backgroundColor:y},k=void 0!==P?{opacity:1}:{backgroundColor:j};c=e.animate([{margin:0,borderWidth:g,borderStyle:_,borderColor:v,borderRadius:b,zIndex:se,transformOrigin:"0 0",...i,...m},{margin:0,borderWidth:O,borderStyle:I,borderColor:q,borderRadius:D,zIndex:le,transformOrigin:"0 0",transform:B,...d,...k}],{duration:o.duration,easing:o.easing,fill:o.fill,delay:o.delay}),l=void 0===P?void 0:P.animate([{opacity:o.tweenFromOpacity,margin:0,borderWidth:g,borderStyle:_,borderColor:v,borderRadius:b,zIndex:se,transformOrigin:"0 0",transform:w,...h},{opacity:0,margin:0,borderWidth:O,borderStyle:I,borderColor:q,borderRadius:D,zIndex:le,transformOrigin:"0 0",...f}],{duration:o.duration,easing:o.easing,fill:o.fill,delay:o.delay}),s=!0===o.hideFromClone||!0===ie?void 0:T.animate([{margin:`${Z<0?Z/2:0}px ${Q<0?Q/2:0}px`,width:`${ee+p.marginH}px`,height:`${te+p.marginV}px`},{margin:0,width:0,height:0}],{duration:o.duration,easing:o.easing,fill:o.fill,delay:o.delay}),u=!0===o.keepToClone?void 0:z.animate([!0===ie?{margin:`${Z<0?Z/2:0}px ${Q<0?Q/2:0}px`,width:`${ee+p.marginH}px`,height:`${te+p.marginV}px`}:{margin:0,width:0,height:0},{margin:`${X<0?X/2:0}px ${J<0?J/2:0}px`,width:`${ne+H.marginH}px`,height:`${ae+H.marginV}px`}],{duration:o.duration,easing:o.easing,fill:o.fill,delay:o.delay});let x=e=>{s?.cancel(),l?.cancel(),u?.cancel(),c.cancel(),c.removeEventListener("finish",x),c.removeEventListener("cancel",x),ce(e),s=void 0,l=void 0,u=void 0,c=void 0};r.qMorphCancel=()=>{r.qMorphCancel=void 0,n=!0,x()},e.qMorphCancel=()=>{e.qMorphCancel=void 0,n=!0,x()},c.addEventListener("finish",x),c.addEventListener("cancel",x),t=e=>!0!==n&&void 0!==c&&(!0===e?(x(!0),!0):(a=!0!==a,s?.reverse(),l?.reverse(),u?.reverse(),c.reverse(),!0))}else{let i="q-morph-anim-"+ ++hd,s=document.createElement("style"),l=!0===o.resize?`\n transform: translate(${W}px, ${G}px);\n width: ${ee}px;\n height: ${te}px;\n `:`transform: translate(${W}px, ${G}px) scale(${K}, ${Y});`,u=!0===o.resize?`\n width: ${ne}px;\n height: ${ae}px;\n `:"",c=!0===o.resize?`\n width: ${ee}px;\n height: ${te}px;\n `:"",d=!0===o.resize?`\n transform: translate(${-1*W}px, ${-1*G}px);\n width: ${ne}px;\n height: ${ae}px;\n `:`transform: translate(${-1*W}px, ${-1*G}px) scale(${1/K}, ${1/Y});`,h=void 0!==P?`opacity: ${o.tweenToOpacity};`:`background-color: ${y};`,f=void 0!==P?"opacity: 1;":`background-color: ${j};`,m=void 0===P?"":`\n @keyframes ${i}-from-tween {\n 0% {\n opacity: ${o.tweenFromOpacity};\n margin: 0;\n border-width: ${g};\n border-style: ${_};\n border-color: ${v};\n border-radius: ${b};\n z-index: ${se};\n transform-origin: 0 0;\n transform: ${w};\n ${c}\n }\n\n 100% {\n opacity: 0;\n margin: 0;\n border-width: ${O};\n border-style: ${I};\n border-color: ${q};\n border-radius: ${D};\n z-index: ${le};\n transform-origin: 0 0;\n ${d}\n }\n }\n `,k=!0===o.hideFromClone||!0===ie?"":`\n @keyframes ${i}-from {\n 0% {\n margin: ${Z<0?Z/2:0}px ${Q<0?Q/2:0}px;\n width: ${ee+p.marginH}px;\n height: ${te+p.marginV}px;\n }\n\n 100% {\n margin: 0;\n width: 0;\n height: 0;\n }\n }\n `,x=!0===ie?`\n margin: ${Z<0?Z/2:0}px ${Q<0?Q/2:0}px;\n width: ${ee+p.marginH}px;\n height: ${te+p.marginV}px;\n `:"\n margin: 0;\n width: 0;\n height: 0;\n ",S=!0===o.keepToClone?"":`\n @keyframes ${i}-to {\n 0% {\n ${x}\n }\n\n 100% {\n margin: ${X<0?X/2:0}px ${J<0?J/2:0}px;\n width: ${ne+H.marginH}px;\n height: ${ae+H.marginV}px;\n }\n }\n `;s.innerHTML=`\n @keyframes ${i} {\n 0% {\n margin: 0;\n border-width: ${g};\n border-style: ${_};\n border-color: ${v};\n border-radius: ${b};\n background-color: ${y};\n z-index: ${se};\n transform-origin: 0 0;\n ${l}\n ${h}\n }\n\n 100% {\n margin: 0;\n border-width: ${O};\n border-style: ${I};\n border-color: ${q};\n border-radius: ${D};\n background-color: ${j};\n z-index: ${le};\n transform-origin: 0 0;\n transform: ${B};\n ${u}\n ${f}\n }\n }\n\n ${k}\n\n ${m}\n\n ${S}\n `,document.head.appendChild(s);let C="normal";T.style.animation=`${o.duration}ms ${o.easing} ${o.delay}ms ${C} ${o.fill} ${i}-from`,void 0!==P&&(P.style.animation=`${o.duration}ms ${o.easing} ${o.delay}ms ${C} ${o.fill} ${i}-from-tween`),z.style.animation=`${o.duration}ms ${o.easing} ${o.delay}ms ${C} ${o.fill} ${i}-to`,e.style.animation=`${o.duration}ms ${o.easing} ${o.delay}ms ${C} ${o.fill} ${i}`;let E=t=>{t===Object(t)&&t.animationName!==i||(e.removeEventListener("animationend",E),e.removeEventListener("animationcancel",E),ce(),s.remove())};r.qMorphCancel=()=>{r.qMorphCancel=void 0,n=!0,E()},e.qMorphCancel=()=>{e.qMorphCancel=void 0,n=!0,E()},e.addEventListener("animationend",E),e.addEventListener("animationcancel",E),t=t=>!!(!0!==n&&e&&T&&z)&&(!0===t?(E(),!0):(a=!0!==a,C="normal"===C?"reverse":"normal",T.style.animationDirection=C,P.style.animationDirection=C,z.style.animationDirection=C,e.style.animationDirection=C,!0))}};o.waitFor>0||"transitionend"===o.waitFor||o.waitFor===Object(o.waitFor)&&"function"==typeof o.waitFor.then?(o.waitFor>0?new Promise(e=>setTimeout(e,o.waitFor)):"transitionend"===o.waitFor?new Promise(t=>{let n=()=>{null!==a&&(clearTimeout(a),a=null),e&&(e.removeEventListener("transitionend",n),e.removeEventListener("transitioncancel",n)),t()},a=setTimeout(n,400);e.addEventListener("transitionend",n),e.addEventListener("transitioncancel",n)}):o.waitFor).then(L).catch(()=>{"function"==typeof e.qMorphCancel&&e.qMorphCancel()}):L()}),e=>t(e)}var Cd={},Td=["duration","delay","easing","fill","classes","style","duration","resize","useCSS","hideFromClone","keepToClone","tween","tweenFromOpacity","tweenToOpacity","waitFor","onEnd"],Pd=["resize","useCSS","hideFromClone","keepToClone","tween"];function Ed(e,t){e.clsAction!==t&&(e.clsAction=t,e.el.classList[t]("q-morph--invisible"))}function Ad(e){if(!0===e.animating||e.queue.length<2)return;let[t,n]=e.queue;e.animating=!0,t.animating=!0,n.animating=!0,Ed(t,"remove"),Ed(n,"remove");let a=Sd({from:t.el,to:n.el,onToggle(){Ed(t,"add"),Ed(n,"remove")},...n.opts,onEnd(a,i){n.opts.onEnd?.(a,i),!0!==i&&(t.animating=!1,n.animating=!1,e.animating=!1,e.cancel=void 0,e.queue.shift(),Ad(e))}});e.cancel=()=>{a(!0),e.cancel=void 0}}function Md(e,t){let n=t.opts;Pd.forEach(t=>{n[t]=!0===e[t]})}function Ld(e,t){if(t.name===e){let n=Cd[t.group];return void(void 0===n?(Cd[t.group]={name:t.group,model:e,queue:[t],animating:!1},Ed(t,"remove")):n.model!==e&&(n.model=e,n.queue.push(t),!1===n.animating&&2===n.queue.length&&Ad(n)))}!1===t.animating&&Ed(t,"add")}function Rd(e,t){let n;Object(t)===t?(n=""+t.model,function(e,t){void 0!==e.group&&(t.group=e.group),void 0!==e.name&&(t.name=e.name);let n=t.opts;Td.forEach(t=>{void 0!==e[t]&&(n[t]=e[t])})}(t,e),Md(t,e)):n=""+t,n!==e.model?(e.model=n,Ld(n,e)):!1===e.animating&&void 0!==e.clsAction&&e.el.classList[e.clsAction]("q-morph--invisible")}var zd=V({name:"morph",mounted(e,t){let n={el:e,animating:!1,opts:{}};Md(t.modifiers,n),function(e,t){let n="string"==typeof e&&0!==e.length?e.split(":"):[];t.name=n[0],t.group=n[1],Object.assign(t.opts,{duration:!0===isNaN(n[2])?300:parseFloat(n[2]),waitFor:n[3]})}(t.arg,n),Rd(n,t.value),e.__qmorph=n},updated(e,t){Rd(e.__qmorph,t.value)},beforeUnmount(e){let t=e.__qmorph,n=Cd[t.group];void 0!==n&&-1!==n.queue.indexOf(t)&&(n.queue=n.queue.filter(e=>e!==t),0===n.queue.length&&(n.cancel?.(),delete Cd[t.group])),"add"===t.clsAction&&e.classList.remove("q-morph--invisible"),delete e.__qmorph}}),Nd={childList:!0,subtree:!0,attributes:!0,characterData:!0,attributeOldValue:!0,characterDataOldValue:!0};function Od(e,t,n){t.handler=n,t.observer?.disconnect(),t.observer=new MutationObserver(n=>{"function"==typeof t.handler&&(!1===t.handler(n)||!0===t.once)&&Id(e)}),t.observer.observe(e,t.opts)}function Id(e){let t=e.__qmutation;void 0!==t&&(t.observer?.disconnect(),delete e.__qmutation)}var qd=V({name:"mutation",mounted(e,{modifiers:{once:t,...n},value:a}){let i={once:t,opts:0===Object.keys(n).length?Nd:n};Od(e,i,a),e.__qmutation=i},updated(e,{oldValue:t,value:n}){let a=e.__qmutation;void 0!==a&&t!==n&&Od(e,a,n)},beforeUnmount:Id}),{passive:Dd}=H;function jd(e,{value:t,oldValue:n}){"function"==typeof t?(e.handler=t,"function"!=typeof n&&(e.scrollTarget.addEventListener("scroll",e.scroll,Dd),e.scroll())):e.scrollTarget.removeEventListener("scroll",e.scroll,Dd)}var Bd=V({name:"scroll-fire",mounted(e,t){let n={scrollTarget:sa(e),scroll:ae(()=>{let t,a;n.scrollTarget===window?(a=e.getBoundingClientRect().bottom,t=window.innerHeight):(a=sn(e).top+ln(e),t=sn(n.scrollTarget).top+ln(n.scrollTarget)),a>0&&a{a.styleCleanup=void 0;let t=()=>{document.body.classList.remove("non-selectable")};!0===e?(Ln(),setTimeout(t,10)):t()}),a.triggered=!1,a.sensitivity=!0===t?a.mouseSensitivity:a.touchSensitivity,a.timer=setTimeout(()=>{a.timer=void 0,Ln(),a.triggered=!0,a.handler({evt:e,touch:!0!==t,mouse:!0===t,position:a.origin,duration:Date.now()-n})},a.duration)},move(e){let{top:t,left:n}=K(e);void 0!==a.timer&&(Math.abs(n-a.origin.left)>=a.sensitivity||Math.abs(t-a.origin.top)>=a.sensitivity)&&(clearTimeout(a.timer),a.timer=void 0)},end(e){te(a,"temp"),a.styleCleanup?.(a.triggered),!0===a.triggered?void 0!==e&&J(e):void 0!==a.timer&&(clearTimeout(a.timer),a.timer=void 0)}},i=[600,5,7];if("string"==typeof t.arg&&0!==t.arg.length&&t.arg.split(":").forEach((e,t)=>{let n=parseInt(e,10);n&&(i[t]=n)}),[a.duration,a.touchSensitivity,a.mouseSensitivity]=i,e.__qtouchhold=a,!0===n.mouse){let t=!0===n.mouseCapture||!0===n.mousecapture?"Capture":"";ee(a,"main",[[e,"mousedown","mouseStart",`passive${t}`]])}!0===j.has.touch&&ee(a,"main",[[e,"touchstart","touchStart","passive"+(!0===n.capture?"Capture":"")],[e,"touchend","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchhold;void 0!==n&&t.oldValue!==t.value&&("function"!=typeof t.value&&n.end(),n.handler=t.value)},beforeUnmount(e){let t=e.__qtouchhold;void 0!==t&&(te(t,"main"),te(t,"temp"),void 0!==t.timer&&clearTimeout(t.timer),t.styleCleanup?.(),delete e.__qtouchhold)}}),Ud={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Hd=new RegExp(`^([\\d+]+|${Object.keys(Ud).join("|")})$`,"i");var Wd,Gd=V({name:"touch-repeat",beforeMount(e,{modifiers:t,value:n,arg:a}){let i=Object.keys(t).reduce((e,t)=>{if(!0===Hd.test(t)){let n=isNaN(parseInt(t,10))?Ud[t.toLowerCase()]:parseInt(t,10);n>=0&&e.push(n)}return e},[]);if(!0!==t.mouse&&!0!==j.has.touch&&0===i.length)return;let o="string"==typeof a&&0!==a.length?a.split(":").map(e=>parseInt(e,10)):[0,600,300],r=o.length-1,s={keyboard:i,handler:n,noop:W,mouseStart(e){void 0===s.event&&"function"==typeof s.handler&&!0===G(e)&&(ee(s,"temp",[[document,"mousemove","move","passiveCapture"],[document,"click","end","notPassiveCapture"]]),s.start(e,!0))},keyboardStart(t){if("function"==typeof s.handler&&!0===pe(t,i)){if((0===o[0]||void 0!==s.event)&&(J(t),e.focus(),void 0!==s.event))return;ee(s,"temp",[[document,"keyup","end","notPassiveCapture"],[document,"click","end","notPassiveCapture"]]),s.start(t,!1,!0)}},touchStart(e){if(void 0!==e.target&&"function"==typeof s.handler){let t=e.target;ee(s,"temp",[[t,"touchmove","move","passiveCapture"],[t,"touchcancel","end","notPassiveCapture"],[t,"touchend","end","notPassiveCapture"]]),s.start(e)}},start(e,t,n){function a(e){s.styleCleanup=void 0,document.documentElement.style.cursor="";let t=()=>{document.body.classList.remove("non-selectable")};!0===e?(Ln(),setTimeout(t,10)):t()}!0!==n&&(s.origin=K(e)),!0===j.is.mobile&&(document.body.classList.add("non-selectable"),Ln(),s.styleCleanup=a),s.event={touch:!0!==t&&!0!==n,mouse:!0===t,keyboard:!0===n,startTime:Date.now(),repeatCount:0};let i=()=>{if(s.timer=void 0,void 0===s.event)return;0===s.event.repeatCount&&(s.event.evt=e,!0===n?s.event.keyCode=e.keyCode:s.event.position=K(e),!0!==j.is.mobile&&(document.documentElement.style.cursor="pointer",document.body.classList.add("non-selectable"),Ln(),s.styleCleanup=a)),s.event.duration=Date.now()-s.event.startTime,s.event.repeatCount+=1,s.handler(s.event);let t=r=7||Math.abs(n-t.top)>=7}(e,s.origin)&&(clearTimeout(s.timer),s.timer=void 0)},end(e){void 0!==s.event&&(s.styleCleanup?.(!0),void 0!==e&&s.event.repeatCount>0&&J(e),te(s,"temp"),void 0!==s.timer&&(clearTimeout(s.timer),s.timer=void 0),s.event=void 0)}};if(e.__qtouchrepeat=s,!0===t.mouse){let n=!0===t.mouseCapture||!0===t.mousecapture?"Capture":"";ee(s,"main",[[e,"mousedown","mouseStart",`passive${n}`]])}if(!0===j.has.touch&&ee(s,"main",[[e,"touchstart","touchStart","passive"+(!0===t.capture?"Capture":"")],[e,"touchend","noop","passiveCapture"]]),0!==i.length){let n=!0===t.keyCapture||!0===t.keycapture?"Capture":"";ee(s,"main",[[e,"keydown","keyboardStart",`notPassive${n}`]])}},updated(e,{oldValue:t,value:n}){let a=e.__qtouchrepeat;void 0!==a&&t!==n&&("function"!=typeof n&&a.end(),a.handler=n)},beforeUnmount(e){let t=e.__qtouchrepeat;void 0!==t&&(void 0!==t.timer&&clearTimeout(t.timer),te(t,"main"),te(t,"temp"),t.styleCleanup?.(),delete e.__qtouchrepeat)}}),Kd={};function Yd(e,t=document.body){if("string"!=typeof e)throw new TypeError("Expected a string as propName");if(!(t instanceof Element))throw new TypeError("Expected a DOM element");return getComputedStyle(t).getPropertyValue(`--q-${e}`).trim()||null}function Qd(e){void 0===Wd&&(Wd=j.is.winphone?"msapplication-navbutton-color":"theme-color");let t=function(e){let t=document.getElementsByTagName("META");for(let n in t)if(t[n].name===e)return t[n]}(Wd),n=void 0===t;n&&(t=document.createElement("meta"),t.setAttribute("name",Wd)),t.setAttribute("content",e),n&&document.head.appendChild(t)}t(Kd,{AddressbarColor:()=>Zd,AppFullscreen:()=>oh,AppVisibility:()=>sh,BottomSheet:()=>dh,Cookies:()=>wh,Dark:()=>le,Dialog:()=>xh,IconSet:()=>Te,Lang:()=>xe,Loading:()=>Rh,LoadingBar:()=>Oh,LocalStorage:()=>up,Meta:()=>Vh,Notify:()=>ip,Platform:()=>F,Screen:()=>re,SessionStorage:()=>hp});var Zd={set:!0!==j.is.mobile||!0!==j.is.nativeMobile&&!0!==j.is.winphone&&!0!==j.is.safari&&!0!==j.is.webkit&&!0!==j.is.vivaldi?W:e=>{let t=e||Yd("primary");!0===j.is.nativeMobile&&window.StatusBar?window.StatusBar.backgroundColorByHexString(t):Qd(t)},install({$q:e}){e.addressbarColor=this,e.config.addressbarColor&&this.set(e.config.addressbarColor)}},Jd={};function Xd(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement||null}function eh(){let e=ih.activeEl=!1===ih.isActive?null:Xd();!function(e){if(e===Gn)return;if((Gn=e)===document.body||Hn.reduce((e,t)=>"dialog"===t?e+1:e,0)<2)return void Un.forEach(e=>{!1===e.contains(Gn)&&Gn.appendChild(e)});let t=Hn.lastIndexOf("dialog");for(let e=0;evoid 0!==document.documentElement[e]),ih.isCapable=void 0!==Jd.request,!1===ih.isCapable?(ah=()=>Promise.reject("Not capable"),Object.assign(ih,{request:ah,exit:ah,toggle:ah})):(Object.assign(ih,{request(e){let t=e||document.documentElement,{activeEl:n}=ih;return t===n?Promise.resolve():(null!==n&&!0===t.contains(n)?ih.exit():Promise.resolve()).finally(()=>nh(t,Jd.request))},exit:()=>!0===ih.isActive?nh(document,Jd.exit):Promise.resolve(),toggle:e=>!0===ih.isActive?ih.exit():ih.request(e)}),Jd.exit=["exitFullscreen","msExitFullscreen","mozCancelFullScreen","webkitExitFullscreen"].find(e=>document[e]),ih.isActive=!!Xd(),!0===ih.isActive&&eh(),["onfullscreenchange","onmsfullscreenchange","onwebkitfullscreenchange"].forEach(e=>{document[e]=th}));var oh=ih,rh=U({appVisible:!0},{install({$q:e}){z(e,"appVisible",()=>this.appVisible)}});{let e,t;if(typeof document.hidden<"u"?(e="hidden",t="visibilitychange"):typeof document.msHidden<"u"?(e="msHidden",t="msvisibilitychange"):typeof document.webkitHidden<"u"&&(e="webkitHidden",t="webkitvisibilitychange"),t&&typeof document[e]<"u"){let n=()=>{rh.appVisible=!document[e]};document.addEventListener(t,n,!1)}}var sh=rh,lh=$({name:"BottomSheetComponent",props:{...Nt,title:String,message:String,actions:Array,grid:Boolean,cardClass:[String,Array,Object],cardStyle:[String,Array,Object]},emits:["ok","hide"],setup(e,{emit:t}){let{proxy:i}=k(),o=Ot(e,i.$q),r=a(null);function s(){r.value.hide()}function l(e){t("ok",e),s()}function u(){t("hide")}function c(){let t=[];return e.title&&t.push(n(ui,{class:"q-dialog__title"},()=>e.title)),e.message&&t.push(n(ui,{class:"q-dialog__message"},()=>e.message)),t.push(!0===e.grid?n("div",{class:"row items-stretch justify-start",role:"list"},e.actions.map(e=>{let t=e.avatar||e.img;return void 0===e.label?n(ws,{class:"col-all",dark:o.value}):n("div",{class:["q-bottom-sheet__item q-hoverable q-focusable cursor-pointer relative-position",e.class],style:e.style,tabindex:0,role:"listitem",onClick(){l(e)},onKeyup(t){13===t.keyCode&&l(e)}},[n("div",{class:"q-focus-helper"}),e.icon?n(Mt,{name:e.icon,color:e.color}):t?n("img",{class:e.avatar?"q-bottom-sheet__avatar":"",src:t}):n("div",{class:"q-bottom-sheet__empty-icon"}),n("div",e.label)])})):n("div",{role:"list"},e.actions.map(e=>{let t=e.avatar||e.img;return void 0===e.label?n(ws,{spaced:!0,dark:o.value}):n(as,{class:["q-bottom-sheet__item",e.classes],style:e.style,tabindex:0,clickable:!0,dark:o.value,onClick(){l(e)}},()=>[n(is,{avatar:!0},()=>e.icon?n(Mt,{name:e.icon,color:e.color}):t?n("img",{class:e.avatar?"q-bottom-sheet__avatar":"",src:t}):null),n(is,()=>e.label)])}))),t}function d(){return[n(li,{class:["q-bottom-sheet q-bottom-sheet--"+(!0===e.grid?"grid":"list")+(!0===o.value?" q-bottom-sheet--dark q-dark":""),e.cardClass],style:e.cardStyle},c)]}return Object.assign(i,{show:function(){r.value.show()},hide:s}),()=>n(Yr,{ref:r,position:"bottom",onHide:u},d)}});function uh(e,t){for(let n in t)"spinner"!==n&&Object(t[n])===t[n]?(e[n]=Object(e[n])!==e[n]?{}:{...e[n]},uh(e[n],t[n])):e[n]=t[n]}function ch(e,t,i){return o=>{let r,s,l=!0===t&&void 0!==o.component;if(!0===l){let{component:e,componentProps:t}=o;r="string"==typeof e?i.component(e):e,s=t||{}}else{let{class:t,style:n,...a}=o;r=e,s=a,void 0!==t&&(a.cardClass=t),void 0!==n&&(a.cardStyle=n)}let u,c=!1,h=a(null),p=Kn(!1,"dialog"),f=e=>{if(void 0!==h.value?.[e])return void h.value[e]();let t=u.$.subTree;if(t?.component){if(t.component.proxy&&t.component.proxy[e])return void t.component.proxy[e]();if(t.component.subTree&&t.component.subTree.component&&t.component.subTree.component.proxy&&t.component.subTree.component.proxy[e])return void t.component.subTree.component.proxy[e]()}console.error("[Quasar] Incorrectly defined Dialog component")},m=[],g=[],_={onOk:e=>(m.push(e),_),onCancel:e=>(g.push(e),_),onDismiss:e=>(m.push(e),g.push(e),_),hide:()=>(f("hide"),_),update(e){if(null!==u){if(!0===l)Object.assign(s,e);else{let{class:t,style:n,...a}=e;void 0!==t&&(a.cardClass=t),void 0!==n&&(a.cardStyle=n),uh(s,a)}u.$forceUpdate()}return _}},v=e=>{c=!0,m.forEach(t=>{t(e)})},b=()=>{y.unmount(p),Yn(p),y=null,u=null,!0!==c&&g.forEach(e=>{e()})},y=He({name:"QGlobalDialog",setup:()=>()=>n(r,{...s,ref:h,onOk:v,onHide:b,onVnodeMounted(...e){"function"==typeof s.onVnodeMounted&&s.onVnodeMounted(...e),d(()=>f("show"))}})},i);return u=y.mount(p),_}}var dh={install({$q:e,parentApp:t}){e.bottomSheet=this.create=ch(lh,!1,t)}};function hh(e){return encodeURIComponent(e)}function ph(e){return decodeURIComponent(e)}function fh(e){if(""===e)return e;0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\")),e=ph(e.replace(/\+/g," "));try{let t=JSON.parse(e);(t===Object(t)||!0===Array.isArray(t))&&(e=t)}catch{}return e}function mh(e){let t=new Date;return t.setMilliseconds(t.getMilliseconds()+e),t.toUTCString()}function gh(e,t,n={},a){let i,o;void 0!==n.expires&&("[object Date]"===Object.prototype.toString.call(n.expires)?i=n.expires.toUTCString():"string"==typeof n.expires?i=function(e){let t=0,n=e.match(/(\d+)d/),a=e.match(/(\d+)h/),i=e.match(/(\d+)m/),o=e.match(/(\d+)s/);return n&&(t+=864e5*n[1]),a&&(t+=36e5*a[1]),i&&(t+=6e4*i[1]),o&&(t+=1e3*o[1]),0===t?e:mh(t)}(n.expires):(o=parseFloat(n.expires),i=!1===isNaN(o)?mh(864e5*o):n.expires));let r=`${hh(e)}=${function(e){return hh(e===Object(e)?JSON.stringify(e):""+e)}(t)}`,s=[r,void 0!==i?"; Expires="+i:"",n.path?"; Path="+n.path:"",n.domain?"; Domain="+n.domain:"",n.sameSite?"; SameSite="+n.sameSite:"",n.httpOnly?"; HttpOnly":"",n.secure?"; Secure":"",n.other?"; "+n.other:""].join("");if(a){a.req.qCookies?a.req.qCookies.push(s):a.req.qCookies=[s],a.res.setHeader("Set-Cookie",a.req.qCookies);let t=a.req.headers.cookie||"";if(void 0!==i&&o<0){let n=_h(e,a);void 0!==n&&(t=t.replace(`${e}=${n}; `,"").replace(`; ${e}=${n}`,"").replace(`${e}=${n}`,""))}else t=t?`${r}; ${t}`:s;a.req.headers.cookie=t}else document.cookie=s}function _h(e,t){let n,a,i,o=t?t.req.headers:document,r=o.cookie?o.cookie.split("; "):[],s=r.length,l=e?null:{},u=0;for(;u_h(t,e),set:(t,n,a)=>gh(t,n,a,e),has:t=>function(e,t){return null!==_h(e,t)}(t,e),remove:(t,n)=>function(e,t,n){gh(e,"",{expires:-1,...t},n)}(t,n,e),getAll:()=>_h(null,e)}}());var bh,yh,wh=vh,kh=$({name:"DialogPluginComponent",props:{...Nt,title:String,message:String,prompt:Object,options:Object,progress:[Boolean,Object],html:Boolean,ok:{type:[String,Object,Boolean],default:!0},cancel:[String,Object,Boolean],focus:{type:String,default:"ok",validator:e=>["ok","cancel","none"].includes(e)},stackButtons:Boolean,color:String,cardClass:[String,Array,Object],cardStyle:[String,Array,Object]},emits:["ok","hide"],setup(e,{emit:t}){let{proxy:r}=k(),{$q:l}=r,u=Ot(e,l),c=a(null),d=a(void 0!==e.prompt?e.prompt.model:void 0!==e.options?e.options.model:void 0),h=i(()=>"q-dialog-plugin"+(!0===u.value?" q-dialog-plugin--dark q-dark":"")+(!1!==e.progress?" q-dialog-plugin--progress":"")),p=i(()=>e.color||(!0===u.value?"amber":"primary")),f=i(()=>!1===e.progress?null:!0===je(e.progress)?{component:e.progress.spinner||rn,props:{color:e.progress.color||p.value}}:{component:rn,props:{color:p.value}}),m=i(()=>void 0!==e.prompt||void 0!==e.options),g=i(()=>{if(!0!==m.value)return{};let{model:t,isValid:n,items:a,...i}=void 0!==e.prompt?e.prompt:e.options;return i}),_=i(()=>!0===je(e.ok)||!0===e.ok?l.lang.label.ok:e.ok),v=i(()=>!0===je(e.cancel)||!0===e.cancel?l.lang.label.cancel:e.cancel),b=i(()=>void 0!==e.prompt?void 0!==e.prompt.isValid&&!0!==e.prompt.isValid(d.value):void 0!==e.options&&(void 0!==e.options.isValid&&!0!==e.options.isValid(d.value))),y=i(()=>({color:p.value,label:_.value,ripple:!1,disable:b.value,...!0===je(e.ok)?e.ok:{flat:!0},"data-autofocus":"ok"===e.focus&&!0!==m.value||void 0,onClick:S})),w=i(()=>({color:p.value,label:v.value,ripple:!1,...!0===je(e.cancel)?e.cancel:{flat:!0},"data-autofocus":"cancel"===e.focus&&!0!==m.value||void 0,onClick:C}));function x(){c.value.hide()}function S(){t("ok",s(d.value)),x()}function C(){x()}function T(){t("hide")}function P(e){d.value=e}function E(t){!0!==b.value&&"textarea"!==e.prompt.type&&!0===pe(t,13)&&S()}function A(t,a){return!0===e.html?n(ui,{class:t,innerHTML:a}):n(ui,{class:t},()=>a)}function M(){return[n(kl,{color:p.value,dense:!0,autofocus:!0,dark:u.value,...g.value,modelValue:d.value,"onUpdate:modelValue":P,onKeyup:E})]}function L(){return[n(Hl,{color:p.value,options:e.options.items,dark:u.value,...g.value,modelValue:d.value,"onUpdate:modelValue":P})]}function R(){let t=[];return e.title&&t.push(A("q-dialog__title",e.title)),!1!==e.progress&&t.push(n(ui,{class:"q-dialog__progress"},()=>n(f.value.component,f.value.props))),e.message&&t.push(A("q-dialog__message",e.message)),void 0!==e.prompt?t.push(n(ui,{class:"scroll q-dialog-plugin__form"},M)):void 0!==e.options&&t.push(n(ws,{dark:u.value}),n(ui,{class:"scroll q-dialog-plugin__form"},L),n(ws,{dark:u.value})),(e.ok||e.cancel)&&t.push(function(){let t=[];return e.cancel&&t.push(n(An,w.value)),e.ok&&t.push(n(An,y.value)),n(ci,{class:!0===e.stackButtons?"items-end":"",vertical:e.stackButtons,align:"right"},()=>t)}()),t}function z(){return[n(li,{class:[h.value,e.cardClass],style:e.cardStyle,dark:u.value},R)]}return o(()=>e.prompt&&e.prompt.model,P),o(()=>e.options&&e.options.model,P),Object.assign(r,{show:function(){c.value.show()},hide:x}),()=>n(Yr,{ref:c,onHide:T},z)}}),xh={install({$q:e,parentApp:t}){e.dialog=this.create=ch(kh,!0,t)}},Sh=0,Ch=null,Th={},Ph={},Eh={group:"__default_quasar_group__",delay:0,message:!1,html:!1,spinnerSize:80,spinnerColor:"",messageColor:"",backgroundColor:"",boxClass:"",spinner:rn,customClass:""},Ah={...Eh};var Mh,Lh=U({isActive:!1},{show(e){Th=function(e){if(void 0!==e?.group&&void 0!==Ph[e.group])return Object.assign(Ph[e.group],e);let t=!0===je(e)&&!0===e.ignoreDefaults?{...Eh,...e}:{...Ah,...e};return Ph[t.group]=t,t}(e);let{group:t}=Th;return Lh.isActive=!0,void 0!==bh?(Th.uid=Sh,yh.$forceUpdate()):(Th.uid=++Sh,null!==Ch&&clearTimeout(Ch),Ch=setTimeout(()=>{Ch=null;let e=Kn("q-loading");bh=He({name:"QLoading",setup(){function t(){!0!==Lh.isActive&&void 0!==bh&&(Ur(!1),bh.unmount(e),Yn(e),bh=void 0,yh=void 0)}function a(){if(!0!==Lh.isActive)return null;let e=[n(Th.spinner,{class:"q-loading__spinner",color:Th.spinnerColor,size:Th.spinnerSize})];return Th.message&&e.push(n("div",{class:"q-loading__message"+(Th.messageColor?` text-${Th.messageColor}`:""),[!0===Th.html?"innerHTML":"textContent"]:Th.message})),n("div",{class:"q-loading fullscreen flex flex-center z-max "+Th.customClass.trim(),key:Th.uid},[n("div",{class:"q-loading__backdrop"+(Th.backgroundColor?` bg-${Th.backgroundColor}`:"")}),n("div",{class:"q-loading__box column items-center "+Th.boxClass},e)])}return m(()=>{Ur(!0)}),()=>n(S,{name:"q-transition--fade",appear:!0,onAfterLeave:t},a)}},Lh.__parentApp),yh=bh.mount(e)},Th.delay)),e=>{void 0!==e&&Object(e)===e?Lh.show({...e,group:t}):Lh.hide(t)}},hide(e){if(!0===Lh.isActive){if(void 0===e)Ph={};else{if(void 0===Ph[e])return;{delete Ph[e];let t=Object.keys(Ph);if(0!==t.length){let e=t[t.length-1];return void Lh.show({group:e})}}}null!==Ch&&(clearTimeout(Ch),Ch=null),Lh.isActive=!1}},setDefaults(e){!0===je(e)&&Object.assign(Ah,e)},install({$q:e,parentApp:t}){e.loading=this,Lh.__parentApp=t,void 0!==e.config.loading&&this.setDefaults(e.config.loading)}}),Rh=Lh,zh=a(null),Nh=U({isActive:!1},{start:W,stop:W,increment:W,setDefaults:W,install({$q:e,parentApp:t}){if(e.loadingBar=this,!0===this.__installed)return void(void 0!==e.config.loadingBar&&this.setDefaults(e.config.loadingBar));let i=a(void 0!==e.config.loadingBar?{...e.config.loadingBar}:{});function o(){Nh.isActive=!0}function r(){Nh.isActive=!1}let s=Kn("q-loading-bar");He({name:"LoadingBar",devtools:{hide:!0},setup:()=>()=>n(st,{...i.value,onStart:o,onStop:r,ref:zh})},t).mount(s),Object.assign(this,{start(e){zh.value.start(e)},stop(){zh.value.stop()},increment(){zh.value.increment.apply(null,arguments)},setDefaults(e){!0===je(e)&&Object.assign(i.value,e)}})}}),Oh=Nh,Ih=null,qh=[];function Dh(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!0;for(let n in e)if(e[n]!==t[n])return!0}function jh(e){return!1===["class","style"].includes(e)}function Bh(e){return!1===["lang","dir"].includes(e)}function Fh(){Ih=null;let e={title:"",titleTemplate:null,meta:{},link:{},script:{},htmlAttr:{},bodyAttr:{}};for(let t=0;t{let n=e[t[0]],a=t[1];for(let e in n){let t=n[e];t.template&&(1===Object.keys(t).length?delete n[e]:(t[a]=t.template(t[a]||""),delete t.template))}})})(e),function({add:e,remove:t}){e.title&&(document.title=e.title),0!==Object.keys(t).length&&(["meta","link","script"].forEach(e=>{t[e].forEach(t=>{document.head.querySelector(`${e}[data-qmeta="${t}"]`).remove()})}),t.htmlAttr.filter(Bh).forEach(e=>{document.documentElement.removeAttribute(e)}),t.bodyAttr.filter(jh).forEach(e=>{document.body.removeAttribute(e)})),["meta","link","script"].forEach(t=>{let n=e[t];for(let e in n){let a=document.createElement(t);for(let t in n[e])"innerHTML"!==t&&a.setAttribute(t,n[e][t]);a.setAttribute("data-qmeta",e),"script"===t&&(a.innerHTML=n[e].innerHTML||""),document.head.appendChild(a)}}),Object.keys(e.htmlAttr).filter(Bh).forEach(t=>{document.documentElement.setAttribute(t,e.htmlAttr[t]||"")}),Object.keys(e.bodyAttr).filter(jh).forEach(t=>{document.body.setAttribute(t,e.bodyAttr[t]||"")})}(function(e,t){let n={},a={};return void 0===e?{add:t,remove:a}:(e.title!==t.title&&(n.title=t.title),["meta","link","script","htmlAttr","bodyAttr"].forEach(i=>{let o=e[i],r=t[i];if(a[i]=[],null!=o){n[i]={};for(let e in o)!1===r.hasOwnProperty(e)&&a[i].push(e);for(let e in r)!1===o.hasOwnProperty(e)?n[i][e]=r[e]:!0===Dh(o[e],r[e])&&(a[i].push(e),n[i][e]=r[e])}else n[i]=r}),{add:n,remove:a})}(Mh,e)),Mh=e}function $h(){null!==Ih&&clearTimeout(Ih),Ih=setTimeout(Fh,50)}var Vh={install(e){!0!==this.__installed&&!0===I.value&&(Mh=window.__Q_META__,document.getElementById("qmeta-init").remove())}},Uh=0,Hh={},Wh={},Gh={},Kh={},Yh=/^\s*$/,Qh=[],Zh=[void 0,null,!0,!1,""],Jh=["top-left","top-right","bottom-left","bottom-right","top","bottom","left","right","center"],Xh=["top-left","top-right","bottom-left","bottom-right"],ep={positive:{icon:e=>e.iconSet.type.positive,color:"positive"},negative:{icon:e=>e.iconSet.type.negative,color:"negative"},warning:{icon:e=>e.iconSet.type.warning,color:"warning",textColor:"dark"},info:{icon:e=>e.iconSet.type.info,color:"info"},ongoing:{group:!1,timeout:0,spinner:!0,color:"grey-8"}};function tp(e,t,n){if(!e)return ap("parameter required");let a,i={textColor:"white"};if(!0!==e.ignoreDefaults&&Object.assign(i,Hh),!1===je(e)&&(i.type&&Object.assign(i,ep[i.type]),e={message:e}),Object.assign(i,ep[e.type||i.type],e),"function"==typeof i.icon&&(i.icon=i.icon(t)),i.spinner?(!0===i.spinner&&(i.spinner=rn),i.spinner=x(i.spinner)):i.spinner=!1,i.meta={hasMedia:!(!1===i.spinner&&!i.icon&&!i.avatar),hasText:np(i.message)||np(i.caption)},i.position){if(!1===Jh.includes(i.position))return ap("wrong position",e)}else i.position="bottom";if(!0===Zh.includes(i.timeout))i.timeout=5e3;else{let t=Number(i.timeout);if(isNaN(t)||t<0)return ap("wrong timeout",e);i.timeout=Number.isFinite(t)?t:0}0===i.timeout?i.progress=!1:!0===i.progress&&(i.meta.progressClass="q-notification__progress"+(i.progressClass?` ${i.progressClass}`:""),i.meta.progressStyle={animationDuration:`${i.timeout+1e3}ms`});let o=(!0===Array.isArray(e.actions)?e.actions:[]).concat(!0!==e.ignoreDefaults&&!0===Array.isArray(Hh.actions)?Hh.actions:[]).concat(!0===Array.isArray(ep[e.type]?.actions)?ep[e.type].actions:[]),{closeBtn:r}=i;if(r&&o.push({label:"string"==typeof r?r:t.lang.label.close}),i.actions=o.map(({handler:e,noDismiss:t,...n})=>({flat:!0,...n,onClick:"function"==typeof e?()=>{e(),!0!==t&&s()}:()=>{s()}})),void 0===i.multiLine&&(i.multiLine=i.actions.length>1),Object.assign(i.meta,{class:"q-notification row items-stretch q-notification--"+(!0===i.multiLine?"multi-line":"standard")+(void 0!==i.color?` bg-${i.color}`:"")+(void 0!==i.textColor?` text-${i.textColor}`:"")+(void 0!==i.classes?` ${i.classes}`:""),wrapperClass:"q-notification__wrapper col relative-position border-radius-inherit "+(!0===i.multiLine?"column no-wrap justify-center":"row items-center"),contentClass:"q-notification__content row items-center"+(!0===i.multiLine?"":" col"),leftClass:!0===i.meta.hasText?"additional":"single",attrs:{role:"alert",...i.attrs}}),!1===i.group?(i.group=void 0,i.meta.group=void 0):((void 0===i.group||!0===i.group)&&(i.group=[i.message,i.caption,i.multiline].concat(i.actions.map(e=>`${e.label}*${e.icon}`)).join("|")),i.meta.group=i.group+"|"+i.position),0===i.actions.length?i.actions=void 0:i.meta.actionsClass="q-notification__actions row items-center "+(!0===i.multiLine?"justify-end":"col-auto")+(!0===i.meta.hasMedia?" q-notification__actions--with-media":""),void 0!==n){n.notif.meta.timer&&(clearTimeout(n.notif.meta.timer),n.notif.meta.timer=void 0),i.meta.uid=n.notif.meta.uid;let e=Gh[i.position].value.indexOf(n.notif);Gh[i.position].value[e]=i}else{let t=Wh[i.meta.group];if(void 0===t){if(i.meta.uid=Uh++,i.meta.badge=1,-1!==["left","right","center"].indexOf(i.position))Gh[i.position].value.splice(Math.floor(Gh[i.position].value.length/2),0,i);else{let e=-1!==i.position.indexOf("top")?"unshift":"push";Gh[i.position].value[e](i)}void 0!==i.group&&(Wh[i.meta.group]=i)}else{if(t.meta.timer&&(clearTimeout(t.meta.timer),t.meta.timer=void 0),void 0!==i.badgePosition){if(!1===Xh.includes(i.badgePosition))return ap("wrong badgePosition",e)}else i.badgePosition="top-"+(-1!==i.position.indexOf("left")?"right":"left");i.meta.uid=t.meta.uid,i.meta.badge=t.meta.badge+1,i.meta.badgeClass=`q-notification__badge q-notification__badge--${i.badgePosition}`+(void 0!==i.badgeColor?` bg-${i.badgeColor}`:"")+(void 0!==i.badgeTextColor?` text-${i.badgeTextColor}`:"")+(i.badgeClass?` ${i.badgeClass}`:"");let n=Gh[i.position].value.indexOf(t);Gh[i.position].value[n]=Wh[i.meta.group]=i}}let s=()=>{(function(e){e.meta.timer&&(clearTimeout(e.meta.timer),e.meta.timer=void 0);let t=Gh[e.position].value.indexOf(e);if(-1!==t){void 0!==e.group&&delete Wh[e.meta.group];let n=Qh[""+e.meta.uid];if(n){let{width:e,height:t}=getComputedStyle(n);n.style.left=`${n.offsetLeft}px`,n.style.width=e,n.style.height=t}Gh[e.position].value.splice(t,1),"function"==typeof e.onDismiss&&e.onDismiss()}})(i),a=void 0};return i.timeout>0&&(i.meta.timer=setTimeout(()=>{i.meta.timer=void 0,s()},i.timeout+1e3)),void 0!==i.group?t=>{void 0!==t?ap("trying to update a grouped one which is forbidden",e):s()}:(a={dismiss:s,config:e,notif:i},void 0===n?e=>{if(void 0!==a)if(void 0===e)a.dismiss();else{tp(Object.assign({},a.config,e,{group:!1,position:i.position}),t,a)}}:void Object.assign(n,a))}function np(e){return null!=e&&!0!==Yh.test(e)}function ap(e,t){return console.error(`Notify: ${e}`,t),!1}var ip={setDefaults(e){!0===je(e)&&Object.assign(Hh,e)},registerType(e,t){!0===je(t)&&(ep[e]=t)},install({$q:e,parentApp:t}){if(e.notify=this.create=t=>tp(t,e),e.notify.setDefaults=this.setDefaults,e.notify.registerType=this.registerType,void 0!==e.config.notify&&this.setDefaults(e.config.notify),!0!==this.__installed){Jh.forEach(e=>{Gh[e]=a([]);let t=!0===["left","center","right"].includes(e)?"center":-1!==e.indexOf("top")?"top":"bottom",n=-1!==e.indexOf("left")?"start":-1!==e.indexOf("right")?"end":"center",i=["left","right"].includes(e)?`items-${"left"===e?"start":"end"} justify-center`:"center"===e?"flex-center":`items-${n}`;Kh[e]=`q-notifications__list q-notifications__list--${t} fixed column no-wrap ${i}`});let e=Kn("q-notify");He($({name:"QNotifications",devtools:{hide:!0},setup:()=>()=>n("div",{class:"q-notifications"},Jh.map(e=>n(C,{key:e,class:Kh[e],tag:"div",name:`q-notification--${e}`},()=>Gh[e].value.map(e=>{let t=e.meta,a=[];if(!0===t.hasMedia&&(!1!==e.spinner?a.push(n(e.spinner,{class:"q-notification__spinner q-notification__spinner--"+t.leftClass,color:e.spinnerColor,size:e.spinnerSize})):e.icon?a.push(n(Mt,{class:"q-notification__icon q-notification__icon--"+t.leftClass,name:e.icon,color:e.iconColor,size:e.iconSize,role:"img"})):e.avatar&&a.push(n(Lt,{class:"q-notification__avatar q-notification__avatar--"+t.leftClass},()=>n("img",{src:e.avatar,"aria-hidden":"true"})))),!0===t.hasText){let t,i={class:"q-notification__message col"};if(!0===e.html)i.innerHTML=e.caption?`
${e.message}
${e.caption}
`:e.message;else{let a=[e.message];t=e.caption?[n("div",a),n("div",{class:"q-notification__caption"},[e.caption])]:a}a.push(n("div",i,t))}let i=[n("div",{class:t.contentClass},a)];return!0===e.progress&&i.push(n("div",{key:`${t.uid}|p|${t.badge}`,class:t.progressClass,style:t.progressStyle})),void 0!==e.actions&&i.push(n("div",{class:t.actionsClass},e.actions.map(e=>n(An,e)))),t.badge>1&&i.push(n("div",{key:`${t.uid}|${t.badge}`,class:e.meta.badgeClass,style:e.badgeStyle},[t.badge])),n("div",{ref:e=>{Qh[""+t.uid]=e},key:t.uid,class:t.class,...t.attrs},[n("div",{class:t.wrapperClass},i)])}))))}),t).mount(e)}}};function op(){let e=()=>null;return{has:()=>!1,hasItem:()=>!1,getLength:()=>0,getItem:e,getIndex:e,getKey:e,getAll:()=>{},getAllKeys:()=>[],set:W,setItem:W,remove:W,removeItem:W,clear:W,isEmpty:()=>!0}}function rp(e){let t=window[e+"Storage"],n=e=>{let n=t.getItem(e);return n?function(e){if(e.length<9)return e;let t=e.substring(0,8),n=e.substring(9);switch(t){case"__q_date":let t=Number(n);return new Date(!0===Number.isNaN(t)?n:t);case"__q_expr":return new RegExp(n);case"__q_numb":return Number(n);case"__q_bool":return"1"===n;case"__q_strn":return""+n;case"__q_objt":return JSON.parse(n);default:return e}}(n):null},a=e=>null!==t.getItem(e),i=(e,n)=>{t.setItem(e,function(e){return!0===Be(e)?"__q_date|"+e.getTime():!0===Fe(e)?"__q_expr|"+e.source:"number"==typeof e?"__q_numb|"+e:"boolean"==typeof e?"__q_bool|"+(e?"1":"0"):"string"==typeof e?"__q_strn|"+e:"function"==typeof e?"__q_strn|"+e.toString():e===Object(e)?"__q_objt|"+JSON.stringify(e):e}(n))},o=e=>{t.removeItem(e)};return{has:a,hasItem:a,getLength:()=>t.length,getItem:n,getIndex:e=>ee{let e,a={},i=t.length;for(let o=0;o{let e=[],n=t.length;for(let a=0;a{t.clear()},isEmpty:()=>0===t.length}}var sp=!1===j.has.webStorage?op():rp("local"),lp={install({$q:e}){e.localStorage=sp}};Object.assign(lp,sp);var up=lp,cp=!1===j.has.webStorage?op():rp("session"),dp={install({$q:e}){e.sessionStorage=cp}};Object.assign(dp,cp);var hp=dp,pp={};function fp(e){return void 0!==navigator.clipboard?navigator.clipboard.writeText(e):new Promise((t,n)=>{let a=function(e){let t=document.createElement("textarea");t.value=e,t.contentEditable="true",t.style.position="fixed";let n=()=>{};Ma(n),document.body.appendChild(t),t.focus(),t.select();let a=document.execCommand("copy");return t.remove(),La(n),a}(e);a?t(!0):n(a)})}t(pp,{EventBus:()=>gp,clone:()=>au,colors:()=>Oo,copyToClipboard:()=>fp,createMetaMixin:()=>mp,createUploaderComponent:()=>td,date:()=>kr,debounce:()=>ae,dom:()=>dn,event:()=>ne,exportFile:()=>vp,extend:()=>ms,format:()=>tt,frameDebounce:()=>eu,getCssVar:()=>Yd,is:()=>Ve,morph:()=>Sd,noop:()=>W,openURL:()=>yp,patterns:()=>To,runSequentialPromises:()=>wp,scroll:()=>ya,setCssVar:()=>ue,throttle:()=>hn,uid:()=>Ja});var mp=e=>{let t={activated(){this.__qMeta.active=!0,$h()},deactivated(){this.__qMeta.active=!1,$h()},unmounted(){qh.splice(qh.indexOf(this.__qMeta),1),$h(),this.__qMeta=void 0}};return"function"==typeof e?Object.assign(t,{computed:{__qMetaOptions(){return e.call(this)||{}}},watch:{__qMetaOptions(e){this.__qMeta.val=e,!0===this.__qMeta.active&&$h()}},created(){this.__qMeta={active:!0,val:this.__qMetaOptions},qh.push(this.__qMeta),$h()}}):t.created=function(){this.__qMeta={active:!0,val:e},qh.push(this.__qMeta),$h()},t},gp=class{constructor(){this.__stack={}}on(e,t,n){return(this.__stack[e]||(this.__stack[e]=[])).push({fn:t,ctx:n}),this}once(e,t,n){let a=(...i)=>{this.off(e,a),t.apply(n,i)};return a.__callback=t,this.on(e,a,n)}emit(e){let t=this.__stack[e];if(void 0!==t){let e=[].slice.call(arguments,1);t.forEach(t=>{t.fn.apply(t.ctx,e)})}return this}off(e,t){let n=this.__stack[e];if(void 0===n)return this;if(void 0===t)return delete this.__stack[e],this;let a=n.filter(e=>e.fn!==t&&e.fn.__callback!==t);return 0!==a.length?this.__stack[e]=a:delete this.__stack[e],this}};function _p(e){setTimeout(()=>{window.URL.revokeObjectURL(e.href)},1e4),e.remove()}function vp(e,t,n={}){let{mimeType:a,byteOrderMark:i,encoding:o}="string"==typeof n?{mimeType:n}:n,r=void 0!==o?new TextEncoder(o).encode([t]):t,s=new Blob(void 0!==i?[i,r]:[r],{type:a||"application/octet-stream"}),l=document.createElement("a");l.href=window.URL.createObjectURL(s),l.setAttribute("download",e),typeof l.download>"u"&&l.setAttribute("target","_blank"),l.classList.add("hidden"),l.style.position="fixed",document.body.appendChild(l);try{return l.click(),_p(l),!0}catch(e){return _p(l),e}}function bp(e,t,n){let a=window.open;if(!0===F.is.cordova)if(void 0!==cordova?.InAppBrowser?.open)a=cordova.InAppBrowser.open;else if(void 0!==navigator?.app)return navigator.app.loadUrl(e,{openExternal:!0});let i=a(e,"_blank",function(e){let t=Object.assign({noopener:!0},e),n=[];for(let e in t){let a=t[e];!0===a?n.push(e):($e(a)||"string"==typeof a&&""!==a)&&n.push(e+"="+a)}return n.join(",")}(n));if(i)return F.is.desktop&&i.focus(),i;t?.()}var yp=(e,t,n)=>{if(!0!==F.is.ios||void 0===window.SafariViewController)return bp(e,t,n);window.SafariViewController.isAvailable(a=>{a?window.SafariViewController.show({url:e},W,t):bp(e,t,n)})};function wp(e,{threadsNumber:t=1,abortOnFail:n=!0}={}){let a=-1,i=!1,{isList:o,totalJobs:r,resultAggregator:s,resultKeys:l}=function(e){let t=Array.isArray(e);if(!0===t){let n=e.length;return{isList:t,totalJobs:n,resultAggregator:Array(n).fill(null)}}let n=Object.keys(e),a={};return n.forEach(e=>{a[e]=null}),{isList:t,totalJobs:n.length,resultAggregator:a,resultKeys:n}}(e),u=Array(t).fill(null).map(()=>new Promise((t,u)=>{!function c(){let d=++a;if(!0===i||d>=r)return void t();let h=!0===o?d:l[d];e[h](s).then(e=>{!0!==i?(s[h]={key:h,status:"fulfilled",value:e},setTimeout(c)):t()}).catch(e=>{if(!0===i)return void t();let a={key:h,status:"rejected",reason:e};if(s[h]=a,!0===n)return i=!0,void u({...a,resultAggregator:s});setTimeout(c)})}()}));return Promise.all(u).then(()=>s)}var kp={};function xp(){let{emit:e,proxy:t}=k(),n=a(null);function i(){n.value.hide()}return Object.assign(t,{show:function(){n.value.show()},hide:i}),{dialogRef:n,onDialogHide:function(){e("hide")},onDialogOK:function(t){e("ok",t),i()},onDialogCancel:i}}t(kp,{useDialogPluginComponent:()=>xp,useFormChild:()=>Ns,useHydration:()=>io,useId:()=>ei,useInterval:()=>Pp,useMeta:()=>Cp,useQuasar:()=>Tp,useRenderCache:()=>vi,useSplitAttrs:()=>cs,useTick:()=>na,useTimeout:()=>aa});var Sp=["ok","hide"];function Cp(e){{let t={active:!0};if("function"==typeof e){let n=i(e);t.val=n.value,o(n,e=>{t.val=e,!0===t.active&&$h()})}else t.val=e;qh.push(t),$h(),h(()=>{t.active=!0,$h()}),p(()=>{t.active=!1,$h()}),_(()=>{qh.splice(qh.indexOf(t),1),$h()})}}function Tp(){return y("_q_")}function Pp(){let e=null,t=k();function n(){null!==e&&(clearInterval(e),e=null)}return p(n),g(n),{removeInterval:n,registerInterval(a,i){n(),!1===Wt(t)&&(e=setInterval(a,i))}}}xp.emits=Sp,xp.emitsObject=Xc(Sp),void 0===window.Vue&&console.error("[ Quasar ] Vue is required to run. Please add a script tag for it before loading Quasar."),window.Quasar={version:"2.18.6",install(e,t){Ge(e,{components:Ke,directives:ld,plugins:Kd,...t})},lang:xe,iconSet:Te,...Ke,...ld,...Kd,...kp,...pp}})(); +* Quasar Framework v2.22.0 +* (c) 2015-present Razvan Stoenescu +* Released under the MIT License. +*/!function(e){var t=Object.defineProperty,n=(e,n)=>{let a={};for(var i in e)t(a,i,{get:e[i],enumerable:!0});return n||t(a,Symbol.toStringTag,{value:"Module"}),a};function a(e,t,n,a){return Object.defineProperty(e,t,{get:n,set:a,enumerable:!0}),e}function i(e,t){for(let n in t)a(e,n,t[n]);return e}let r,o=(0,e.ref)(!1);let s="ontouchstart"in window||window.navigator.maxTouchPoints>0;let l=navigator.userAgent||navigator.vendor||window.opera,u={has:{touch:!1,webStorage:!1},within:{iframe:!1}},c={userAgent:l,is:function(e){let t=e.toLowerCase(),n=function(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||/(opr)[\/]([\w.]+)/.exec(e)||/(vivaldi)[\/]([\w.]+)/.exec(e)||/(chrome|crios)[\/]([\w.]+)/.exec(e)||/(version)(applewebkit)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||/(firefox|fxios)[\/]([\w.]+)/.exec(e)||/(webkit)[\/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[\/]([\w.]+)/.exec(e)||[];return{browser:n[5]||n[3]||n[1]||"",version:n[4]||n[2]||"0",platform:t[0]||""}}(t,function(e){return/(ipad)/.exec(e)||/(ipod)/.exec(e)||/(windows phone)/.exec(e)||/(iphone)/.exec(e)||/(kindle)/.exec(e)||/(silk)/.exec(e)||/(android)/.exec(e)||/(win)/.exec(e)||/(mac)/.exec(e)||/(linux)/.exec(e)||/(cros)/.exec(e)||/(playbook)/.exec(e)||/(bb)/.exec(e)||/(blackberry)/.exec(e)||[]}(t)),a={mobile:!1,desktop:!1,cordova:!1,capacitor:!1,nativeMobile:!1,electron:!1,bex:!1,linux:!1,mac:!1,win:!1,cros:!1,chrome:!1,firefox:!1,opera:!1,safari:!1,vivaldi:!1,edge:!1,edgeChromium:!1,ie:!1,webkit:!1,android:!1,ios:!1,ipad:!1,iphone:!1,ipod:!1,kindle:!1,winphone:!1,blackberry:!1,playbook:!1,silk:!1};n.browser&&(a[n.browser]=!0,a.version=n.version,a.versionNumber=Number.parseInt(n.version,10)),n.platform&&(a[n.platform]=!0);let i=a.android||a.ios||a.bb||a.blackberry||a.ipad||a.iphone||a.ipod||a.kindle||a.playbook||a.silk||a["windows phone"];if(!0===i||t.includes("mobile")?a.mobile=!0:a.desktop=!0,a["windows phone"]&&(a.winphone=!0,delete a["windows phone"]),a.edga||a.edgios||a.edg?(a.edge=!0,n.browser="edge"):a.crios?(a.chrome=!0,n.browser="chrome"):a.fxios&&(a.firefox=!0,n.browser="firefox"),(a.ipod||a.ipad||a.iphone)&&(a.ios=!0),a.vivaldi&&=(n.browser="vivaldi",!0),(a.chrome||a.opr||a.safari||a.vivaldi||a.mobile&&!a.ios&&!i)&&(a.webkit=!0),a.opr&&(n.browser="opera",a.opera=!0),a.safari&&(a.blackberry||a.bb?(n.browser="blackberry",a.blackberry=!0):a.playbook?(n.browser="playbook",a.playbook=!0):a.android?(n.browser="android",a.android=!0):a.kindle?(n.browser="kindle",a.kindle=!0):a.silk&&=(n.browser="silk",!0)),a.name=n.browser,a.platform=n.platform,t.includes("electron"))a.electron=!0;else if(document.location.href.includes("-extension://"))a.bex=!0;else{if(void 0===window.Capacitor?(void 0!==window._cordovaNative||void 0!==window.cordova)&&(a.cordova=!0,a.nativeMobile=!0,a.nativeMobileWrapper="cordova"):(a.capacitor=!0,a.nativeMobile=!0,a.nativeMobileWrapper="capacitor"),o.value&&(r={is:{...a}}),s&&a.mac&&(a.desktop&&a.safari||a.nativeMobile&&!a.android&&!a.ios&&!a.ipad)){delete a.mac,delete a.desktop;let e=Math.min(window.innerHeight,window.innerWidth)>414?"ipad":"iphone";Object.assign(a,{mobile:!0,ios:!0,platform:e,[e]:!0})}!a.mobile&&window.navigator.userAgentData&&window.navigator.userAgentData.mobile&&(delete a.desktop,a.mobile=!0)}return a}(l),has:{touch:s},within:{iframe:window.self!==window.top}},d={install(t){let{$q:n}=t;o.value?(t.onSSRHydrated.push(()=>{Object.assign(n.platform,c),o.value=!1}),n.platform=(0,e.reactive)(this)):n.platform=this}};{let e;a(c.has,"webStorage",()=>{if(void 0!==e)return e;try{if(window.localStorage)return e=!0,!0}catch{}return e=!1,!1}),Object.assign(d,c),o.value&&(Object.assign(d,r,u),r=null)}function h(t){return(0,e.markRaw)((0,e.defineComponent)(t))}function p(t){return(0,e.markRaw)(t)}let f=(t,n)=>{let i=(0,e.reactive)(t);for(let e in t)a(n,e,()=>i[e],t=>{i[e]=t});return n},m={hasPassive:!1,passiveCapture:!0,notPassiveCapture:!0};try{let e=Object.defineProperty({},"passive",{get(){Object.assign(m,{hasPassive:!0,passive:{passive:!0},notPassive:{passive:!1},passiveCapture:{passive:!0,capture:!0},notPassiveCapture:{passive:!1,capture:!0}})}});window.addEventListener("qtest",null,e),window.removeEventListener("qtest",null,e)}catch{}function _(){}function g(e){return 0===e.button}function v(e){return e.touches&&e.touches[0]?e=e.touches[0]:e.changedTouches&&e.changedTouches[0]?e=e.changedTouches[0]:e.targetTouches&&e.targetTouches[0]&&(e=e.targetTouches[0]),{top:e.clientY,left:e.clientX}}function b(e){e.stopPropagation()}function y(e){!1!==e.cancelable&&e.preventDefault()}function w(e){!1!==e.cancelable&&e.preventDefault(),e.stopPropagation()}function k(e,t){if(void 0===e||t&&e.__dragPrevented)return;let n=t?e=>{e.__dragPrevented=!0,e.addEventListener("dragstart",y,m.notPassiveCapture)}:e=>{delete e.__dragPrevented,e.removeEventListener("dragstart",y,m.notPassiveCapture)};e.querySelectorAll("a, img").forEach(n)}function x(e,t,n){let a=`__q_${t}_evt`;e[a]=[...e[a]??[],...n],n.forEach(t=>{t[0].addEventListener(t[1],e[t[2]],m[t[3]])})}function S(e,t){let n=`__q_${t}_evt`;void 0!==e[n]&&(e[n].forEach(t=>{t[0].removeEventListener(t[1],e[t[2]],m[t[3]])}),e[n]=void 0)}var C={listenOpts:m,leftClick:g,middleClick:function(e){return 1===e.button},rightClick:function(e){return 2===e.button},position:v,getEventPath:function(e){if(e.path)return e.path;if(e.composedPath)return e.composedPath();let t=[],n=e.target;for(;n;){if(t.push(n),"HTML"===n.tagName)return t.push(document,window),t;n=n.parentElement}},getMouseWheelDistance:function(e){let t=e.deltaX,n=e.deltaY;if((t||n)&&e.deltaMode){let a=1===e.deltaMode?40:800;t*=a,n*=a}return e.shiftKey&&!t&&([n,t]=[t,n]),{x:t,y:n}},stop:b,prevent:y,stopAndPrevent:w,preventDraggable:k};function T(e,t=250,n){let a=null;function i(...i){null===a?n&&e.apply(this,i):clearTimeout(a),a=setTimeout(()=>{a=null,n||e.apply(this,i)},t)}return i.cancel=()=>{null!==a&&clearTimeout(a)},i}let P=["sm","md","lg","xl"],{passive:E}=m;var A=f({width:0,height:0,name:"xs",sizes:{sm:600,md:1024,lg:1440,xl:1920},lt:{sm:!0,md:!0,lg:!0,xl:!0},gt:{xs:!1,sm:!1,md:!1,lg:!1},xs:!0,sm:!1,md:!1,lg:!1,xl:!1},{setSizes:_,setDebounce:_,install({$q:e,onSSRHydrated:t}){if(e.screen=this,this.__installed)return void(void 0!==e.config.screen&&(e.config.screen.bodyClasses?this.__update(!0):document.body.classList.remove(`screen--${this.name}`)));let{visualViewport:n}=window,a=n||window,i=document.scrollingElement||document.documentElement,r=void 0===n||c.is.mobile?()=>[Math.max(window.innerWidth,i.clientWidth),Math.max(window.innerHeight,i.clientHeight)]:()=>[n.width*n.scale+window.innerWidth-i.clientWidth,n.height*n.scale+window.innerHeight-i.clientHeight],s=!0===e.config.screen?.bodyClasses;this.__update=e=>{let[t,n]=r();if(n!==this.height&&(this.height=n),t!==this.width)this.width=t;else if(!0!==e)return;let a=this.sizes;this.gt.xs=t>=a.sm,this.gt.sm=t>=a.md,this.gt.md=t>=a.lg,this.gt.lg=t>=a.xl,this.lt.sm=t{P.forEach(t=>{void 0!==e[t]&&(u[t]=e[t])})},this.setDebounce=e=>{d=e};let h=()=>{let e=getComputedStyle(document.body);e.getPropertyValue("--q-size-sm")&&P.forEach(t=>{this.sizes[t]=Number.parseInt(e.getPropertyValue(`--q-size-${t}`),10)}),this.setSizes=e=>{P.forEach(t=>{e[t]&&(this.sizes[t]=e[t])}),this.__update(!0)},this.setDebounce=e=>{void 0!==l&&a.removeEventListener("resize",l,E),l=e>0?T(this.__update,e):this.__update,a.addEventListener("resize",l,E)},this.setDebounce(d),0===Object.keys(u).length?this.__update():(this.setSizes(u),u=void 0),s&&"xs"===this.name&&document.body.classList.add("screen--xs")};o.value?t.push(h):h()}});let L=f({isActive:!1,mode:!1},{__media:void 0,set(e){L.mode=e,"auto"===e?(void 0===L.__media&&(L.__media=window.matchMedia("(prefers-color-scheme: dark)"),L.__updateMedia=()=>{L.set("auto")},L.__media.addListener(L.__updateMedia)),e=L.__media.matches):void 0!==L.__media&&(L.__media.removeListener(L.__updateMedia),L.__media=void 0),L.isActive=!0===e,document.body.classList.remove("body--"+(!0===e?"light":"dark")),document.body.classList.add("body--"+(!0===e?"dark":"light"))},toggle(){L.set(!L.isActive)},install({$q:e,ssrContext:t}){let n=e.config.dark;e.dark=this,this.__installed||this.set(void 0!==n&&n)}});function M(e,t,n=document.body){if("string"!=typeof e)throw TypeError("Expected a string as propName");if("string"!=typeof t)throw TypeError("Expected a string as value");if(!(n instanceof Element))throw TypeError("Expected a DOM element");n.style.setProperty(`--q-${e}`,t)}let R=!1;function z(e){R=!0===e.isComposing}function I(e){return R||e!==Object(e)||e.isComposing||e.qKeyEvent}function N(e,t){return!I(e)&&[t].flat().includes(e.keyCode)}function O(e){return e.ios?"ios":e.android?"android":void 0}var j={install(e){if(!this.__installed){if(o.value)!function(){let{is:e}=c,t=document.body.className,n=new Set(t.replaceAll(/ {2}/g," ").split(" "));if(!e.nativeMobile&&!e.electron&&!e.bex)if(e.desktop)n.delete("mobile"),n.delete("platform-ios"),n.delete("platform-android"),n.add("desktop");else if(e.mobile){n.delete("desktop"),n.add("mobile"),n.delete("platform-ios"),n.delete("platform-android");let t=O(e);void 0!==t&&n.add(`platform-${t}`)}c.has.touch&&(n.delete("no-touch"),n.add("touch")),c.within.iframe&&n.add("within-iframe");let a=[...n].join(" ");t!==a&&(document.body.className=a)}();else{let{$q:t}=e;void 0!==t.config.brand&&function(e){for(let t in e)M(t,e[t])}(t.config.brand),document.body.classList.add(...function({is:e,has:t,within:n},a){let i=[e.desktop?"desktop":"mobile",(t.touch?"":"no-")+"touch"];if(e.mobile){let t=O(e);void 0!==t&&i.push("platform-"+t)}if(e.nativeMobile){let t=e.nativeMobileWrapper;i.push(t,"native-mobile"),e.ios&&(void 0===a[t]||a[t].iosStatusBarPadding)&&i.push("q-ios-padding")}else e.electron?i.push("electron"):e.bex&&i.push("bex");return n.iframe&&i.push("within-iframe"),i}(c,t.config))}c.is.ios&&document.body.addEventListener("touchstart",_),window.addEventListener("keydown",z,!0)}}};let D=()=>!0;function q(e){return"string"==typeof e&&""!==e&&"/"!==e&&"#/"!==e}function B(e){return e.startsWith("#")&&(e=e.slice(1)),e.startsWith("/")||(e="/"+e),e.endsWith("/")&&(e=e.slice(0,-1)),"#"+e}var F={__history:[],add:_,remove:_,install({$q:e}){if(this.__installed)return;let{cordova:t,capacitor:n}=c.is;if(!t&&!n)return;let a=e.config[t?"cordova":"capacitor"];if(!1===a?.backButton||n&&(void 0===window.Capacitor||void 0===window.Capacitor.Plugins.App))return;this.add=e=>{void 0===e.condition&&(e.condition=D),this.__history.push(e)},this.remove=e=>{let t=this.__history.indexOf(e);-1!==t&&this.__history.splice(t,1)};let i=function(e){if(!1===e.backButtonExit)return()=>!1;if("*"===e.backButtonExit)return D;let t=["#/"];return Array.isArray(e.backButtonExit)&&t.push(...e.backButtonExit.filter(q).map(B)),()=>t.includes(window.location.hash)}({backButtonExit:!0,...a}),r=()=>{if(0!==this.__history.length){let e=this.__history.at(-1);e.condition()&&(this.__history.pop(),e.handler())}else i()?navigator.app.exitApp():window.history.back()};t?document.addEventListener("deviceready",()=>{document.addEventListener("backbutton",r,!1)}):window.Capacitor.Plugins.App.addListener("backButton",r)}},V={isoName:"en-US",nativeName:"English (US)",label:{clear:"Clear",ok:"OK",cancel:"Cancel",close:"Close",set:"Set",select:"Select",reset:"Reset",remove:"Remove",update:"Update",create:"Create",search:"Search",filter:"Filter",refresh:"Refresh",expand:e=>e?`Expand "${e}"`:"Expand",collapse:e=>e?`Collapse "${e}"`:"Collapse"},date:{days:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),daysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),firstDayOfWeek:0,format24h:!1,pluralDay:"days",prevMonth:"Previous month",nextMonth:"Next month",prevYear:"Previous year",nextYear:"Next year",today:"Today",prevRangeYears:e=>`Previous ${e} years`,nextRangeYears:e=>`Next ${e} years`},table:{noData:"No data available",noResults:"No matching records found",loading:"Loading...",selectedRecords:e=>1===e?"1 record selected.":(0===e?"No":e)+" records selected.",recordsPerPage:"Records per page:",allRows:"All",pagination:(e,t,n)=>e+"–"+t+" of "+n,columns:"Columns"},pagination:{first:"First page",prev:"Previous page",next:"Next page",last:"Last page"},editor:{url:"URL",bold:"Bold",italic:"Italic",strikethrough:"Strikethrough",underline:"Underline",unorderedList:"Unordered List",orderedList:"Ordered List",subscript:"Subscript",superscript:"Superscript",hyperlink:"Hyperlink",toggleFullscreen:"Toggle Fullscreen",quote:"Quote",left:"Left align",center:"Center align",right:"Right align",justify:"Justify align",print:"Print",outdent:"Decrease indentation",indent:"Increase indentation",removeFormat:"Remove formatting",formatting:"Formatting",fontSize:"Font Size",align:"Align",hr:"Insert Horizontal Rule",undo:"Undo",redo:"Redo",heading1:"Heading 1",heading2:"Heading 2",heading3:"Heading 3",heading4:"Heading 4",heading5:"Heading 5",heading6:"Heading 6",paragraph:"Paragraph",code:"Code",size1:"Very small",size2:"A bit small",size3:"Normal",size4:"Medium-large",size5:"Big",size6:"Very big",size7:"Maximum",defaultFont:"Default Font",viewSource:"View Source"},tree:{noNodes:"No nodes available",noResults:"No matching nodes found"}};function U(){let e=Array.isArray(navigator.languages)&&0!==navigator.languages.length?navigator.languages[0]:navigator.language;if("string"==typeof e)return e.split(/[-_]/).map((e,t)=>0===t?e.toLowerCase():t>1||e.length<4?e.toUpperCase():e[0].toUpperCase()+e.slice(1).toLowerCase()).join("-")}let $=f({__qLang:{}},{getLocale:U,set(e=V,t){let n={...e,rtl:!0===e.rtl,getLocale:U};if(n.set=$.set,void 0===$.__langConfig||!$.__langConfig.noHtmlAttrs){let e=document.documentElement;e.setAttribute("dir",n.rtl?"rtl":"ltr"),e.setAttribute("lang",n.isoName)}Object.assign($.__qLang,n)},install({$q:e,lang:t,ssrContext:n}){e.lang=$.__qLang,$.__langConfig=e.config.lang,this.__installed?void 0!==t&&this.set(t):(this.props=new Proxy(this.__qLang,{get:Reflect.get,ownKeys:e=>Reflect.ownKeys(e).filter(e=>"set"!==e&&"getLocale"!==e)}),this.set(t||V))}});var H={name:"material-icons",type:{positive:"check_circle",negative:"warning",info:"info",warning:"priority_high"},arrow:{up:"arrow_upward",right:"arrow_forward",down:"arrow_downward",left:"arrow_back",dropdown:"arrow_drop_down"},chevron:{left:"chevron_left",right:"chevron_right"},colorPicker:{spectrum:"gradient",tune:"tune",palette:"style"},pullToRefresh:{icon:"refresh"},carousel:{left:"chevron_left",right:"chevron_right",up:"keyboard_arrow_up",down:"keyboard_arrow_down",navigationIcon:"lens"},chip:{remove:"cancel",selected:"check"},datetime:{arrowLeft:"chevron_left",arrowRight:"chevron_right",now:"access_time",today:"today"},editor:{bold:"format_bold",italic:"format_italic",strikethrough:"strikethrough_s",underline:"format_underlined",unorderedList:"format_list_bulleted",orderedList:"format_list_numbered",subscript:"vertical_align_bottom",superscript:"vertical_align_top",hyperlink:"link",toggleFullscreen:"fullscreen",quote:"format_quote",left:"format_align_left",center:"format_align_center",right:"format_align_right",justify:"format_align_justify",print:"print",outdent:"format_indent_decrease",indent:"format_indent_increase",removeFormat:"format_clear",formatting:"text_format",fontSize:"format_size",align:"format_align_left",hr:"remove",undo:"undo",redo:"redo",heading:"format_size",code:"code",size:"format_size",font:"font_download",viewSource:"code"},expansionItem:{icon:"keyboard_arrow_down",denseIcon:"arrow_drop_down"},fab:{icon:"add",activeIcon:"close"},field:{clear:"cancel",error:"error"},pagination:{first:"first_page",prev:"keyboard_arrow_left",next:"keyboard_arrow_right",last:"last_page"},rating:{icon:"grade"},stepper:{done:"check",active:"edit",error:"warning"},tabs:{left:"chevron_left",right:"chevron_right",up:"keyboard_arrow_up",down:"keyboard_arrow_down"},table:{arrowUp:"arrow_upward",warning:"warning",firstPage:"first_page",prevPage:"chevron_left",nextPage:"chevron_right",lastPage:"last_page"},tree:{icon:"play_arrow"},uploader:{done:"done",clear:"clear",add:"add_box",upload:"cloud_upload",removeQueue:"clear_all",removeUploaded:"done_all"}};let W=f({iconMapFn:null,__qIconSet:{}},{set(e,t){let n={...e};n.set=W.set,Object.assign(W.__qIconSet,n)},install({$q:e,iconSet:t,ssrContext:n}){void 0!==e.config.iconMapFn&&(this.iconMapFn=e.config.iconMapFn),e.iconSet=this.__qIconSet,a(e,"iconMapFn",()=>this.iconMapFn,e=>{this.iconMapFn=e}),this.__installed?void 0!==t&&this.set(t):(this.props=new Proxy(this.__qIconSet,{get:Reflect.get,ownKeys:e=>Reflect.ownKeys(e).filter(e=>"set"!==e)}),this.set(t||H))}}),G="_q_t_",K="_q_s_",Y="_q_l_",Q="_q_f_",Z="_q_fo_",J="_q_tabs_",X="_q_u_";function ee(){}function te(e,t){if(e===t)return!0;if(null!==e&&null!==t&&"object"==typeof e&&"object"==typeof t){if(e.constructor!==t.constructor)return!1;let n,a;if(e.constructor===Array){if(n=e.length,n!==t.length)return!1;for(a=n;0!==a--;)if(!te(e[a],t[a]))return!1;return!0}if(e.constructor===Map){if(e.size!==t.size)return!1;let n=e.entries();for(a=n.next();!a.done;){if(!t.has(a.value[0]))return!1;a=n.next()}for(n=e.entries(),a=n.next();!a.done;){if(!te(a.value[1],t.get(a.value[0])))return!1;a=n.next()}return!0}if(e.constructor===Set){if(e.size!==t.size)return!1;let n=e.entries();for(a=n.next();!a.done;){if(!t.has(a.value[0]))return!1;a=n.next()}return!0}if(null!=e.buffer&&e.buffer.constructor===ArrayBuffer){if(n=e.length,n!==t.length)return!1;for(a=n;0!==a--;)if(e[a]!==t[a])return!1;return!0}if(e.constructor===RegExp)return e.source===t.source&&e.flags===t.flags;if(e.valueOf!==Object.prototype.valueOf)return e.valueOf()===t.valueOf();if(e.toString!==Object.prototype.toString)return e.toString()===t.toString();let i=Object.keys(e).filter(t=>void 0!==e[t]);if(n=i.length,n!==Object.keys(t).filter(e=>void 0!==t[e]).length)return!1;for(a=n;0!==a--;){let n=i[a];if(!te(e[n],t[n]))return!1}return!0}return e!=e&&t!=t}function ne(e){return"object"==typeof e&&!!e&&!Array.isArray(e)}function ae(e){return"[object Date]"===Object.prototype.toString.call(e)}function ie(e){return"[object RegExp]"===Object.prototype.toString.call(e)}function re(e){return"number"==typeof e&&Number.isFinite(e)}var oe={deepEqual:te,object:ne,date:ae,regexp:ie,number:re};let se={},le=!1;let ue=[d,j,L,A,F,$,W];function ce(t,n){let a=(0,e.createApp)(t);a.config.globalProperties=n.config.globalProperties;let{reload:i,...r}=n._context;return Object.assign(a._context,r),a}function de(e,t){t.forEach(t=>{t.install(e),t.__installed=!0})}var he=function(e,t={}){let n={version:"2.22.0"};le?n.config=t.config||{}:(void 0!==t.config&&Object.assign(se,t.config),n.config={...se},le=!0),function(e,t,n){e.config.globalProperties.$q=n.$q,e.provide("_q_",n.$q),de(n,ue),void 0!==t.components&&Object.values(t.components).forEach(t=>{ne(t)&&void 0!==t.name&&e.component(t.name,t)}),void 0!==t.directives&&Object.values(t.directives).forEach(t=>{ne(t)&&void 0!==t.name&&e.directive(t.name,t)}),void 0!==t.plugins&&de(n,Object.values(t.plugins).filter(e=>"function"==typeof e.install&&!ue.includes(e))),o.value&&(n.$q.onSSRHydrated=()=>{n.onSSRHydrated.forEach(e=>{e()}),n.$q.onSSRHydrated=()=>{}})}(e,t,{parentApp:e,$q:n,lang:t.lang,iconSet:t.iconSet,onSSRHydrated:[]})};let pe=["B","KB","MB","GB","TB","PB"];function fe(e,t=1){let n=0;for(;Number.parseInt(e,10)>=1024&&nke.includes(e)},size:{type:String,default:"2px"},color:String,skipHijack:Boolean,reverse:Boolean,hijackFilter:Function},emits:["start","stop"],setup(t,{emit:n}){let a,{proxy:i}=(0,e.getCurrentInstance)(),r=(0,e.ref)(0),o=(0,e.ref)(!1),s=(0,e.ref)(!0),l=0,u=null,c=(0,e.computed)(()=>`q-loading-bar q-loading-bar--${t.position}`+(void 0===t.color?"":` bg-${t.color}`)+(s.value?"":" no-transition")),d=(0,e.computed)(()=>"top"===t.position||"bottom"===t.position),h=(0,e.computed)(()=>d.value?"height":"width"),p=(0,e.computed)(()=>{let e=o.value,n=function({p:e,pos:t,active:n,horiz:a,reverse:i,dir:r}){let o=1,s=1;return a?(i&&(o=-1),"bottom"===t&&(s=-1),{transform:`translate3d(${o*(e-100)}%,${n?0:-200*s}%,0)`}):(i&&(s=-1),"right"===t&&(o=-1),{transform:`translate3d(${n?0:r*o*-200}%,${s*(e-100)}%,0)`})}({p:r.value,pos:t.position,active:e,horiz:d.value,reverse:i.$q.lang.rtl&&["top","bottom"].includes(t.position)?!t.reverse:t.reverse,dir:i.$q.lang.rtl?-1:1});return n[h.value]=t.size,n.opacity=+!!e,n}),f=(0,e.computed)(()=>o.value?{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":r.value}:{"aria-hidden":"true"});function m(e=300){let t=a;return a=Math.max(0,e)||0,l++,l>1?(0===t&&e>0?v():null!==u&&t>0&&e<=0&&(clearTimeout(u),u=null),l):(null!==u&&clearTimeout(u),n("start"),r.value=0,u=setTimeout(()=>{u=null,s.value=!0,e>0&&v()},!0===o._value?500:1),!0!==o._value&&(o.value=!0,s.value=!1),l)}function _(e){return l>0&&(r.value=function(e,t){return"number"!=typeof t&&(t=e<25?3*Math.random()+3:e<65?3*Math.random():e<85?2*Math.random():e<99?.6:0),_e(e+t,0,100)}(r.value,e)),l}function g(){if(l=Math.max(0,l-1),l>0)return l;null!==u&&(clearTimeout(u),u=null),n("stop");let e=()=>{s.value=!0,r.value=100,u=setTimeout(()=>{u=null,o.value=!1},1e3)};return 0===r.value?u=setTimeout(e,1):e(),l}function v(){r.value<100&&(u=setTimeout(()=>{u=null,_(),v()},a))}let b=!1;return(0,e.onMounted)(()=>{t.skipHijack||(b=!0,function(e){Se++,xe.push(e),!(Se>1)&&(ye.prototype.open=function(e,t,...n){let a=[];this.addEventListener("loadstart",()=>{xe.forEach(e=>{(null===e.hijackFilter.value||e.hijackFilter.value(t))&&(e.start(),a.push(e.stop))})},{once:!0}),this.addEventListener("loadend",()=>{a.forEach(e=>{e()})},{once:!0}),we.call(this,e,t,...n)})}({start:m,stop:g,hijackFilter:(0,e.computed)(()=>t.hijackFilter||null)}))}),(0,e.onBeforeUnmount)(()=>{null!==u&&clearTimeout(u),b&&function(e){xe=xe.filter(t=>t.start!==e),Se=Math.max(0,Se-1),0===Se&&(ye.prototype.open=we)}(m)}),Object.assign(i,{start:m,stop:g,increment:_}),()=>(0,e.h)("div",{class:c.value,style:p.value,...f.value})}});let Te={xs:18,sm:24,md:32,lg:38,xl:46},Pe={size:String};function Ee(t,n=Te){return(0,e.computed)(()=>void 0===t.size?null:{fontSize:t.size in n?`${n[t.size]}px`:t.size})}function Ae(e,t){return void 0===e?t:e()||t}function Le(e,t){if(void 0!==e){let t=e();if(null!=t)return[...t]}return t}function Me(e,t){return void 0===e?t:t.concat(e())}function Re(e,t){return void 0===e?t:void 0===t?e():t.concat(e())}function ze(t,n,a,i,r,o){n.key=i+r;let s=(0,e.h)(t,n,a);return r?(0,e.withDirectives)(s,o()):s}let Ie="0 0 24 24",Ne=e=>e,Oe=e=>`ionicons ${e}`,je={"mdi-":e=>`mdi ${e}`,"icon-":Ne,"bt-":e=>`bt ${e}`,"eva-":e=>`eva ${e}`,"ion-md":Oe,"ion-ios":Oe,"ion-logo":Oe,"iconfont ":Ne,"ti-":e=>`themify-icon ${e}`,"bi-":e=>`bootstrap-icons ${e}`,"i-":Ne},De={o_:"-outlined",r_:"-round",s_:"-sharp"},qe={sym_o_:"-outlined",sym_r_:"-rounded",sym_s_:"-sharp"},Be=RegExp("^("+Object.keys(je).join("|")+")"),Fe=RegExp("^("+Object.keys(De).join("|")+")"),Ve=RegExp("^("+Object.keys(qe).join("|")+")"),Ue=/^[Mm]\s?[-+]?\.?\d/,$e=/^img:/,He=/^svguse:/,We=/^ion-/,Ge=/^(fa-(classic|sharp|solid|regular|light|brands|duotone|thin)|[lf]a[srlbdk]?) /;var Ke=h({name:"QIcon",props:{...Pe,tag:{type:String,default:"i"},name:String,color:String,left:Boolean,right:Boolean},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=Ee(t),r=(0,e.computed)(()=>"q-icon"+(t.left?" on-left":"")+(t.right?" on-right":"")+(void 0===t.color?"":` text-${t.color}`)),o=(0,e.computed)(()=>{let n,i=t.name;if("none"===i||!i)return{none:!0};if(null!==a.iconMapFn){let e=a.iconMapFn(i);if(void 0!==e){if(void 0===e.icon)return{cls:e.cls,content:void 0===e.content?" ":e.content};if(i=e.icon,"none"===i||!i)return{none:!0}}}if(Ue.test(i)){let[t,n=Ie]=i.split("|");return{svg:!0,viewBox:n,nodes:t.split("&&").map(t=>{let[n,a,i]=t.split("@@");return(0,e.h)("path",{style:a,d:n,transform:i})})}}if($e.test(i))return{img:!0,src:i.slice(4)};if(He.test(i)){let[e,t=Ie]=i.split("|");return{svguse:!0,src:e.slice(7),viewBox:t}}let r=" ",o=i.match(Be);if(null!==o)n=je[o[1]](i);else if(Ge.test(i))n=i;else if(We.test(i))n=`ionicons ion-${a.platform.is.ios?"ios":"md"}${i.slice(3)}`;else if(Ve.test(i)){n="notranslate material-symbols";let e=i.match(Ve);null!==e&&(i=i.slice(6),n+=qe[e[1]]),r=i}else{n="notranslate material-icons";let e=i.match(Fe);null!==e&&(i=i.slice(2),n+=De[e[1]]),r=i}return{cls:n,content:r}});return()=>{let a={class:r.value,style:i.value,"aria-hidden":"true"};return o.value.none?(0,e.h)(t.tag,a,Ae(n.default)):o.value.img?(0,e.h)(t.tag,a,Me(n.default,[(0,e.h)("img",{src:o.value.src})])):o.value.svg?(0,e.h)(t.tag,a,Me(n.default,[(0,e.h)("svg",{viewBox:o.value.viewBox||"0 0 24 24"},o.value.nodes)])):o.value.svguse?(0,e.h)(t.tag,a,Me(n.default,[(0,e.h)("svg",{viewBox:o.value.viewBox},[(0,e.h)("use",{"xlink:href":o.value.src})])])):(void 0!==o.value.cls&&(a.class+=" "+o.value.cls),(0,e.h)(t.tag,a,Me(n.default,[o.value.content])))}}}),Ye=h({name:"QAvatar",props:{...Pe,fontSize:String,color:String,textColor:String,icon:String,square:Boolean,rounded:Boolean},setup(t,{slots:n}){let a=Ee(t),i=(0,e.computed)(()=>"q-avatar"+(t.color?` bg-${t.color}`:"")+(t.textColor?` text-${t.textColor} q-chip--colored`:"")+(t.square?" q-avatar--square":t.rounded?" rounded-borders":"")),r=(0,e.computed)(()=>t.fontSize?{fontSize:t.fontSize}:null);return()=>{let o=void 0===t.icon?void 0:[(0,e.h)(Ke,{name:t.icon})];return(0,e.h)("div",{class:i.value,style:a.value},[(0,e.h)("div",{class:"q-avatar__content row flex-center overflow-hidden",style:r.value},Re(n.default,o))])}}});let Qe=["top","middle","bottom"];var Ze=h({name:"QBadge",props:{color:String,textColor:String,floating:Boolean,transparent:Boolean,multiLine:Boolean,outline:Boolean,rounded:Boolean,label:[Number,String],align:{type:String,validator:e=>Qe.includes(e)}},setup(t,{slots:n}){let a=(0,e.computed)(()=>void 0===t.align?null:{verticalAlign:t.align}),i=(0,e.computed)(()=>{let e=t.outline&&t.color||t.textColor;return`q-badge flex inline items-center no-wrap q-badge--${t.multiLine?"multi":"single"}-line`+(t.outline?" q-badge--outline":void 0===t.color?"":` bg-${t.color}`)+(void 0===e?"":` text-${e}`)+(t.floating?" q-badge--floating":"")+(t.rounded?" q-badge--rounded":"")+(t.transparent?" q-badge--transparent":"")});return()=>(0,e.h)("div",{class:i.value,style:a.value,role:"status","aria-label":t.label},Me(n.default,void 0===t.label?[]:[t.label]))}});let Je={dark:{type:Boolean,default:null}};function Xe(t,n){return(0,e.computed)(()=>null===t.dark?n.dark.isActive:t.dark)}var et=h({name:"QBanner",props:{...Je,inlineActions:Boolean,dense:Boolean,rounded:Boolean},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=Xe(t,a),r=(0,e.computed)(()=>"q-banner row items-center"+(t.dense?" q-banner--dense":"")+(i.value?" q-banner--dark q-dark":"")+(t.rounded?" rounded-borders":"")),o=(0,e.computed)(()=>"q-banner__actions row items-center justify-end col-"+(t.inlineActions?"auto":"all"));return()=>{let a=[(0,e.h)("div",{class:"q-banner__avatar col-auto row items-center self-start"},Ae(n.avatar)),(0,e.h)("div",{class:"q-banner__content col text-body2"},Ae(n.default))],i=Ae(n.action);return void 0!==i&&a.push((0,e.h)("div",{class:o.value},i)),(0,e.h)("div",{class:r.value+(t.inlineActions||void 0===i?"":" q-banner--top-padding"),role:"alert"},a)}}}),tt=h({name:"QBar",props:{...Je,dense:Boolean},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=Xe(t,a),r=(0,e.computed)(()=>`q-bar row no-wrap items-center q-bar--${t.dense?"dense":"standard"} q-bar--${i.value?"dark":"light"}`);return()=>(0,e.h)("div",{class:r.value,role:"toolbar"},Ae(n.default))}});let nt={left:"start",center:"center",right:"end",between:"between",around:"around",evenly:"evenly",stretch:"stretch"},at=Object.keys(nt),it={align:{type:String,validator:e=>at.includes(e)}};function rt(t){return(0,e.computed)(()=>{let e=void 0===t.align?t.vertical?"stretch":"left":t.align;return`${t.vertical?"items":"justify"}-${nt[e]}`})}function ot(e){if(Object(e.$parent)===e.$parent)return e.$parent;let{parent:t}=e.$;for(;Object(t)===t;){if(Object(t.proxy)===t.proxy)return t.proxy;t=t.parent}}function st(e,t){"symbol"==typeof t.type?Array.isArray(t.children)&&t.children.forEach(t=>{st(e,t)}):e.add(t)}function lt(e){let t=new Set;return e.forEach(e=>{st(t,e)}),[...t]}function ut(e){return void 0!==e.appContext.config.globalProperties.$router}function ct(e){return!0===e.isUnmounted||!0===e.isDeactivated}let dt=["",!0];var ht=h({name:"QBreadcrumbs",props:{...it,separator:{type:String,default:"/"},separatorColor:String,activeColor:{type:String,default:"primary"},gutter:{type:String,validator:e=>["none","xs","sm","md","lg","xl"].includes(e),default:"sm"}},setup(t,{slots:n}){let a=rt(t),i=(0,e.computed)(()=>`flex items-center ${a.value}${"none"===t.gutter?"":` q-gutter-${t.gutter}`}`),r=(0,e.computed)(()=>t.separatorColor?` text-${t.separatorColor}`:""),o=(0,e.computed)(()=>` text-${t.activeColor}`);return()=>{if(void 0===n.default)return;let a=lt(Ae(n.default));if(0===a.length)return;let s=1,l=[],u=a.filter(e=>"QBreadcrumbsEl"===e.type?.name).length,c=void 0===n.separator?()=>t.separator:n.separator;return a.forEach(t=>{if("QBreadcrumbsEl"===t.type?.name){let n=se===t[n]):1===e.length&&e[0]===t}function _t(e,t){return Array.isArray(e)?mt(e,t):Array.isArray(t)?mt(t,e):e===t}let gt={to:[String,Object],replace:Boolean,href:String,target:String,disable:Boolean},vt={...gt,exact:Boolean,activeClass:{type:String,default:"q-router-link--active"},exactActiveClass:{type:String,default:"q-router-link--exact-active"}};function bt({fallbackTag:t,useDisableForRouterLinkProps:n=!0}={}){let a=(0,e.getCurrentInstance)(),{props:i,proxy:r,emit:o}=a,s=ut(a),l=(0,e.computed)(()=>!i.disable&&void 0!==i.href),u=n?(0,e.computed)(()=>s&&!i.disable&&!l.value&&void 0!==i.to&&null!==i.to&&""!==i.to):(0,e.computed)(()=>s&&!l.value&&void 0!==i.to&&null!==i.to&&""!==i.to),c=(0,e.computed)(()=>u.value?b(i.to):null),d=(0,e.computed)(()=>null!==c.value),h=(0,e.computed)(()=>l.value||d.value),p=(0,e.computed)(()=>"a"===i.type||h.value?"a":i.tag||t||"div"),f=(0,e.computed)(()=>l.value?{href:i.href,target:i.target}:d.value?{href:c.value.href,target:i.target}:{}),m=(0,e.computed)(()=>{if(!d.value)return-1;let{matched:e}=c.value,{length:t}=e,n=e[t-1];if(void 0===n)return-1;let a=r.$route.matched;if(0===a.length)return-1;let i=a.findIndex(ft.bind(null,n));if(-1!==i)return i;let o=pt(e[t-2]);return t>1&&pt(n)===o&&a.at(-1).path!==o?a.findIndex(ft.bind(null,e[t-2])):i}),_=(0,e.computed)(()=>d.value&&-1!==m.value&&function(e,t){for(let n in t){let a=t[n],i=e[n];if("string"==typeof a){if(a!==i)return!1}else if(!Array.isArray(i)||i.length!==a.length||a.some((e,t)=>e!==i[t]))return!1}return!0}(r.$route.params,c.value.params)),g=(0,e.computed)(()=>_.value&&m.value===r.$route.matched.length-1&&function(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(let n in e)if(!_t(e[n],t[n]))return!1;return!0}(r.$route.params,c.value.params)),v=(0,e.computed)(()=>d.value?g.value?` ${i.exactActiveClass} ${i.activeClass}`:i.exact?"":_.value?` ${i.activeClass}`:"":"");function b(e){try{return r.$router.resolve(e)}catch{}return null}function y(e,{returnRouterError:t,to:n=i.to,replace:a=i.replace}={}){if(i.disable)return e.preventDefault(),Promise.resolve(!1);if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey||void 0!==e.button&&0!==e.button||"_blank"===i.target)return Promise.resolve(!1);e.preventDefault();let o=r.$router[a?"replace":"push"](n);return t?o:o.then(()=>{}).catch(()=>{})}return{hasRouterLink:d,hasHrefLink:l,hasLink:h,linkTag:p,resolvedLink:c,linkIsActive:_,linkIsExactActive:g,linkClass:v,linkAttrs:f,getLink:b,navigateToRouterLink:y,navigateOnClick:function(e){if(d.value){let t=t=>y(e,t);o("click",e,t),e.defaultPrevented||t()}else o("click",e)}}}var yt=h({name:"QBreadcrumbsEl",props:{...vt,label:String,icon:String,tag:{type:String,default:"span"}},emits:["click"],setup(t,{slots:n}){let{linkTag:a,linkAttrs:i,linkClass:r,navigateOnClick:o}=bt(),s=(0,e.computed)(()=>({class:"q-breadcrumbs__el q-link flex inline items-center relative-position "+(t.disable?"q-breadcrumbs__el--disable":"q-link--focusable"+r.value),...i.value,onClick:o})),l=(0,e.computed)(()=>"q-breadcrumbs__el-icon"+(void 0===t.label?"":" q-breadcrumbs__el-icon--with-label"));return()=>{let i=[];return void 0!==t.icon&&i.push((0,e.h)(Ke,{class:l.value,name:t.icon})),void 0!==t.label&&i.push(t.label),(0,e.h)(a.value,{...s.value},Me(n.default,i))}}});let wt={size:{type:[String,Number],default:"1em"},color:String};function kt(t){return{cSize:(0,e.computed)(()=>t.size in Te?`${Te[t.size]}px`:t.size),classes:(0,e.computed)(()=>"q-spinner"+(t.color?` text-${t.color}`:""))}}var xt=h({name:"QSpinner",props:{...wt,thickness:{type:Number,default:5}},setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value+" q-spinner-mat",width:n.value,height:n.value,viewBox:"25 25 50 50"},[(0,e.h)("circle",{class:"path",cx:"50",cy:"50",r:"20",fill:"none",stroke:"currentColor","stroke-width":t.thickness,"stroke-miterlimit":"10"})])}});function St(e){if(e===window)return{top:0,left:0};let{top:t,left:n}=e.getBoundingClientRect();return{top:t,left:n}}function Ct(e){return e===window?window.innerHeight:e.getBoundingClientRect().height}function Tt(e,t){let n=e.style;for(let e in t)n[e]=t[e]}function Pt(t){if(null==t)return;if("string"==typeof t)try{return document.querySelector(t)||void 0}catch{return}let n=(0,e.unref)(t);return n?n.$el||n:void 0}function Et(e,t){if(null==e||e.contains(t))return!0;for(let n=e.nextElementSibling;null!==n;n=n.nextElementSibling)if(n.contains(t))return!0;return!1}var At={offset:St,style:function(e,t){return window.getComputedStyle(e).getPropertyValue(t)},height:Ct,width:function(e){return e===window?window.innerWidth:e.getBoundingClientRect().width},css:Tt,cssBatch:function(e,t){e.forEach(e=>Tt(e,t))},ready:function(e){if("function"==typeof e){if("loading"!==document.readyState)return e();document.addEventListener("DOMContentLoaded",e,!1)}}};function Lt(e,t=250){let n,a=!1;return function(...i){return a||(a=!0,setTimeout(()=>{a=!1},t),n=e.apply(this,i)),n}}function Mt(e,t,n,a){n.modifiers.stop&&b(e);let i=n.modifiers.color,r=n.modifiers.center||!0===a,o=document.createElement("span"),s=document.createElement("span"),l=v(e),{left:u,top:c,width:d,height:h}=t.getBoundingClientRect(),p=Math.hypot(d,h),f=p/2,m=(d-p)/2+"px",_=r?m:l.left-u-f+"px",g=(h-p)/2+"px",y=r?g:l.top-c-f+"px";s.className="q-ripple__inner",Tt(s,{height:`${p}px`,width:`${p}px`,transform:`translate3d(${_},${y},0) scale3d(.2,.2,1)`,opacity:0}),o.className="q-ripple"+(i?" text-"+i:""),o.setAttribute("dir","ltr"),o.append(s),t.append(o);let w=()=>{o.remove(),clearTimeout(k)};n.abort.push(w);let k=setTimeout(()=>{s.classList.add("q-ripple__inner--enter"),s.style.transform=`translate3d(${m},${g},0) scale3d(1,1,1)`,s.style.opacity=.2,k=setTimeout(()=>{s.classList.remove("q-ripple__inner--enter"),s.classList.add("q-ripple__inner--leave"),s.style.opacity=0,k=setTimeout(()=>{o.remove(),n.abort.splice(n.abort.indexOf(w),1)},275)},250)},50)}function Rt(e,{modifiers:t,value:n,arg:a}){let i={...e.cfg.ripple,...t,...n};e.modifiers={early:!0===i.early,stop:!0===i.stop,center:!0===i.center,color:i.color||a,keyCodes:[i.keyCodes||13].flat()}}var zt=p({name:"ripple",beforeMount(e,t){let n=t.instance.$.appContext.config.globalProperties.$q.config||{};if(!1===n.ripple)return;let a={cfg:n,enabled:!1!==t.value,modifiers:{},abort:[],start(t){a.enabled&&!t.qSkipRipple&&t.type===(a.modifiers.early?"pointerdown":"click")&&Mt(t,e,a,!0===t.qKeyEvent)},keystart:Lt(t=>{a.enabled&&!t.qSkipRipple&&N(t,a.modifiers.keyCodes)&&t.type==="key"+(a.modifiers.early?"down":"up")&&Mt(t,e,a,!0)},300)};Rt(a,t),e.__qripple=a,x(a,"main",[[e,"pointerdown","start","passive"],[e,"click","start","passive"],[e,"keydown","keystart","passive"],[e,"keyup","keystart","passive"]])},updated(e,t){if(t.oldValue!==t.value){let n=e.__qripple;void 0!==n&&(n.enabled=!1!==t.value,n.enabled&&Object(t.value)===t.value&&Rt(n,t))}},beforeUnmount(e){let t=e.__qripple;void 0!==t&&(t.abort.forEach(e=>{e()}),S(t,"main"),delete e.__qripple)}});let It={none:0,xs:4,sm:8,md:16,lg:24,xl:32},Nt={xs:8,sm:10,md:14,lg:20,xl:24},Ot=["button","submit","reset"],jt=/[^\s]\/[^\s]/,Dt=["flat","outline","push","unelevated"];function qt(e,t){return e.flat?"flat":e.outline?"outline":e.push?"push":e.unelevated?"unelevated":t}function Bt(e){let t=qt(e);return void 0===t?{}:{[t]:!0}}let Ft={...Pe,...gt,type:{type:String,default:"button"},label:[Number,String],icon:String,iconRight:String,...Dt.reduce((e,t)=>(e[t]=Boolean)&&e,{}),square:Boolean,rounded:Boolean,glossy:Boolean,size:String,fab:Boolean,fabMini:Boolean,padding:String,color:String,textColor:String,noCaps:Boolean,noWrap:Boolean,dense:Boolean,tabindex:[Number,String],ripple:{type:[Boolean,Object],default:!0},align:{...it.align,default:"center"},stack:Boolean,stretch:Boolean,loading:{type:Boolean,default:null},disable:Boolean},Vt={...Ft,round:Boolean};let{passiveCapture:Ut}=m,$t=null,Ht=null,Wt=null;function Gt(e){w(e),e.qSkipRipple=!0}var Kt=h({name:"QBtn",props:{...Vt,percentage:Number,darkPercentage:Boolean,onTouchstart:[Function,Array]},emits:["click","keydown","mousedown","keyup"],setup(t,{slots:n,emit:a}){let i,{proxy:r}=(0,e.getCurrentInstance)(),{classes:o,style:s,innerClasses:l,attributes:u,hasLink:c,linkTag:d,navigateOnClick:h,isActionable:p}=function(t){let n=Ee(t,Nt),a=rt(t),{hasRouterLink:i,hasLink:r,linkTag:o,linkAttrs:s,navigateOnClick:l}=bt({fallbackTag:"button"}),u=(0,e.computed)(()=>{let e=t.fab||t.fabMini?{}:n.value;return void 0===t.padding?e:{...e,padding:t.padding.split(/\s+/).map(e=>e in It?It[e]+"px":e).join(" "),minWidth:"0",minHeight:"0"}}),c=(0,e.computed)(()=>t.rounded||t.fab||t.fabMini),d=(0,e.computed)(()=>!t.disable&&!t.loading),h=(0,e.computed)(()=>d.value?t.tabindex||0:-1),p=(0,e.computed)(()=>qt(t,"standard")),f=(0,e.computed)(()=>{let e={tabindex:h.value};return r.value?Object.assign(e,s.value):Ot.includes(t.type)&&(e.type=t.type),"a"===o.value?(t.disable?e["aria-disabled"]="true":void 0===e.href&&(e.role="button"),!i.value&&jt.test(t.type)&&(e.type=t.type)):t.disable&&(e.disabled="",e["aria-disabled"]="true"),t.loading&&void 0!==t.percentage&&Object.assign(e,{role:"progressbar","aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":t.percentage}),e});return{classes:(0,e.computed)(()=>{let e;void 0===t.color?t.textColor&&(e=`text-${t.textColor}`):e=t.flat||t.outline?`text-${t.textColor||t.color}`:`bg-${t.color} text-${t.textColor||"white"}`;let n=t.round?"round":"rectangle"+(c.value?" q-btn--rounded":t.square?" q-btn--square":"");return`q-btn--${p.value} q-btn--${n}`+(void 0===e?"":" "+e)+(d.value?" q-btn--actionable q-focusable q-hoverable":t.disable?" disabled":"")+(t.fab?" q-btn--fab":t.fabMini?" q-btn--fab-mini":"")+(t.noCaps?" q-btn--no-uppercase":"")+(t.dense?" q-btn--dense":"")+(t.stretch?" no-border-radius self-stretch":"")+(t.glossy?" glossy":"")+(t.square?" q-btn--square":"")}),style:u,innerClasses:(0,e.computed)(()=>a.value+(t.stack?" column":" row")+(t.noWrap?" no-wrap text-no-wrap":"")+(t.loading?" q-btn__content--hidden":"")),attributes:f,hasLink:r,linkTag:o,navigateOnClick:l,isActionable:d}}(t),f=(0,e.ref)(null),m=(0,e.ref)(null),_=null,g=null,v=(0,e.computed)(()=>void 0!==t.label&&null!==t.label&&""!==t.label),k=(0,e.computed)(()=>!t.disable&&!1!==t.ripple&&{keyCodes:c.value?[13,32]:[13],...!0===t.ripple?{}:t.ripple}),x=(0,e.computed)(()=>({center:t.round})),S=(0,e.computed)(()=>{let e=Math.max(0,Math.min(100,t.percentage));return e>0?{transition:"transform 0.6s",transform:`translateX(${e-100}%)`}:{}}),C=(0,e.computed)(()=>{if(t.loading)return{onMousedown:Gt,onTouchstart:Gt,onClick:Gt,onKeydown:Gt,onKeyup:Gt};if(p.value){let e={onClick:P,onKeydown:E,onMousedown:L};if(r.$q.platform.has.touch){e[`onTouchstart${void 0===t.onTouchstart?"Passive":""}`]=A}return e}return{onClick:w}}),T=(0,e.computed)(()=>({ref:f,class:"q-btn q-btn-item non-selectable no-outline "+o.value,style:s.value,...u.value,...C.value}));function P(e){if(null!==f.value){if(void 0!==e){if(e.defaultPrevented)return;let n=document.activeElement;if("submit"===t.type&&n!==document.body&&!f.value.contains(n)&&!n.contains(f.value)){e.qAvoidFocus||f.value.focus();let t=()=>{document.removeEventListener("keydown",w,!0),document.removeEventListener("keyup",t,Ut),f.value?.removeEventListener("blur",t,Ut)};document.addEventListener("keydown",w,!0),document.addEventListener("keyup",t,Ut),f.value.addEventListener("blur",t,Ut)}}h(e)}}function E(e){null!==f.value&&(a("keydown",e),N(e,[13,32])&&Ht!==f.value&&(null!==Ht&&R(),e.defaultPrevented||(e.qAvoidFocus||f.value.focus(),Ht=f.value,f.value.classList.add("q-btn--active"),document.addEventListener("keyup",M,!0),f.value.addEventListener("blur",M,Ut)),w(e)))}function A(e){null!==f.value&&(a("touchstart",e),!e.defaultPrevented&&($t!==f.value&&(null!==$t&&R(),$t=f.value,_=e.target,_.addEventListener("touchcancel",M,Ut),_.addEventListener("touchend",M,Ut)),i=!0,null!==g&&clearTimeout(g),g=setTimeout(()=>{g=null,i=!1},200)))}function L(e){null!==f.value&&(e.qSkipRipple=!0===i,a("mousedown",e),!e.defaultPrevented&&Wt!==f.value&&(null!==Wt&&R(),Wt=f.value,f.value.classList.add("q-btn--active"),document.addEventListener("mouseup",M,Ut)))}function M(e){if(null!==f.value&&("blur"!==e?.type||document.activeElement!==f.value)){if("keyup"===e?.type){if(Ht===f.value&&N(e,[13,32])){let t=new MouseEvent("click",e);t.qKeyEvent=!0,e.defaultPrevented&&y(t),e.cancelBubble&&b(t),f.value.dispatchEvent(t),w(e),e.qKeyEvent=!0}a("keyup",e)}R()}}function R(e){let t=m.value;!e&&($t===f.value||Wt===f.value)&&null!==t&&t!==document.activeElement&&(t.setAttribute("tabindex",-1),t.focus()),$t===f.value&&(null!==_&&(_.removeEventListener("touchcancel",M,Ut),_.removeEventListener("touchend",M,Ut)),$t=_=null),Wt===f.value&&(document.removeEventListener("mouseup",M,Ut),Wt=null),Ht===f.value&&(document.removeEventListener("keyup",M,!0),f.value?.removeEventListener("blur",M,Ut),Ht=null),f.value?.classList.remove("q-btn--active")}return(0,e.onBeforeUnmount)(()=>{R(!0)}),Object.assign(r,{click:e=>{p.value&&P(e)}}),()=>{let a=[];void 0!==t.icon&&a.push((0,e.h)(Ke,{name:t.icon,left:!t.stack&&v.value,role:"img"})),v.value&&a.push((0,e.h)("span",{class:"block"},[t.label])),a=Me(n.default,a),void 0!==t.iconRight&&!t.round&&a.push((0,e.h)(Ke,{name:t.iconRight,right:!t.stack&&v.value,role:"img"}));let i=[(0,e.h)("span",{class:"q-focus-helper",ref:m})];return t.loading&&void 0!==t.percentage&&i.push((0,e.h)("span",{class:"q-btn__progress absolute-full overflow-hidden"+(t.darkPercentage?" q-btn__progress--dark":"")},[(0,e.h)("span",{class:"q-btn__progress-indicator fit block",style:S.value})])),i.push((0,e.h)("span",{class:"q-btn__content text-center col items-center q-anchor--skip "+l.value},a)),null!==t.loading&&i.push((0,e.h)(e.Transition,{name:"q-transition--fade"},()=>t.loading?[(0,e.h)("span",{key:"loading",class:"absolute-full flex flex-center"},void 0===n.loading?[(0,e.h)(xt)]:n.loading())]:null)),(0,e.withDirectives)((0,e.h)(d.value,T.value,i),[[zt,k.value,void 0,x.value]])}}}),Yt=h({name:"QBtnGroup",props:{unelevated:Boolean,outline:Boolean,flat:Boolean,rounded:Boolean,square:Boolean,push:Boolean,stretch:Boolean,glossy:Boolean,spread:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>{let e=["unelevated","outline","flat","rounded","square","push","stretch","glossy"].filter(e=>t[e]).map(e=>`q-btn-group--${e}`).join(" ");return"q-btn-group row no-wrap"+(0===e.length?"":" "+e)+(t.spread?" q-btn-group--spread":" inline")});return()=>(0,e.h)("div",{class:a.value},Ae(n.default))}});function Qt(){if(void 0!==window.getSelection){let e=window.getSelection();void 0===e.empty?void 0!==e.removeAllRanges&&(e.removeAllRanges(),d.is.mobile||e.addRange(document.createRange())):e.empty()}else void 0!==document.selection&&document.selection.empty()}let Zt={target:{type:[Boolean,String,Element],default:!0},noParentEvent:Boolean},Jt={...Zt,contextMenu:Boolean};function Xt({showing:t,avoidEmit:n,configureAnchorEl:a}){let{props:i,proxy:r,emit:o}=(0,e.getCurrentInstance)(),s=(0,e.ref)(null),l=null;function u(e){return null!==s.value&&(void 0===e||void 0===e.touches||e.touches.length<=1)}let c={};function d(){S(c,"anchor")}function h(){if(!1===i.target||""===i.target||null===r.$el.parentNode)s.value=null;else if(!0===i.target)!function(e){for(s.value=e;s.value.classList.contains("q-anchor--skip");)s.value=s.value.parentNode;a()}(r.$el.parentNode);else{let e=i.target;if("string"==typeof i.target)try{e=document.querySelector(i.target)}catch{e=void 0}null==e?(s.value=null,console.error(`Anchor: target "${i.target}" not found`)):(s.value=e.$el||e,a())}}return void 0===a&&(Object.assign(c,{hide(e){r.hide(e)},toggle(e){r.toggle(e),e.qAnchorHandled=!0},toggleKey(e){N(e,13)&&c.toggle(e)},contextClick(t){r.hide(t),y(t),(0,e.nextTick)(()=>{r.show(t),t.qAnchorHandled=!0})},prevent:y,mobileTouch(e){if(c.mobileCleanup(e),!u(e))return;r.hide(e),s.value.classList.add("non-selectable");let t=e.target;x(c,"anchor",[[t,"touchmove","mobileCleanup","passive"],[t,"touchend","mobileCleanup","passive"],[t,"touchcancel","mobileCleanup","passive"],[s.value,"contextmenu","prevent","notPassive"]]),l=setTimeout(()=>{l=null,r.show(e),e.qAnchorHandled=!0},300)},mobileCleanup(e){s.value.classList.remove("non-selectable"),null!==l&&(clearTimeout(l),l=null),t.value&&void 0!==e&&Qt()}}),a=function(e=i.contextMenu){if(i.noParentEvent||null===s.value)return;let t=e?r.$q.platform.is.mobile?[[s.value,"touchstart","mobileTouch","passive"]]:[[s.value,"mousedown","hide","passive"],[s.value,"contextmenu","contextClick","notPassive"]]:[[s.value,"click","toggle","passive"],[s.value,"keyup","toggleKey","passive"]];x(c,"anchor",t)}),(0,e.watch)(()=>i.contextMenu,e=>{null!==s.value&&(d(),a(e))}),(0,e.watch)(()=>i.target,()=>{null!==s.value&&d(),h()}),(0,e.watch)(()=>i.noParentEvent,e=>{null!==s.value&&(e?d():a())}),(0,e.onMounted)(()=>{h(),!n&&i.modelValue&&null===s.value&&o("update:modelValue",!1)}),(0,e.onBeforeUnmount)(()=>{null!==l&&clearTimeout(l),d()}),{anchorEl:s,canShow:u,anchorEvents:c}}function en(t,n){let a,i=(0,e.ref)(null);function r(e,t){let n=(void 0===t?"remove":"add")+"EventListener",i=void 0===t?a:t;e!==window&&e[n]("scroll",i,m.passive),window[n]("scroll",i,m.passive),a=t}function o(){null!==i.value&&(r(i.value),i.value=null)}return(0,e.onBeforeUnmount)((0,e.watch)(()=>t.noParentEvent,()=>{null!==i.value&&(o(),n())})),{localScrollTarget:i,unconfigureScrollTarget:o,changeScrollEvent:r}}let tn={modelValue:{type:Boolean,default:null},"onUpdate:modelValue":[Function,Array]},nn=["beforeShow","show","beforeHide","hide"];function an({showing:t,canShow:n,hideOnRouteChange:a,handleShow:i,handleHide:r,handleRouteChange:o,processOnMount:s}){let l,u=(0,e.getCurrentInstance)(),{props:c,emit:d,proxy:h}=u;function p(t){if(c.disable||!0===t?.qAnchorHandled||void 0!==n&&!n(t))return;let a=void 0!==c["onUpdate:modelValue"];a&&(d("update:modelValue",!0),l=t,(0,e.nextTick)(()=>{l===t&&(l=void 0)})),(null===c.modelValue||!a)&&f(t)}function f(e){t.value||(t.value=!0,d("beforeShow",e),void 0===i?d("show",e):i(e))}function m(t){if(c.disable)return;let n=void 0!==c["onUpdate:modelValue"];n&&(d("update:modelValue",!1),l=t,(0,e.nextTick)(()=>{l===t&&(l=void 0)})),(null===c.modelValue||!n)&&_(t)}function _(e){t.value&&(t.value=!1,d("beforeHide",e),void 0===r?d("hide",e):r(e))}function g(e){c.disable&&e?void 0!==c["onUpdate:modelValue"]&&d("update:modelValue",!1):!0===e!==t.value&&(e?f:_)(l)}(0,e.watch)(()=>c.modelValue,g),void 0!==a&&ut(u)&&(0,e.watch)(()=>h.$route.fullPath,()=>{a.value&&t.value&&(o?.(),m())}),s&&(0,e.onMounted)(()=>{g(c.modelValue)});let v={show:p,hide:m,toggle:function(e){t.value?m(e):p(e)}};return Object.assign(h,v),v}let rn=[];function on(e,t){do{if("QMenu"===e.$options.name){if(e.hide(t),e.$props.separateClosePopup)return ot(e)}else if(e.__qPortal){let n=ot(e);return"QPopupProxy"===n?.$options.name?(e.hide(t),n):e}e=ot(e)}while(null!=e)}let sn=[],ln=[];function un(e){ln=ln.filter(t=>t!==e)}function cn(e){un(e),0===ln.length&&0!==sn.length&&(sn.at(-1)(),sn=[])}function dn(e){0===ln.length?e():sn.push(e)}let hn=[],pn=[],fn=1,mn=document.body;function _n(e,t){let n=document.createElement("div");if(n.id=void 0===t?e:`q-portal--${t}--${fn++}`,void 0!==se.globalNodes){let e=se.globalNodes.class;void 0!==e&&(n.className=e)}return mn.append(n),hn.push(n),pn.push(t),n}function gn(e){let t=hn.indexOf(e);hn.splice(t,1),pn.splice(t,1),e.remove()}let vn=h({name:"QPortal",setup:(e,{slots:t})=>()=>t.default()});function bn(t,n,i,r){let o=(0,e.ref)(!1),s=(0,e.ref)(!1),l=null,u={},c="dialog"===r&&function(e){for(e=e.parent;null!=e;){if("QGlobalDialog"===e.type.name)return!0;if("QDialog"===e.type.name||"QMenu"===e.type.name)return!1;e=e.parent}return!1}(t);function d(e){if(s.value=!1,!e)return;cn(u),o.value=!1;let n=rn.indexOf(t.proxy);-1!==n&&rn.splice(n,1),null!==l&&(gn(l),l=null)}return(0,e.onUnmounted)(()=>{d(!0)}),t.proxy.__qPortal=!0,a(t.proxy,"contentEl",()=>n.value),{showPortal:function(e){if(e)return cn(u),void(s.value=!0);s.value=!1,o.value||(!c&&null===l&&(l=_n(!1,r)),o.value=!0,rn.push(t.proxy),function(e){un(e),ln.push(e)}(u))},hidePortal:d,portalIsActive:o,portalIsAccessible:s,renderPortal:()=>c?i():o.value?[(0,e.h)(e.Teleport,{to:l},(0,e.h)(vn,i))]:void 0}}let yn={transitionShow:{type:String,default:"fade"},transitionHide:{type:String,default:"fade"},transitionDuration:{type:[String,Number],default:300}};function wn(t,n=()=>{},a=()=>{}){return{transitionProps:(0,e.computed)(()=>{let e=`q-transition--${t.transitionShow||n()}`,i=`q-transition--${t.transitionHide||a()}`;return{appear:!0,enterFromClass:`${e}-enter-from`,enterActiveClass:`${e}-enter-active`,enterToClass:`${e}-enter-to`,leaveFromClass:`${i}-leave-from`,leaveActiveClass:`${i}-leave-active`,leaveToClass:`${i}-leave-to`}}),transitionStyle:(0,e.computed)(()=>`--q-transition-duration: ${t.transitionDuration}ms`)}}function kn(){let t,n=(0,e.getCurrentInstance)();function a(){t=void 0}return(0,e.onDeactivated)(a),(0,e.onBeforeUnmount)(a),{removeTick:a,registerTick(a){t=a,(0,e.nextTick)(()=>{t===a&&(ct(n)||t(),t=void 0)})}}}function xn(){let t=null,n=(0,e.getCurrentInstance)();function a(){null!==t&&(clearTimeout(t),t=null)}return(0,e.onDeactivated)(a),(0,e.onBeforeUnmount)(a),{removeTimeout:a,registerTimeout(e,i){a(),ct(n)||(t=setTimeout(()=>{t=null,e()},i))}}}let Sn,Cn=[Element,String],Tn=[null,document,document.body,document.scrollingElement,document.documentElement];function Pn(e,t){let n=Pt(t);if(void 0===n){if(null==e)return window;n=e.closest(".scroll,.scroll-y,.overflow-auto")}return Tn.includes(n)?window:n}function En(e){return(e===window?document.body:e).scrollHeight}function An(e){return e===window?window.pageYOffset||window.scrollY||document.body.scrollTop||0:e.scrollTop}function Ln(e){return e===window?window.pageXOffset||window.scrollX||document.body.scrollLeft||0:e.scrollLeft}function Mn(e,t,n=0,a){let i=void 0===a?performance.now():a,r=An(e);n<=0?r!==t&&zn(e,t):requestAnimationFrame(a=>{let o=a-i,s=r+(t-r)/Math.max(o,n)*o;zn(e,s),s!==t&&Mn(e,t,n-o,a)})}function Rn(e,t,n=0,a){let i=void 0===a?performance.now():a,r=Ln(e);n<=0?r!==t&&In(e,t):requestAnimationFrame(a=>{let o=a-i,s=r+(t-r)/Math.max(o,n)*o;In(e,s),s!==t&&Rn(e,t,n-o,a)})}function zn(e,t){e!==window?e.scrollTop=t:window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,t)}function In(e,t){e!==window?e.scrollLeft=t:window.scrollTo(t,window.pageYOffset||window.scrollY||document.body.scrollTop||0)}function Nn(e,t,n){n?Mn(e,t,n):zn(e,t)}function On(e,t,n){n?Rn(e,t,n):In(e,t)}function jn(){if(void 0!==Sn)return Sn;let e=document.createElement("p"),t=document.createElement("div");Tt(e,{width:"100%",height:"200px"}),Tt(t,{position:"absolute",top:"0px",left:"0px",visibility:"hidden",width:"200px",height:"150px",overflow:"hidden"}),t.append(e),document.body.append(t);let n=e.offsetWidth;t.style.overflow="scroll";let a=e.offsetWidth;return n===a&&(a=t.clientWidth),t.remove(),Sn=n-a,Sn}let Dn=["auto","scroll"];var qn={getScrollTarget:Pn,getScrollHeight:En,getScrollWidth:function(e){return(e===window?document.body:e).scrollWidth},getVerticalScrollPosition:An,getHorizontalScrollPosition:Ln,animVerticalScrollTo:Mn,animHorizontalScrollTo:Rn,setVerticalScrollPosition:Nn,setHorizontalScrollPosition:On,getScrollbarWidth:jn,hasScrollbar:function(e,t=!0){return!(!e||e.nodeType!==Node.ELEMENT_NODE)&&(t?e.scrollHeight>e.clientHeight&&(e.classList.contains("scroll")||e.classList.contains("overflow-auto")||Dn.includes(window.getComputedStyle(e)["overflow-y"])):e.scrollWidth>e.clientWidth&&(e.classList.contains("scroll")||e.classList.contains("overflow-auto")||Dn.includes(window.getComputedStyle(e)["overflow-x"])))}};let Bn,Fn=[];function Vn(e){Bn=27===e.keyCode}function Un(){Bn&&=!1}function $n(e){Bn&&(Bn=!1,N(e,27)&&Fn.at(-1)(e))}function Hn(e){window[e]("keydown",Vn),window[e]("blur",Un),window[e]("keyup",$n),Bn=!1}function Wn(e){c.is.desktop&&(Fn.push(e),1===Fn.length&&Hn("addEventListener"))}function Gn(e){let t=Fn.indexOf(e);-1!==t&&(Fn.splice(t,1),0===Fn.length&&Hn("removeEventListener"))}let Kn=[];function Yn(e){Kn.at(-1)(e)}function Qn(e){c.is.desktop&&(Kn.push(e),1===Kn.length&&document.body.addEventListener("focusin",Yn))}function Zn(e){let t=Kn.indexOf(e);-1!==t&&(Kn.splice(t,1),0===Kn.length&&document.body.removeEventListener("focusin",Yn))}let Jn=null,{notPassiveCapture:Xn}=m,ea=[];function ta(e){null!==Jn&&(clearTimeout(Jn),Jn=null);let t=e.target;if(void 0===t||8===t.nodeType||t.classList.contains("no-pointer-events"))return;let n=rn.length-1;for(;n>=0;){let e=rn[n].$;if("QTooltip"!==e.type.name){if("QDialog"!==e.type.name)break;if(!e.props.seamless)return;n--}else n--}for(let n=ea.length-1;n>=0;n--){let a=ea[n];if(null!==a.anchorEl.value&&a.anchorEl.value.contains(t)||t!==document.body&&(null===a.innerRef.value||a.innerRef.value.contains(t)))return;e.qClickOutside=!0,a.onClickOutside(e)}}function na(e){ea.push(e),1===ea.length&&(document.addEventListener("mousedown",ta,Xn),document.addEventListener("touchstart",ta,Xn))}function aa(e){let t=ea.indexOf(e);-1!==t&&(ea.splice(t,1),0===ea.length&&(null!==Jn&&(clearTimeout(Jn),Jn=null),document.removeEventListener("mousedown",ta,Xn),document.removeEventListener("touchstart",ta,Xn)))}let ia,ra,oa=["top","center","bottom"],sa=["left","middle","right","start","end"];function la(e){let t=e.split(" ");return 2===t.length&&(oa.includes(t[0])?!!sa.includes(t[1])||(console.error("Anchor/Self position must end with one of left/middle/right/start/end"),!1):(console.error("Anchor/Self position must start with one of top/center/bottom"),!1))}function ua(e){return!e||2===e.length&&"number"==typeof e[0]&&"number"==typeof e[1]}let ca={"start#ltr":"left","start#rtl":"right","end#ltr":"right","end#rtl":"left"};function da(e,t){let n=e.split(" ");return{vertical:n[0],horizontal:ca[`${n[1]}#${t?"rtl":"ltr"}`]}}function ha(e,t,n,a){return{top:e[n.vertical]-t[a.vertical],left:e[n.horizontal]-t[a.horizontal]}}function pa(e,t=0){if(null===e.targetEl||null===e.anchorEl||t>5)return;if(0===e.targetEl.offsetHeight||0===e.targetEl.offsetWidth)return void setTimeout(()=>{pa(e,t+1)},10);let{targetEl:n,offset:a,anchorEl:i,anchorOrigin:r,selfOrigin:o,absoluteOffset:s,fit:l,cover:u,maxHeight:d,maxWidth:h}=e;if(c.is.ios&&void 0!==window.visualViewport){let e=document.body.style,{offsetLeft:t,offsetTop:n}=window.visualViewport;t!==ia&&(e.setProperty("--q-pe-left",t+"px"),ia=t),n!==ra&&(e.setProperty("--q-pe-top",n+"px"),ra=n)}let{scrollLeft:p,scrollTop:f}=n,m=void 0===s?function(e,t){let{top:n,left:a,right:i,bottom:r,width:o,height:s}=e.getBoundingClientRect();return void 0!==t&&(n-=t[1],a-=t[0],r+=t[1],i+=t[0],o+=t[0],s+=t[1]),{top:n,bottom:r,height:s,left:a,right:i,width:o,middle:a+(i-a)/2,center:n+(r-n)/2}}(i,u?[0,0]:a):function(e,t,n){let{top:a,left:i}=e.getBoundingClientRect();return a+=t.top,i+=t.left,void 0!==n&&(a+=n[1],i+=n[0]),{top:a,bottom:a+1,height:1,left:i,right:i+1,width:1,middle:i,center:a}}(i,s,a);Object.assign(n.style,{top:0,left:0,minWidth:null,minHeight:null,maxWidth:h,maxHeight:d,visibility:"visible"});let{offsetWidth:_,offsetHeight:g}=n,{elWidth:v,elHeight:b}=l||u?{elWidth:Math.max(m.width,_),elHeight:u?Math.max(m.height,g):g}:{elWidth:_,elHeight:g},y={maxWidth:h,maxHeight:d};(l||u)&&(y.minWidth=m.width+"px",u&&(y.minHeight=m.height+"px")),Object.assign(n.style,y);let w=function(e,t){return{top:0,center:t/2,bottom:t,left:0,middle:e/2,right:e}}(v,b),k=ha(m,w,r,o);if(void 0===s||void 0===a)fa(k,m,w,r,o);else{let{top:e,left:t}=k;fa(k,m,w,r,o);let n=!1;if(k.top!==e){n=!0;let e=2*a[1];m.center=m.top-=e,m.bottom-=e+2}if(k.left!==t){n=!0;let e=2*a[0];m.middle=m.left-=e,m.right-=e+2}n&&(k=ha(m,w,r,o),fa(k,m,w,r,o))}y={top:k.top+"px",left:k.left+"px"},void 0!==k.maxHeight&&(y.maxHeight=k.maxHeight+"px",m.height>k.maxHeight&&(y.minHeight=y.maxHeight)),void 0!==k.maxWidth&&(y.maxWidth=k.maxWidth+"px",m.width>k.maxWidth&&(y.minWidth=y.maxWidth)),Object.assign(n.style,y),n.scrollTop!==f&&(n.scrollTop=f),n.scrollLeft!==p&&(n.scrollLeft=p)}function fa(e,t,n,a,i){let r=n.bottom,o=n.right,s=jn(),l=window.innerHeight-s,u=document.body.clientWidth;if(e.top<0||e.top+r>l)if("center"===i.vertical)e.top=t[a.vertical]>l/2?Math.max(0,l-r):0,e.maxHeight=Math.min(r,l);else if(t[a.vertical]>l/2){let n=Math.min(l,"center"===a.vertical?t.center:a.vertical===i.vertical?t.bottom:t.top);e.maxHeight=Math.min(r,n),e.top=Math.max(0,n-r)}else e.top=Math.max(0,"center"===a.vertical?t.center:a.vertical===i.vertical?t.top:t.bottom),e.maxHeight=Math.min(r,l-e.top);if(e.left<0||e.left+o>u)if(e.maxWidth=Math.min(o,u),"middle"===i.horizontal)e.left=t[a.horizontal]>u/2?Math.max(0,u-o):0;else if(t[a.horizontal]>u/2){let n=Math.min(u,"middle"===a.horizontal?t.middle:a.horizontal===i.horizontal?t.right:t.left);e.maxWidth=Math.min(o,n),e.left=Math.max(0,n-e.maxWidth)}else e.left=Math.max(0,"middle"===a.horizontal?t.middle:a.horizontal===i.horizontal?t.left:t.right),e.maxWidth=Math.min(o,u-e.left)}["left","middle","right"].forEach(e=>{ca[`${e}#ltr`]=e,ca[`${e}#rtl`]=e});var ma=h({name:"QMenu",inheritAttrs:!1,props:{...Jt,...tn,...Je,...yn,persistent:Boolean,autoClose:Boolean,separateClosePopup:Boolean,noEscDismiss:Boolean,noRouteDismiss:Boolean,noRefocus:Boolean,noFocus:Boolean,fit:Boolean,cover:Boolean,square:Boolean,anchor:{type:String,validator:la},self:{type:String,validator:la},offset:{type:Array,validator:ua},scrollTarget:Cn,touchPosition:Boolean,maxHeight:{type:String,default:null},maxWidth:{type:String,default:null}},emits:[...nn,"click","escapeKey"],setup(t,{slots:n,emit:a,attrs:i}){let r,o,s,l=null,u=(0,e.getCurrentInstance)(),{proxy:c}=u,{$q:d}=c,h=(0,e.ref)(null),p=(0,e.ref)(!1),f=(0,e.computed)(()=>!t.persistent&&!t.noRouteDismiss),m=Xe(t,d),{registerTick:_,removeTick:g}=kn(),{registerTimeout:b}=xn(),{transitionProps:y,transitionStyle:k}=wn(t),{localScrollTarget:x,changeScrollEvent:S,unconfigureScrollTarget:C}=en(t,B),{anchorEl:T,canShow:P}=Xt({showing:p}),{hide:E}=an({showing:p,canShow:P,handleShow:function(n){if(l=t.noRefocus?null:document.activeElement,Qn(V),A(),B(),r=void 0,void 0!==n&&(t.touchPosition||t.contextMenu)){let e=v(n);if(void 0!==e.left){let{top:t,left:n}=T.value.getBoundingClientRect();r={left:e.left-n,top:e.top-t}}}void 0===o&&(o=(0,e.watch)(()=>d.screen.width+"|"+d.screen.height+"|"+t.self+"|"+t.anchor+"|"+d.lang.rtl,$)),t.noFocus||document.activeElement.blur(),_(()=>{$(),t.noFocus||D()}),b(()=>{d.platform.is.ios&&(s=t.autoClose,h.value.click()),$(),A(!0),a("show",n)},t.transitionDuration)},handleHide:function(e){if(g(),L(),q(!0),null!==l&&(void 0===e||!e.qClickOutside)){let t=(0===e?.type.indexOf("key")?l.closest('[tabindex]:not([tabindex^="-"])'):void 0)||l;l=null,dn(()=>{t.isConnected&&t.focus()})}b(()=>{L(!0),a("hide",e)},t.transitionDuration)},handleRouteChange:function(){l=null},hideOnRouteChange:f,processOnMount:!0}),{showPortal:A,hidePortal:L,renderPortal:M}=bn(u,h,function(){return(0,e.h)(e.Transition,y.value,()=>p.value?(0,e.h)("div",{role:"menu",...i,ref:h,tabindex:-1,class:["q-menu q-position-engine scroll"+N.value,i.class],style:[i.style,k.value],...O.value},Ae(n.default)):null)},"menu"),R={anchorEl:T,innerRef:h,onClickOutside(e){if(!t.persistent&&p.value)return E(e),("touchstart"===e.type||e.target.classList.contains("q-dialog__backdrop"))&&w(e),!0}},z=(0,e.computed)(()=>da(t.anchor||(t.cover?"center middle":"bottom start"),d.lang.rtl)),I=(0,e.computed)(()=>t.cover?z.value:da(t.self||"top start",d.lang.rtl)),N=(0,e.computed)(()=>(t.square?" q-menu--square":"")+(m.value?" q-menu--dark q-dark":"")),O=(0,e.computed)(()=>t.autoClose?{onClick:F}:{}),j=(0,e.computed)(()=>p.value&&!t.persistent);function D(){dn(()=>{let e=h.value;e&&!e.contains(document.activeElement)&&(e=e.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||e.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||e.querySelector("[autofocus], [data-autofocus]")||e,e.focus({preventScroll:!0}))})}function q(e){r=void 0,void 0!==o&&(o(),o=void 0),(e||p.value)&&(Zn(V),C(),aa(R),Gn(U)),e||(l=null)}function B(){(null!==T.value||void 0!==t.scrollTarget)&&(x.value=Pn(T.value,t.scrollTarget),S(x.value,$))}function F(e){s?s=!1:(on(c,e),a("click",e))}function V(e){j.value&&!t.noFocus&&!Et(h.value,e.target)&&D()}function U(e){t.noEscDismiss||(a("escapeKey"),E(e))}function $(){pa({targetEl:h.value,offset:t.offset,anchorEl:T.value,anchorOrigin:z.value,selfOrigin:I.value,absoluteOffset:r,fit:t.fit,cover:t.cover,maxHeight:t.maxHeight,maxWidth:t.maxWidth})}return(0,e.watch)(j,e=>{e?(Wn(U),na(R)):(Gn(U),aa(R))}),(0,e.onBeforeUnmount)(()=>{q()}),Object.assign(c,{focus:D,updatePosition:$}),M}});var _a=function(){if(typeof crypto>"u")return()=>{throw Error("[Quasar uid()] Secure RNG not available. Cannot generate collision-resistant UUID.")};if(crypto.randomUUID)return()=>crypto.randomUUID();let e,t,n=Array.from({length:256},(e,t)=>(t+256).toString(16).slice(1));return()=>{(void 0===e||t+16>4096)&&(t=0,e=new Uint8Array(4096),crypto.getRandomValues(e));let a=t;return t+=16,e[a+6]=15&e[a+6]|64,e[a+8]=63&e[a+8]|128,n[e[a]]+n[e[a+1]]+n[e[a+2]]+n[e[a+3]]+"-"+n[e[a+4]]+n[e[a+5]]+"-"+n[e[a+6]]+n[e[a+7]]+"-"+n[e[a+8]]+n[e[a+9]]+"-"+n[e[a+10]]+n[e[a+11]]+n[e[a+12]]+n[e[a+13]]+n[e[a+14]]+n[e[a+15]]}}();function ga(e,t){return e??(t?`f_${_a()}`:null)}function va({getValue:t,required:n=!0}={}){if(o.value){let a=void 0===t?(0,e.ref)(null):(0,e.ref)(function(e){return e??null}(t()));return n&&null===a.value&&(0,e.onMounted)(()=>{a.value=`f_${_a()}`}),void 0!==t&&(0,e.watch)(t,e=>{a.value=ga(e,n)}),a}return void 0===t?(0,e.ref)(`f_${_a()}`):(0,e.computed)(()=>ga(t(),n))}let ba=Object.keys(Ft);var ya=h({name:"QBtnDropdown",props:{...Ft,...yn,modelValue:Boolean,split:Boolean,dropdownIcon:String,contentClass:[Array,String,Object],contentStyle:[Array,String,Object],cover:Boolean,persistent:Boolean,noEscDismiss:Boolean,noRouteDismiss:Boolean,autoClose:Boolean,noRefocus:Boolean,noFocus:Boolean,menuAnchor:{type:String,default:"bottom end"},menuSelf:{type:String,default:"top end"},menuOffset:Array,disableMainBtn:Boolean,disableDropdown:Boolean,noIconAnimation:Boolean,toggleAriaLabel:String},emits:["update:modelValue","click","beforeShow","show","beforeHide","hide"],setup(t,{slots:n,emit:a}){let{proxy:i}=(0,e.getCurrentInstance)(),r=(0,e.ref)(t.modelValue),o=(0,e.ref)(null),s=va(),l=(0,e.computed)(()=>{let e={"aria-expanded":r.value?"true":"false","aria-haspopup":"true","aria-controls":s.value,"aria-label":t.toggleAriaLabel||i.$q.lang.label[r.value?"collapse":"expand"](t.label)};return(t.disable||!t.split&&t.disableMainBtn||t.disableDropdown)&&(e["aria-disabled"]="true"),e}),u=(0,e.computed)(()=>"q-btn-dropdown__arrow"+(r.value&&!t.noIconAnimation?" rotate-180":"")+(t.split?"":" q-btn-dropdown__arrow-container")),c=(0,e.computed)(()=>Bt(t)),d=(0,e.computed)(()=>function(e){return ba.reduce((t,n)=>{let a=e[n];return void 0!==a&&(t[n]=a),t},{})}(t));function h(e){r.value=!0,a("beforeShow",e)}function p(e){a("show",e),a("update:modelValue",!0)}function f(e){r.value=!1,a("beforeHide",e)}function m(e){a("hide",e),a("update:modelValue",!1)}function _(e){a("click",e)}function g(e){b(e),y(),a("click",e)}function v(e){o.value?.show(e)}function y(e){o.value?.hide(e)}return(0,e.watch)(()=>t.modelValue,e=>{o.value?.[e?"show":"hide"]()}),(0,e.watch)(()=>t.split,y),Object.assign(i,{show:v,hide:y,toggle:function(e){o.value?.toggle(e)}}),(0,e.onMounted)(()=>{t.modelValue&&v()}),()=>{let a=[(0,e.h)(Ke,{class:u.value,name:t.dropdownIcon||i.$q.iconSet.arrow.dropdown})];return t.disableDropdown||a.push((0,e.h)(ma,{ref:o,id:s.value,class:t.contentClass,style:t.contentStyle,cover:t.cover,fit:!0,persistent:t.persistent,noEscDismiss:t.noEscDismiss,noRouteDismiss:t.noRouteDismiss,autoClose:t.autoClose,noFocus:t.noFocus,noRefocus:t.noRefocus,anchor:t.menuAnchor,self:t.menuSelf,offset:t.menuOffset,separateClosePopup:!0,transitionShow:t.transitionShow,transitionHide:t.transitionHide,transitionDuration:t.transitionDuration,onBeforeShow:h,onShow:p,onBeforeHide:f,onHide:m},n.default)),t.split?(0,e.h)(Yt,{class:"q-btn-dropdown q-btn-dropdown--split no-wrap q-btn-item",rounded:t.rounded,square:t.square,...c.value,glossy:t.glossy,stretch:t.stretch},()=>[(0,e.h)(Kt,{class:"q-btn-dropdown--current",...d.value,disable:t.disable||t.disableMainBtn,noWrap:!0,round:!1,onClick:g},{default:n.label,loading:n.loading}),(0,e.h)(Kt,{class:"q-btn-dropdown__arrow-container q-anchor--skip",...l.value,...c.value,disable:t.disable||t.disableDropdown,rounded:t.rounded,color:t.color,textColor:t.textColor,dense:t.dense,size:t.size,padding:t.padding,ripple:t.ripple},()=>a)]):(0,e.h)(Kt,{class:"q-btn-dropdown q-btn-dropdown--simple",...d.value,...l.value,disable:t.disable||t.disableMainBtn,noWrap:!0,round:!1,onClick:_},{default:()=>Ae(n.label,[]).concat(a),loading:n.loading})}}});let wa={name:String};function ka(t){return(0,e.computed)(()=>({type:"hidden",name:t.name,value:t.modelValue}))}function xa(t={}){return(n,a,i)=>{n[a]((0,e.h)("input",{class:"hidden"+(i||""),...t.value}))}}function Sa(t){return(0,e.computed)(()=>t.name||t.for)}var Ca=h({name:"QBtnToggle",props:{...wa,modelValue:{required:!0},options:{type:Array,required:!0,validator:e=>e.every(e=>("label"in e||"icon"in e||"slot"in e)&&"value"in e)},color:String,textColor:String,toggleColor:{type:String,default:"primary"},toggleTextColor:String,outline:Boolean,flat:Boolean,unelevated:Boolean,rounded:Boolean,push:Boolean,glossy:Boolean,size:String,padding:String,noCaps:Boolean,noWrap:Boolean,dense:Boolean,readonly:Boolean,disable:Boolean,stack:Boolean,stretch:Boolean,spread:Boolean,clearable:Boolean,ripple:{type:[Boolean,Object],default:!0}},emits:["update:modelValue","clear","click"],setup(t,{slots:n,emit:a}){let i=(0,e.computed)(()=>void 0!==t.options.find(e=>e.value===t.modelValue)),r=xa((0,e.computed)(()=>({type:"hidden",name:t.name,value:t.modelValue}))),o=(0,e.computed)(()=>Bt(t)),s=(0,e.computed)(()=>({rounded:t.rounded,dense:t.dense,...o.value})),l=(0,e.computed)(()=>t.options.map((e,n)=>{let{attrs:a,value:i,slot:r,...o}=e;return{slot:r,props:{key:n,"aria-pressed":i===t.modelValue?"true":"false",...a,...o,...s.value,disable:t.disable||!0===o.disable,color:i===t.modelValue?c(o,"toggleColor"):c(o,"color"),textColor:i===t.modelValue?c(o,"toggleTextColor"):c(o,"textColor"),noCaps:!0===c(o,"noCaps"),noWrap:!0===c(o,"noWrap"),size:c(o,"size"),padding:c(o,"padding"),ripple:c(o,"ripple"),stack:!0===c(o,"stack"),stretch:!0===c(o,"stretch"),onClick(t){u(i,e,t)}}}}));function u(e,n,i){t.readonly||(t.modelValue===e?t.clearable&&(a("update:modelValue",null,null),a("clear")):a("update:modelValue",e,n),a("click",i))}function c(e,n){return void 0===e[n]?t[n]:e[n]}function d(){let a=l.value.map(t=>(0,e.h)(Kt,t.props,void 0===t.slot?void 0:n[t.slot]));return void 0!==t.name&&!t.disable&&i.value&&r(a,"push"),Me(n.default,a)}return()=>(0,e.h)(Yt,{class:"q-btn-toggle",...o.value,rounded:t.rounded,stretch:t.stretch,glossy:t.glossy,spread:t.spread},d)}}),Ta=h({name:"QCard",props:{...Je,tag:{type:String,default:"div"},square:Boolean,flat:Boolean,bordered:Boolean},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=Xe(t,a),r=(0,e.computed)(()=>"q-card"+(i.value?" q-card--dark q-dark":"")+(t.bordered?" q-card--bordered":"")+(t.square?" q-card--square no-border-radius":"")+(t.flat?" q-card--flat no-shadow":""));return()=>(0,e.h)(t.tag,{class:r.value},Ae(n.default))}}),Pa=h({name:"QCardSection",props:{tag:{type:String,default:"div"},horizontal:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>"q-card__section q-card__section--"+(t.horizontal?"horiz row no-wrap":"vert"));return()=>(0,e.h)(t.tag,{class:a.value},Ae(n.default))}}),Ea=h({name:"QCardActions",props:{...it,vertical:Boolean},setup(t,{slots:n}){let a=rt(t),i=(0,e.computed)(()=>`q-card__actions ${a.value} q-card__actions--${t.vertical?"vert column":"horiz row"}`);return()=>(0,e.h)("div",{class:i.value},Ae(n.default))}});let Aa={left:!0,right:!0,up:!0,down:!0,horizontal:!0,vertical:!0},La=Object.keys(Aa);function Ma(e){let t={};for(let n of La)e[n]&&(t[n]=!0);return 0===Object.keys(t).length?Aa:(t.horizontal?t.left=t.right=!0:t.left&&t.right&&(t.horizontal=!0),t.vertical?t.up=t.down=!0:t.up&&t.down&&(t.vertical=!0),t.horizontal&&t.vertical&&(t.all=!0),t)}Aa.all=!0;let Ra=["INPUT","TEXTAREA"];function za(e,t){return!(void 0!==t.event||void 0===e.target||e.target.draggable||"function"!=typeof t.handler||Ra.includes(e.target.nodeName.toUpperCase())||void 0!==e.qClonedBy&&e.qClonedBy.includes(t.uid))}function Ia(e){let t=[.06,6,50];return"string"==typeof e&&0!==e.length&&e.split(":").forEach((e,n)=>{let a=Number.parseFloat(e);a&&(t[n]=a)}),t}function Na(){document.body.classList.remove("no-pointer-events--children")}var Oa=p({name:"touch-swipe",beforeMount(e,{value:t,arg:n,modifiers:a}){if(!a.mouse&&!c.has.touch)return;let i=a.mouseCapture||a.mousecapture?"Capture":"",r={handler:t,sensitivity:Ia(n),direction:Ma(a),noop:_,mouseStart(e){za(e,r)&&g(e)&&(x(r,"temp",[[document,"mousemove","move",`notPassive${i}`],[document,"mouseup","end","notPassiveCapture"]]),r.start(e,!0))},touchStart(e){if(za(e,r)){let t=e.target;x(r,"temp",[[t,"touchmove","move","notPassiveCapture"],[t,"touchcancel","end","notPassiveCapture"],[t,"touchend","end","notPassiveCapture"]]),r.start(e)}},start(t,n){c.is.firefox&&k(e,!0);let a=v(t);r.event={x:a.left,y:a.top,time:Date.now(),mouse:!0===n,dir:!1}},move(e){if(void 0===r.event)return;if(!1!==r.event.dir)return void w(e);let t=Date.now()-r.event.time;if(0===t)return;let n=v(e),a=n.left-r.event.x,i=Math.abs(a),o=n.top-r.event.y,s=Math.abs(o);if(r.event.mouse){if(""!==window.getSelection().toString())return void r.end(e);if(ir.sensitivity[0]&&(r.event.dir=o<0?"up":"down"),r.direction.horizontal&&i>s&&s<100&&l>r.sensitivity[0]&&(r.event.dir=a<0?"left":"right"),r.direction.up&&ir.sensitivity[0]&&(r.event.dir="up"),r.direction.down&&i0&&i<100&&u>r.sensitivity[0]&&(r.event.dir="down"),r.direction.left&&i>s&&a<0&&s<100&&l>r.sensitivity[0]&&(r.event.dir="left"),r.direction.right&&i>s&&a>0&&s<100&&l>r.sensitivity[0]&&(r.event.dir="right"),!1===r.event.dir?r.end(e):(w(e),r.event.mouse&&(document.body.classList.add("no-pointer-events--children","non-selectable"),Qt(),r.styleCleanup=e=>{r.styleCleanup=void 0,document.body.classList.remove("non-selectable"),!0===e?setTimeout(Na,50):Na()}),r.handler({evt:e,touch:!0!==r.event.mouse,mouse:r.event.mouse,direction:r.event.dir,duration:t,distance:{x:i,y:s}}))},end(t){void 0!==r.event&&(S(r,"temp"),c.is.firefox&&k(e,!1),r.styleCleanup?.(!0),void 0!==t&&!1!==r.event.dir&&w(t),r.event=void 0)}};e.__qtouchswipe=r,a.mouse&&x(r,"main",[[e,"mousedown","mouseStart","passive"+(a.mouseCapture||a.mousecapture?"Capture":"")]]),c.has.touch&&x(r,"main",[[e,"touchstart","touchStart","passive"+(a.capture?"Capture":"")],[e,"touchmove","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchswipe;void 0!==n&&(t.oldValue!==t.value&&("function"!=typeof t.value&&n.end(),n.handler=t.value),n.direction=Ma(t.modifiers))},beforeUnmount(e){let t=e.__qtouchswipe;void 0!==t&&(S(t,"main"),S(t,"temp"),c.is.firefox&&k(e,!1),t.styleCleanup?.(),delete e.__qtouchswipe)}});function ja(){let e=Object.create(null);return{getCache:(t,n)=>Object.hasOwn(e,t)?e[t]:e[t]="function"==typeof n?n():n,setCache(t,n){e[t]=n},hasCache:t=>Object.hasOwn(e,t),clearCache(t){void 0===t?e=Object.create(null):delete e[t]}}}let Da={name:{required:!0},disable:Boolean},qa={setup:(t,{slots:n})=>()=>(0,e.h)("div",{class:"q-panel scroll",role:"tabpanel"},Ae(n.default))},Ba={modelValue:{required:!0},animated:Boolean,infinite:Boolean,swipeable:Boolean,vertical:Boolean,transitionPrev:String,transitionNext:String,transitionDuration:{type:[String,Number],default:300},keepAlive:Boolean,keepAliveInclude:[String,Array,RegExp],keepAliveExclude:[String,Array,RegExp],keepAliveMax:Number},Fa=["update:modelValue","beforeTransition","transition"];function Va(e){return null!=e&&""!==e}function Ua(){let t,n,{props:a,emit:i,proxy:r}=(0,e.getCurrentInstance)(),{getCache:o}=ja(),{registerTimeout:s}=xn(),l=(0,e.ref)(null),u={value:null};function c(e){let t=a.vertical?"up":"left";x((r.$q.lang.rtl?-1:1)*(e.direction===t?1:-1))}let d=(0,e.computed)(()=>[[Oa,c,void 0,{horizontal:!a.vertical,vertical:a.vertical,mouse:!0}]]),h=(0,e.computed)(()=>a.transitionPrev||"slide-"+(a.vertical?"down":r.$q.lang.rtl?"left":"right")),p=(0,e.computed)(()=>a.transitionNext||"slide-"+(a.vertical?"up":r.$q.lang.rtl?"right":"left")),f=(0,e.computed)(()=>`--q-transition-duration: ${a.transitionDuration}ms`),m=(0,e.computed)(()=>"string"==typeof a.modelValue||"number"==typeof a.modelValue?a.modelValue:String(a.modelValue)),_=(0,e.computed)(()=>({include:a.keepAliveInclude,exclude:a.keepAliveExclude,max:a.keepAliveMax})),g=(0,e.computed)(()=>void 0!==a.keepAliveInclude||void 0!==a.keepAliveExclude);function v(){x(1)}function b(){x(-1)}function y(e){i("update:modelValue",e)}function w(e){return t.findIndex(t=>t.props.name===e&&""!==t.props.disable&&!0!==t.props.disable)}function k(e){let t=0!==e&&a.animated&&-1!==u.value?"q-transition--"+(-1===e?h.value:p.value):null;l.value!==t&&(l.value=t)}function x(e,r=u.value){let o=r+e;for(;-1!==o&&o{n=!1},0);o+=e}a.infinite&&0!==t.length&&-1!==r&&r!==t.length&&x(e,-1===e?t.length:-1)}function S(){let e=w(a.modelValue);return u.value!==e&&(u.value=e),!0}function C(){let n=Va(a.modelValue)&&S()&&t[u.value];return a.keepAlive?[(0,e.h)(e.KeepAlive,_.value,[(0,e.h)(g.value?o(m.value,()=>({...qa,name:m.value})):qa,{key:m.value,style:f.value},()=>n)])]:[(0,e.h)("div",{class:"q-panel scroll",style:f.value,key:m.value,role:"tabpanel"},[n])]}return(0,e.watch)(()=>a.modelValue,(e,t)=>{let r=Va(e)?w(e):-1;n||k(-1===r?0:r{i("transition",e,t)},a.transitionDuration))}),Object.assign(r,{next:v,previous:b,goTo:y}),{panelIndex:u,panelDirectives:d,updatePanelsList:function(e){return t=lt(Ae(e.default,[])).filter(e=>null!==e.props&&void 0===e.props.slot&&Va(e.props.name)),t.length},updatePanelIndex:S,getPanelContent:function(){if(0!==t.length)return a.animated?[(0,e.h)(e.Transition,{name:l.value},C)]:C()},getEnabledPanels:function(){return t.filter(e=>""!==e.props.disable&&!0!==e.props.disable)},getPanels:function(){return t},isValidPanelName:Va,keepAliveProps:_,needsUniqueKeepAliveWrapper:g,goToPanelByOffset:x,goToPanel:y,nextPanel:v,previousPanel:b}}let $a=0,Ha={fullscreen:Boolean,noRouteFullscreenExit:Boolean},Wa=["update:fullscreen","fullscreen"];function Ga(){let t,n,a=(0,e.getCurrentInstance)(),{props:i,emit:r,proxy:o}=a,s=!1,l=(0,e.ref)(!1);function u(){l.value?d():c()}function c(){l.value||(l.value=!0,o.$el.replaceWith(n),document.body.append(o.$el),$a++,1===$a&&document.body.classList.add("q-body--fullscreen-mixin"),t={handler:d},F.add(t))}function d(){l.value&&(void 0!==t&&(F.remove(t),t=void 0),n.replaceWith(o.$el),l.value=!1,$a=Math.max(0,$a-1),0===$a&&(document.body.classList.remove("q-body--fullscreen-mixin"),!s&&void 0!==o.$el.scrollIntoView&&setTimeout(()=>{o.$el.scrollIntoView()},0)))}return ut(a)&&(0,e.watch)(()=>o.$route.fullPath,()=>{i.noRouteFullscreenExit||d()}),(0,e.watch)(()=>i.fullscreen,e=>{l.value!==e&&u()}),(0,e.watch)(l,e=>{r("update:fullscreen",e),r("fullscreen",e)}),(0,e.onBeforeMount)(()=>{n=document.createElement("span")}),(0,e.onMounted)(()=>{i.fullscreen&&c()}),(0,e.onBeforeUnmount)(()=>{s=!0,d()}),Object.assign(o,{toggleFullscreen:u,setFullscreen:c,exitFullscreen:d}),{inFullscreen:l,toggleFullscreen:u}}let Ka=["top","right","bottom","left"],Ya=["regular","flat","outline","push","unelevated"];var Qa=h({name:"QCarousel",props:{...Je,...Ba,...Ha,transitionPrev:{type:String,default:"fade"},transitionNext:{type:String,default:"fade"},height:String,padding:Boolean,controlColor:String,controlTextColor:String,controlType:{type:String,validator:e=>Ya.includes(e),default:"flat"},autoplay:[Number,Boolean],arrows:Boolean,prevIcon:String,nextIcon:String,navigation:Boolean,navigationPosition:{type:String,validator:e=>Ka.includes(e)},navigationIcon:String,navigationActiveIcon:String,thumbnails:Boolean},emits:[...Wa,...Fa],setup(t,{slots:n}){let a,{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Xe(t,i),o=null,{updatePanelsList:s,updatePanelIndex:l,getPanelContent:u,panelDirectives:c,goToPanel:d,previousPanel:h,nextPanel:p,getEnabledPanels:f,panelIndex:m}=Ua(),{inFullscreen:_}=Ga(),g=(0,e.computed)(()=>_.value||void 0===t.height?{}:{height:t.height}),v=(0,e.computed)(()=>t.vertical?"vertical":"horizontal"),b=(0,e.computed)(()=>t.navigationPosition||(t.vertical?"right":"bottom")),y=(0,e.computed)(()=>`q-carousel q-panel-parent q-carousel--with${t.padding?"":"out"}-padding`+(_.value?" fullscreen":"")+(r.value?" q-carousel--dark q-dark":"")+(t.arrows?` q-carousel--arrows-${v.value}`:"")+(t.navigation?` q-carousel--navigation-${b.value}`:"")),w=(0,e.computed)(()=>{let e=[t.prevIcon||i.iconSet.carousel[t.vertical?"up":"left"],t.nextIcon||i.iconSet.carousel[t.vertical?"down":"right"]];return!t.vertical&&i.lang.rtl?e.reverse():e}),k=(0,e.computed)(()=>t.navigationIcon||i.iconSet.carousel.navigationIcon),x=(0,e.computed)(()=>t.navigationActiveIcon||k.value),S=(0,e.computed)(()=>({color:t.controlColor,textColor:t.controlTextColor,round:!0,[t.controlType]:!0,dense:!0}));function C(){let e=re(t.autoplay)?Math.abs(t.autoplay):5e3;null!==o&&clearTimeout(o),o=setTimeout(()=>{o=null,e>=0?p():h()},e)}function T(n,a){return(0,e.h)("div",{class:`q-carousel__control q-carousel__navigation no-wrap absolute flex q-carousel__navigation--${n} q-carousel__navigation--${b.value}`+(void 0===t.controlColor?"":` text-${t.controlColor}`)},[(0,e.h)("div",{class:"q-carousel__navigation-inner flex flex-center no-wrap"},f().map(a))])}function P(){let i=[];if(t.navigation){let t=void 0===n["navigation-icon"]?t=>(0,e.h)(Kt,{key:"nav"+t.name,class:`q-carousel__navigation-icon q-carousel__navigation-icon--${!0===t.active?"":"in"}active`,...t.btnProps,onClick:t.onClick}):n["navigation-icon"],r=a-1;i.push(T("buttons",(e,n)=>{let a=e.props.name,i=m.value===n;return t({index:n,maxIndex:r,name:a,active:i,btnProps:{icon:i?x.value:k.value,size:"sm",...S.value},onClick:()=>{d(a)}})}))}else if(t.thumbnails){let n=void 0===t.controlColor?"":` text-${t.controlColor}`;i.push(T("thumbnails",a=>{let i=a.props;return(0,e.h)("img",{key:"tmb#"+i.name,class:`q-carousel__thumbnail q-carousel__thumbnail--${i.name===t.modelValue?"":"in"}active`+n,src:i.imgSrc||i["img-src"],onClick:()=>{d(i.name)}})}))}return t.arrows&&m.value>=0&&((t.infinite||m.value>0)&&i.push((0,e.h)("div",{key:"prev",class:`q-carousel__control q-carousel__arrow q-carousel__prev-arrow q-carousel__prev-arrow--${v.value} absolute flex flex-center`},[(0,e.h)(Kt,{icon:w.value[0],...S.value,onClick:h})])),(t.infinite||m.valuet.modelValue,()=>{t.autoplay&&C()}),(0,e.watch)(()=>t.autoplay,e=>{e?C():null!==o&&(clearTimeout(o),o=null)}),(0,e.onMounted)(()=>{t.autoplay&&C()}),(0,e.onBeforeUnmount)(()=>{null!==o&&clearTimeout(o)}),()=>(a=s(n),l(),(0,e.h)("div",{class:y.value,style:g.value},[ze("div",{class:"q-carousel__slides-container"},u(),"sl-cont",t.swipeable,()=>c.value),...P()]))}}),Za=h({name:"QCarouselSlide",props:{...Da,imgSrc:String},setup(t,{slots:n}){let a=(0,e.computed)(()=>t.imgSrc?{backgroundImage:`url("${t.imgSrc}")`}:{});return()=>(0,e.h)("div",{class:"q-carousel__slide",style:a.value},Ae(n.default))}}),Ja=h({name:"QCarouselControl",props:{position:{type:String,default:"bottom-right",validator:e=>["top-right","top-left","bottom-right","bottom-left","top","right","bottom","left"].includes(e)},offset:{type:Array,default:()=>[18,18],validator:e=>2===e.length}},setup(t,{slots:n}){let a=(0,e.computed)(()=>`q-carousel__control absolute absolute-${t.position}`),i=(0,e.computed)(()=>({margin:`${t.offset[1]}px ${t.offset[0]}px`}));return()=>(0,e.h)("div",{class:a.value,style:i.value},Ae(n.default))}}),Xa=h({name:"QChatMessage",props:{sent:Boolean,label:String,bgColor:String,textColor:String,name:String,avatar:String,text:Array,stamp:String,size:String,labelHtml:Boolean,nameHtml:Boolean,textHtml:Boolean,stampHtml:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>t.sent?"sent":"received"),i=(0,e.computed)(()=>`q-message-text-content q-message-text-content--${a.value}`+(void 0===t.textColor?"":` text-${t.textColor}`)),r=(0,e.computed)(()=>`q-message-text q-message-text--${a.value}`+(void 0===t.bgColor?"":` text-${t.bgColor}`)),o=(0,e.computed)(()=>"q-message-container row items-end no-wrap"+(t.sent?" reverse":"")),s=(0,e.computed)(()=>void 0===t.size?"":`col-${t.size}`),l=(0,e.computed)(()=>({msg:t.textHtml?"innerHTML":"textContent",stamp:t.stampHtml?"innerHTML":"textContent",name:t.nameHtml?"innerHTML":"textContent",label:t.labelHtml?"innerHTML":"textContent"}));function u(a){return void 0===n.stamp?t.stamp?[a,(0,e.h)("div",{class:"q-message-stamp",[l.value.stamp]:t.stamp})]:[a]:[a,(0,e.h)("div",{class:"q-message-stamp"},n.stamp())]}function c(t,n){let a=n?t.length>1?e=>e:t=>(0,e.h)("div",[t]):t=>(0,e.h)("div",{[l.value.msg]:t});return t.map((t,n)=>(0,e.h)("div",{key:n,class:r.value},[(0,e.h)("div",{class:i.value},u(a(t)))]))}return()=>{let i=[];void 0===n.avatar?void 0!==t.avatar&&i.push((0,e.h)("img",{class:`q-message-avatar q-message-avatar--${a.value}`,src:t.avatar,"aria-hidden":"true"})):i.push(n.avatar());let r=[];void 0===n.name?void 0!==t.name&&r.push((0,e.h)("div",{class:`q-message-name q-message-name--${a.value}`,[l.value.name]:t.name})):r.push((0,e.h)("div",{class:`q-message-name q-message-name--${a.value}`},n.name())),void 0===n.default?void 0!==t.text&&r.push(c(t.text,!1)):r.push(c(lt(n.default()),!0)),i.push((0,e.h)("div",{class:s.value},r));let u=[];return void 0===n.label?void 0!==t.label&&u.push((0,e.h)("div",{class:"q-message-label",[l.value.label]:t.label})):u.push((0,e.h)("div",{class:"q-message-label"},n.label())),u.push((0,e.h)("div",{class:o.value},i)),(0,e.h)("div",{class:`q-message q-message-${a.value}`},u)}}});function ei(t,n){let a=(0,e.ref)(null);return{refocusTargetEl:(0,e.computed)(()=>t.disable?null:(0,e.h)("span",{ref:a,class:"no-outline",tabindex:-1})),refocusTarget:function(e){let t=n.value;!0!==e?.qAvoidFocus&&(0===e?.type.indexOf("key")?document.activeElement!==t&&!0===t?.contains(document.activeElement)&&t.focus():null!==a.value&&(void 0===e||!0===t?.contains(e.target))&&a.value.focus())}}}var ti={xs:30,sm:35,md:40,lg:50,xl:60};let ni={...Je,...Pe,...wa,modelValue:{required:!0,default:null},val:{},trueValue:{default:!0},falseValue:{default:!1},indeterminateValue:{default:null},checkedIcon:String,uncheckedIcon:String,indeterminateIcon:String,toggleOrder:{type:String,validator:e=>"tf"===e||"ft"===e},toggleIndeterminate:Boolean,label:String,leftLabel:Boolean,color:String,keepColor:Boolean,dense:Boolean,disable:Boolean,tabindex:[String,Number]},ai=["update:modelValue"];function ii(e){(13===e.keyCode||32===e.keyCode)&&w(e)}function ri(t,n){let{props:a,slots:i,emit:r,proxy:o}=(0,e.getCurrentInstance)(),{$q:s}=o,l=Xe(a,s),u=(0,e.ref)(null),{refocusTargetEl:c,refocusTarget:d}=ei(a,u),h=Ee(a,ti),p=(0,e.computed)(()=>void 0!==a.val&&Array.isArray(a.modelValue)),f=(0,e.computed)(()=>{let t=(0,e.toRaw)(a.val);return p.value?a.modelValue.findIndex(n=>(0,e.toRaw)(n)===t):-1}),m=(0,e.computed)(()=>p.value?-1!==f.value:(0,e.toRaw)(a.modelValue)===(0,e.toRaw)(a.trueValue)),_=(0,e.computed)(()=>p.value?-1===f.value:(0,e.toRaw)(a.modelValue)===(0,e.toRaw)(a.falseValue)),g=(0,e.computed)(()=>!m.value&&!_.value),v=(0,e.computed)(()=>a.disable?-1:a.tabindex||0),b=(0,e.computed)(()=>`q-${t} cursor-pointer no-outline row inline no-wrap items-center`+(a.disable?" disabled":"")+(l.value?` q-${t}--dark`:"")+(a.dense?` q-${t}--dense`:"")+(a.leftLabel?" reverse":"")),y=(0,e.computed)(()=>`q-${t}__inner relative-position non-selectable q-${t}__inner--${m.value?"truthy":_.value?"falsy":"indet"}${void 0===a.color||!a.keepColor&&("toggle"===t?!m.value:_.value)?"":` text-${a.color}`}`),k=xa((0,e.computed)(()=>{let e={type:"checkbox"};return void 0!==a.name&&Object.assign(e,{".checked":m.value,"^checked":m.value?"checked":void 0,name:a.name,value:p.value?a.val:a.trueValue}),e})),x=(0,e.computed)(()=>{let e={tabindex:v.value,role:"toggle"===t?"switch":"checkbox","aria-label":a.label,"aria-checked":g.value?"mixed":m.value?"true":"false"};return a.disable&&(e["aria-disabled"]="true"),e});function S(e){void 0!==e&&(w(e),d(e)),a.disable||r("update:modelValue",function(){if(p.value){if(m.value){let e=[...a.modelValue];return e.splice(f.value,1),e}return[...a.modelValue,a.val]}if(m.value){if("ft"!==a.toggleOrder||!a.toggleIndeterminate)return a.falseValue}else{if(!_.value)return"ft"===a.toggleOrder?a.falseValue:a.trueValue;if("ft"===a.toggleOrder||!a.toggleIndeterminate)return a.trueValue}return a.indeterminateValue}(),e)}function C(e){(13===e.keyCode||32===e.keyCode)&&S(e)}let T=n(m,g);return Object.assign(o,{toggle:S}),()=>{let n=T();a.disable||k(n,"unshift",` q-${t}__native absolute q-ma-none q-pa-none`);let r=[(0,e.h)("div",{class:y.value,style:h.value,"aria-hidden":"true"},n)];null!==c.value&&r.push(c.value);let o=void 0===a.label?Ae(i.default):Me(i.default,[a.label]);return void 0!==o&&r.push((0,e.h)("div",{class:`q-${t}__label q-anchor--skip`},o)),(0,e.h)("div",{ref:u,class:b.value,...x.value,onClick:S,onKeydown:ii,onKeyup:C},r)}}var oi=h({name:"QCheckbox",props:ni,emits:ai,setup(t){let n=(0,e.h)("div",{key:"svg",class:"q-checkbox__bg absolute"},[(0,e.h)("svg",{class:"q-checkbox__svg fit absolute-full",viewBox:"0 0 24 24"},[(0,e.h)("path",{class:"q-checkbox__truthy",fill:"none",d:"M1.73,12.91 8.1,19.28 22.79,4.59"}),(0,e.h)("path",{class:"q-checkbox__indet",d:"M4,14H20V10H4"})])]);return ri("checkbox",function(a,i){let r=(0,e.computed)(()=>(a.value?t.checkedIcon:i.value?t.indeterminateIcon:t.uncheckedIcon)||null);return()=>null===r.value?[n]:[(0,e.h)("div",{key:"icon",class:"q-checkbox__icon-container absolute-full flex flex-center no-wrap"},[(0,e.h)(Ke,{class:"q-checkbox__icon",name:r.value})])]})}});function si(e){32===e.keyCode&&w(e)}let li={xs:8,sm:10,md:14,lg:20,xl:24};var ui=h({name:"QChip",props:{...Je,...Pe,dense:Boolean,icon:String,iconRight:String,iconRemove:String,iconSelected:String,label:[String,Number],color:String,textColor:String,modelValue:{type:Boolean,default:!0},selected:{type:Boolean,default:null},square:Boolean,outline:Boolean,clickable:Boolean,removable:Boolean,removeAriaLabel:String,tabindex:[String,Number],disable:Boolean,ripple:{type:[Boolean,Object],default:!0}},emits:["update:modelValue","update:selected","remove","click"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Xe(t,i),o=Ee(t,li),s=(0,e.computed)(()=>t.selected||void 0!==t.icon),l=(0,e.computed)(()=>t.selected?t.iconSelected||i.iconSet.chip.selected:t.icon),u=(0,e.computed)(()=>t.iconRemove||i.iconSet.chip.remove),c=(0,e.computed)(()=>!t.disable&&(t.clickable||null!==t.selected)),d=(0,e.computed)(()=>{let e=t.outline&&t.color||t.textColor;return"q-chip row inline no-wrap items-center"+(t.outline||void 0===t.color?"":` bg-${t.color}`)+(e?` text-${e} q-chip--colored`:"")+(t.disable?" disabled":"")+(t.dense?" q-chip--dense":"")+(t.outline?" q-chip--outline":"")+(t.selected?" q-chip--selected":"")+(c.value?" q-chip--clickable cursor-pointer non-selectable q-hoverable":"")+(t.square?" q-chip--square":"")+(r.value?" q-chip--dark q-dark":"")}),h=(0,e.computed)(()=>{let e=t.disable?{tabindex:-1,"aria-disabled":"true"}:{tabindex:t.tabindex||0,role:"button","aria-pressed":t.selected?"true":"false"};return{chip:e,remove:{...e,role:"button","aria-hidden":"false","aria-label":t.removeAriaLabel||i.lang.label.remove}}});function p(e){[13,32].includes(e.keyCode)&&(f(e),w(e))}function f(e){t.disable||(a("update:selected",!t.selected),a("click",e))}function m(e){(void 0===e.keyCode||[13,32].includes(e.keyCode))&&(w(e),t.disable||(a("update:modelValue",!1),a("remove")))}function _(){let a=[];c.value&&a.push((0,e.h)("div",{class:"q-focus-helper"})),s.value&&a.push((0,e.h)(Ke,{class:"q-chip__icon q-chip__icon--left",name:l.value}));let i=void 0===t.label?void 0:[(0,e.h)("div",{class:"ellipsis"},[t.label])];return a.push((0,e.h)("div",{class:"q-chip__content col row no-wrap items-center q-anchor--skip"},Re(n.default,i))),t.iconRight&&a.push((0,e.h)(Ke,{class:"q-chip__icon q-chip__icon--right",name:t.iconRight})),t.removable&&a.push((0,e.h)(Ke,{class:"q-chip__icon q-chip__icon--remove cursor-pointer",name:u.value,...h.value.remove,onClick:m,onKeydown:si,onKeyup:m})),a}return()=>{if(!t.modelValue)return;let e={class:d.value,style:o.value};return c.value&&Object.assign(e,h.value.chip,{onClick:f,onKeydown:si,onKeyup:p}),ze("div",e,_(),"ripple",!1!==t.ripple&&!t.disable,()=>[[zt,t.ripple]])}}});let ci={...Pe,min:{type:Number,default:0},max:{type:Number,default:100},color:String,centerColor:String,trackColor:String,fontSize:String,rounded:Boolean,thickness:{type:Number,default:.2,validator:e=>e>=0&&e<=1},angle:{type:Number,default:0},showValue:Boolean,reverse:Boolean,instantFeedback:Boolean},di=100*Math.PI,hi=Math.round(1e3*di)/1e3;var pi=h({name:"QCircularProgress",props:{...ci,value:{type:Number,default:0},animationSpeed:{type:[String,Number],default:600},indeterminate:Boolean},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=Ee(t),r=(0,e.computed)(()=>{let e=(a.lang.rtl?-1:1)*t.angle;return{transform:t.reverse===(!0===a.lang.rtl)?`rotate3d(0, 0, 1, ${e-90}deg)`:`scale3d(-1, 1, 1) rotate3d(0, 0, 1, ${-90-e}deg)`}}),o=(0,e.computed)(()=>t.instantFeedback||t.indeterminate?"":{transition:`stroke-dashoffset ${t.animationSpeed}ms ease 0s, stroke ${t.animationSpeed}ms ease`}),s=(0,e.computed)(()=>100/(1-t.thickness/2)),l=(0,e.computed)(()=>`${s.value/2} ${s.value/2} ${s.value} ${s.value}`),u=(0,e.computed)(()=>_e(t.value,t.min,t.max)),c=(0,e.computed)(()=>t.max-t.min),d=(0,e.computed)(()=>t.thickness/2*s.value),h=(0,e.computed)(()=>{let e=(t.max-u.value)/c.value,n=t.rounded&&u.value{let a=[];void 0!==t.centerColor&&"transparent"!==t.centerColor&&a.push((0,e.h)("circle",{class:`q-circular-progress__center text-${t.centerColor}`,fill:"currentColor",r:50-d.value/2,cx:s.value,cy:s.value})),void 0!==t.trackColor&&"transparent"!==t.trackColor&&a.push(p({cls:"track",thickness:d.value,offset:0,color:t.trackColor})),a.push(p({cls:"circle",thickness:d.value,offset:h.value,color:t.color,rounded:t.rounded?"round":void 0}));let o=[(0,e.h)("svg",{class:"q-circular-progress__svg",style:r.value,viewBox:l.value,"aria-hidden":"true"},a)];return t.showValue&&o.push((0,e.h)("div",{class:"q-circular-progress__text absolute-full row flex-center content-center",style:{fontSize:t.fontSize}},void 0===n.default?[(0,e.h)("div",u.value)]:n.default())),(0,e.h)("div",{class:`q-circular-progress q-circular-progress--${t.indeterminate?"in":""}determinate`,style:i.value,role:"progressbar","aria-valuemin":t.min,"aria-valuemax":t.max,"aria-valuenow":t.indeterminate?void 0:u.value},Re(n.internal,o))}}});function fi(e,t,n){let a,i=v(e),r=i.left-t.event.x,o=i.top-t.event.y,s=Math.abs(r),l=Math.abs(o),u=t.direction;u.horizontal&&!u.vertical?a=r<0?"left":"right":!u.horizontal&&u.vertical?a=o<0?"up":"down":u.up&&o<0?(a="up",s>l&&(u.left&&r<0?a="left":u.right&&r>0&&(a="right"))):u.down&&o>0?(a="down",s>l&&(u.left&&r<0?a="left":u.right&&r>0&&(a="right"))):u.left&&r<0?(a="left",s0&&(a="down"))):u.right&&r>0&&(a="right",s0&&(a="down")));let c=!1;if(void 0===a&&!1===n){if(t.event.isFirst||void 0===t.event.lastDir)return{};a=t.event.lastDir,c=!0,"left"===a||"right"===a?(i.left-=r,s=0,r=0):(i.top-=o,l=0,o=0)}return{synthetic:c,payload:{evt:e,touch:!0!==t.event.mouse,mouse:!0===t.event.mouse,position:i,direction:a,isFirst:t.event.isFirst,isFinal:!0===n,duration:Date.now()-t.event.time,distance:{x:s,y:l},offset:{x:r,y:o},delta:{x:i.left-t.event.lastX,y:i.top-t.event.lastY}}}}function mi(){document.body.classList.remove("no-pointer-events--children")}let _i=0;var gi=p({name:"touch-pan",beforeMount(e,{value:t,modifiers:n}){if(!n.mouse&&!c.has.touch)return;function a(e,t){n.mouse&&t?w(e):(n.stop&&b(e),n.prevent&&y(e))}let i={uid:"qvtp_"+_i++,handler:t,modifiers:n,direction:Ma(n),noop:_,mouseStart(e){za(e,i)&&g(e)&&(x(i,"temp",[[document,"mousemove","move","notPassiveCapture"],[document,"mouseup","end","passiveCapture"]]),i.start(e,!0))},touchStart(e){if(za(e,i)){let t=e.target;x(i,"temp",[[t,"touchmove","move","notPassiveCapture"],[t,"touchcancel","end","passiveCapture"],[t,"touchend","end","passiveCapture"]]),i.start(e)}},start(t,a){if(c.is.firefox&&k(e,!0),i.lastEvt=t,a||n.stop){if(!(i.direction.all||a&&(i.modifiers.mouseAllDir||i.modifiers.mousealldir))){let e=t.type.includes("mouse")?new MouseEvent(t.type,t):new TouchEvent(t.type,t);t.defaultPrevented&&y(e),t.cancelBubble&&b(e),Object.assign(e,{qKeyEvent:t.qKeyEvent,qClickOutside:t.qClickOutside,qAnchorHandled:t.qAnchorHandled,qClonedBy:void 0===t.qClonedBy?[i.uid]:t.qClonedBy.concat(i.uid)}),i.initialEvent={target:t.target,event:e}}b(t)}let{left:r,top:o}=v(t);i.event={x:r,y:o,time:Date.now(),mouse:!0===a,detected:!1,isFirst:!0,isFinal:!1,lastX:r,lastY:o}},move(e){if(void 0===i.event)return;let t=v(e),r=t.left-i.event.x,o=t.top-i.event.y;if(0===r&&0===o)return;i.lastEvt=e;let s=!0===i.event.mouse,l=()=>{let t;a(e,s),!n.preserveCursor&&!n.preservecursor&&(t=document.documentElement.style.cursor||"",document.documentElement.style.cursor="grabbing"),s&&document.body.classList.add("no-pointer-events--children"),document.body.classList.add("non-selectable"),Qt(),i.styleCleanup=e=>{i.styleCleanup=void 0,void 0!==t&&(document.documentElement.style.cursor=t),document.body.classList.remove("non-selectable"),s?void 0===e?mi():setTimeout(()=>{mi(),e()},50):void 0!==e&&e()}};if(i.event.detected){i.event.isFirst||a(e,i.event.mouse);let{payload:t,synthetic:n}=fi(e,i,!1);return void(void 0!==t&&(!1===i.handler(t)?i.end(e):(void 0===i.styleCleanup&&i.event.isFirst&&l(),i.event.lastX=t.position.left,i.event.lastY=t.position.top,i.event.lastDir=n?void 0:t.direction,i.event.isFirst=!1)))}if(i.direction.all||s&&(i.modifiers.mouseAllDir||i.modifiers.mousealldir))return l(),i.event.detected=!0,void i.move(e);let u=Math.abs(r),c=Math.abs(o);u!==c&&(i.direction.horizontal&&u>c||i.direction.vertical&&u0||i.direction.left&&u>c&&r<0||i.direction.right&&u>c&&r>0?(i.event.detected=!0,i.move(e)):i.end(e,!0))},end(t,n){if(void 0!==i.event){if(S(i,"temp"),c.is.firefox&&k(e,!1),n)i.styleCleanup?.(),!i.event.detected&&void 0!==i.initialEvent&&i.initialEvent.target.dispatchEvent(i.initialEvent.event);else if(i.event.detected){i.event.isFirst&&i.handler(fi(void 0===t?i.lastEvt:t,i).payload);let{payload:e}=fi(void 0===t?i.lastEvt:t,i,!0),n=()=>{i.handler(e)};void 0===i.styleCleanup?n():i.styleCleanup(n)}i.event=void 0,i.initialEvent=void 0,i.lastEvt=void 0}}};e.__qtouchpan=i,n.mouse&&x(i,"main",[[e,"mousedown","mouseStart","passive"+(n.mouseCapture||n.mousecapture?"Capture":"")]]),c.has.touch&&x(i,"main",[[e,"touchstart","touchStart","passive"+(n.capture?"Capture":"")],[e,"touchmove","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchpan;void 0!==n&&(t.oldValue!==t.value&&("function"!=typeof value&&n.end(),n.handler=t.value),n.direction=Ma(t.modifiers))},beforeUnmount(e){let t=e.__qtouchpan;void 0!==t&&(void 0!==t.event&&t.end(),S(t,"main"),S(t,"temp"),c.is.firefox&&k(e,!1),t.styleCleanup?.(),delete e.__qtouchpan)}});let vi=e=>({value:e}),bi=({marker:t})=>(0,e.h)("div",{key:t.value,style:t.style,class:t.classes},t.label),yi=[34,37,40,33,39,38],wi={...Je,...wa,min:{type:Number,default:0},max:{type:Number,default:100},innerMin:Number,innerMax:Number,step:{type:Number,default:1,validator:e=>e>=0},snap:Boolean,vertical:Boolean,reverse:Boolean,color:String,markerLabelsClass:String,label:Boolean,labelColor:String,labelTextColor:String,labelAlways:Boolean,switchLabelSide:Boolean,markers:[Boolean,Number],markerLabels:[Boolean,Array,Object,Function],switchMarkerLabelsSide:Boolean,trackImg:String,trackColor:String,innerTrackImg:String,innerTrackColor:String,selectionColor:String,selectionImg:String,thumbSize:{type:String,default:"20px"},trackSize:{type:String,default:"4px"},disable:Boolean,readonly:Boolean,dense:Boolean,tabindex:[String,Number],thumbColor:String,thumbPath:{type:String,default:"M 4, 10 a 6,6 0 1,0 12,0 a 6,6 0 1,0 -12,0"}},ki=["pan","update:modelValue","change"];function xi({updateValue:t,updatePosition:n,getDragging:a,formAttrs:i}){let{props:r,emit:o,slots:s,proxy:{$q:l}}=(0,e.getCurrentInstance)(),u=Xe(r,l),c=xa(i),d=(0,e.ref)(!1),h=(0,e.ref)(!1),p=(0,e.ref)(!1),f=(0,e.ref)(!1),m=(0,e.computed)(()=>r.vertical?"--v":"--h"),_=(0,e.computed)(()=>"-"+(r.switchLabelSide?"switched":"standard")),g=(0,e.computed)(()=>r.vertical?r.reverse:r.reverse!==(!0===l.lang.rtl)),b=(0,e.computed)(()=>!Number.isFinite(r.innerMin)||r.innerMin!Number.isFinite(r.innerMax)||r.innerMax>r.max?r.max:r.innerMax),w=(0,e.computed)(()=>!r.disable&&!r.readonly&&b.value{if(0===r.step)return e=>e;let e=(String(r.step).trim().split(".")[1]||"").length;return t=>Number.parseFloat(t.toFixed(e))}),x=(0,e.computed)(()=>0===r.step?1:r.step),S=(0,e.computed)(()=>w.value?r.tabindex||0:-1),C=(0,e.computed)(()=>r.max-r.min),T=(0,e.computed)(()=>y.value-b.value),P=(0,e.computed)(()=>K(b.value)),E=(0,e.computed)(()=>K(y.value)),A=(0,e.computed)(()=>r.vertical?g.value?"bottom":"top":g.value?"right":"left"),L=(0,e.computed)(()=>r.vertical?"height":"width"),M=(0,e.computed)(()=>r.vertical?"width":"height"),R=(0,e.computed)(()=>r.vertical?"vertical":"horizontal"),z=(0,e.computed)(()=>{let e={role:"slider","aria-valuemin":b.value,"aria-valuemax":y.value,"aria-orientation":R.value,"data-step":r.step};return r.disable?e["aria-disabled"]="true":r.readonly&&(e["aria-readonly"]="true"),e}),I=(0,e.computed)(()=>`q-slider q-slider${m.value} q-slider--${d.value?"":"in"}active inline no-wrap `+(r.vertical?"row":"column")+(r.disable?" disabled":" q-slider--enabled"+(w.value?" q-slider--editable":""))+("both"===p.value?" q-slider--focus":"")+(r.label||r.labelAlways?" q-slider--label":"")+(r.labelAlways?" q-slider--label-always":"")+(u.value?" q-slider--dark":"")+(r.dense?" q-slider--dense q-slider--dense"+m.value:""));function N(e){let t="q-slider__"+e;return`${t} ${t}${m.value} ${t}${m.value}${_.value}`}function O(e){let t="q-slider__"+e;return`${t} ${t}${m.value}`}let j=(0,e.computed)(()=>{let e=r.selectionColor||r.color;return"q-slider__selection absolute"+(void 0===e?"":` text-${e}`)}),D=(0,e.computed)(()=>O("markers")+" absolute overflow-hidden"),q=(0,e.computed)(()=>O("track-container")),B=(0,e.computed)(()=>N("pin")),F=(0,e.computed)(()=>N("label")),V=(0,e.computed)(()=>N("text-container")),U=(0,e.computed)(()=>N("marker-labels-container")+(void 0===r.markerLabelsClass?"":` ${r.markerLabelsClass}`)),$=(0,e.computed)(()=>"q-slider__track relative-position no-outline"+(void 0===r.trackColor?"":` bg-${r.trackColor}`)),H=(0,e.computed)(()=>{let e={[M.value]:r.trackSize};return void 0!==r.trackImg&&(e.backgroundImage=`url(${r.trackImg}) !important`),e}),W=(0,e.computed)(()=>"q-slider__inner absolute"+(void 0===r.innerTrackColor?"":` bg-${r.innerTrackColor}`)),G=(0,e.computed)(()=>{let e=E.value-P.value,t={[A.value]:100*P.value+"%",[L.value]:0===e?"2px":100*e+"%"};return void 0!==r.innerTrackImg&&(t.backgroundImage=`url(${r.innerTrackImg}) !important`),t});function K(e){return 0===C.value?0:(e-r.min)/C.value}let Y=(0,e.computed)(()=>re(r.markers)?r.markers:x.value),Q=(0,e.computed)(()=>{let e=[],t=Y.value,n=r.max,a=r.min;do{e.push(a),a+=t}while(a{let e=` q-slider__marker-labels${m.value}-`;return`q-slider__marker-labels${e}${r.switchMarkerLabelsSide?"switched":"standard"}${e}${g.value?"rtl":"ltr"}`}),J=(0,e.computed)(()=>!1===r.markerLabels?null:function(e){if(!1===e)return null;if(!0===e)return Q.value.map(vi);if("function"==typeof e)return Q.value.map(t=>{let n=e(t);return ne(n)?{...n,value:t}:{value:t,label:n}});let t=({value:e})=>e>=r.min&&e<=r.max;return Array.isArray(e)?e.map(e=>ne(e)?e:{value:e}).filter(t):Object.keys(e).map(t=>{let n=e[t],a=Number(t);return ne(n)?{...n,value:a}:{value:a,label:n}}).filter(t)}(r.markerLabels).map((e,t)=>({index:t,value:e.value,label:e.label||e.value,classes:Z.value+(void 0===e.classes?"":" "+e.classes),style:{...te(e.value),...e.style}}))),X=(0,e.computed)(()=>({markerList:J.value,markerMap:ae.value,classes:Z.value,getStyle:te})),ee=(0,e.computed)(()=>{let e=0===T.value?"2px":100*Y.value/T.value;return{...G.value,backgroundSize:r.vertical?`2px ${e}%`:`${e}% 2px`}});function te(e){return{[A.value]:100*(e-r.min)/C.value+"%"}}let ae=(0,e.computed)(()=>{if(!1===r.markerLabels)return null;let e={};return J.value.forEach(t=>{e[t.value]=t}),e});function ie(){if(void 0!==s["marker-label-group"])return s["marker-label-group"](X.value);let e=s["marker-label"]||bi;return J.value.map(t=>e({marker:t,...X.value}))}let oe=(0,e.computed)(()=>[[gi,se,void 0,{[R.value]:!0,prevent:!0,stop:!0,mouse:!0,mouseAllDir:!0}]]);function se(e){e.isFinal?(void 0!==f.value&&(n(e.evt),e.touch&&t(!0),f.value=void 0,o("pan","end")),d.value=!1,p.value=!1):e.isFirst?(f.value=a(e.evt),n(e.evt),t(),d.value=!0,o("pan","start")):(n(e.evt),t())}function le(){p.value=!1}function ue(){h.value=!1,d.value=!1,t(!0),le(),document.removeEventListener("mouseup",ue,!0)}function ce(e){if(r.vertical)return null;let t=l.lang.rtl===r.reverse?e:1-e;return{transform:`translateX(calc(${2*t-1} * ${r.thumbSize} / 2 + ${50-100*t}%))`}}return(0,e.onBeforeUnmount)(()=>{document.removeEventListener("mouseup",ue,!0)}),{state:{active:d,focus:p,preventFocus:h,dragging:f,editable:w,classes:I,tabindex:S,attributes:z,roundValueFn:k,keyStep:x,trackLen:C,innerMin:b,innerMinRatio:P,innerMax:y,innerMaxRatio:E,positionProp:A,sizeProp:L,isReversed:g},methods:{onActivate:function(e){n(e,a(e)),t(),h.value=!0,d.value=!0,document.addEventListener("mouseup",ue,!0)},onMobileClick:function(e){n(e,a(e)),t(!0)},onBlur:le,onKeyup:function(e){yi.includes(e.keyCode)&&t(!0)},getContent:function(t,n,a,i){let o=[];"transparent"!==r.innerTrackColor&&o.push((0,e.h)("div",{key:"inner",class:W.value,style:G.value})),"transparent"!==r.selectionColor&&o.push((0,e.h)("div",{key:"selection",class:j.value,style:t.value})),!1!==r.markers&&o.push((0,e.h)("div",{key:"marker",class:D.value,style:ee.value})),i(o);let s=[ze("div",{key:"trackC",class:q.value,tabindex:n.value,...a.value},[(0,e.h)("div",{class:$.value,style:H.value},o)],"slide",w.value,()=>oe.value)];return!1!==r.markerLabels&&s[r.switchMarkerLabelsSide?"unshift":"push"]((0,e.h)("div",{key:"markerL",class:U.value},ie())),s},getThumbRenderFn:function(t){let n=(0,e.computed)(()=>h.value||p.value!==t.focusValue&&"both"!==p.value?"":" q-slider--focus"),a=(0,e.computed)(()=>`q-slider__thumb q-slider__thumb${m.value} q-slider__thumb${m.value}-${g.value?"rtl":"ltr"} absolute non-selectable`+n.value+(void 0===t.thumbColor.value?"":` text-${t.thumbColor.value}`)),i=(0,e.computed)(()=>({width:r.thumbSize,height:r.thumbSize,[A.value]:100*t.ratio.value+"%",zIndex:p.value===t.focusValue?2:void 0})),o=(0,e.computed)(()=>void 0===t.labelColor.value?"":` text-${t.labelColor.value}`),s=(0,e.computed)(()=>ce(t.ratio.value)),l=(0,e.computed)(()=>"q-slider__text"+(void 0===t.labelTextColor.value?"":` text-${t.labelTextColor.value}`));return()=>{let n=[(0,e.h)("svg",{class:"q-slider__thumb-shape absolute-full",viewBox:"0 0 20 20","aria-hidden":"true"},[(0,e.h)("path",{d:r.thumbPath})]),(0,e.h)("div",{class:"q-slider__focus-ring fit"})];return(r.label||r.labelAlways)&&n.push((0,e.h)("div",{class:B.value+" absolute fit no-pointer-events"+o.value},[(0,e.h)("div",{class:F.value,style:{minWidth:r.thumbSize}},[(0,e.h)("div",{class:V.value,style:s.value},[(0,e.h)("span",{class:l.value},t.label.value)])])])),!1!==t.injectFormInput&&void 0!==r.name&&!r.disable&&c(n,"push"),(0,e.h)("div",{class:a.value,style:i.value,...t.getNodeData()},n)}},convertRatioToModel:function(e){let{min:t,max:n,step:a}=r,i=t+e*(n-t);if(a>0){let e=(i-b.value)%a;i+=(Math.abs(e)>=a/2?(e<0?-1:1)*a:0)-e}return i=k.value(i),_e(i,b.value,y.value)},convertModelToRatio:K,getDraggingRatio:function(e,t){let n=v(e),a=r.vertical?_e((n.top-t.top)/t.height,0,1):_e((n.left-t.left)/t.width,0,1);return _e(g.value?1-a:a,P.value,E.value)}}}}let Si=()=>({});var Ci=h({name:"QSlider",props:{...wi,modelValue:{required:!0,default:null,validator:e=>"number"==typeof e||null===e},labelValue:[String,Number]},emits:ki,setup(t,{emit:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),{state:i,methods:r}=xi({updateValue:f,updatePosition:function(e,n=i.dragging.value){let a=r.getDraggingRatio(e,n);l.value=r.convertRatioToModel(a),s.value=t.snap&&0!==t.step?r.convertModelToRatio(l.value):a},getDragging:function(){return o.value.getBoundingClientRect()},formAttrs:ka(t)}),o=(0,e.ref)(null),s=(0,e.ref)(0),l=(0,e.ref)(0);(0,e.watch)(()=>`${t.modelValue}|${i.innerMin.value}|${i.innerMax.value}`,function(){l.value=null===t.modelValue?i.innerMin.value:_e(t.modelValue,i.innerMin.value,i.innerMax.value)},{immediate:!0});let u=(0,e.computed)(()=>r.convertModelToRatio(l.value)),c=(0,e.computed)(()=>i.active.value?s.value:u.value),d=(0,e.computed)(()=>{let e={[i.positionProp.value]:100*i.innerMinRatio.value+"%",[i.sizeProp.value]:100*(c.value-i.innerMinRatio.value)+"%"};return void 0!==t.selectionImg&&(e.backgroundImage=`url(${t.selectionImg}) !important`),e}),h=r.getThumbRenderFn({focusValue:!0,getNodeData:Si,ratio:c,label:(0,e.computed)(()=>void 0===t.labelValue?l.value:t.labelValue),thumbColor:(0,e.computed)(()=>t.thumbColor||t.color),labelColor:(0,e.computed)(()=>t.labelColor),labelTextColor:(0,e.computed)(()=>t.labelTextColor)}),p=(0,e.computed)(()=>i.editable.value?a.platform.is.mobile?{onClick:r.onMobileClick}:{onMousedown:r.onActivate,onFocus:m,onBlur:r.onBlur,onKeydown:_,onKeyup:r.onKeyup}:{});function f(e){l.value!==t.modelValue&&n("update:modelValue",l.value),e&&n("change",l.value)}function m(){i.focus.value=!0}function _(e){if(!yi.includes(e.keyCode))return;w(e);let n=([34,33].includes(e.keyCode)?10:1)*i.keyStep.value,a=([34,37,40].includes(e.keyCode)?-1:1)*(i.isReversed.value?-1:1)*(t.vertical?-1:1)*n;l.value=_e(i.roundValueFn.value(l.value+a),i.innerMin.value,i.innerMax.value),f()}return()=>{let n=r.getContent(d,i.tabindex,p,e=>{e.push(h())});return(0,e.h)("div",{ref:o,class:i.classes.value+(null===t.modelValue?" q-slider--no-value":""),...i.attributes.value,"aria-valuenow":t.modelValue},n)}}});function Ti(){let t=(0,e.ref)(!o.value);return t.value||(0,e.onMounted)(()=>{t.value=!0}),{isHydrated:t}}let Pi=typeof ResizeObserver<"u",Ei=Pi?{}:{style:"display:block;position:absolute;top:0;left:0;right:0;bottom:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1;",url:"about:blank"};var Ai=h({name:"QResizeObserver",props:{debounce:{type:[String,Number],default:100}},emits:["resize"],setup(t,{emit:n}){let a,i=null,r={width:-1,height:-1};function o(e){!0===e||0===t.debounce||"0"===t.debounce?s():null===i&&(i=setTimeout(s,t.debounce))}function s(){if(null!==i&&(clearTimeout(i),i=null),a){let{offsetWidth:e,offsetHeight:t}=a;(e!==r.width||t!==r.height)&&(r={width:e,height:t},n("resize",r))}}let{proxy:l}=(0,e.getCurrentInstance)();if(l.trigger=o,Pi){let t,n=!1,r=i=>{n||(a=l.$el.parentNode,a?(t=new ResizeObserver(o),t.observe(a),s()):i||(0,e.nextTick)(()=>{r(!0)}))};return(0,e.onMounted)(()=>{r()}),(0,e.onBeforeUnmount)(()=>{n=!0,null!==i&&clearTimeout(i),void 0!==t&&(void 0===t.disconnect?a&&t.unobserve(a):t.disconnect())}),_}let u,{isHydrated:c}=Ti(),d=!1,h=()=>{null!==i&&(clearTimeout(i),i=null),void 0!==u&&(void 0!==u.removeEventListener&&u.removeEventListener("resize",o,m.passive),u=void 0)},p=()=>{h(),a?.contentDocument&&(u=a.contentDocument.defaultView,u.addEventListener("resize",o,m.passive),s())};return(0,e.onMounted)(()=>{(0,e.nextTick)(()=>{d||(a=l.$el,a&&p())})}),(0,e.onBeforeUnmount)(()=>{d=!0,h()}),()=>{if(c.value)return(0,e.h)("object",{class:"q--avoid-card-border",style:Ei.style,tabindex:-1,type:"text/html",data:Ei.url,"aria-hidden":"true",onLoad:p})}}});let Li=!1;{let e=document.createElement("div");e.setAttribute("dir","rtl"),Object.assign(e.style,{width:"1px",height:"1px",overflow:"auto"});let t=document.createElement("div");Object.assign(t.style,{width:"1000px",height:"1px"}),document.body.append(e),e.append(t),e.scrollLeft=-1e3,Li=e.scrollLeft>=0,e.remove()}function Mi(e,t,n){let a=n?["left","right"]:["top","bottom"];return`absolute-${t?a[0]:a[1]}${e?` text-${e}`:""}`}function Ri(e,t){for(let n in e)if(e[n]!==t[n])return!1;return!0}let zi=["left","center","right","justify"];var Ii=h({name:"QTabs",props:{modelValue:[Number,String],align:{type:String,default:"center",validator:e=>zi.includes(e)},breakpoint:{type:[String,Number],default:600},vertical:Boolean,shrink:Boolean,stretch:Boolean,activeClass:String,activeColor:String,activeBgColor:String,indicatorColor:String,leftIcon:String,rightIcon:String,outsideArrows:Boolean,mobileArrows:Boolean,switchIndicator:Boolean,narrowIndicator:Boolean,inlineLabel:Boolean,noCaps:Boolean,dense:Boolean,contentClass:String,"onUpdate:modelValue":[Function,Array]},setup(t,{slots:n,emit:a}){let i,{proxy:r}=(0,e.getCurrentInstance)(),{$q:o}=r,{registerTick:s}=kn(),{registerTick:l}=kn(),{registerTick:u}=kn(),{registerTimeout:c,removeTimeout:d}=xn(),{registerTimeout:h,removeTimeout:p}=xn(),f=(0,e.ref)(null),m=(0,e.ref)(null),_=(0,e.ref)(t.modelValue),g=(0,e.ref)(!1),v=(0,e.ref)(!0),b=(0,e.ref)(!1),y=(0,e.ref)(!1),w=[],k=(0,e.ref)(0),x=(0,e.ref)(!1),S=null,C=null,T=(0,e.computed)(()=>({activeClass:t.activeClass,activeColor:t.activeColor,activeBgColor:t.activeBgColor,indicatorClass:Mi(t.indicatorColor,t.switchIndicator,t.vertical),narrowIndicator:t.narrowIndicator,inlineLabel:t.inlineLabel,noCaps:t.noCaps})),P=(0,e.computed)(()=>{let e=k.value,t=_.value;for(let n=0;n`q-tabs__content--align-${g.value?"left":y.value?"justify":t.align}`),A=(0,e.computed)(()=>`q-tabs row no-wrap items-center q-tabs--${g.value?"":"not-"}scrollable q-tabs--${t.vertical?"vertical":"horizontal"} q-tabs__arrows--${t.outsideArrows?"outside":"inside"} q-tabs--mobile-with${t.mobileArrows?"":"out"}-arrows`+(t.dense?" q-tabs--dense":"")+(t.shrink?" col-shrink":"")+(t.stretch?" self-stretch":"")),L=(0,e.computed)(()=>"q-tabs__content scroll--mobile row no-wrap items-center self-stretch hide-scrollbar relative-position "+E.value+(void 0===t.contentClass?"":` ${t.contentClass}`)),M=(0,e.computed)(()=>t.vertical?{container:"height",content:"offsetHeight",scroll:"scrollHeight"}:{container:"width",content:"offsetWidth",scroll:"scrollWidth"}),R=(0,e.computed)(()=>!t.vertical&&!0===o.lang.rtl),z=(0,e.computed)(()=>!Li&&R.value);function I({name:e,setCurrent:n,skipEmit:i}){_.value!==e&&(!i&&void 0!==t["onUpdate:modelValue"]&&a("update:modelValue",e),(n||void 0===t["onUpdate:modelValue"])&&(function(e,n){let a=null!=e&&""!==e?w.find(t=>t.name.value===e):null,i=null!=n&&""!==n?w.find(e=>e.name.value===n):null;if(X)X=!1;else if(a&&i){let e=a.tabIndicatorRef.value,n=i.tabIndicatorRef.value;null!==S&&(clearTimeout(S),S=null),e.style.transition="none",e.style.transform="none",n.style.transition="none",n.style.transform="none";let r=e.getBoundingClientRect(),o=n.getBoundingClientRect();n.style.transform=t.vertical?`translate3d(0,${r.top-o.top}px,0) scale3d(1,${o.height?r.height/o.height:1},1)`:`translate3d(${r.left-o.left}px,0,0) scale3d(${o.width?r.width/o.width:1},1,1)`,u(()=>{S=setTimeout(()=>{S=null,n.style.transition="transform .25s cubic-bezier(.4, 0, .2, 1)",n.style.transform="none"},70)})}i&&g.value&&j(i.rootRef.value)}(_.value,e),_.value=e))}function N(){s(()=>{f.value&&O({width:f.value.offsetWidth,height:f.value.offsetHeight})})}function O(e){if(void 0===M.value||null===m.value)return;let n=e[M.value.container],a=Math.min(m.value[M.value.scroll],Array.prototype.reduce.call(m.value.children,(e,t)=>e+(t[M.value.content]||0),0)),i=n>0&&a>n;g.value=i,i&&l(D),y.value=n0&&(m.value[t.vertical?"scrollTop":"scrollLeft"]+=Math.ceil(s),D())}function D(){let e=m.value;if(null===e)return;let n=e.getBoundingClientRect(),a=t.vertical?e.scrollTop:Math.abs(e.scrollLeft);R.value?(v.value=Math.ceil(a+n.width)0):(v.value=a>0,b.value=t.vertical?Math.ceil(a+n.height){(function(e){let t=m.value,{get:n,set:a}=U.value,i=!1,r=n(t),o=e=e)&&(i=!0,r=e),a(t,r),D(),i})(e)&&V()},5)}function B(){q(z.value?2**53-1:0)}function F(){q(z.value?0:2**53-1)}function V(){null!==C&&(clearInterval(C),C=null)}(0,e.watch)(R,D),(0,e.watch)(()=>t.modelValue,e=>{I({name:e,setCurrent:!0,skipEmit:!0})}),(0,e.watch)(()=>t.outsideArrows,N);let U=(0,e.computed)(()=>z.value?{get:e=>Math.abs(e.scrollLeft),set:(e,t)=>{e.scrollLeft=-t}}:t.vertical?{get:e=>e.scrollTop,set:(e,t)=>{e.scrollTop=t}}:{get:e=>e.scrollLeft,set:(e,t)=>{e.scrollLeft=t}});function $(){let e=null,t={matchedLen:0,queryDiff:9999,hrefLen:0},n=w.filter(e=>!0===e.routeData?.hasRouterLink.value),{hash:a,query:i}=r.$route,o=Object.keys(i).length;for(let r of n){let n=!0===r.routeData.exact.value;if(!r.routeData[n?"linkIsExactActive":"linkIsActive"].value)continue;let{hash:s,query:l,matched:u,href:c}=r.routeData.resolvedLink.value,d=Object.keys(l).length;if(n){if(s!==a||d!==o||!Ri(i,l))continue;e=r.name.value;break}if(""!==s&&s!==a||0!==d&&!Ri(l,i))continue;let h={matchedLen:u.length,queryDiff:o-d,hrefLen:c.length-s.length};if(h.matchedLen>t.matchedLen)e=r.name.value,t=h;else if(h.matchedLen===t.matchedLen){if(h.queryDifft.hrefLen&&(e=r.name.value,t=h)}}null===e&&w.some(e=>void 0===e.routeData&&e.name.value===_.value)?X=!1:I({name:e,setCurrent:!0})}function H(e){if(d(),!x.value&&null!==f.value&&e.target&&"function"==typeof e.target.closest){let t=e.target.closest(".q-tab");t&&f.value.contains(t)&&(x.value=!0,g.value&&j(t))}}function W(){c(()=>{x.value=!1},30)}function G(){!1===Y.avoidRouteWatcher?h($):p()}function K(){if(void 0===i){let t=(0,e.watch)(()=>r.$route.fullPath,G);i=()=>{t(),i=void 0}}}let Y={currentModel:_,tabProps:T,hasFocus:x,hasActiveTab:P,registerTab:function(e){w.push(e),k.value++,N(),void 0===e.routeData||void 0===r.$route?h(()=>{if(g.value){let e=_.value,t=null!=e&&""!==e?w.find(t=>t.name.value===e):null;t&&j(t.rootRef.value)}}):(K(),e.routeData.hasRouterLink.value&&G())},unregisterTab:function(e){w.splice(w.indexOf(e),1),k.value--,N(),void 0!==i&&void 0!==e.routeData&&(w.every(e=>void 0===e.routeData)&&i(),G())},verifyRouteModel:G,updateModel:I,onKbdNavigate:function(e,n){let a=Array.prototype.filter.call(m.value.children,e=>e===n||e.matches?.(".q-tab.q-focusable")),i=a.length;if(0===i)return;if(36===e)return j(a[0]),a[0].focus(),!0;if(35===e)return j(a[i-1]),a[i-1].focus(),!0;let r=e===(t.vertical?38:37),o=e===(t.vertical?40:39),s=r?-1:o?1:void 0;if(void 0!==s){let e=!0!==t.vertical&&R.value?-1:1,r=(a.indexOf(n)+s*e+i)%i;return j(a[r]),a[r].focus({preventScroll:!0}),!0}},avoidRouteWatcher:!1};function Q(){null!==S&&clearTimeout(S),V(),i?.()}(0,e.provide)(J,Y);let Z=!1,X=!1;return(0,e.onBeforeUnmount)(Q),(0,e.onDeactivated)(()=>{Z=void 0!==i,Q()}),(0,e.onActivated)(()=>{Z&&(K(),X=!0,G()),N()}),()=>(0,e.h)("div",{ref:f,class:A.value,role:"tablist","aria-orientation":t.vertical?"vertical":"horizontal",onFocusin:H,onFocusout:W},[(0,e.h)(Ai,{onResize:O}),(0,e.h)("div",{ref:m,class:L.value,onScroll:D},Ae(n.default)),(0,e.h)(Ke,{class:"q-tabs__arrow q-tabs__arrow--left absolute q-tab__icon"+(v.value?"":" q-tabs__arrow--faded"),name:t.leftIcon||o.iconSet.tabs[t.vertical?"up":"left"],onMousedownPassive:B,onTouchstartPassive:B,onMouseupPassive:V,onMouseleavePassive:V,onTouchendPassive:V}),(0,e.h)(Ke,{class:"q-tabs__arrow q-tabs__arrow--right absolute q-tab__icon"+(b.value?"":" q-tabs__arrow--faded"),name:t.rightIcon||o.iconSet.tabs[t.vertical?"down":"right"],onMousedownPassive:F,onTouchstartPassive:F,onMouseupPassive:V,onMouseleavePassive:V,onTouchendPassive:V})])}});let Ni=0,Oi=["click","keydown"],ji={icon:String,label:[Number,String],alert:[Boolean,String],alertIcon:String,name:{type:[Number,String],default:()=>"t_"+Ni++},noCaps:Boolean,tabindex:[String,Number],disable:Boolean,contentClass:String,ripple:{type:[Boolean,Object],default:!0}};function Di(t,n,a,i){let r=(0,e.inject)(J,ee);if(r===ee)return console.error("QTab/QRouteTab component needs to be child of QTabs"),ee;let{proxy:o}=(0,e.getCurrentInstance)(),s=(0,e.ref)(null),l=(0,e.ref)(null),u=(0,e.ref)(null),c=(0,e.computed)(()=>!t.disable&&!1!==t.ripple&&{keyCodes:[13,32],early:!0,...!0===t.ripple?{}:t.ripple}),d=(0,e.computed)(()=>r.currentModel.value===t.name),h=(0,e.computed)(()=>"q-tab relative-position self-stretch flex flex-center text-center"+(d.value?" q-tab--active"+(r.tabProps.value.activeClass?" "+r.tabProps.value.activeClass:"")+(r.tabProps.value.activeColor?` text-${r.tabProps.value.activeColor}`:"")+(r.tabProps.value.activeBgColor?` bg-${r.tabProps.value.activeBgColor}`:""):" q-tab--inactive")+(t.icon&&t.label&&!r.tabProps.value.inlineLabel?" q-tab--full":"")+(t.noCaps||r.tabProps.value.noCaps?" q-tab--no-caps":"")+(t.disable?" disabled":" q-focusable q-hoverable cursor-pointer")+(void 0===i?"":i.linkClass.value)),p=(0,e.computed)(()=>"q-tab__content self-stretch flex-center relative-position q-anchor--skip non-selectable "+(r.tabProps.value.inlineLabel?"row no-wrap q-tab__content--inline":"column")+(void 0===t.contentClass?"":` ${t.contentClass}`)),f=(0,e.computed)(()=>t.disable||r.hasFocus.value||!d.value&&r.hasActiveTab.value?-1:t.tabindex||0);function m(e,n){if(!n&&!e?.qAvoidFocus&&s.value?.focus(),t.disable)!0===i?.hasRouterLink.value&&w(e);else{if(void 0===i)return r.updateModel({name:t.name}),void a("click",e);if(i.hasRouterLink.value){let n=(n={})=>{let a,o=void 0===n.to||te(n.to,t.to)?r.avoidRouteWatcher=_a():null;return i.navigateToRouterLink(e,{...n,returnRouterError:!0}).catch(e=>{a=e}).then(e=>{if(o===r.avoidRouteWatcher&&(r.avoidRouteWatcher=!1,void 0===a&&(void 0===e||!0===e.message?.startsWith("Avoided redundant navigation"))&&r.updateModel({name:t.name})),n.returnRouterError)return void 0===a?e:Promise.reject(a)})};return a("click",e,n),void(e.defaultPrevented||n())}a("click",e)}}function _(e){N(e,[13,32])?m(e,!0):!I(e)&&e.keyCode>=35&&e.keyCode<=40&&!e.altKey&&!e.metaKey&&r.onKbdNavigate(e.keyCode,o.$el)&&w(e),a("keydown",e)}function g(){let a=r.tabProps.value.narrowIndicator,i=[],o=(0,e.h)("div",{ref:u,class:["q-tab__indicator",r.tabProps.value.indicatorClass]});void 0!==t.icon&&i.push((0,e.h)(Ke,{class:"q-tab__icon",name:t.icon})),void 0!==t.label&&i.push((0,e.h)("div",{class:"q-tab__label"},t.label)),t.alert&&i.push(void 0===t.alertIcon?(0,e.h)("div",{class:"q-tab__alert"+(!0===t.alert?"":` text-${t.alert}`)}):(0,e.h)(Ke,{class:"q-tab__alert-icon",color:!0===t.alert?void 0:t.alert,name:t.alertIcon})),a&&i.push(o);let l=[(0,e.h)("div",{class:"q-focus-helper",tabindex:-1,ref:s}),(0,e.h)("div",{class:p.value},Me(n.default,i))];return a||l.push(o),l}let v={name:(0,e.computed)(()=>t.name),rootRef:l,tabIndicatorRef:u,routeData:i};return(0,e.onBeforeUnmount)(()=>{r.unregisterTab(v)}),(0,e.onMounted)(()=>{r.registerTab(v)}),{renderTab:function(n,a){return(0,e.withDirectives)((0,e.h)(n,{ref:l,class:h.value,tabindex:f.value,role:"tab","aria-selected":d.value?"true":"false","aria-disabled":t.disable?"true":void 0,onClick:m,onKeydown:_,...a},g()),[[zt,c.value]])},$tabs:r}}var qi=h({name:"QTab",props:ji,emits:Oi,setup(e,{slots:t,emit:n}){let{renderTab:a}=Di(e,t,n);return()=>a("div")}}),Bi=h({name:"QTabPanels",props:{...Ba,...Je},emits:Fa,setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),{updatePanelsList:i,getPanelContent:r,panelDirectives:o}=Ua(),s=(0,e.computed)(()=>"q-tab-panels q-panel-parent"+(a.value?" q-tab-panels--dark q-dark":""));return()=>(i(n),ze("div",{class:s.value},r(),"pan",t.swipeable,()=>o.value))}}),Fi=h({name:"QTabPanel",props:Da,setup:(t,{slots:n})=>()=>(0,e.h)("div",{class:"q-tab-panel",role:"tabpanel"},Ae(n.default))});let Vi=/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/,Ui=/^#[0-9a-fA-F]{4}([0-9a-fA-F]{4})?$/,$i=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Hi=/^rgb\(((0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),){2}(0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5])\)$/,Wi=/^rgba\(((0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),){2}(0|[1-9][\d]?|1[\d]{0,2}|2[\d]?|2[0-4][\d]|25[0-5]),(0|0\.[0-9]+[1-9]|0\.[1-9]+|1)\)$/,Gi=/^-?[\d]+\/[0-1]\d\/[0-3]\d$/,Ki=/^([0-1]?\d|2[0-3]):[0-5]\d$/,Yi=/^([0-1]?\d|2[0-3]):[0-5]\d:[0-5]\d$/,Qi=/^([0-1]?\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/,Zi=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,Ji={date:e=>Gi.test(e),time:e=>Ki.test(e),fulltime:e=>Yi.test(e),timeOrFulltime:e=>Qi.test(e),email:e=>Zi.test(e),hexColor:e=>Vi.test(e),hexaColor:e=>Ui.test(e),hexOrHexaColor:e=>$i.test(e),rgbColor:e=>Hi.test(e),rgbaColor:e=>Wi.test(e),rgbOrRgbaColor:e=>Hi.test(e)||Wi.test(e),hexOrRgbColor:e=>Vi.test(e)||Hi.test(e),hexaOrRgbaColor:e=>Ui.test(e)||Wi.test(e),anyColor:e=>$i.test(e)||Hi.test(e)||Wi.test(e)};var Xi={testPattern:Ji};let er=/^rgb(a)?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?([01]?\.?\d*?)?\)$/;function tr({r:e,g:t,b:n,a:a}){let i=void 0!==a;if(e=Math.round(e),t=Math.round(t),n=Math.round(n),e>255||t>255||n>255||i&&a>100)throw TypeError("Expected 3 numbers below 256 (and optionally one below 100)");return a=i?(256|Math.round(255*a/100)).toString(16).slice(1):"","#"+(n|t<<8|e<<16|1<<24).toString(16).slice(1)+a}function nr({r:e,g:t,b:n,a:a}){return`rgb${void 0===a?"":"a"}(${e},${t},${n}${void 0===a?"":","+a/100})`}function ar(e){if("string"!=typeof e)throw TypeError("Expected a string");3===(e=e.replace(/^#/,"")).length?e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]:4===e.length&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]);let t=Number.parseInt(e,16);return e.length>6?{r:t>>24&255,g:t>>16&255,b:t>>8&255,a:Math.round((255&t)/2.55)}:{r:t>>16,g:t>>8&255,b:255&t}}function ir({h:e,s:t,v:n,a:a}){let i,r,o;t/=100,n/=100,e/=360;let s=Math.floor(6*e),l=6*e-s,u=n*(1-t),c=n*(1-l*t),d=n*(1-(1-l)*t);switch(s%6){case 0:i=n,r=d,o=u;break;case 1:i=c,r=n,o=u;break;case 2:i=u,r=n,o=d;break;case 3:i=u,r=c,o=n;break;case 4:i=d,r=u,o=n;break;case 5:i=n,r=u,o=c}return{r:Math.round(255*i),g:Math.round(255*r),b:Math.round(255*o),a:a}}function rr({r:e,g:t,b:n,a:a}){let i,r=Math.max(e,t,n),o=Math.min(e,t,n),s=r-o,l=0===r?0:s/r,u=r/255;switch(r){case o:i=0;break;case e:i=t-n+s*(t1)throw TypeError("Expected offset to be between -1 and 1");let{r:n,g:a,b:i,a:r}=or(e),o=void 0===r?0:r/100;return tr({r:n,g:a,b:i,a:Math.round(100*Math.min(1,Math.max(0,o+t)))})},getPaletteColor:function(e){if("string"!=typeof e)throw TypeError("Expected a string as color");let t=document.createElement("div");t.className=`text-${e} invisible fixed no-pointer-events`,document.body.append(t);let n=getComputedStyle(t).getPropertyValue("color");return t.remove(),tr(or(n))}};let ur="rgb(255,204,204).rgb(255,230,204).rgb(255,255,204).rgb(204,255,204).rgb(204,255,230).rgb(204,255,255).rgb(204,230,255).rgb(204,204,255).rgb(230,204,255).rgb(255,204,255).rgb(255,153,153).rgb(255,204,153).rgb(255,255,153).rgb(153,255,153).rgb(153,255,204).rgb(153,255,255).rgb(153,204,255).rgb(153,153,255).rgb(204,153,255).rgb(255,153,255).rgb(255,102,102).rgb(255,179,102).rgb(255,255,102).rgb(102,255,102).rgb(102,255,179).rgb(102,255,255).rgb(102,179,255).rgb(102,102,255).rgb(179,102,255).rgb(255,102,255).rgb(255,51,51).rgb(255,153,51).rgb(255,255,51).rgb(51,255,51).rgb(51,255,153).rgb(51,255,255).rgb(51,153,255).rgb(51,51,255).rgb(153,51,255).rgb(255,51,255).rgb(255,0,0).rgb(255,128,0).rgb(255,255,0).rgb(0,255,0).rgb(0,255,128).rgb(0,255,255).rgb(0,128,255).rgb(0,0,255).rgb(128,0,255).rgb(255,0,255).rgb(245,0,0).rgb(245,123,0).rgb(245,245,0).rgb(0,245,0).rgb(0,245,123).rgb(0,245,245).rgb(0,123,245).rgb(0,0,245).rgb(123,0,245).rgb(245,0,245).rgb(214,0,0).rgb(214,108,0).rgb(214,214,0).rgb(0,214,0).rgb(0,214,108).rgb(0,214,214).rgb(0,108,214).rgb(0,0,214).rgb(108,0,214).rgb(214,0,214).rgb(163,0,0).rgb(163,82,0).rgb(163,163,0).rgb(0,163,0).rgb(0,163,82).rgb(0,163,163).rgb(0,82,163).rgb(0,0,163).rgb(82,0,163).rgb(163,0,163).rgb(92,0,0).rgb(92,46,0).rgb(92,92,0).rgb(0,92,0).rgb(0,92,46).rgb(0,92,92).rgb(0,46,92).rgb(0,0,92).rgb(46,0,92).rgb(92,0,92).rgb(255,255,255).rgb(205,205,205).rgb(178,178,178).rgb(153,153,153).rgb(127,127,127).rgb(102,102,102).rgb(76,76,76).rgb(51,51,51).rgb(25,25,25).rgb(0,0,0)".split("."),cr="M5 5 h10 v10 h-10 v-10 z",dr=/^[0-9]+$/,hr=/^#[0-9A-Fa-f]+$/,pr=/^rgb\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3}\)$/,fr=/^rgba\([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},(0|0\.[0-9]+[1-9]|0\.[1-9]+|1)\)$/;var mr=h({name:"QColor",props:{...Je,...wa,modelValue:String,defaultValue:String,defaultView:{type:String,default:"spectrum",validator:e=>["spectrum","tune","palette"].includes(e)},formatModel:{type:String,default:"auto",validator:e=>["auto","hex","rgb","hexa","rgba"].includes(e)},palette:Array,noHeader:Boolean,noHeaderTabs:Boolean,noFooter:Boolean,square:Boolean,flat:Boolean,bordered:Boolean,disable:Boolean,readonly:Boolean},emits:["update:modelValue","change"],setup(t,{emit:n}){let{proxy:a}=(0,e.getCurrentInstance)(),{$q:i}=a,r=Xe(t,i),{getCache:o}=ja(),s=(0,e.ref)(null),l=(0,e.ref)(null),u=(0,e.computed)(()=>"auto"===t.formatModel?null:t.formatModel.includes("hex")),c=(0,e.computed)(()=>"auto"===t.formatModel?null:t.formatModel.includes("a")),d=(0,e.ref)("auto"===t.formatModel?void 0===t.modelValue||null===t.modelValue||""===t.modelValue||t.modelValue.startsWith("#")?"hex":"rgb":t.formatModel.startsWith("hex")?"hex":"rgb"),h=(0,e.ref)(t.defaultView),p=(0,e.ref)(A(t.modelValue||t.defaultValue)),f=(0,e.computed)(()=>!t.disable&&!t.readonly),m=(0,e.computed)(()=>void 0===t.modelValue||null===t.modelValue||""===t.modelValue||t.modelValue.startsWith("#")),_=(0,e.computed)(()=>null===u.value?m.value:u.value),g=xa((0,e.computed)(()=>({type:"hidden",name:t.name,value:p.value[_.value?"hex":"rgb"]}))),v=(0,e.computed)(()=>null===c.value?void 0!==p.value.a:c.value),y=(0,e.computed)(()=>({backgroundColor:p.value.rgb||"#000"})),w=(0,e.computed)(()=>"q-color-picker__header-content q-color-picker__header-content--"+(void 0!==p.value.a&&p.value.a<65||sr(p.value)>.4?"light":"dark")),k=(0,e.computed)(()=>({background:`hsl(${p.value.h},100%,50%)`})),x=(0,e.computed)(()=>({top:100-p.value.v+"%",[i.lang.rtl?"right":"left"]:`${p.value.s}%`})),S=(0,e.computed)(()=>void 0!==t.palette&&0!==t.palette.length?t.palette:ur),C=(0,e.computed)(()=>"q-color-picker"+(t.bordered?" q-color-picker--bordered":"")+(t.square?" q-color-picker--square no-border-radius":"")+(t.flat?" q-color-picker--flat no-shadow":"")+(t.disable?" disabled":"")+(r.value?" q-color-picker--dark q-dark":"")),T=(0,e.computed)(()=>t.disable?{"aria-disabled":"true"}:{}),P=(0,e.computed)(()=>[[gi,N,void 0,{prevent:!0,stop:!0,mouse:!0}]]);function E(e,t){p.value.hex=tr(e),p.value.rgb=nr(e),p.value.r=e.r,p.value.g=e.g,p.value.b=e.b,p.value.a=e.a;let a=p.value[_.value?"hex":"rgb"];n("update:modelValue",a),t&&n("change",a)}function A(e){let n=void 0===c.value?"auto"===t.formatModel?null:t.formatModel.includes("a"):c.value;if("string"!=typeof e||0===e.length||!Ji.anyColor(e.replaceAll(" ","")))return{h:0,s:0,v:0,r:0,g:0,b:0,a:n?100:void 0,hex:void 0,rgb:void 0};let a=or(e);return n&&void 0===a.a&&(a.a=100),a.hex=tr(a),a.rgb=nr(a),Object.assign(a,rr(a))}function L(e,t,n){let a=s.value;if(null===a)return;let r=a.clientWidth,o=a.clientHeight,l=a.getBoundingClientRect(),u=Math.min(r,Math.max(0,e-l.left));i.lang.rtl&&(u=r-u);let c=Math.min(o,Math.max(0,t-l.top)),d=Math.round(100*u/r),h=Math.round(100*Math.max(0,Math.min(1,-c/o+1))),f=ir({h:p.value.h,s:d,v:h,a:v.value?p.value.a:void 0});p.value.s=d,p.value.v=h,E(f,n)}function M(e,t){let n=Math.round(e),a=ir({h:n,s:p.value.s,v:p.value.v,a:v.value?p.value.a:void 0});p.value.h=n,E(a,t)}function R(e){M(e,!0)}function z(t,n,i,r,o){if(void 0!==r&&b(r),!dr.test(t))return void(o&&a.$forceUpdate());let s=Math.floor(Number(t));if(s<0||s>i)return void(o&&a.$forceUpdate());let l={r:"r"===n?s:p.value.r,g:"g"===n?s:p.value.g,b:"b"===n?s:p.value.b,a:v.value?"a"===n?s:p.value.a:void 0};if("a"!==n){let e=rr(l);p.value.h=e.h,p.value.s=e.s,p.value.v=e.v}if(E(l,o),!o&&void 0!==r?.target.selectionEnd){let t=r.target.selectionEnd;(0,e.nextTick)(()=>{r.target.setSelectionRange(t,t)})}}function I(t,n){let a,i=t.target.value;if(b(t),"hex"===d.value){if(i.length!==(v.value?9:7)||!hr.test(i))return!0;a=ar(i)}else{let e;if(!i.endsWith(")"))return!0;if(!v.value&&i.startsWith("rgb(")){if(e=i.slice(4,-1).split(",").map(e=>Number.parseInt(e,10)),3!==e.length||!pr.test(i))return!0}else{if(!v.value||!i.startsWith("rgba("))return!0;{if(e=i.slice(5,-1).split(","),4!==e.length||!fr.test(i))return!0;for(let t=0;t<3;t++){let n=Number.parseInt(e[t],10);if(n<0||n>255)return!0;e[t]=n}let t=Number.parseFloat(e[3]);if(t<0||t>1)return!0;e[3]=t}}if(e[0]<0||e[0]>255||e[1]<0||e[1]>255||e[2]<0||e[2]>255||v.value&&(e[3]<0||e[3]>1))return!0;a={r:e[0],g:e[1],b:e[2],a:v.value?100*e[3]:void 0}}let r=rr(a);if(p.value.h=r.h,p.value.s=r.s,p.value.v=r.v,E(a,n),!n){let n=t.target.selectionEnd;(0,e.nextTick)(()=>{t.target.setSelectionRange(n,n)})}}function N(e){e.isFinal?L(e.position.left,e.position.top,!0):O(e)}(0,e.watch)(()=>t.modelValue,e=>{let n=A(e||t.defaultValue);n.hex!==p.value.hex&&(p.value=n)}),(0,e.watch)(()=>t.defaultValue,e=>{if(!t.modelValue&&e){let t=A(e);t.hex!==p.value.hex&&(p.value=t)}});let O=Lt(e=>{L(e.position.left,e.position.top)},20);function j(e){L(e.pageX-window.pageXOffset,e.pageY-window.pageYOffset,!0)}function D(e){L(e.pageX-window.pageXOffset,e.pageY-window.pageYOffset)}function q(e){null!==l.value&&(l.value.$el.style.opacity=+!!e)}function B(e){d.value=e}function F(e){h.value=e}function V(){let t={ref:s,class:"q-color-picker__spectrum non-selectable relative-position cursor-pointer"+(f.value?"":" readonly"),style:k.value,...f.value?{onClick:j,onMousedown:D}:{}},n=[(0,e.h)("div",{style:{paddingBottom:"100%"}}),(0,e.h)("div",{class:"q-color-picker__spectrum-white absolute-full"}),(0,e.h)("div",{class:"q-color-picker__spectrum-black absolute-full"}),(0,e.h)("div",{class:"absolute",style:x.value},[void 0===p.value.hex?null:(0,e.h)("div",{class:"q-color-picker__spectrum-circle"})])],a=[(0,e.h)(Ci,{class:"q-color-picker__hue non-selectable",modelValue:p.value.h,min:0,max:360,trackSize:"8px",innerTrackColor:"transparent",selectionColor:"transparent",readonly:!f.value,thumbPath:cr,"onUpdate:modelValue":M,onChange:R})];return v.value&&a.push((0,e.h)(Ci,{class:"q-color-picker__alpha non-selectable",modelValue:p.value.a,min:0,max:100,trackSize:"8px",trackColor:"white",innerTrackColor:"transparent",selectionColor:"transparent",trackImg:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAH0lEQVQoU2NkYGAwZkAFZ5G5jPRRgOYEVDeB3EBjBQBOZwTVugIGyAAAAABJRU5ErkJggg==",readonly:!f.value,hideSelection:!0,thumbPath:cr,...o("alphaSlide",{"onUpdate:modelValue":e=>z(e,"a",100),onChange:e=>z(e,"a",100,void 0,!0)})})),[ze("div",t,n,"spec",f.value,()=>P.value),(0,e.h)("div",{class:"q-color-picker__sliders"},a)]}function U(){return[(0,e.h)("div",{class:"row items-center no-wrap"},[(0,e.h)("div","R"),(0,e.h)(Ci,{modelValue:p.value.r,min:0,max:255,color:"red",dark:r.value,readonly:!f.value,...o("rSlide",{"onUpdate:modelValue":e=>z(e,"r",255),onChange:e=>z(e,"r",255,void 0,!0)})}),(0,e.h)("input",{value:p.value.r,maxlength:3,readonly:!f.value,onChange:b,...o("rIn",{onInput:e=>z(e.target.value,"r",255,e),onBlur:e=>z(e.target.value,"r",255,e,!0)})})]),(0,e.h)("div",{class:"row items-center no-wrap"},[(0,e.h)("div","G"),(0,e.h)(Ci,{modelValue:p.value.g,min:0,max:255,color:"green",dark:r.value,readonly:!f.value,...o("gSlide",{"onUpdate:modelValue":e=>z(e,"g",255),onChange:e=>z(e,"g",255,void 0,!0)})}),(0,e.h)("input",{value:p.value.g,maxlength:3,readonly:!f.value,onChange:b,...o("gIn",{onInput:e=>z(e.target.value,"g",255,e),onBlur:e=>z(e.target.value,"g",255,e,!0)})})]),(0,e.h)("div",{class:"row items-center no-wrap"},[(0,e.h)("div","B"),(0,e.h)(Ci,{modelValue:p.value.b,min:0,max:255,color:"blue",readonly:!f.value,dark:r.value,...o("bSlide",{"onUpdate:modelValue":e=>z(e,"b",255),onChange:e=>z(e,"b",255,void 0,!0)})}),(0,e.h)("input",{value:p.value.b,maxlength:3,readonly:!f.value,onChange:b,...o("bIn",{onInput:e=>z(e.target.value,"b",255,e),onBlur:e=>z(e.target.value,"b",255,e,!0)})})]),v.value?(0,e.h)("div",{class:"row items-center no-wrap"},[(0,e.h)("div","A"),(0,e.h)(Ci,{modelValue:p.value.a,color:"grey",readonly:!f.value,dark:r.value,...o("aSlide",{"onUpdate:modelValue":e=>z(e,"a",100),onChange:e=>z(e,"a",100,void 0,!0)})}),(0,e.h)("input",{value:p.value.a,maxlength:3,readonly:!f.value,onChange:b,...o("aIn",{onInput:e=>z(e.target.value,"a",100,e),onBlur:e=>z(e.target.value,"a",100,e,!0)})})]):null]}function $(){return[(0,e.h)("div",{class:"row items-center q-color-picker__palette-rows"+(f.value?" q-color-picker__palette-rows--editable":"")},S.value.map(t=>(0,e.h)("div",{class:"q-color-picker__cube col-auto",style:{backgroundColor:t},...f.value?o("palette#"+t,{onClick:()=>{!function(e){let t=A(e),n={r:t.r,g:t.g,b:t.b,a:t.a};void 0===n.a&&(n.a=p.value.a),p.value.h=t.h,p.value.s=t.s,p.value.v=t.v,E(n,!0)}(t)}}):{}})))]}return()=>{let n=[(0,e.h)(Bi,{modelValue:h.value,animated:!0},()=>[(0,e.h)(Fi,{class:"q-color-picker__spectrum-tab overflow-hidden",name:"spectrum"},V),(0,e.h)(Fi,{class:"q-pa-md q-color-picker__tune-tab",name:"tune"},U),(0,e.h)(Fi,{class:"q-color-picker__palette-tab",name:"palette"},$)])];return void 0!==t.name&&!t.disable&&g(n,"push"),t.noHeader||n.unshift(function(){let n=[];return t.noHeaderTabs||n.push((0,e.h)(Ii,{class:"q-color-picker__header-tabs",modelValue:d.value,dense:!0,align:"justify","onUpdate:modelValue":B},()=>[(0,e.h)(qi,{label:"HEX"+(v.value?"A":""),name:"hex",ripple:!1}),(0,e.h)(qi,{label:"RGB"+(v.value?"A":""),name:"rgb",ripple:!1})])),n.push((0,e.h)("div",{class:"q-color-picker__header-banner row flex-center no-wrap"},[(0,e.h)("input",{class:"fit",value:p.value[d.value],...f.value?{}:{readonly:!0},...o("topIn",{onInput:e=>{q(I(e))},onChange:b,onBlur:e=>{I(e,!0)&&a.$forceUpdate(),q(!1)}})}),(0,e.h)(Ke,{ref:l,class:"q-color-picker__error-icon absolute no-pointer-events",name:i.iconSet.type.negative})])),(0,e.h)("div",{class:"q-color-picker__header relative-position overflow-hidden"},[(0,e.h)("div",{class:"q-color-picker__header-bg absolute-full"}),(0,e.h)("div",{class:w.value,style:y.value},n)])}()),t.noFooter||n.push((0,e.h)("div",{class:"q-color-picker__footer relative-position overflow-hidden"},[(0,e.h)(Ii,{class:"absolute-full",modelValue:h.value,dense:!0,align:"justify","onUpdate:modelValue":F},()=>[(0,e.h)(qi,{icon:i.iconSet.colorPicker.spectrum,name:"spectrum",ripple:!1}),(0,e.h)(qi,{icon:i.iconSet.colorPicker.tune,name:"tune",ripple:!1}),(0,e.h)(qi,{icon:i.iconSet.colorPicker.palette,name:"palette",ripple:!1})])])),(0,e.h)("div",{class:C.value,...T.value},n)}}});let _r=[-61,9,38,199,426,686,756,818,1111,1181,1210,1635,2060,2097,2192,2262,2324,2394,2456,3178];function gr(e,t,n){return"[object Date]"===Object.prototype.toString.call(e)&&(n=e.getDate(),t=e.getMonth()+1,e=e.getFullYear()),function(e){let t,n,a,i=xr(e).gy,r=i-621,o=wr(r,!1);if(a=e-kr(i,3,o.march),a>=0){if(a<=185)return n=1+Sr(a,31),t=Cr(a,31)+1,{jy:r,jm:n,jd:t};a-=186}else--r,a+=179,1===o.leap&&(a+=1);return n=7+Sr(a,30),t=Cr(a,30)+1,{jy:r,jm:n,jd:t}}(kr(e,t,n))}function vr(e,t,n){return xr(function(e,t,n){let a=wr(e,!0);return kr(a.gy,3,a.march)+31*(t-1)-Sr(t,7)*(t-7)+n-1}(e,t,n))}function br(e){return 0===function(e){let t,n,a,i,r,o=_r.length,s=_r[0];if(e=_r[o-1])throw Error("Invalid Jalaali year "+e);for(r=1;r=_r[s-1])throw Error("Invalid Jalaali year "+e);for(o=1;oTr.includes(e),default:"gregorian"},landscape:Boolean,color:String,textColor:String,square:Boolean,flat:Boolean,bordered:Boolean,readonly:Boolean,disable:Boolean},Er=["update:modelValue"];function Ar(e){return e.year+"/"+ve(e.month)+"/"+ve(e.day)}function Lr(t,n){let a=(0,e.computed)(()=>!t.disable&&!t.readonly),i=(0,e.computed)(()=>a.value?0:-1),r=(0,e.computed)(()=>{let e=[];return void 0!==t.color&&e.push(`bg-${t.color}`),void 0!==t.textColor&&e.push(`text-${t.textColor}`),e.join(" ")});return{editable:a,tabindex:i,headerClass:r,getLocale:function(){return void 0===t.locale?n.lang.date:{...n.lang.date,...t.locale}},getCurrentDate:function(e){let n=new Date,a=e?null:0;if("persian"===t.calendar){let e=gr(n);return{year:e.jy,month:e.jm,day:e.jd}}return{year:n.getFullYear(),month:n.getMonth()+1,day:n.getDate(),hour:a,minute:a,second:a,millisecond:a}}}}let Mr=864e5,Rr=6e4,zr="YYYY-MM-DDTHH:mm:ss.SSSZ",Ir=/\[((?:[^\]\\]|\\]|\\)*)\]|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]/g,Nr=/(\[[^\]]*\])|do|d{1,4}|Mo|M{1,4}|m{1,2}|wo|w{1,2}|Qo|Do|DDDo|D{1,4}|YY(?:YY)?|H{1,2}|h{1,2}|s{1,2}|S{1,3}|Z{1,2}|a{1,2}|[AQExX]|([.*+:?^,\s${}()|\\]+)/g,Or={};function jr(e,t){return void 0===e?void 0===t?V.date:t.date:e}function Dr(e,t=""){let n=e>0?"-":"+",a=Math.abs(e),i=a%60;return n+ve(Math.floor(a/60))+t+ve(i)}function qr(e,t,n){let a=Br(t),i=new Date(e),r=void 0!==a.year||void 0!==a.month||void 0!==a.date?function(e,t,n){let a=e.getFullYear(),i=e.getMonth(),r=e.getDate();return void 0!==t.year&&(a+=n*t.year,delete t.year),void 0!==t.month&&(i+=n*t.month,delete t.month),e.setDate(1),e.setMonth(2),e.setFullYear(a),e.setMonth(i),e.setDate(Math.min(r,Yr(e))),void 0!==t.date&&(e.setDate(e.getDate()+n*t.date),delete t.date),e}(i,a,n):i;for(let e in a){let t=me(e);r[`set${t}`](r[`get${t}`]()+n*a[e])}return r}function Br(e){let t={...e};return void 0!==e.years&&(t.year=e.years,delete t.years),void 0!==e.months&&(t.month=e.months,delete t.months),void 0!==e.days&&(t.date=e.days,delete t.days),void 0!==e.day&&(t.date=e.day,delete t.day),void 0!==e.hour&&(t.hours=e.hour,delete t.hour),void 0!==e.minute&&(t.minutes=e.minute,delete t.minute),void 0!==e.second&&(t.seconds=e.second,delete t.second),void 0!==e.millisecond&&(t.milliseconds=e.millisecond,delete t.millisecond),t}function Fr(e,t,n){let a=Br(t),i=n?"UTC":"",r=new Date(e),o=void 0!==a.year||void 0!==a.month||void 0!==a.date?function(e,t,n){let a=void 0===t.year?e[`get${n}FullYear`]():t.year,i=void 0===t.month?e[`get${n}Month`]():t.month-1,r=new Date(a,i+1,0).getDate(),o=Math.min(r,void 0===t.date?e[`get${n}Date`]():t.date);return e[`set${n}Date`](1),e[`set${n}Month`](2),e[`set${n}FullYear`](a),e[`set${n}Month`](i),e[`set${n}Date`](o),delete t.year,delete t.month,delete t.date,e}(r,a,i):r;for(let e in a)o[`set${i}${e.at(0).toUpperCase()+e.slice(1)}`](a[e]);return o}function Vr(e,t,n,a,i){let r={year:null,month:null,day:null,hour:null,minute:null,second:null,millisecond:null,timezoneOffset:null,dateHash:null,timeHash:null};if(void 0!==i&&Object.assign(r,i),null==e||""===e||"string"!=typeof e)return r;void 0===t&&(t=zr);let o=jr(n,$.props),s=o.months,l=o.monthsShort,{regex:u,map:c}=function(e,t){let n="("+t.days.join("|")+")",a=e+n;if(void 0!==Or[a])return Or[a];let i="("+t.daysShort.join("|")+")",r="("+t.months.join("|")+")",o="("+t.monthsShort.join("|")+")",s={},l=0,u=e.replace(Nr,e=>{switch(l++,e){case"YY":return s.YY=l,String.raw`(-?\d{1,2})`;case"YYYY":return s.YYYY=l,String.raw`(-?\d{1,4})`;case"M":return s.M=l,String.raw`(\d{1,2})`;case"Mo":return s.M=l++,String.raw`(\d{1,2}(st|nd|rd|th))`;case"MM":return s.M=l,String.raw`(\d{2})`;case"MMM":return s.MMM=l,o;case"MMMM":return s.MMMM=l,r;case"D":return s.D=l,String.raw`(\d{1,2})`;case"Do":return s.D=l++,String.raw`(\d{1,2}(st|nd|rd|th))`;case"DD":return s.D=l,String.raw`(\d{2})`;case"H":return s.H=l,String.raw`(\d{1,2})`;case"HH":return s.H=l,String.raw`(\d{2})`;case"h":return s.h=l,String.raw`(\d{1,2})`;case"hh":return s.h=l,String.raw`(\d{2})`;case"m":return s.m=l,String.raw`(\d{1,2})`;case"mm":return s.m=l,String.raw`(\d{2})`;case"s":return s.s=l,String.raw`(\d{1,2})`;case"ss":return s.s=l,String.raw`(\d{2})`;case"S":return s.S=l,String.raw`(\d{1})`;case"SS":return s.S=l,String.raw`(\d{2})`;case"SSS":return s.S=l,String.raw`(\d{3})`;case"A":return s.A=l,"(AM|PM)";case"a":return s.a=l,"(am|pm)";case"aa":return s.aa=l,String.raw`(a\.m\.|p\.m\.)`;case"ddd":return i;case"dddd":return n;case"Q":case"d":case"E":return String.raw`(\d{1})`;case"do":return l++,String.raw`(\d{1}(st|nd|rd|th))`;case"Qo":return"(1st|2nd|3rd|4th)";case"DDD":case"DDDD":return String.raw`(\d{1,3})`;case"DDDo":return l++,String.raw`(\d{1,3}(st|nd|rd|th))`;case"w":return String.raw`(\d{1,2})`;case"wo":return l++,String.raw`(\d{1,2}(st|nd|rd|th))`;case"ww":return String.raw`(\d{2})`;case"Z":return s.Z=l,String.raw`(Z|[+-]\d{2}:\d{2})`;case"ZZ":return s.ZZ=l,String.raw`(Z|[+-]\d{2}\d{2})`;case"X":return s.X=l,String.raw`(-?\d+)`;case"x":return s.x=l,String.raw`(-?\d{4,})`;default:return l--,"["===e[0]&&(e=e.slice(1,-1)),e.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`)}}),c={map:s,regex:RegExp("^"+u)};return Or[a]=c,c}(t,o),d=e.match(u);if(null===d)return r;let h="";if(void 0!==c.X||void 0!==c.x){let e=Number.parseInt(d[c.X??c.x],10);if(Number.isNaN(e)||e<0)return r;let t=new Date(e*(void 0===c.X?1:1e3));r.year=t.getFullYear(),r.month=t.getMonth()+1,r.day=t.getDate(),r.hour=t.getHours(),r.minute=t.getMinutes(),r.second=t.getSeconds(),r.millisecond=t.getMilliseconds()}else{if(void 0!==c.YYYY)r.year=Number.parseInt(d[c.YYYY],10);else if(void 0!==c.YY){let e=Number.parseInt(d[c.YY],10);r.year=e<0?e:2e3+e}if(void 0!==c.M){if(r.month=Number.parseInt(d[c.M],10),r.month<1||r.month>12)return r}else void 0===c.MMM?void 0!==c.MMMM&&(r.month=s.indexOf(d[c.MMMM])+1):r.month=l.indexOf(d[c.MMM])+1;if(void 0!==c.D){if(r.day=Number.parseInt(d[c.D],10),null===r.year||null===r.month||r.day<1)return r;let e="persian"===a?yr(r.year,r.month):new Date(r.year,r.month,0).getDate();if(r.day>e)return r}void 0===c.H?void 0!==c.h&&(r.hour=Number.parseInt(d[c.h],10)%12,(c.A&&"PM"===d[c.A]||c.a&&"pm"===d[c.a]||c.aa&&"p.m."===d[c.aa])&&(r.hour+=12),r.hour%=24):r.hour=Number.parseInt(d[c.H],10)%24,void 0!==c.m&&(r.minute=Number.parseInt(d[c.m],10)%60),void 0!==c.s&&(r.second=Number.parseInt(d[c.s],10)%60),void 0!==c.S&&(r.millisecond=Number.parseInt(d[c.S],10)*10**(3-d[c.S].length)),(void 0!==c.Z||void 0!==c.ZZ)&&(h=void 0===c.Z?d[c.ZZ]:d[c.Z].replace(":",""),r.timezoneOffset=("+"===h[0]?-1:1)*(60*h.slice(1,3)+Number(h.slice(3,5))))}return r.dateHash=ve(r.year,4)+"/"+ve(r.month)+"/"+ve(r.day),r.timeHash=ve(r.hour)+":"+ve(r.minute)+":"+ve(r.second)+h,r}function Ur(e){let t=new Date(e.getFullYear(),e.getMonth(),e.getDate());t.setDate(t.getDate()-(t.getDay()+6)%7+3);let n=new Date(t.getFullYear(),0,4);n.setDate(n.getDate()-(n.getDay()+6)%7+3);let a=t.getTimezoneOffset()-n.getTimezoneOffset();t.setHours(t.getHours()-a);let i=(t-n)/(7*Mr);return 1+Math.floor(i)}function $r(e,t){let n=new Date(e);return t?function(e){return 1e4*e.getFullYear()+100*e.getMonth()+e.getDate()}(n):n.getTime()}function Hr(e,t,n){let a=new Date(e),i="set"+(n?"UTC":"");switch(t){case"year":case"years":a[`${i}Month`](0);case"month":case"months":a[`${i}Date`](1);case"day":case"days":case"date":a[`${i}Hours`](0);case"hour":case"hours":a[`${i}Minutes`](0);case"minute":case"minutes":a[`${i}Seconds`](0);case"second":case"seconds":a[`${i}Milliseconds`](0)}return a}function Wr(e,t,n){return(e.getTime()-e.getTimezoneOffset()*Rr-(t.getTime()-t.getTimezoneOffset()*Rr))/n}function Gr(e,t,n="days"){let a=new Date(e),i=new Date(t);switch(n){case"years":case"year":return a.getFullYear()-i.getFullYear();case"months":case"month":return 12*(a.getFullYear()-i.getFullYear())+a.getMonth()-i.getMonth();case"days":case"day":case"date":return Wr(Hr(a,"day"),Hr(i,"day"),Mr);case"hours":case"hour":return Wr(Hr(a,"hour"),Hr(i,"hour"),36e5);case"minutes":case"minute":return Wr(Hr(a,"minute"),Hr(i,"minute"),Rr);case"seconds":case"second":return Wr(Hr(a,"second"),Hr(i,"second"),1e3)}}function Kr(e){return Gr(e,Hr(e,"year"),"days")+1}function Yr(e){return new Date(e.getFullYear(),e.getMonth()+1,0).getDate()}function Qr(e){if(e>=11&&e<=13)return`${e}th`;switch(e%10){case 1:return`${e}st`;case 2:return`${e}nd`;case 3:return`${e}rd`}return`${e}th`}let Zr={YY(e,t,n){let a=this.YYYY(e,t,n)%100;return a>=0?ve(a):"-"+ve(Math.abs(a))},YYYY:(e,t,n)=>n??e.getFullYear(),M:e=>e.getMonth()+1,Mo:e=>Qr(e.getMonth()+1),MM:e=>ve(e.getMonth()+1),MMM:(e,t)=>t.monthsShort[e.getMonth()],MMMM:(e,t)=>t.months[e.getMonth()],Q:e=>Math.ceil((e.getMonth()+1)/3),Qo(e){return Qr(this.Q(e))},D:e=>e.getDate(),Do:e=>Qr(e.getDate()),DD:e=>ve(e.getDate()),DDD:e=>Kr(e),DDDo:e=>Qr(Kr(e)),DDDD:e=>ve(Kr(e),3),d:e=>e.getDay(),do:e=>Qr(e.getDay()),dd:(e,t)=>t.days[e.getDay()].slice(0,2),ddd:(e,t)=>t.daysShort[e.getDay()],dddd:(e,t)=>t.days[e.getDay()],E:e=>e.getDay()||7,w:e=>Ur(e),wo:e=>Qr(Ur(e)),ww:e=>ve(Ur(e)),H:e=>e.getHours(),HH:e=>ve(e.getHours()),h(e){let t=e.getHours();return 0===t?12:t>12?t%12:t},hh(e){return ve(this.h(e))},m:e=>e.getMinutes(),mm:e=>ve(e.getMinutes()),s:e=>e.getSeconds(),ss:e=>ve(e.getSeconds()),S:e=>Math.floor(e.getMilliseconds()/100),SS:e=>ve(Math.floor(e.getMilliseconds()/10)),SSS:e=>ve(e.getMilliseconds(),3),A:e=>e.getHours()<12?"AM":"PM",a:e=>e.getHours()<12?"am":"pm",aa:e=>e.getHours()<12?"a.m.":"p.m.",Z:(e,t,n,a)=>Dr(a??e.getTimezoneOffset(),":"),ZZ:(e,t,n,a)=>Dr(a??e.getTimezoneOffset()),X:e=>Math.floor(e.getTime()/1e3),x:e=>e.getTime()};function Jr(e,t,n,a,i){if(0!==e&&!e||e===1/0||e===-1/0)return;let r=new Date(e);if(Number.isNaN(r))return;void 0===t&&(t=zr);let o=jr(n,$.props);return t.replace(Ir,(e,t)=>e in Zr?Zr[e](r,o,a,i):void 0===t?e:t.split(String.raw`\]`).join("]"))}var Xr={isValid:function(e){return Number.isFinite(e)||Number.isFinite(Date.parse(e))},extractDate:function(e,t,n){let a=Vr(e,t,n),i=new Date(a.year,null===a.month?null:a.month-1,null===a.day?1:a.day,a.hour,a.minute,a.second,a.millisecond),r=i.getTimezoneOffset();return null===a.timezoneOffset||a.timezoneOffset===r?i:qr(i,{minutes:a.timezoneOffset-r},1)},buildDate:function(e,t){return Fr(new Date,e,t)},getDayOfWeek:function(e){let t=new Date(e).getDay();return 0===t?7:t},getWeekOfYear:Ur,isBetweenDates:function(e,t,n,a={}){let i=$r(t,a.onlyDate),r=$r(n,a.onlyDate),o=$r(e,a.onlyDate);return(o>i||a.inclusiveFrom&&o===i)&&(onew Date(e).getTime()));return new Date(n)},getMinDate:function(e,...t){let n=Math.min(new Date(e).getTime(),...t.map(e=>new Date(e).getTime()));return new Date(n)},getDateDiff:Gr,getDayOfYear:Kr,inferDateFormat:function(e){return ae(e)?"date":"number"==typeof e?"number":"string"},getDateBetween:function(e,t,n){let a=new Date(e);if(t){let e=new Date(t);if(ae)return e}return a},isSameDate:function(e,t,n){let a=new Date(e),i=new Date(t);if(void 0===n)return a.getTime()===i.getTime();switch(n){case"second":case"seconds":if(a.getSeconds()!==i.getSeconds())return!1;case"minute":case"minutes":if(a.getMinutes()!==i.getMinutes())return!1;case"hour":case"hours":if(a.getHours()!==i.getHours())return!1;case"day":case"days":case"date":if(a.getDate()!==i.getDate())return!1;case"month":case"months":if(a.getMonth()!==i.getMonth())return!1;case"year":case"years":if(a.getFullYear()!==i.getFullYear())return!1;break;default:throw Error(`date isSameDate unknown unit ${n}`)}return!0},daysInMonth:Yr,formatDate:Jr,clone:function(e){return ae(e)?new Date(e):e}};let eo=["Calendar","Years","Months"],to=e=>eo.includes(e),no=/^-?[\d]+\/[0-1]\d$/,ao=e=>no.test(e),io=" — ";function ro(e){return e.year+"/"+ve(e.month)}function oo(e){return{year:e.year,month:e.month,day:e.day}}var so=h({name:"QDate",props:{...Pr,...wa,...Je,modelValue:{required:!0,validator:e=>"string"==typeof e||Array.isArray(e)||Object(e)===e||null===e},multiple:Boolean,range:Boolean,title:String,subtitle:String,mask:{...Pr.mask,default:"YYYY/MM/DD"},defaultYearMonth:{type:String,validator:ao},yearsInMonthView:Boolean,events:[Array,Function],eventColor:[String,Function],emitImmediately:Boolean,options:[Array,Function],navigationMinYearMonth:{type:String,validator:ao},navigationMaxYearMonth:{type:String,validator:ao},noUnset:Boolean,firstDayOfWeek:[String,Number],todayBtn:Boolean,minimal:Boolean,defaultView:{type:String,default:"Calendar",validator:to}},emits:[...Er,"rangeStart","rangeEnd","navigation"],setup(t,{slots:n,emit:a}){let i,{proxy:r}=(0,e.getCurrentInstance)(),{$q:o}=r,s=Xe(t,o),{getCache:l}=ja(),{isHydrated:u}=Ti(),{tabindex:c,headerClass:d,getLocale:h,getCurrentDate:p}=Lr(t,o),f=xa(ka(t)),m=(0,e.ref)(null),_=(0,e.ref)(ce()),g=(0,e.ref)(h()),v=(0,e.computed)(()=>ce()),b=(0,e.computed)(()=>h()),y=(0,e.computed)(()=>p()),w=(0,e.ref)(he(_.value,g.value)),k=(0,e.ref)(t.defaultView),x=(0,e.computed)(()=>o.lang.rtl?"right":"left"),S=(0,e.ref)(x.value),C=(0,e.ref)(x.value),T=w.value.year,P=(0,e.ref)(T-T%20-(T<0?20:0)),E=(0,e.ref)(null),A=(0,e.computed)(()=>{let e=t.landscape?"landscape":"portrait";return`q-date q-date--${e} q-date--${e}-${t.minimal?"minimal":"standard"}`+(s.value?" q-date--dark q-dark":"")+(t.bordered?" q-date--bordered":"")+(t.square?" q-date--square no-border-radius":"")+(t.flat?" q-date--flat no-shadow":"")+(t.disable?" disabled":t.readonly?" q-date--readonly":"")}),L=(0,e.computed)(()=>t.color||"primary"),M=(0,e.computed)(()=>t.textColor||"white"),R=(0,e.computed)(()=>t.emitImmediately&&!t.multiple&&!t.range),z=(0,e.computed)(()=>Array.isArray(t.modelValue)?t.modelValue:null!==t.modelValue&&void 0!==t.modelValue?[t.modelValue]:[]),I=(0,e.computed)(()=>z.value.filter(e=>"string"==typeof e).map(e=>de(e,_.value,g.value)).filter(e=>null!==e.dateHash&&null!==e.day&&null!==e.month&&null!==e.year)),N=(0,e.computed)(()=>{let e=e=>de(e,_.value,g.value);return z.value.filter(e=>ne(e)&&void 0!==e.from&&void 0!==e.to).map(t=>({from:e(t.from),to:e(t.to)})).filter(e=>null!==e.from.dateHash&&null!==e.to.dateHash&&e.from.dateHash"persian"===t.calendar?e=>{let t=vr(e.year,e.month,e.day);return new Date(t.gy,t.gm-1,t.gd)}:e=>new Date(e.year,e.month-1,e.day)),j=(0,e.computed)(()=>"persian"===t.calendar?Ar:(e,t,n)=>Jr(new Date(e.year,e.month-1,e.day,e.hour,e.minute,e.second,e.millisecond),void 0===t?_.value:t,void 0===n?g.value:n,e.year,e.timezoneOffset)),D=(0,e.computed)(()=>I.value.length+N.value.reduce((e,t)=>e+1+Gr(O.value(t.to),O.value(t.from)),0)),q=(0,e.computed)(()=>{if(void 0!==t.title&&null!==t.title&&0!==t.title.length)return t.title;if(null!==E.value){let e=E.value.init,t=O.value(e);return g.value.daysShort[t.getDay()]+", "+g.value.monthsShort[e.month-1]+" "+e.day+" — ?"}if(0===D.value)return io;if(D.value>1)return`${D.value} ${g.value.pluralDay}`;let e=I.value[0],n=O.value(e);return Number.isNaN(n.valueOf())?io:void 0===g.value.headerTitle?g.value.daysShort[n.getDay()]+", "+g.value.monthsShort[e.month-1]+" "+e.day:g.value.headerTitle(n,e)}),B=(0,e.computed)(()=>[...I.value,...N.value.map(e=>e.from)].sort((e,t)=>e.year-t.year||e.month-t.month)[0]),F=(0,e.computed)(()=>[...I.value,...N.value.map(e=>e.to)].sort((e,t)=>t.year-e.year||t.month-e.month)[0]),V=(0,e.computed)(()=>{if(void 0!==t.subtitle&&null!==t.subtitle&&0!==t.subtitle.length)return t.subtitle;if(0===D.value)return io;if(D.value>1){let e=B.value,t=F.value,n=g.value.monthsShort;return n[e.month-1]+(e.year===t.year?e.month===t.month?"":io+n[t.month-1]:" "+e.year+io+n[t.month-1]+" ")+" "+t.year}return I.value[0].year}),U=(0,e.computed)(()=>{let e=[o.iconSet.datetime.arrowLeft,o.iconSet.datetime.arrowRight];return o.lang.rtl?e.reverse():e}),$=(0,e.computed)(()=>void 0===t.firstDayOfWeek?g.value.firstDayOfWeek:Number(t.firstDayOfWeek)),H=(0,e.computed)(()=>{let e=g.value.daysShort,t=$.value;return t>0?[...e.slice(t,7),...e.slice(0,t)]:e}),W=(0,e.computed)(()=>{let e=w.value;return"persian"===t.calendar?yr(e.year,e.month):new Date(e.year,e.month,0).getDate()}),G=(0,e.computed)(()=>"function"==typeof t.eventColor?t.eventColor:()=>t.eventColor),K=(0,e.computed)(()=>{if(void 0===t.navigationMinYearMonth)return null;let e=t.navigationMinYearMonth.split("/");return{year:Number.parseInt(e[0],10),month:Number.parseInt(e[1],10)}}),Y=(0,e.computed)(()=>{if(void 0===t.navigationMaxYearMonth)return null;let e=t.navigationMaxYearMonth.split("/");return{year:Number.parseInt(e[0],10),month:Number.parseInt(e[1],10)}}),Q=(0,e.computed)(()=>{let e={month:{prev:!0,next:!0},year:{prev:!0,next:!0}};return null!==K.value&&K.value.year>=w.value.year&&(e.year.prev=!1,K.value.year===w.value.year&&K.value.month>=w.value.month&&(e.month.prev=!1)),null!==Y.value&&Y.value.year<=w.value.year&&(e.year.next=!1,Y.value.year===w.value.year&&Y.value.month<=w.value.month&&(e.month.next=!1)),e}),Z=(0,e.computed)(()=>{let e={};return I.value.forEach(t=>{let n=ro(t);void 0===e[n]&&(e[n]=[]),e[n].push(t.day)}),e}),J=(0,e.computed)(()=>{let e={};return N.value.forEach(t=>{let n=ro(t.from),a=ro(t.to);if(void 0===e[n]&&(e[n]=[]),e[n].push({from:t.from.day,to:n===a?t.to.day:void 0,range:t}),n12&&(o.year++,o.month=1)}}),e}),X=(0,e.computed)(()=>{if(null===E.value)return;let{init:e,initHash:t,final:n,finalHash:a}=E.value,[i,r]=t<=a?[e,n]:[n,e],o=ro(i),s=ro(r);if(o!==ee.value&&s!==ee.value)return;let l={};return o===ee.value?(l.from=i.day,l.includeFrom=!0):l.from=1,s===ee.value?(l.to=r.day,l.includeTo=!0):l.to=W.value,l}),ee=(0,e.computed)(()=>ro(w.value)),te=(0,e.computed)(()=>{let e={};if(void 0===t.options){for(let t=1;t<=W.value;t++)e[t]=!0;return e}let n="function"==typeof t.options?t.options:e=>t.options.includes(e);for(let t=1;t<=W.value;t++)e[t]=n(ee.value+"/"+ve(t));return e}),ae=(0,e.computed)(()=>{let e={};if(void 0===t.events)for(let t=1;t<=W.value;t++)e[t]=!1;else{let n="function"==typeof t.events?t.events:e=>t.events.includes(e);for(let t=1;t<=W.value;t++){let a=ee.value+"/"+ve(t);e[t]=n(a)&&G.value(a)}}return e}),ie=(0,e.computed)(()=>{let e,n,{year:a,month:i}=w.value;if("persian"!==t.calendar)e=new Date(a,i-1,1),n=new Date(a,i-1,0).getDate();else{let t=vr(a,i,1);e=new Date(t.gy,t.gm-1,t.gd);let r=i-1,o=a;0===r&&(r=12,o--),n=yr(o,r)}return{days:e.getDay()-$.value-1,endDay:n}}),re=(0,e.computed)(()=>{let e=[],{days:t,endDay:n}=ie.value,a=t<0?t+7:t;if(a<6)for(let t=n-a;t<=n;t++)e.push({i:t,fill:!0});let i=e.length;for(let t=1;t<=W.value;t++){let n={i:t,event:ae.value[t],classes:[]};te.value[t]&&(n.in=!0,n.flat=!0),e.push(n)}if(void 0!==Z.value[ee.value]&&Z.value[ee.value].forEach(t=>{let n=i+t-1;Object.assign(e[n],{selected:!0,unelevated:!0,flat:!1,color:L.value,textColor:M.value})}),void 0!==J.value[ee.value]&&J.value[ee.value].forEach(t=>{if(void 0!==t.from){let n=i+t.from-1,a=i+(t.to||W.value)-1;for(let i=n;i<=a;i++)Object.assign(e[i],{range:t.range,unelevated:!0,color:L.value,textColor:M.value});Object.assign(e[n],{rangeFrom:!0,flat:!1}),void 0!==t.to&&Object.assign(e[a],{rangeTo:!0,flat:!1})}else if(void 0!==t.to){let n=i+t.to-1;for(let a=i;a<=n;a++)Object.assign(e[a],{range:t.range,unelevated:!0,color:L.value,textColor:M.value});Object.assign(e[n],{flat:!1,rangeTo:!0})}else{let n=i+W.value-1;for(let a=i;a<=n;a++)Object.assign(e[a],{range:t.range,unelevated:!0,color:L.value,textColor:M.value})}}),void 0!==X.value){let t=i+X.value.from-1,n=i+X.value.to-1;for(let a=t;a<=n;a++)e[a].color=L.value,e[a].editRange=!0;X.value.includeFrom&&(e[t].editRangeFrom=!0),X.value.includeTo&&(e[n].editRangeTo=!0)}u.value&&w.value.year===y.value.year&&w.value.month===y.value.month&&(e[i+y.value.day-1].today=!0);let r=e.length%7;if(r>0){let t=7-r;for(let n=1;n<=t;n++)e.push({i:n,fill:!0})}return e.forEach(e=>{let t="q-date__calendar-item ";e.fill?t+="q-date__calendar-item--fill":(t+="q-date__calendar-item--"+(e.in?"in":"out"),void 0!==e.range&&(t+=" q-date__range"+(e.rangeTo?"-to":e.rangeFrom?"-from":"")),e.editRange&&(t+=` q-date__edit-range${e.editRangeFrom?"-from":""}${e.editRangeTo?"-to":""}`),(void 0!==e.range||e.editRange)&&(t+=` text-${e.color}`)),e.classes=t}),e}),oe=(0,e.computed)(()=>t.disable?{"aria-disabled":"true"}:{});function se(e){i=JSON.stringify(e)}function le(){let{year:e,month:t,day:n}=y.value,a={...w.value,year:e,month:t,day:n},i=Z.value[ro(a)];(void 0===i||!i.includes(a.day))&&xe(a),ue(a.year,a.month)}function ue(e,t){k.value="Calendar",ge(e,t)}function ce(){return"persian"===t.calendar?"YYYY/MM/DD":t.mask}function de(e,n,a){return Vr(e,n,a,t.calendar,{hour:0,minute:0,second:0,millisecond:0})}function he(e,n){let a=Array.isArray(t.modelValue)?t.modelValue:t.modelValue?[t.modelValue]:[];if(0===a.length)return pe();let i=a.at(-1),r=de(void 0===i.from?i:i.from,e,n);return null===r.dateHash?pe():r}function pe(){let e,n;if(void 0!==t.defaultYearMonth){let a=t.defaultYearMonth.split("/");e=Number.parseInt(a[0],10),n=Number.parseInt(a[1],10)}else{let t=void 0===y.value?p():y.value;e=t.year,n=t.month}return{year:e,month:n,day:1,hour:0,minute:0,second:0,millisecond:0,dateHash:e+"/"+ve(n)+"/01"}}function fe(e){let t=w.value.year,n=Number(w.value.month)+e;13===n?(n=1,t++):0===n&&(n=12,t--),ge(t,n),R.value&&ye("month")}function me(e){ge(Number(w.value.year)+e,w.value.month),R.value&&ye("year")}function _e(e){ge(e,w.value.month),k.value="Years"===t.defaultView?"Months":"Calendar",R.value&&ye("year")}function ge(t,n,a){if(null!==K.value&&t<=K.value.year&&((n=Y.value.year&&((n>Y.value.month||t>Y.value.year)&&(n=Y.value.month),t=Y.value.year),void 0!==a){let{hour:e,minute:t,second:n,millisecond:i,timezoneOffset:r,timeHash:o}=a;Object.assign(w.value,{hour:e,minute:t,second:n,millisecond:i,timezoneOffset:r,timeHash:o})}let i=t+"/"+ve(n)+"/01";i!==w.value.dateHash&&(S.value=w.value.dateHash{P.value=t-t%20-(t<0?20:0),Object.assign(w.value,{year:t,month:n,day:1,dateHash:i})}))}function be(e,n,i){let r=null===e||1!==e.length||t.multiple?e:e[0],{reason:o,details:s}=we(n,i);se(r),a("update:modelValue",r,o,s)}function ye(n){let i=void 0!==I.value[0]&&null!==I.value[0].dateHash?{...I.value[0]}:{...w.value};(0,e.nextTick)(()=>{i.year=w.value.year,i.month=w.value.month;let e="persian"===t.calendar?yr(i.year,i.month):new Date(i.year,i.month,0).getDate();i.day=Math.min(Math.max(1,i.day),e);let r=ke(i),{details:o}=we("",i);se(r),a("update:modelValue",r,n,o)})}function we(e,t){return void 0===t.from?{reason:`${e}-day`,details:oo(t)}:{reason:`${e}-range`,details:{...oo(t.target),from:oo(t.from),to:oo(t.to)}}}function ke(e,t,n){return void 0===e.from?j.value(e,t,n):{from:j.value(e.from,t,n),to:j.value(e.to,t,n)}}function xe(e){let n;if(t.multiple)if(void 0!==e.from){let t=Ar(e.from),a=Ar(e.to),i=I.value.filter(e=>e.dateHasha),r=N.value.filter(({from:e,to:n})=>n.dateHasha);n=[...i,...r,e].map(e=>ke(e))}else n=[...z.value,ke(e)];else n=ke(e);be(n,"add",e)}function Se(e){if(t.noUnset)return;let n=null;if(t.multiple&&Array.isArray(t.modelValue)){let a=ke(e);n=void 0===e.from?t.modelValue.filter(e=>e!==a):t.modelValue.filter(e=>void 0===e.from||e.from!==a.from&&e.to!==a.to),0===n.length&&(n=null)}be(n,"remove",e)}function Ce(e,n,i){let r=[...I.value,...N.value].map(t=>ke(t,e,n)).filter(e=>void 0===e.from?null!==e.dateHash:null!==e.from.dateHash&&null!==e.to.dateHash),o=(t.multiple?r:r[0])||null;se(o),a("update:modelValue",o,i)}function Te(){if(!t.minimal)return(0,e.h)("div",{class:"q-date__header "+d.value},[(0,e.h)("div",{class:"relative-position"},[(0,e.h)(e.Transition,{name:"q-transition--fade"},()=>(0,e.h)("div",{key:"h-yr-"+V.value,class:"q-date__header-subtitle q-date__header-link "+("Years"===k.value?"q-date__header-link--active":"cursor-pointer"),tabindex:c.value,...l("vY",{onClick(){k.value="Years"},onKeyup(e){13===e.keyCode&&(k.value="Years")}})},[V.value]))]),(0,e.h)("div",{class:"q-date__header-title relative-position flex no-wrap"},[(0,e.h)("div",{class:"relative-position col"},[(0,e.h)(e.Transition,{name:"q-transition--fade"},()=>(0,e.h)("div",{key:"h-sub"+q.value,class:"q-date__header-title-label q-date__header-link "+("Calendar"===k.value?"q-date__header-link--active":"cursor-pointer"),tabindex:c.value,...l("vC",{onClick(){k.value="Calendar"},onKeyup(e){13===e.keyCode&&(k.value="Calendar")}})},[q.value]))]),t.todayBtn?(0,e.h)(Kt,{class:"q-date__header-today self-start",icon:o.iconSet.datetime.today,"aria-label":o.lang.date.today,flat:!0,size:"sm",round:!0,tabindex:c.value,onClick:le}):null])])}function Pe({label:t,type:n,key:a,dir:i,goTo:r,boundaries:s,cls:u}){return[(0,e.h)("div",{class:"row items-center q-date__arrow"},[(0,e.h)(Kt,{round:!0,dense:!0,size:"sm",flat:!0,icon:U.value[0],"aria-label":"Years"===n?o.lang.date.prevYear:o.lang.date.prevMonth,tabindex:c.value,disable:!s.prev,...l("go-#"+n,{onClick(){r(-1)}})})]),(0,e.h)("div",{class:"relative-position overflow-hidden flex flex-center"+u},[(0,e.h)(e.Transition,{name:"q-transition--jump-"+i},()=>(0,e.h)("div",{key:a},[(0,e.h)(Kt,{flat:!0,dense:!0,noCaps:!0,label:t,tabindex:c.value,...l("view#"+n,{onClick:()=>{k.value=n}})})]))]),(0,e.h)("div",{class:"row items-center q-date__arrow"},[(0,e.h)(Kt,{round:!0,dense:!0,size:"sm",flat:!0,icon:U.value[1],"aria-label":"Years"===n?o.lang.date.nextYear:o.lang.date.nextMonth,tabindex:c.value,disable:!s.next,...l("go+#"+n,{onClick(){r(1)}})})])]}(0,e.watch)(()=>t.modelValue,e=>{if(i===JSON.stringify(e))i=0;else{let e=he(_.value,g.value);ge(e.year,e.month,e)}}),(0,e.watch)(k,()=>{null!==m.value&&r.$el.contains(document.activeElement)&&m.value.focus()}),(0,e.watch)(()=>w.value.year+"|"+w.value.month,()=>{a("navigation",{year:w.value.year,month:w.value.month})}),(0,e.watch)(v,e=>{Ce(e,g.value,"mask"),_.value=e}),(0,e.watch)(b,e=>{Ce(_.value,e,"locale"),g.value=e});let Ee={Calendar:()=>[(0,e.h)("div",{key:"calendar-view",class:"q-date__view q-date__calendar"},[(0,e.h)("div",{class:"q-date__navigation row items-center no-wrap"},[...Pe({label:g.value.months[w.value.month-1],type:"Months",key:w.value.month,dir:S.value,goTo:fe,boundaries:Q.value.month,cls:" col"}),...Pe({label:w.value.year,type:"Years",key:w.value.year,dir:C.value,goTo:me,boundaries:Q.value.year,cls:""})]),(0,e.h)("div",{class:"q-date__calendar-weekdays row items-center no-wrap"},H.value.map(t=>(0,e.h)("div",{class:"q-date__calendar-item"},[(0,e.h)("div",t)]))),(0,e.h)("div",{class:"q-date__calendar-days-container relative-position overflow-hidden"},[(0,e.h)(e.Transition,{name:"q-transition--slide-"+S.value},()=>(0,e.h)("div",{key:ee.value,class:"q-date__calendar-days fit"},re.value.map(t=>(0,e.h)("div",{class:t.classes},[t.in?(0,e.h)(Kt,{class:t.today?"q-date__today":"",dense:!0,flat:t.flat,unelevated:t.unelevated,color:t.color,textColor:t.textColor,label:t.i,tabindex:c.value,...l("day#"+t.i,{onClick:()=>{Le(t.i)},onMouseover:()=>{!function(e){if(null!==E.value){let t={...w.value,day:e};Object.assign(E.value,{final:t,finalHash:Ar(t)})}}(t.i)}})},t.event?()=>(0,e.h)("div",{class:"q-date__event bg-"+t.event}):null):(0,e.h)("div",String(t.i))]))))])])],Months(){let n=u.value&&w.value.year===y.value.year,a=e=>null!==K.value&&w.value.year===K.value.year&&K.value.month>e||null!==Y.value&&w.value.year===Y.value.year&&Y.value.month{let r=w.value.month===i+1;return(0,e.h)("div",{class:"q-date__months-item flex flex-center"},[(0,e.h)(Kt,{class:n&&y.value.month===i+1?"q-date__today":null,flat:!r,label:t,unelevated:r,color:r?L.value:null,textColor:r?M.value:null,tabindex:c.value,disable:a(i+1),...l("month#"+i,{onClick:()=>{!function(e){ge(w.value.year,e),k.value="Calendar",R.value&&ye("month")}(i+1)}})})])});return t.yearsInMonthView&&i.unshift((0,e.h)("div",{class:"row no-wrap full-width"},[Pe({label:w.value.year,type:"Years",key:w.value.year,dir:C.value,goTo:me,boundaries:Q.value.year,cls:" col"})])),(0,e.h)("div",{key:"months-view",class:"q-date__view q-date__months flex flex-center"},i)},Years(){let t=P.value,n=t+20,a=[],i=e=>null!==K.value&&K.value.year>e||null!==Y.value&&Y.value.year{_e(r)}})})]))}return(0,e.h)("div",{class:"q-date__view q-date__years flex flex-center"},[(0,e.h)("div",{class:"col-auto"},[(0,e.h)(Kt,{round:!0,dense:!0,flat:!0,icon:U.value[0],"aria-label":o.lang.date.prevRangeYears(20),tabindex:c.value,disable:i(t),...l("y-",{onClick:()=>{P.value-=20}})})]),(0,e.h)("div",{class:"q-date__years-content col self-stretch row items-center"},a),(0,e.h)("div",{class:"col-auto"},[(0,e.h)(Kt,{round:!0,dense:!0,flat:!0,icon:U.value[1],"aria-label":o.lang.date.nextRangeYears(20),tabindex:c.value,disable:i(n),...l("y+",{onClick:()=>{P.value+=20}})})])])}};function Le(e){let n={...w.value,day:e};if(t.range)if(null===E.value){let i=re.value.find(t=>!t.fill&&t.i===e);if(!t.noUnset&&void 0!==i.range)return void Se({target:n,from:i.range.from,to:i.range.to});if(i.selected)return void Se(n);let r=Ar(n);E.value={init:n,initHash:r,final:n,finalHash:r},a("rangeStart",oo(n))}else{let e=E.value.initHash,t=Ar(n),i=e<=t?{from:E.value.init,to:n}:{from:n,to:E.value.init};E.value=null,xe(e===t?n:{target:n,...i}),a("rangeEnd",{from:oo(i.from),to:oo(i.to)})}else!function(e,t){(!0===Z.value[t]?.includes(e.day)?Se:xe)(e)}(n,ee.value)}return Object.assign(r,{setToday:le,setView:function(e){to(e)&&(k.value=e)},offsetCalendar:function(e,t){["month","year"].includes(e)&&("month"===e?fe:me)(t?-1:1)},setCalendarTo:ue,setEditingRange:function(e,n){if(!t.range||!e)return void(E.value=null);let a={...w.value,...e},i=void 0===n?a:{...w.value,...n};E.value={init:a,initHash:Ar(a),final:i,finalHash:Ar(i)},ue(a.year,a.month)}}),()=>{let a=[(0,e.h)("div",{class:"q-date__content col relative-position"},[(0,e.h)(e.Transition,{name:"q-transition--fade"},Ee[k.value])])],i=Ae(n.default);return void 0!==i&&a.push((0,e.h)("div",{class:"q-date__actions"},i)),void 0!==t.name&&!t.disable&&f(a,"push"),(0,e.h)("div",{class:A.value,...oe.value},[Te(),(0,e.h)("div",{ref:m,class:"q-date__main col column",tabindex:-1},a)])}}});function lo(t,n,a){let i;function r(){void 0!==i&&(F.remove(i),i=void 0)}return(0,e.onBeforeUnmount)(()=>{t.value&&r()}),{removeFromHistory:r,addToHistory(){i={condition:()=>a.value,handler:n},F.add(i)}}}let uo,co,ho,po,fo,mo,_o=0,go=!1,vo=null;function bo(e){e.target===document&&(document.scrollingElement.scrollTop=document.scrollingElement.scrollTop)}function yo(e){go||(go=!0,requestAnimationFrame(()=>{go=!1;let{height:t}=e.target,{clientHeight:n,scrollTop:a}=document.scrollingElement;(void 0===ho||t!==window.innerHeight)&&(ho=n-t,document.scrollingElement.scrollTop=a),a>ho&&(document.scrollingElement.scrollTop-=Math.ceil((a-ho)/8))}))}function wo(e){let t=document.body,n=void 0!==window.visualViewport;if("add"===e){let{overflowY:e,overflowX:a}=window.getComputedStyle(t);uo=Ln(window),co=An(window),po=t.style.left,fo=t.style.top,mo=window.location.pathname,t.style.left=`-${uo}px`,t.style.top=`-${co}px`,"hidden"!==a&&("scroll"===a||t.scrollWidth>window.innerWidth)&&t.classList.add("q-body--force-scrollbar-x"),"hidden"!==e&&("scroll"===e||t.scrollHeight>window.innerHeight)&&t.classList.add("q-body--force-scrollbar-y"),document.documentElement.classList.add("q-document--prevent-scroll"),document.qScrollPrevented=!0,c.is.ios&&(n?(window.scrollTo(0,0),window.visualViewport.addEventListener("resize",yo,m.passiveCapture),window.visualViewport.addEventListener("scroll",yo,m.passiveCapture),window.scrollTo(0,0)):window.addEventListener("scroll",bo,m.passiveCapture))}else c.is.ios&&(n?(window.visualViewport.removeEventListener("resize",yo,m.passiveCapture),window.visualViewport.removeEventListener("scroll",yo,m.passiveCapture)):window.removeEventListener("scroll",bo,m.passiveCapture)),document.documentElement.classList.remove("q-document--prevent-scroll"),t.classList.remove("q-body--force-scrollbar-x","q-body--force-scrollbar-y"),document.qScrollPrevented=!1,t.style.left=po,t.style.top=fo,window.location.pathname===mo&&window.scrollTo(uo,co),ho=void 0}function ko(e){let t="add";if(!0===e){if(_o++,null!==vo)return clearTimeout(vo),void(vo=null);if(_o>1)return}else{if(0===_o||(_o--,_o>0))return;if(t="remove",c.is.ios&&c.is.nativeMobile)return null!==vo&&clearTimeout(vo),void(vo=setTimeout(()=>{wo(t),vo=null},100))}wo(t)}function xo(){let e;return{preventBodyScroll(t){t!==e&&(void 0!==e||t)&&(e=t,ko(t))}}}let So=0,Co={standard:"fixed-full flex-center",top:"fixed-top justify-center",bottom:"fixed-bottom justify-center",right:"fixed-right items-center",left:"fixed-left items-center"},To={standard:["scale","scale"],top:["slide-down","slide-up"],bottom:["slide-up","slide-down"],right:["slide-left","slide-right"],left:["slide-right","slide-left"]};var Po=h({name:"QDialog",inheritAttrs:!1,props:{...tn,...yn,transitionShow:String,transitionHide:String,persistent:Boolean,autoClose:Boolean,allowFocusOutside:Boolean,noEscDismiss:Boolean,noBackdropDismiss:Boolean,noRouteDismiss:Boolean,noRefocus:Boolean,noFocus:Boolean,noShake:Boolean,seamless:Boolean,maximized:Boolean,fullWidth:Boolean,fullHeight:Boolean,square:Boolean,backdropFilter:String,position:{type:String,default:"standard",validator:e=>["standard","top","bottom","left","right"].includes(e)}},emits:[...nn,"shake","click","escapeKey"],setup(t,{slots:n,emit:a,attrs:i}){let r=(0,e.getCurrentInstance)(),o=(0,e.ref)(null),s=(0,e.ref)(!1),l=(0,e.ref)(!1),u=null,c=null,d=!1,h=!1,p=(0,e.computed)(()=>!t.persistent&&!t.noRouteDismiss&&!t.seamless),{preventBodyScroll:f}=xo(),{registerTimeout:m}=xn(),{registerTick:_,removeTick:g}=kn(),{transitionProps:v,transitionStyle:b}=wn(t,()=>To[t.position][0],()=>To[t.position][1]),y=(0,e.computed)(()=>b.value+(void 0===t.backdropFilter?"":`;backdrop-filter:${t.backdropFilter};-webkit-backdrop-filter:${t.backdropFilter}`)),{showPortal:w,hidePortal:k,portalIsAccessible:x,renderPortal:S}=bn(r,o,function(){return(0,e.h)("div",{role:"dialog","aria-modal":A.value?"true":"false",...i,class:M.value},[(0,e.h)(e.Transition,{name:"q-transition--fade",appear:!0},()=>A.value?(0,e.h)("div",{class:"q-dialog__backdrop fixed-full",style:y.value,"aria-hidden":"true",onClick:D}):null),(0,e.h)(e.Transition,v.value,()=>s.value?(0,e.h)("div",{ref:o,class:E.value,style:b.value,tabindex:-1,...L.value},Ae(n.default)):null)])},"dialog"),{hide:C}=an({showing:s,hideOnRouteChange:p,handleShow:function(e){T(),c=t.noRefocus||null===document.activeElement?null:document.activeElement,O(t.maximized),w(),l.value=!0,t.noFocus?g():(document.activeElement?.blur(),_(R)),m(()=>{if(r.proxy.$q.platform.is.ios){if(!t.seamless&&document.activeElement){let{top:e,bottom:t}=document.activeElement.getBoundingClientRect(),{innerHeight:n}=window,a=void 0===window.visualViewport?n:window.visualViewport.height;e>0&&t>a/2&&(document.scrollingElement.scrollTop=Math.min(document.scrollingElement.scrollHeight-a,t>=n?1/0:Math.ceil(document.scrollingElement.scrollTop+t-a/2))),document.activeElement.scrollIntoView()}h=!0,o.value.click(),h=!1}w(!0),l.value=!1,a("show",e)},t.transitionDuration)},handleHide:function(e){if(g(),P(),N(!0),l.value=!0,k(),null!==c){let t=(0===e?.type.indexOf("key")?c.closest('[tabindex]:not([tabindex^="-"])'):void 0)||c;c=null,dn(()=>{t.isConnected&&t.focus()})}m(()=>{k(!0),l.value=!1,a("hide",e)},t.transitionDuration)},handleRouteChange:function(){c=null},processOnMount:!0}),{addToHistory:T,removeFromHistory:P}=lo(s,C,p),E=(0,e.computed)(()=>`q-dialog__inner flex no-pointer-events q-dialog__inner--${t.maximized?"maximized":"minimized"} q-dialog__inner--${t.position} ${Co[t.position]}`+(l.value?" q-dialog__inner--animating":"")+(t.fullWidth?" q-dialog__inner--fullwidth":"")+(t.fullHeight?" q-dialog__inner--fullheight":"")+(t.square?" q-dialog__inner--square":"")),A=(0,e.computed)(()=>s.value&&!t.seamless),L=(0,e.computed)(()=>t.autoClose?{onClick:j}:{}),M=(0,e.computed)(()=>["q-dialog fullscreen no-pointer-events q-dialog--"+(A.value?"modal":"seamless"),i.class]);function R(e){dn(()=>{let t=o.value;if(null!==t){if(void 0!==e){let n=t.querySelector(e);if(null!==n)return void n.focus({preventScroll:!0})}t.contains(document.activeElement)||(t=t.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||t.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||t.querySelector("[autofocus], [data-autofocus]")||t,t.focus({preventScroll:!0}))}})}function z(e){e&&"function"==typeof e.focus?e.focus({preventScroll:!0}):R(),a("shake");let t=o.value;null!==t&&(t.classList.remove("q-animate--scale"),t.classList.add("q-animate--scale"),null!==u&&clearTimeout(u),u=setTimeout(()=>{u=null,null!==o.value&&(t.classList.remove("q-animate--scale"),R())},170))}function I(){t.seamless||(t.persistent||t.noEscDismiss?!t.maximized&&!t.noShake&&z():(a("escapeKey"),C()))}function N(e){null!==u&&(clearTimeout(u),u=null),(e||s.value)&&(O(!1),t.seamless||(f(!1),Zn(q),Gn(I))),e||(c=null)}function O(e){e?d||=(So<1&&document.body.classList.add("q-body--dialog"),So++,!0):d&&=(So<2&&document.body.classList.remove("q-body--dialog"),So--,!1)}function j(e){h||(C(e),a("click",e))}function D(e){t.persistent||t.noBackdropDismiss?t.noShake||z():C(e)}function q(e){!t.allowFocusOutside&&x.value&&!Et(o.value,e.target)&&R('[tabindex]:not([tabindex="-1"])')}return(0,e.watch)(()=>t.maximized,e=>{s.value&&O(e)}),(0,e.watch)(A,e=>{f(e),e?(Qn(q),Wn(I)):(Zn(q),Gn(I))}),Object.assign(r.proxy,{focus:R,shake:z,__updateRefocusTarget(e){c=e||null}}),(0,e.onBeforeUnmount)(N),S}});var Eo=h({name:"QDrawer",inheritAttrs:!1,props:{...tn,...Je,side:{type:String,default:"left",validator:e=>["left","right"].includes(e)},width:{type:Number,default:300},mini:Boolean,miniToOverlay:Boolean,miniWidth:{type:Number,default:57},noMiniAnimation:Boolean,breakpoint:{type:Number,default:1023},showIfAbove:Boolean,behavior:{type:String,validator:e=>["default","desktop","mobile"].includes(e),default:"default"},bordered:Boolean,elevated:Boolean,overlay:Boolean,persistent:Boolean,noSwipeOpen:Boolean,noSwipeClose:Boolean,noSwipeBackdrop:Boolean},emits:[...nn,"onLayout","miniState"],setup(t,{slots:n,emit:a,attrs:i}){let r=(0,e.getCurrentInstance)(),{proxy:{$q:o}}=r,s=Xe(t,o),{preventBodyScroll:l}=xo(),{registerTimeout:u,removeTimeout:c}=xn(),d=(0,e.inject)(Y,ee);if(d===ee)return console.error("QDrawer needs to be child of QLayout"),ee;let h,p,f=null,m=(0,e.ref)("mobile"===t.behavior||"desktop"!==t.behavior&&d.totalWidth.value<=t.breakpoint),_=(0,e.computed)(()=>t.mini&&!m.value),g=(0,e.computed)(()=>_.value?t.miniWidth:t.width),v=(0,e.computed)(()=>t.overlay||t.miniToOverlay||d.view.value.includes(L.value?"R":"L")||o.platform.is.ios&&d.isContainer.value),b=(0,e.ref)(t.showIfAbove&&!m.value||!0===t.modelValue),y=(0,e.computed)(()=>!t.overlay&&b.value&&!m.value),w=(0,e.computed)(()=>t.overlay&&b.value&&!m.value),k=(0,e.computed)(()=>!t.persistent&&(m.value||w.value));function x(e,t){if(P(),!1!==e&&d.animate(),Z(0),m.value){let e=d.instances[O.value];!0===e?.belowBreakpoint&&e.hide(!1),J(1),d.isContainer.value||l(!0)}else J(0),!1!==e&&X(!1);u(()=>{!1!==e&&X(!0),t||a("show",e)},150)}function S(e,t){E(),!1!==e&&d.animate(),J(0),Z(M.value*g.value),ae(),t?c():u(()=>{a("hide",e)},150)}let{show:C,hide:T}=an({showing:b,hideOnRouteChange:k,handleShow:x,handleHide:S}),{addToHistory:P,removeFromHistory:E}=lo(b,T,k),A={belowBreakpoint:m,hide:T},L=(0,e.computed)(()=>"right"===t.side),M=(0,e.computed)(()=>(o.lang.rtl?-1:1)*(L.value?1:-1)),R=(0,e.ref)(0),z=(0,e.ref)(!1),I=(0,e.ref)(!1),N=(0,e.ref)(g.value*M.value),O=(0,e.computed)(()=>L.value?"left":"right"),j=(0,e.computed)(()=>!b.value||m.value||t.overlay?0:t.miniToOverlay?t.miniWidth:g.value),D=(0,e.computed)(()=>"fullscreen q-drawer__backdrop"+(b.value||z.value?"":" hidden")),q=(0,e.computed)(()=>({backgroundColor:`rgba(0,0,0,${.4*R.value})`})),B=(0,e.computed)(()=>L.value?"r"===d.rows.value.top[2]:"l"===d.rows.value.top[0]),F=(0,e.computed)(()=>L.value?"r"===d.rows.value.bottom[2]:"l"===d.rows.value.bottom[0]),V=(0,e.computed)(()=>{let e={};return d.header.space&&!B.value&&(v.value?e.top=`${d.header.offset}px`:d.header.space&&(e.top=`${d.header.size}px`)),d.footer.space&&!F.value&&(v.value?e.bottom=`${d.footer.offset}px`:d.footer.space&&(e.bottom=`${d.footer.size}px`)),e}),U=(0,e.computed)(()=>{let e={width:`${g.value}px`,transform:`translateX(${N.value}px)`};return m.value?e:Object.assign(e,V.value)}),$=(0,e.computed)(()=>"q-drawer__content fit "+(d.isContainer.value?"overflow-auto":"scroll")),H=(0,e.computed)(()=>`q-drawer q-drawer--${t.side}`+(I.value?" q-drawer--mini-animate":"")+(t.bordered?" q-drawer--bordered":"")+(s.value?" q-drawer--dark q-dark":"")+(z.value?" no-transition":b.value?"":" q-layout--prevent-focus")+(m.value?" fixed q-drawer--on-top q-drawer--mobile q-drawer--top-padding":" q-drawer--"+(_.value?"mini":"standard")+(v.value||!y.value?" fixed":"")+(t.overlay||t.miniToOverlay?" q-drawer--on-top":"")+(B.value?" q-drawer--top-padding":""))),W=(0,e.computed)(()=>[[gi,te,void 0,{[o.lang.rtl?t.side:O.value]:!0,mouse:!0}]]),G=(0,e.computed)(()=>[[gi,ne,void 0,{[o.lang.rtl?O.value:t.side]:!0,mouse:!0}]]),K=(0,e.computed)(()=>[[gi,ne,void 0,{[o.lang.rtl?O.value:t.side]:!0,mouse:!0,mouseAllDir:!0}]]);function Q(){!function(e,t){e.value!==t&&(e.value=t)}(m,"mobile"===t.behavior||"desktop"!==t.behavior&&d.totalWidth.value<=t.breakpoint)}function Z(t){void 0===t?(0,e.nextTick)(()=>{t=b.value?0:g.value,Z(M.value*t)}):(d.isContainer.value&&L.value&&(m.value||Math.abs(t)===g.value)&&(t+=M.value*d.scrollbarWidth.value),N.value=t)}function J(e){R.value=e}function X(e){let t=e?"remove":d.isContainer.value?"":"add";""!==t&&document.body.classList[t]("q-body--drawer-toggle")}function te(e){if(b.value)return;let t=g.value,n=_e(e.distance.x,0,t);if(e.isFinal)return n>=Math.min(75,t)?C():(d.animate(),J(0),Z(M.value*t)),void(z.value=!1);Z((o.lang.rtl?!L.value:L.value)?Math.max(t-n,0):Math.min(0,n-t)),J(_e(n/t,0,1)),e.isFirst&&(z.value=!0)}function ne(e){if(!b.value)return;let n=g.value,a=e.direction===t.side,i=(o.lang.rtl?!a:a)?_e(e.distance.x,0,n):0;if(e.isFinal)return Math.abs(i){e?(h=b.value,b.value&&T(!1)):!t.overlay&&"mobile"!==t.behavior&&!1!==h&&(b.value?(Z(0),J(0),ae()):C(!1))}),(0,e.watch)(()=>t.side,(e,t)=>{d.instances[t]===A&&(d.instances[t]=void 0,d[t].space=!1,d[t].offset=0),d.instances[e]=A,d[e].size=g.value,d[e].space=y.value,d[e].offset=j.value}),(0,e.watch)(d.totalWidth,()=>{(d.isContainer.value||!document.qScrollPrevented)&&Q()}),(0,e.watch)(()=>t.behavior+t.breakpoint,Q),(0,e.watch)(d.isContainer,e=>{b.value&&l(!e),e&&Q()}),(0,e.watch)(d.scrollbarWidth,()=>{Z(b.value?0:void 0)}),(0,e.watch)(j,e=>{ie("offset",e)}),(0,e.watch)(y,e=>{a("onLayout",e),ie("space",e)}),(0,e.watch)(L,()=>{Z()}),(0,e.watch)(g,e=>{Z(),re(t.miniToOverlay,e)}),(0,e.watch)(()=>t.miniToOverlay,e=>{re(e,g.value)}),(0,e.watch)(()=>o.lang.rtl,()=>{Z()}),(0,e.watch)(()=>t.mini,()=>{t.noMiniAnimation||t.modelValue&&(null!==f&&clearTimeout(f),r.proxy&&r.proxy.$el&&r.proxy.$el.classList.add("q-drawer--mini-animate"),I.value=!0,f=setTimeout(()=>{f=null,I.value=!1,r?.proxy?.$el?.classList.remove("q-drawer--mini-animate")},150),d.animate())}),(0,e.watch)(_,e=>{a("miniState",e)}),d.instances[t.side]=A,re(t.miniToOverlay,g.value),ie("space",y.value),ie("offset",j.value),t.showIfAbove&&!t.modelValue&&b.value&&void 0!==t["onUpdate:modelValue"]&&a("update:modelValue",!0),(0,e.onMounted)(()=>{a("onLayout",y.value),a("miniState",_.value),h=t.showIfAbove;let n=()=>{(b.value?x:S)(!1,!0)};0===d.totalWidth.value?p=(0,e.watch)(d.totalWidth,()=>{p(),p=void 0,b.value||!t.showIfAbove||m.value?n():C(!1)}):(0,e.nextTick)(n)}),(0,e.onBeforeUnmount)(()=>{p?.(),null!==f&&(clearTimeout(f),f=null),b.value&&ae(),d.instances[t.side]===A&&(d.instances[t.side]=void 0,ie("size",0),ie("offset",0),ie("space",!1))}),()=>{let a=[];m.value&&(t.noSwipeOpen||a.push((0,e.withDirectives)((0,e.h)("div",{key:"open",class:`q-drawer__opener fixed-${t.side}`,"aria-hidden":"true"}),W.value)),a.push(ze("div",{ref:"backdrop",class:D.value,style:q.value,"aria-hidden":"true",onClick:T},void 0,"backdrop",!t.noSwipeBackdrop&&b.value,()=>K.value)));let r=_.value&&void 0!==n.mini,o=[(0,e.h)("div",{...i,key:String(r),class:[$.value,i.class]},r?n.mini():Ae(n.default))];return t.elevated&&b.value&&o.push((0,e.h)("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),a.push(ze("aside",{ref:"content",class:H.value,style:U.value},o,"contentclose",!t.noSwipeClose&&m.value,()=>G.value)),(0,e.h)("div",{class:"q-drawer-container"},a)}}});let Ao=["div","li","ul","ol","blockquote"];function Lo(e,t){if(t&&e===t)return null;let n=e.nodeName.toLowerCase();if(Ao.includes(n))return e;let a=(window.getComputedStyle?window.getComputedStyle(e):e.currentStyle).display;return"block"===a||"table"===a?e:Lo(e.parentNode)}function Mo(e,t,n){return!(!e||e===document.body)&&(n&&e===t||(t===document?document.body:t).contains(e.parentNode))}function Ro(e,t,n){if(n||((n=document.createRange()).selectNode(e),n.setStart(e,0)),0===t.count)n.setEnd(e,t.count);else if(t.count>0)if(e.nodeType===Node.TEXT_NODE)e.textContent.length0&&this.savedPos\n \n \n Print - ${document.title}\n \n \n
${this.el.innerHTML}
\n \n \n `),e.print(),void e.close()}if("link"===e){let e=this.getParentAttribute("href");if(null===e){let e=this.selectWord(this.selection),t=e?e.toString():"";if(!(0!==t.length||this.range&&this.range.cloneContents().querySelector("img")))return;this.eVm.editLinkUrl.value=zo.test(t)?t:"https://",this.save(e.getRangeAt(0)),document.execCommand("createLink",!1,this.eVm.editLinkUrl.value)}else this.eVm.editLinkUrl.value=e,this.range.selectNodeContents(this.parent),this.save();return}if("fullscreen"===e)return this.eVm.toggleFullscreen(),void n();if("viewsource"===e)return this.eVm.isViewingSource.value=!this.eVm.isViewingSource.value,this.eVm.setContent(this.eVm.props.modelValue),void n()}document.execCommand(e,!1,t),n()}selectWord(e){if(null===e||!e.isCollapsed)return e;let t=document.createRange();t.setStart(e.anchorNode,e.anchorOffset),t.setEnd(e.focusNode,e.focusOffset);let n=t.collapsed?["backward","forward"]:["forward","backward"];t.detach();let a=e.focusNode,i=e.focusOffset;return e.collapse(e.anchorNode,e.anchorOffset),e.modify("move",n[0],"character"),e.modify("move",n[1],"word"),e.extend(a,i),e.modify("extend",n[1],"character"),e.modify("extend",n[0],"word"),e}};let No=0;var Oo=h({name:"QTooltip",inheritAttrs:!1,props:{...Zt,...tn,...yn,maxHeight:{type:String,default:null},maxWidth:{type:String,default:null},transitionShow:{...yn.transitionShow,default:"jump-down"},transitionHide:{...yn.transitionHide,default:"jump-up"},anchor:{type:String,default:"bottom middle",validator:la},self:{type:String,default:"top middle",validator:la},offset:{type:Array,default:()=>[14,14],validator:ua},scrollTarget:Cn,delay:{type:Number,default:0},hideDelay:{type:Number,default:0},persistent:Boolean},emits:[...nn],setup(t,{slots:n,emit:a,attrs:i}){let r,o,s,l,u=!1,c=(0,e.getCurrentInstance)(),{proxy:{$q:d}}=c,h=(0,e.ref)(null),p=(0,e.ref)(!1),f=va(),m=(0,e.computed)(()=>i.id||f.value),_=(0,e.computed)(()=>da(t.anchor,d.lang.rtl)),g=(0,e.computed)(()=>da(t.self,d.lang.rtl)),v=(0,e.computed)(()=>!t.persistent),{registerTick:b,removeTick:y}=kn(),{registerTimeout:k}=xn(),{transitionProps:C,transitionStyle:T}=wn(t),{localScrollTarget:P,changeScrollEvent:E,unconfigureScrollTarget:A}=en(t,U),{anchorEl:L,canShow:M,anchorEvents:R}=Xt({showing:p,configureAnchorEl:function(){if(t.noParentEvent||null===L.value)return;let e=d.platform.is.mobile?[[L.value,"touchstart","delayShow","passive"]]:[[L.value,"mouseenter","delayShow","passive"],[L.value,"mouseleave","delayHide","passive"],[L.value,"focusin","onFocusin","passive"],[L.value,"focusout","delayHide","passive"]];x(R,"anchor",e)}}),{show:z,hide:I}=an({showing:p,canShow:M,handleShow:function(n){N(),function(){let e=L.value,t=m.value;if(null===e||void 0===t)return;let n=(e.getAttribute("aria-describedby")||"").split(/\s+/).filter(Boolean);l={el:e,id:t,added:!n.includes(t)},l.added&&(n.push(t),e.setAttribute("aria-describedby",n.join(" ")))}(),b(()=>{o?.disconnect(),null!==h.value?(o=new MutationObserver(()=>q()),o.observe(h.value,{attributes:!1,childList:!0,characterData:!0,subtree:!0}),q(),U()):o=void 0}),void 0===r&&(r=(0,e.watch)(()=>d.screen.width+"|"+d.screen.height+"|"+t.self+"|"+t.anchor+"|"+d.lang.rtl,q)),k(()=>{N(!0),a("show",n)},t.transitionDuration)},handleHide:function(e){y(),O(),D(),k(()=>{O(!0),a("hide",e)},t.transitionDuration)},hideOnRouteChange:v,processOnMount:!0});Object.assign(R,{delayShow:B,delayHide:function(e){d.platform.is.mobile&&(S(R,"tooltipTemp"),Qt(),s=setTimeout(()=>{s=void 0,V(!1)},10)),k(()=>{I(e)},t.hideDelay)},onFocusin:function(e){let t=e.target;if(t){try{if(!1===t.matches(":focus-visible"))return}catch{}B(e)}}});let{showPortal:N,hidePortal:O,renderPortal:j}=bn(c,h,function(){return(0,e.h)(e.Transition,C.value,$)},"tooltip");if(d.platform.is.mobile){let n={anchorEl:L,innerRef:h,onClickOutside:e=>(I(e),e.target.classList.contains("q-dialog__backdrop")&&w(e),!0)};(0,e.watch)((0,e.computed)(()=>null===t.modelValue&&!t.persistent&&p.value),e=>{(e?na:aa)(n)}),(0,e.onBeforeUnmount)(()=>{aa(n)})}else(0,e.watch)(()=>(null===t.modelValue||t["onUpdate:modelValue"])&&!0===p.value&&!0!==t.persistent,e=>{(!0===e?Wn:Gn)(F)});function D(){void 0!==o&&(o.disconnect(),o=void 0),void 0!==r&&(r(),r=void 0),A(),Gn(F),S(R,"tooltipTemp"),function(){if(!0===l?.added){let{el:e,id:t}=l,n=(e.getAttribute("aria-describedby")||"").split(/\s+/).filter(e=>""!==e&&e!==t);0===n.length?e.removeAttribute("aria-describedby"):e.setAttribute("aria-describedby",n.join(" "))}l=void 0}(),V(!1)}function q(){pa({targetEl:h.value,offset:t.offset,anchorEl:L.value,anchorOrigin:_.value,selfOrigin:g.value,maxHeight:t.maxHeight,maxWidth:t.maxWidth})}function B(e){if(d.platform.is.mobile){void 0!==s&&(clearTimeout(s),s=void 0),Qt(),V(!0);let e=L.value,t=["touchmove","touchcancel","touchend","click"].map(t=>[e,t,"delayHide","passiveCapture"]);x(R,"tooltipTemp",t)}k(()=>{z(e)},t.delay)}function F(e){I(e)}function V(e){u!==e&&(u=e,No+=e?1:-1,document.body.classList.toggle("non-selectable",No>0),!e&&void 0!==s&&(clearTimeout(s),s=void 0))}function U(){if(null!==L.value||void 0!==t.scrollTarget){P.value=Pn(L.value,t.scrollTarget);let e=t.noParentEvent?q:I;E(P.value,e)}}function $(){return p.value?(0,e.h)("div",{...i,id:m.value,ref:h,class:["q-tooltip q-tooltip--style q-position-engine no-pointer-events",i.class],style:[i.style,T.value],role:"tooltip"},Ae(n.default)):null}return(0,e.onBeforeUnmount)(D),Object.assign(c.proxy,{updatePosition:q}),j}}),jo=h({name:"QItem",props:{...Je,...vt,tag:{type:String,default:"div"},active:{type:Boolean,default:null},clickable:Boolean,dense:Boolean,insetLevel:Number,tabindex:[String,Number],focused:Boolean,manualFocus:Boolean},emits:["click","keyup"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Xe(t,i),{hasLink:o,linkAttrs:s,linkClass:l,linkTag:u,navigateOnClick:c}=bt(),d=(0,e.ref)(null),h=(0,e.ref)(null),p=(0,e.computed)(()=>t.clickable||o.value||"label"===t.tag),f=(0,e.computed)(()=>!t.disable&&p.value),m=(0,e.computed)(()=>"q-item q-item-type row no-wrap"+(t.dense?" q-item--dense":"")+(r.value?" q-item--dark":"")+(o.value&&null===t.active?l.value:t.active?" q-item--active"+(void 0===t.activeClass?"":` ${t.activeClass}`):"")+(t.disable?" disabled":"")+(f.value?" q-item--clickable q-link cursor-pointer "+(t.manualFocus?"q-manual-focusable":"q-focusable q-hoverable")+(t.focused?" q-manual-focusable--focused":""):"")),_=(0,e.computed)(()=>void 0===t.insetLevel?null:{["padding"+(i.lang.rtl?"Right":"Left")]:16+56*t.insetLevel+"px"});function g(e){f.value&&(null!==h.value&&!e.qAvoidFocus&&(e.qKeyEvent||document.activeElement!==d.value?document.activeElement===h.value&&d.value.focus():h.value.focus()),c(e))}function v(e){if(f.value&&N(e,[13,32])){w(e),e.qKeyEvent=!0;let t=new MouseEvent("click",e);t.qKeyEvent=!0,d.value.dispatchEvent(t)}a("keyup",e)}function b(e){f.value&&32===e.keyCode&&w(e)}function y(){let t=Le(n.default,[]);return f.value&&t.unshift((0,e.h)("div",{class:"q-focus-helper",tabindex:-1,ref:h})),t}return()=>{let n={ref:d,class:m.value,style:_.value,role:o.value?void 0:f.value?"button":"listitem",onClick:g,onKeydown:b,onKeyup:v};return f.value?(n.tabindex=t.tabindex||"0",Object.assign(n,s.value)):p.value&&(n["aria-disabled"]="true"),(0,e.h)(u.value,n,y())}}}),Do=h({name:"QItemSection",props:{avatar:Boolean,thumbnail:Boolean,side:Boolean,top:Boolean,noWrap:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>"q-item__section column q-item__section--"+(t.avatar||t.side||t.thumbnail?"side":"main")+(t.top?" q-item__section--top justify-start":" justify-center")+(t.avatar?" q-item__section--avatar":"")+(t.thumbnail?" q-item__section--thumbnail":"")+(t.noWrap?" q-item__section--nowrap":""));return()=>(0,e.h)("div",{class:a.value},Ae(n.default))}});function qo(e,t,n){t.handler?t.handler(e,n,n.caret):n.runCmd(t.cmd,t.param)}function Bo(t){return(0,e.h)("div",{class:"q-editor__toolbar-group"},t)}function Fo(t,n,a,i=!1){let r=i||"toggle"===n.type&&(n.toggled?n.toggled(t):n.cmd&&t.caret.is(n.cmd,n.param)),o=[];if(t.$q.platform.is.desktop&&(n.tip||n.htmlTip)){let t=n.key?(0,e.h)("div",[(0,e.h)("small",`(CTRL + ${String.fromCodePoint(n.key)})`)]):null;o.push((0,e.h)(Oo,{delay:1e3},()=>[(0,e.h)("div",n.htmlTip?{innerHTML:n.htmlTip}:n.tip),t]))}return(0,e.h)(Kt,{...t.buttonProps.value,icon:null===n.icon?void 0:n.icon,color:r?n.toggleColor||t.props.toolbarToggleColor:n.color||t.props.toolbarColor,textColor:r&&!t.props.toolbarPush?null:n.textColor||t.props.toolbarTextColor,label:n.label,"aria-label":null===n.label?n.tip:void 0,disable:!!n.disable&&("function"!=typeof n.disable||n.disable(t)),size:"sm",onClick(e){a?.(),qo(e,n,t)}},()=>o)}function Vo(t,n){let a,i,r="only-icons"===n.list,o=n.label,s=null===n.icon?void 0:n.icon;function l(){c.component.proxy.hide()}if(r)i=n.options.map(e=>{let n=void 0===e.type&&t.caret.is(e.cmd,e.param);return n&&(o=e.tip,s=null===e.icon?void 0:e.icon),Fo(t,e,l,n)}),a=t.toolbarBackgroundClass.value,i=[Bo(i)];else{let r=void 0===t.props.toolbarToggleColor?null:`text-${t.props.toolbarToggleColor}`,u=void 0===t.props.toolbarTextColor?null:`text-${t.props.toolbarTextColor}`,c="no-icons"===n.list;i=n.options.map(n=>{let a=!!n.disable&&n.disable(t),i=void 0===n.type&&t.caret.is(n.cmd,n.param);i&&(o=n.tip,s=null===n.icon?void 0:n.icon);let d=n.htmlTip;return(0,e.h)(jo,{active:i,activeClass:r,clickable:!0,disable:a,dense:!0,onClick(e){l(),!0!==e?.qAvoidFocus&&t.contentRef.value?.focus(),t.caret.restore(),qo(e,n,t)}},()=>[c?null:(0,e.h)(Do,{class:i?r:u,side:!0},()=>(0,e.h)(Ke,{name:null===n.icon?void 0:n.icon})),(0,e.h)(Do,d?()=>(0,e.h)("div",{class:"text-no-wrap",innerHTML:n.htmlTip}):n.tip?()=>(0,e.h)("div",{class:"text-no-wrap"},n.tip):void 0)])}),a=[t.toolbarBackgroundClass.value,u]}let u=n.highlight&&o!==n.label,c=(0,e.h)(ya,{...t.buttonProps.value,noCaps:!0,noWrap:!0,color:u?t.props.toolbarToggleColor:t.props.toolbarColor,textColor:u&&!t.props.toolbarPush?null:t.props.toolbarTextColor,label:n.fixedLabel?n.label:o,icon:n.fixedIcon?null===n.icon?void 0:n.icon:s,contentClass:a,onShow:e=>t.emit("dropdownShow",e),onHide:e=>t.emit("dropdownHide",e),onBeforeShow:e=>t.emit("dropdownBeforeShow",e),onBeforeHide:e=>t.emit("dropdownBeforeHide",e)},()=>i);return c}function Uo(e){if(e.caret)return e.buttons.value.filter(t=>!e.isViewingSource.value||t.find(e=>"viewsource"===e.cmd)).map(t=>Bo(t.map(t=>(!e.isViewingSource.value||"viewsource"===t.cmd)&&("slot"===t.type?Ae(e.slots[t.slot]):"dropdown"===t.type?Vo(e,t):Fo(e,t)))))}function $o(t){if(t.caret){let n=t.props.toolbarColor||t.props.toolbarTextColor,a=t.editLinkUrl.value,i=()=>{t.caret.restore(),a!==t.editLinkUrl.value&&document.execCommand("createLink",!1,""===a?" ":a),t.editLinkUrl.value=null};return[(0,e.h)("div",{class:`q-mx-xs text-${n}`},`${t.$q.lang.editor.url}: `),(0,e.h)("input",{key:"qedt_btm_input",class:"col q-editor__link-input",value:a,onInput:e=>{b(e),a=e.target.value},onKeydown:e=>{if(!I(e))switch(e.keyCode){case 13:return y(e),i();case 27:y(e),t.caret.restore(),(!t.editLinkUrl.value||"https://"===t.editLinkUrl.value)&&document.execCommand("unlink"),t.editLinkUrl.value=null}}}),Bo([(0,e.h)(Kt,{key:"qedt_btm_rem",...t.buttonProps.value,label:t.$q.lang.label.remove,noCaps:!0,onClick:()=>{t.caret.restore(),document.execCommand("unlink"),t.editLinkUrl.value=null}}),(0,e.h)(Kt,{key:"qedt_btm_upd",...t.buttonProps.value,label:t.$q.lang.label.update,noCaps:!0,onClick:i})])]}}let Ho=/^on[A-Z]/;function Wo(){let{attrs:t,vnode:n}=(0,e.getCurrentInstance)(),a={listeners:(0,e.ref)({}),attributes:(0,e.ref)({})};function i(){let e={},i={};for(let n in t)"class"!==n&&"style"!==n&&!Ho.test(n)&&(e[n]=t[n]);for(let e in n.props)Ho.test(e)&&(i[e]=n.props[e]);a.attributes.value=e,a.listeners.value=i}return(0,e.onBeforeUpdate)(i),i(),a}let Go=Object.prototype.toString,Ko=Object.prototype.hasOwnProperty,Yo=new Set(["Boolean","Number","String","Function","Array","Date","RegExp"].map(e=>"[object "+e+"]"));function Qo(e){if(e!==Object(e)||Yo.has(Go.call(e))||e.constructor&&!Ko.call(e,"constructor")&&!Ko.call(e.constructor.prototype,"isPrototypeOf"))return!1;let t;for(t in e);return void 0===t||Ko.call(e,t)}function Zo(...e){let t,n,a,i,r,o,s=e[0]||{},l=1,u=!1,c=e.length;for("boolean"==typeof s&&(u=s,s=e[1]||{},l=2),Object(s)!==s&&"function"!=typeof s&&(s={}),c===l&&(s=this,l--);le.every(e=>e.length),default:()=>[["left","center","right","justify"],["bold","italic","underline","strike"],["undo","redo"]]},toolbarColor:String,toolbarBg:String,toolbarTextColor:String,toolbarToggleColor:{type:String,default:"primary"},toolbarOutline:Boolean,toolbarPush:Boolean,toolbarRounded:Boolean,paragraphTag:{type:String,validator:e=>["div","p"].includes(e),default:"div"},contentStyle:Object,contentClass:[Object,Array,String],square:Boolean,flat:Boolean,dense:Boolean},emits:[...Wa,"update:modelValue","keydown","click","focus","blur","dropdownShow","dropdownHide","dropdownBeforeShow","dropdownBeforeHide","linkShow","linkHide"],setup(t,{slots:n,emit:a}){let i,r,{proxy:s}=(0,e.getCurrentInstance)(),{$q:l}=s,u=Xe(t,l),{inFullscreen:c,toggleFullscreen:d}=Ga(),h=Wo(),p=(0,e.ref)(null),f=(0,e.ref)(null),m=(0,e.ref)(null),_=(0,e.ref)(!1),g=(0,e.computed)(()=>!t.readonly&&!t.disable),v=null,b=t.modelValue,y=o.value;document.execCommand("defaultParagraphSeparator",!1,t.paragraphTag),i=window.getComputedStyle(document.body).fontFamily;let k=(0,e.computed)(()=>t.toolbarBg?` bg-${t.toolbarBg}`:""),x=(0,e.computed)(()=>({type:"a",flat:!t.toolbarOutline&&!t.toolbarPush,noWrap:!0,outline:t.toolbarOutline,push:t.toolbarPush,rounded:t.toolbarRounded,dense:!0,color:t.toolbarColor,disable:!g.value,size:"sm"})),S=(0,e.computed)(()=>{let e=l.lang.editor,n=l.iconSet.editor;return{bold:{cmd:"bold",icon:n.bold,tip:e.bold,key:66},italic:{cmd:"italic",icon:n.italic,tip:e.italic,key:73},strike:{cmd:"strikeThrough",icon:n.strikethrough,tip:e.strikethrough,key:83},underline:{cmd:"underline",icon:n.underline,tip:e.underline,key:85},unordered:{cmd:"insertUnorderedList",icon:n.unorderedList,tip:e.unorderedList},ordered:{cmd:"insertOrderedList",icon:n.orderedList,tip:e.orderedList},subscript:{cmd:"subscript",icon:n.subscript,tip:e.subscript,htmlTip:"x2"},superscript:{cmd:"superscript",icon:n.superscript,tip:e.superscript,htmlTip:"x2"},link:{cmd:"link",disable:e=>e.caret&&!e.caret.can("link"),icon:n.hyperlink,tip:e.hyperlink,key:76},fullscreen:{cmd:"fullscreen",icon:n.toggleFullscreen,tip:e.toggleFullscreen,key:70},viewsource:{cmd:"viewsource",icon:n.viewSource,tip:e.viewSource},quote:{cmd:"formatBlock",param:"BLOCKQUOTE",icon:n.quote,tip:e.quote,key:81},left:{cmd:"justifyLeft",icon:n.left,tip:e.left},center:{cmd:"justifyCenter",icon:n.center,tip:e.center},right:{cmd:"justifyRight",icon:n.right,tip:e.right},justify:{cmd:"justifyFull",icon:n.justify,tip:e.justify},print:{type:"no-state",cmd:"print",icon:n.print,tip:e.print,key:80},outdent:{type:"no-state",disable:e=>e.caret&&!e.caret.can("outdent"),cmd:"outdent",icon:n.outdent,tip:e.outdent},indent:{type:"no-state",disable:e=>e.caret&&!e.caret.can("indent"),cmd:"indent",icon:n.indent,tip:e.indent},removeFormat:{type:"no-state",cmd:"removeFormat",icon:n.removeFormat,tip:e.removeFormat},hr:{type:"no-state",cmd:"insertHorizontalRule",icon:n.hr,tip:e.hr},undo:{type:"no-state",cmd:"undo",icon:n.undo,tip:e.undo,key:90},redo:{type:"no-state",cmd:"redo",icon:n.redo,tip:e.redo,key:89},h1:{cmd:"formatBlock",param:"H1",icon:n.heading1||n.heading,tip:e.heading1,htmlTip:`

${e.heading1}

`},h2:{cmd:"formatBlock",param:"H2",icon:n.heading2||n.heading,tip:e.heading2,htmlTip:`

${e.heading2}

`},h3:{cmd:"formatBlock",param:"H3",icon:n.heading3||n.heading,tip:e.heading3,htmlTip:`

${e.heading3}

`},h4:{cmd:"formatBlock",param:"H4",icon:n.heading4||n.heading,tip:e.heading4,htmlTip:`

${e.heading4}

`},h5:{cmd:"formatBlock",param:"H5",icon:n.heading5||n.heading,tip:e.heading5,htmlTip:`
${e.heading5}
`},h6:{cmd:"formatBlock",param:"H6",icon:n.heading6||n.heading,tip:e.heading6,htmlTip:`
${e.heading6}
`},p:{cmd:"formatBlock",param:t.paragraphTag,icon:n.heading,tip:e.paragraph},code:{cmd:"formatBlock",param:"PRE",icon:n.code,htmlTip:`${e.code}`},"size-1":{cmd:"fontSize",param:"1",icon:n.size1||n.size,tip:e.size1,htmlTip:`${e.size1}`},"size-2":{cmd:"fontSize",param:"2",icon:n.size2||n.size,tip:e.size2,htmlTip:`${e.size2}`},"size-3":{cmd:"fontSize",param:"3",icon:n.size3||n.size,tip:e.size3,htmlTip:`${e.size3}`},"size-4":{cmd:"fontSize",param:"4",icon:n.size4||n.size,tip:e.size4,htmlTip:`${e.size4}`},"size-5":{cmd:"fontSize",param:"5",icon:n.size5||n.size,tip:e.size5,htmlTip:`${e.size5}`},"size-6":{cmd:"fontSize",param:"6",icon:n.size6||n.size,tip:e.size6,htmlTip:`${e.size6}`},"size-7":{cmd:"fontSize",param:"7",icon:n.size7||n.size,tip:e.size7,htmlTip:`${e.size7}`}}}),C=(0,e.computed)(()=>{let e=t.definitions||{},n=t.definitions||t.fonts?Zo(!0,{},S.value,e,function(e,t,n,a={}){let i=Object.keys(a);if(0===i.length)return{};let r={default_font:{cmd:"fontName",param:e,icon:n,tip:t}};return i.forEach(e=>{let t=a[e];r[e]={cmd:"fontName",param:t,icon:n,tip:t,htmlTip:`${t}`}}),r}(i,l.lang.editor.defaultFont,l.iconSet.editor.font,t.fonts)):S.value;return t.toolbar.map(t=>t.map(t=>{if(t.options)return{type:"dropdown",icon:t.icon,label:t.label,size:"sm",dense:!0,fixedLabel:t.fixedLabel,fixedIcon:t.fixedIcon,highlight:t.highlight,list:t.list,options:t.options.map(e=>n[e])};let a=n[t];return a?"no-state"===a.type||e[t]&&(void 0===a.cmd||S.value[a.cmd]&&"no-state"===S.value[a.cmd].type)?a:{type:"toggle",...a}:{type:"slot",slot:t}}))}),T={$q:l,props:t,slots:n,emit:a,inFullscreen:c,toggleFullscreen:d,runCmd:$,isViewingSource:_,editLinkUrl:m,toolbarBackgroundClass:k,buttonProps:x,contentRef:f,buttons:C,setContent:U};(0,e.watch)(()=>t.modelValue,e=>{b!==e&&(b=e,U(e,!0))}),(0,e.watch)(m,e=>{a("link"+(e?"Show":"Hide"))});let P=(0,e.computed)(()=>t.toolbar&&0!==t.toolbar.length),E=(0,e.computed)(()=>{let e={},t=t=>{t.key&&(e[t.key]={cmd:t.cmd,param:t.param})};return C.value.forEach(e=>{e.forEach(e=>{e.options?e.options.forEach(t):t(e)})}),e}),A=(0,e.computed)(()=>c.value?t.contentStyle:[{minHeight:t.minHeight,height:t.height,maxHeight:t.maxHeight},t.contentStyle]),L=(0,e.computed)(()=>"q-editor q-editor--"+(_.value?"source":"default")+(t.disable?" disabled":"")+(c.value?" fullscreen column":"")+(t.square?" q-editor--square no-border-radius":"")+(t.flat?" q-editor--flat":"")+(t.dense?" q-editor--dense":"")+(u.value?" q-editor--dark q-dark":"")),M=(0,e.computed)(()=>[t.contentClass,"q-editor__content",{col:c.value,"overflow-auto":c.value||t.maxHeight}]),R=(0,e.computed)(()=>t.disable?{"aria-disabled":"true"}:{});function z(){if(null!==f.value){let e="inner"+(_.value?"Text":"HTML"),n=f.value[e];n!==t.modelValue&&(b=n,a("update:modelValue",n))}}function N(e){if(a("keydown",e),!e.ctrlKey||I(e))return void H();let t=e.keyCode,n=E.value[t];if(void 0!==n){let{cmd:t,param:a}=n;w(e),$(t,a,!1)}}function O(e){H(),a("click",e)}function j(e){if(null!==f.value){let{scrollTop:e,scrollHeight:t}=f.value;r=t-e}T.caret.save(),a("blur",e)}function D(t){(0,e.nextTick)(()=>{null!==f.value&&void 0!==r&&(f.value.scrollTop=f.value.scrollHeight-r)}),a("focus",t)}function q(e){let t=p.value;if(null!==t&&t.contains(e.target)&&(null===e.relatedTarget||!t.contains(e.relatedTarget))){let e="inner"+(_.value?"Text":"HTML");T.caret.restorePosition(f.value[e].length),H()}}function B(e){let t=p.value;null!==t&&t.contains(e.target)&&(null===e.relatedTarget||!t.contains(e.relatedTarget))&&(T.caret.savePosition(),H())}function F(){r=void 0}function V(){T.caret.save()}function U(e,t){if(null!==f.value){t&&T.caret.savePosition();let n="inner"+(_.value?"Text":"HTML");f.value[n]=e,t&&(T.caret.restorePosition(f.value[n].length),H())}}function $(e,t,n=!0){W(),T.caret.restore(),T.caret.apply(e,t,()=>{W(),T.caret.save(),n&&H()})}function H(){null!==v&&clearTimeout(v),v=setTimeout(()=>{v=null,m.value=null,s.$forceUpdate()},1)}function W(){dn(()=>{f.value?.focus({preventScroll:!0})})}return(0,e.onMounted)(()=>{T.caret=s.caret=new Io(f.value,T),U(t.modelValue),H(),document.addEventListener("selectionchange",V)}),(0,e.onBeforeUnmount)(()=>{null!==v&&clearTimeout(v),document.removeEventListener("selectionchange",V)}),Object.assign(s,{runCmd:$,refreshToolbar:H,focus:W,getContentEl:function(){return f.value}}),()=>{let n;if(P.value){let t=[(0,e.h)("div",{key:"qedt_top",class:"q-editor__toolbar row no-wrap scroll-x"+k.value},Uo(T))];null!==m.value&&t.push((0,e.h)("div",{key:"qedt_btm",class:"q-editor__toolbar row no-wrap items-center scroll-x"+k.value},$o(T))),n=(0,e.h)("div",{key:"toolbar_ctainer",class:"q-editor__toolbars-container"},t)}return(0,e.h)("div",{ref:p,class:L.value,style:{height:c.value?"100%":null},...R.value,onFocusin:q,onFocusout:B},[n,(0,e.h)("div",{ref:f,style:A.value,class:M.value,contenteditable:g.value,placeholder:t.placeholder,...y?{innerHTML:t.modelValue}:{},...h.listeners.value,onInput:z,onKeydown:N,onClick:O,onBlur:j,onFocus:D,onMousedown:F,onTouchstartPassive:F})])}}}),Xo=h({name:"QItemLabel",props:{overline:Boolean,caption:Boolean,header:Boolean,lines:[Number,String]},setup(t,{slots:n}){let a=(0,e.computed)(()=>Number.parseInt(t.lines,10)),i=(0,e.computed)(()=>"q-item__label"+(t.overline?" q-item__label--overline text-overline":"")+(t.caption?" q-item__label--caption text-caption":"")+(t.header?" q-item__label--header":"")+(1===a.value?" ellipsis":"")),r=(0,e.computed)(()=>void 0!==t.lines&&a.value>1?{overflow:"hidden",display:"-webkit-box","-webkit-box-orient":"vertical","-webkit-line-clamp":a.value}:null);return()=>(0,e.h)("div",{style:r.value,class:i.value},Ae(n.default))}}),es=h({name:"QSlideTransition",props:{appear:Boolean,duration:{type:Number,default:300}},emits:["show","hide"],setup(t,{slots:n,emit:a}){let i,r,o,s,l=!1,u=null,c=null;function d(){i?.(),i=null,l=!1,null!==u&&(clearTimeout(u),u=null),null!==c&&(clearTimeout(c),c=null),r?.removeEventListener("transitionend",o),o=null}function h(e,n,a){void 0!==n&&(e.style.height=`${n}px`),e.style.transition=`height ${t.duration}ms cubic-bezier(.25, .8, .50, 1)`,l=!0,i=a}function p(e,t){e.style.overflowY=null,e.style.height=null,e.style.transition=null,d(),t!==s&&a(t)}function f(e,n){let a=0;r=e,l?(d(),a=e.offsetHeight===e.scrollHeight?0:void 0):(s="hide",e.style.overflowY="hidden"),h(e,a,n),u=setTimeout(()=>{u=null,e.style.height=`${e.scrollHeight}px`,o=t=>{c=null,(Object(t)!==t||t.target===e)&&p(e,"show")},e.addEventListener("transitionend",o),c=setTimeout(o,1.1*t.duration)},100)}function m(e,n){let a;r=e,l?d():(s="show",e.style.overflowY="hidden",a=e.scrollHeight),h(e,a,n),u=setTimeout(()=>{u=null,e.style.height=0,o=t=>{c=null,(Object(t)!==t||t.target===e)&&p(e,"hide")},e.addEventListener("transitionend",o),c=setTimeout(o,1.1*t.duration)},100)}return(0,e.onBeforeUnmount)(()=>{l&&d()}),()=>(0,e.h)(e.Transition,{css:!1,appear:t.appear,onEnter:f,onLeave:m},n.default)}});let ts={true:"inset",item:"item-inset","item-thumbnail":"item-thumbnail-inset"},ns={xs:2,sm:4,md:8,lg:16,xl:24};var as=h({name:"QSeparator",props:{...Je,spaced:[Boolean,String],inset:[Boolean,String],vertical:Boolean,color:String,size:String},setup(t){let n=Xe(t,(0,e.getCurrentInstance)().proxy.$q),a=(0,e.computed)(()=>t.vertical?"vertical":"horizontal"),i=(0,e.computed)(()=>` q-separator--${a.value}`),r=(0,e.computed)(()=>t.inset?`${i.value}-${ts[t.inset]}`:""),o=(0,e.computed)(()=>`q-separator${i.value}${r.value}`+(void 0===t.color?"":` bg-${t.color}`)+(n.value?" q-separator--dark":"")),s=(0,e.computed)(()=>{let e={};if(void 0!==t.size&&(e[t.vertical?"width":"height"]=t.size),t.spaced){let n=!0===t.spaced?`${ns.md}px`:t.spaced in ns?`${ns[t.spaced]}px`:t.spaced,a=t.vertical?["Left","Right"]:["Top","Bottom"];e[`margin${a[0]}`]=e[`margin${a[1]}`]=n}return e});return()=>(0,e.h)("hr",{class:o.value,style:s.value,"aria-orientation":a.value})}});let is=(0,e.shallowReactive)({});function rs(e){32===e.keyCode&&w(e)}let os=Object.keys(vt);var ss=h({name:"QExpansionItem",props:{...vt,...tn,...Je,icon:String,label:String,labelLines:[Number,String],caption:String,captionLines:[Number,String],dense:Boolean,toggleAriaLabel:String,expandIcon:String,expandedIcon:String,expandIconClass:[Array,String,Object],duration:{},headerInsetLevel:Number,contentInsetLevel:Number,expandSeparator:Boolean,defaultOpened:Boolean,hideExpandIcon:Boolean,expandIconToggle:Boolean,switchToggleSide:Boolean,denseToggle:Boolean,group:String,popup:Boolean,headerStyle:[Array,String,Object],headerClass:[Array,String,Object]},emits:[...nn,"click","afterShow","afterHide"],setup(t,{slots:n,emit:a}){let i,r,{proxy:{$q:o}}=(0,e.getCurrentInstance)(),s=Xe(t,o),l=(0,e.ref)(null===t.modelValue?t.defaultOpened:t.modelValue),u=(0,e.ref)(null),c=va(),{show:d,hide:h,toggle:p}=an({showing:l}),f=(0,e.computed)(()=>`q-expansion-item q-item-type q-expansion-item--${l.value?"expanded":"collapsed"} q-expansion-item--${t.popup?"popup":"standard"}`),m=(0,e.computed)(()=>void 0===t.contentInsetLevel?null:{["padding"+(o.lang.rtl?"Right":"Left")]:56*t.contentInsetLevel+"px"}),_=(0,e.computed)(()=>!t.disable&&(void 0!==t.href||void 0!==t.to&&null!==t.to&&""!==t.to)),g=(0,e.computed)(()=>{let e={};return os.forEach(n=>{e[n]=t[n]}),e}),v=(0,e.computed)(()=>_.value||!t.expandIconToggle),b=(0,e.computed)(()=>void 0!==t.expandedIcon&&l.value?t.expandedIcon:t.expandIcon||o.iconSet.expansionItem[t.denseToggle?"denseIcon":"icon"]),y=(0,e.computed)(()=>!t.disable&&(_.value||t.expandIconToggle)),k=(0,e.computed)(()=>({expanded:l.value,detailsId:c.value,toggle:p,show:d,hide:h})),x=(0,e.computed)(()=>{let e=void 0===t.toggleAriaLabel?o.lang.label[l.value?"collapse":"expand"](t.label):t.toggleAriaLabel;return{role:"button","aria-expanded":l.value?"true":"false","aria-controls":c.value,"aria-label":e}});function S(e){_.value||p(e),a("click",e)}function C(e){[13,32].includes(e.keyCode)&&T(e,!0)}function T(e,t){!t&&!e.qAvoidFocus&&u.value?.focus(),p(e),w(e)}function P(){a("afterShow")}function E(){a("afterHide")}function A(){void 0===i&&(i=_a()),l.value&&(is[t.group]=i);let n=(0,e.watch)(l,e=>{e?is[t.group]=i:is[t.group]===i&&delete is[t.group]}),a=(0,e.watch)(()=>is[t.group],(e,t)=>{t===i&&void 0!==e&&e!==i&&h()});r=()=>{n(),a(),is[t.group]===i&&delete is[t.group],r=void 0}}function L(){let a;return void 0===n.header?(a=[(0,e.h)(Do,()=>[(0,e.h)(Xo,{lines:t.labelLines},()=>t.label||""),t.caption?(0,e.h)(Xo,{lines:t.captionLines,caption:!0},()=>t.caption):null])],t.icon&&a[t.switchToggleSide?"push":"unshift"]((0,e.h)(Do,{side:t.switchToggleSide,avatar:!t.switchToggleSide},()=>(0,e.h)(Ke,{name:t.icon})))):a=[n.header(k.value)].flat(),!t.disable&&!t.hideExpandIcon&&a[t.switchToggleSide?"unshift":"push"](function(){let n={class:["q-focusable relative-position cursor-pointer"+(t.denseToggle&&t.switchToggleSide?" items-end":""),t.expandIconClass],side:!t.switchToggleSide,avatar:t.switchToggleSide},a=[(0,e.h)(Ke,{class:"q-expansion-item__toggle-icon"+(void 0===t.expandedIcon&&l.value?" q-expansion-item__toggle-icon--rotated":""),name:b.value})];return y.value&&(Object.assign(n,{tabindex:0,...x.value,onClick:T,onKeydown:rs,onKeyup:C}),a.unshift((0,e.h)("div",{ref:u,class:"q-expansion-item__toggle-focus q-icon q-focus-helper q-focus-helper--rounded",tabindex:-1}))),(0,e.h)(Do,n,()=>a)}()),a}function M(){let n={ref:"item",style:t.headerStyle,class:t.headerClass,dark:s.value,disable:t.disable,dense:t.dense,insetLevel:t.headerInsetLevel};return v.value&&(n.clickable=!0,n.onClick=S,Object.assign(n,_.value?g.value:x.value)),(0,e.h)(jo,n,L)}function R(){return(0,e.withDirectives)((0,e.h)("div",{key:"e-content",class:"q-expansion-item__content relative-position",style:m.value,id:c.value},Ae(n.default)),[[e.vShow,l.value]])}function z(){let n=[M(),(0,e.h)(es,{duration:t.duration,onShow:P,onHide:E},R)];return t.expandSeparator&&n.push((0,e.h)(as,{class:"q-expansion-item__border q-expansion-item__border--top absolute-top",dark:s.value}),(0,e.h)(as,{class:"q-expansion-item__border q-expansion-item__border--bottom absolute-bottom",dark:s.value})),n}return(0,e.watch)(()=>t.group,e=>{r?.(),void 0!==e&&A()}),void 0!==t.group&&A(),(0,e.onBeforeUnmount)(()=>{r?.()}),()=>(0,e.h)("div",{class:f.value},[(0,e.h)("div",{class:"q-expansion-item__container relative-position"},z())])}});let ls=["top","right","bottom","left"],us={type:{type:String,default:"a"},outline:Boolean,push:Boolean,flat:Boolean,unelevated:Boolean,color:String,textColor:String,glossy:Boolean,square:Boolean,padding:String,label:{type:[String,Number],default:""},labelPosition:{type:String,default:"right",validator:e=>ls.includes(e)},externalLabel:Boolean,hideLabel:{type:Boolean},labelClass:[Array,String,Object],labelStyle:[Array,String,Object],disable:Boolean,tabindex:[Number,String]};function cs(t,n){return{formClass:(0,e.computed)(()=>"q-fab--form-"+(t.square?"square":"rounded")),stacked:(0,e.computed)(()=>!t.externalLabel&&["top","bottom"].includes(t.labelPosition)),labelProps:(0,e.computed)(()=>{if(t.externalLabel){let e=null===t.hideLabel?!n.value:t.hideLabel;return{action:"push",data:{class:[t.labelClass,`q-fab__label q-tooltip--style q-fab__label--external q-fab__label--external-${t.labelPosition}`+(e?" q-fab__label--external-hidden":"")],style:t.labelStyle}}}return{action:["left","top"].includes(t.labelPosition)?"unshift":"push",data:{class:[t.labelClass,`q-fab__label q-fab__label--internal q-fab__label--internal-${t.labelPosition}`+(t.hideLabel?" q-fab__label--internal-hidden":"")],style:t.labelStyle}}})}}let ds=["up","right","down","left"],hs=["left","center","right"];var ps=h({name:"QFab",props:{...us,...tn,icon:String,activeIcon:String,hideIcon:Boolean,hideLabel:{...us.hideLabel,default:null},direction:{type:String,default:"right",validator:e=>ds.includes(e)},persistent:Boolean,verticalActionsAlign:{type:String,default:"center",validator:e=>hs.includes(e)}},emits:nn,setup(t,{slots:n}){let a=(0,e.ref)(null),i=(0,e.ref)(!0===t.modelValue),r=va(),{proxy:{$q:o}}=(0,e.getCurrentInstance)(),{formClass:s,labelProps:l}=cs(t,i),{hide:u,toggle:c}=an({showing:i,hideOnRouteChange:(0,e.computed)(()=>!t.persistent)}),d=(0,e.computed)(()=>({opened:i.value})),h=(0,e.computed)(()=>`q-fab z-fab row inline justify-center q-fab--align-${t.verticalActionsAlign} ${s.value}`+(i.value?" q-fab--opened":" q-fab--closed")),p=(0,e.computed)(()=>`q-fab__actions flex no-wrap inline q-fab__actions--${t.direction} q-fab__actions--${i.value?"opened":"closed"}`),f=(0,e.computed)(()=>{let e={id:r.value,role:"menu"};return i.value||(e["aria-hidden"]="true"),e}),m=(0,e.computed)(()=>"q-fab__icon-holder q-fab__icon-holder--"+(i.value?"opened":"closed"));function _(a,i){let r=n[a],s=`q-fab__${a} absolute-full`;return void 0===r?(0,e.h)(Ke,{class:s,name:t[i]||o.iconSet.fab[i]}):(0,e.h)("div",{class:s},r(d.value))}function g(){let a=[];return t.hideIcon||a.push((0,e.h)("div",{class:m.value},[_("icon","icon"),_("active-icon","activeIcon")])),(""!==t.label||void 0!==n.label)&&a[l.value.action]((0,e.h)("div",l.value.data,void 0===n.label?[t.label]:n.label(d.value))),Me(n.tooltip,a)}return(0,e.provide)(Q,{showing:i,onChildClick(e){u(e),!0!==e?.qAvoidFocus&&a.value?.$el.focus()}}),()=>(0,e.h)("div",{class:h.value},[(0,e.h)(Kt,{ref:a,class:s.value,...t,noWrap:!0,stack:t.stacked,align:void 0,icon:void 0,label:void 0,noCaps:!0,fab:!0,"aria-expanded":i.value?"true":"false","aria-haspopup":"true","aria-controls":r.value,onClick:c},g),(0,e.h)("div",{class:p.value,...f.value},Ae(n.default))])}});let fs={start:"self-end",center:"self-center",end:"self-start"},ms=Object.keys(fs);var _s=h({name:"QFabAction",props:{...us,icon:{type:String,default:""},anchor:{type:String,validator:e=>ms.includes(e)},to:[String,Object],replace:Boolean},emits:["click"],setup(t,{slots:n,emit:a}){let i=(0,e.inject)(Q,()=>({showing:{value:!0},onChildClick:_})),{formClass:r,labelProps:o}=cs(t,i.showing),s=(0,e.computed)(()=>{let e=fs[t.anchor];return r.value+(void 0===e?"":` ${e}`)}),l=(0,e.computed)(()=>t.disable||!i.showing.value);function u(e){i.onChildClick(e),a("click",e)}function c(){let a=[];return void 0===n.icon?""!==t.icon&&a.push((0,e.h)(Ke,{name:t.icon})):a.push(n.icon()),(""!==t.label||void 0!==n.label)&&a[o.value.action]((0,e.h)("div",o.value.data,void 0===n.label?[t.label]:n.label())),Me(n.default,a)}let d=(0,e.getCurrentInstance)();return Object.assign(d.proxy,{click:u}),()=>(0,e.h)(Kt,{class:s.value,...t,noWrap:!0,stack:t.stacked,icon:void 0,label:void 0,noCaps:!0,fabMini:!0,disable:l.value,onClick:u},c)}});function gs({validate:t,resetValidation:n,requiresQForm:a}){let i=(0,e.inject)(Z,!1);if(!1!==i){let{props:a,proxy:r}=(0,e.getCurrentInstance)();Object.assign(r,{validate:t,resetValidation:n}),(0,e.watch)(()=>a.disable,e=>{e?("function"==typeof n&&n(),i.unbindComponent(r)):i.bindComponent(r)}),(0,e.onMounted)(()=>{a.disable||i.bindComponent(r)}),(0,e.onBeforeUnmount)(()=>{a.disable||i.unbindComponent(r)})}else a&&console.error("Parent QForm not found on useFormChild()!")}let vs=[!0,!1,"ondemand"],bs={modelValue:{},error:{type:Boolean,default:null},errorMessage:String,noErrorIcon:Boolean,rules:Array,reactiveRules:Boolean,lazyRules:{type:[Boolean,String],default:!1,validator:e=>vs.includes(e)}};function ys(t,n){let{props:i,proxy:r}=(0,e.getCurrentInstance)(),o=(0,e.ref)(!1),s=(0,e.ref)(null),l=(0,e.ref)(!1);gs({validate:g,resetValidation:_});let u,c=0,d=(0,e.computed)(()=>void 0!==i.rules&&null!==i.rules&&0!==i.rules.length),h=(0,e.computed)(()=>!i.disable&&d.value&&!n.value),p=(0,e.computed)(()=>!0===i.error||o.value),f=(0,e.computed)(()=>"string"==typeof i.errorMessage&&0!==i.errorMessage.length?i.errorMessage:s.value);function m(){"ondemand"!==i.lazyRules&&h.value&&l.value&&v()}function _(){c++,n.value=!1,l.value=!1,o.value=!1,s.value=null,v.cancel()}function g(e=i.modelValue){if(i.disable||!d.value)return!0;let t=++c,a=n.value?()=>{}:()=>{l.value=!0},r=(e,t)=>{e&&a(),o.value=e,s.value=t||null,n.value=!1},u=[];for(let t=0;t{if(void 0===e||!Array.isArray(e)||0===e.length)return t===c&&r(!1),!0;let n=e.find(e=>!1===e||"string"==typeof e);return t===c&&r(void 0!==n,n),void 0===n},e=>(t===c&&(console.error(e),r(!0)),!1)))}(0,e.watch)(()=>i.modelValue,()=>{l.value=!0,h.value&&!1===i.lazyRules&&v()}),(0,e.watch)(()=>i.reactiveRules,t=>{t?void 0===u&&(u=(0,e.watch)(()=>i.rules,m,{immediate:!0,deep:!0})):void 0!==u&&(u(),u=void 0)},{immediate:!0}),(0,e.watch)(()=>i.lazyRules,m),(0,e.watch)(t,e=>{e?l.value=!0:h.value&&"ondemand"!==i.lazyRules&&v()});let v=T(g,0);return(0,e.onBeforeUnmount)(()=>{u?.(),v.cancel()}),Object.assign(r,{resetValidation:_,validate:g}),a(r,"hasError",()=>p.value),{isDirtyModel:l,hasRules:d,hasError:p,errorMessage:f,validate:g,resetValidation:_}}function ws(e){return null!=e&&0!==String(e).length}let ks={...Je,...bs,label:String,stackLabel:Boolean,hint:String,hideHint:Boolean,prefix:String,suffix:String,labelColor:String,color:String,bgColor:String,filled:Boolean,outlined:Boolean,borderless:Boolean,standout:[Boolean,String],square:Boolean,loading:Boolean,labelSlot:Boolean,bottomSlots:Boolean,hideBottomSpace:Boolean,rounded:Boolean,dense:Boolean,itemAligned:Boolean,counter:Boolean,clearable:Boolean,clearIcon:String,disable:Boolean,readonly:Boolean,autofocus:Boolean,for:String},xs={...ks,maxlength:[Number,String]},Ss=["update:modelValue","clear","focus","blur"];function Cs({requiredForAttr:t=!0,tagProp:n,changeEvent:a=!1}={}){let{props:i,proxy:r}=(0,e.getCurrentInstance)(),o=Xe(i,r.$q),s=va({required:t,getValue:()=>i.for});return{requiredForAttr:t,changeEvent:a,tag:n?(0,e.computed)(()=>i.tag):{value:"label"},isDark:o,editable:(0,e.computed)(()=>!i.disable&&!i.readonly),innerLoading:(0,e.ref)(!1),focused:(0,e.ref)(!1),hasPopupOpen:!1,splitAttrs:Wo(),targetUid:s,rootRef:(0,e.ref)(null),targetRef:(0,e.ref)(null),controlRef:(0,e.ref)(null)}}function Ts(t,n){return null===n?null:(0,e.h)("div",{key:t,class:"q-field__append q-field__marginal row no-wrap items-center q-anchor--skip"},n)}function Ps(t){let{props:n,emit:a,slots:i,attrs:r,proxy:o}=(0,e.getCurrentInstance)(),{$q:s}=o,l=null;void 0===t.hasValue&&(t.hasValue=(0,e.computed)(()=>ws(n.modelValue))),void 0===t.emitValue&&(t.emitValue=e=>{a("update:modelValue",e)}),void 0===t.controlEvents&&(t.controlEvents={onFocusin:P,onFocusout:E}),Object.assign(t,{clearValue:A,onControlFocusin:P,onControlFocusout:E,focus:T}),void 0===t.computedCounter&&(t.computedCounter=(0,e.computed)(()=>{if(n.counter){let e="string"==typeof n.modelValue||"number"==typeof n.modelValue?String(n.modelValue).length:Array.isArray(n.modelValue)?n.modelValue.length:0,t=void 0===n.maxlength?n.maxValues:n.maxlength;return e+(void 0===t?"":" / "+t)}}));let{isDirtyModel:u,hasRules:c,hasError:d,errorMessage:h,resetValidation:p}=ys(t.focused,t.innerLoading),f=void 0===t.floatingLabel?(0,e.computed)(()=>n.stackLabel||t.focused.value||t.hasValue.value):(0,e.computed)(()=>n.stackLabel||t.focused.value||t.floatingLabel.value),m=(0,e.computed)(()=>n.bottomSlots||void 0!==n.hint||c.value||n.counter||null!==n.error),_=(0,e.computed)(()=>n.filled?"filled":n.outlined?"outlined":n.borderless?"borderless":n.standout?"standout":"standard"),g=(0,e.computed)(()=>`q-field row no-wrap items-start q-field--${_.value}`+(void 0===t.fieldClass?"":` ${t.fieldClass.value}`)+(n.rounded?" q-field--rounded":"")+(n.square?" q-field--square":"")+(f.value?" q-field--float":"")+(b.value?" q-field--labeled":"")+(n.dense?" q-field--dense":"")+(n.itemAligned?" q-field--item-aligned q-item-type":"")+(t.isDark.value?" q-field--dark":"")+(void 0===t.getControl?" q-field--auto-height":"")+(t.focused.value?" q-field--focused":"")+(d.value?" q-field--error":"")+(d.value||t.focused.value?" q-field--highlighted":"")+(!n.hideBottomSpace&&m.value?" q-field--with-bottom":"")+(n.disable?" q-field--disabled":n.readonly?" q-field--readonly":"")),v=(0,e.computed)(()=>"q-field__control relative-position row no-wrap"+(void 0===n.bgColor?"":` bg-${n.bgColor}`)+(d.value?" text-negative":"string"==typeof n.standout&&0!==n.standout.length&&t.focused.value?` ${n.standout}`:void 0===n.color?"":` text-${n.color}`)),b=(0,e.computed)(()=>n.labelSlot||void 0!==n.label),k=(0,e.computed)(()=>"q-field__label no-pointer-events absolute ellipsis"+(void 0===n.labelColor||d.value?"":` text-${n.labelColor}`)),x=(0,e.computed)(()=>({id:t.targetUid.value,editable:t.editable.value,focused:t.focused.value,floatingLabel:f.value,modelValue:n.modelValue,emitValue:t.emitValue})),S=(0,e.computed)(()=>{let e={};return t.targetUid.value&&(e.for=t.targetUid.value),n.disable&&(e["aria-disabled"]="true"),e});function C(){let e=document.activeElement,n=t.targetRef?.value;n&&(null===e||e.id!==t.targetUid.value)&&(n.hasAttribute("tabindex")||(n=n.querySelector("[tabindex]")),n!==e&&n?.focus({preventScroll:!0}))}function T(){dn(C)}function P(e){null!==l&&(clearTimeout(l),l=null),t.editable.value&&!t.focused.value&&(t.focused.value=!0,a("focus",e))}function E(e,n){null!==l&&clearTimeout(l),l=setTimeout(()=>{l=null,(!document.hasFocus()||!t.hasPopupOpen&&void 0!==t.controlRef&&null!==t.controlRef.value&&!t.controlRef.value.contains(document.activeElement))&&(t.focused.value&&(t.focused.value=!1,a("blur",e)),n?.())},0)}function A(i){w(i),s.platform.is.mobile?t.rootRef.value.contains(document.activeElement)&&document.activeElement.blur():(t.targetRef?.value||t.rootRef.value).focus(),"file"===n.type&&(t.inputRef.value.value=null),t.onClear?.(),a("update:modelValue",null),t.changeEvent&&a("change",null),a("clear",n.modelValue),(0,e.nextTick)(()=>{let e=u.value;p(),u.value=e})}function L(e){[13,32].includes(e.keyCode)&&A(e)}function M(){let a=[];return void 0!==i.prepend&&a.push((0,e.h)("div",{class:"q-field__prepend q-field__marginal row no-wrap items-center",key:"prepend",onClick:y},i.prepend())),a.push((0,e.h)("div",{class:"q-field__control-container col relative-position row no-wrap q-anchor--skip"},function(){let a=[];return void 0!==n.prefix&&null!==n.prefix&&a.push((0,e.h)("div",{class:"q-field__prefix no-pointer-events row items-center"},n.prefix)),void 0!==t.getShadowControl&&t.hasShadow.value&&a.push(t.getShadowControl()),b.value&&a.push((0,e.h)("div",{class:k.value},Ae(i.label,n.label))),void 0===t.getControl?void 0===i.rawControl?void 0!==i.control&&a.push((0,e.h)("div",{ref:t.targetRef,class:"q-field__native row",tabindex:-1,...t.splitAttrs.attributes.value,"data-autofocus":n.autofocus||void 0},i.control(x.value))):a.push(i.rawControl()):a.push(t.getControl()),void 0!==n.suffix&&null!==n.suffix&&a.push((0,e.h)("div",{class:"q-field__suffix no-pointer-events row items-center"},n.suffix)),a.concat(Ae(i.default))}())),d.value&&!n.noErrorIcon&&a.push(Ts("error",[(0,e.h)(Ke,{name:s.iconSet.field.error,color:"negative"})])),n.loading||t.innerLoading.value?a.push(Ts("inner-loading-append",void 0===i.loading?[(0,e.h)(xt,{color:n.color})]:i.loading())):n.clearable&&t.hasValue.value&&t.editable.value&&a.push(Ts("inner-clearable-append",[(0,e.h)(Ke,{class:"q-field__focusable-action",name:n.clearIcon||s.iconSet.field.clear,tabindex:0,role:"button","aria-hidden":"false","aria-label":s.lang.label.clear,onKeyup:L,onClick:A})])),void 0!==i.append&&a.push((0,e.h)("div",{class:"q-field__append q-field__marginal row no-wrap items-center",key:"append",onClick:y},i.append())),void 0!==t.getInnerAppend&&a.push(Ts("inner-append",t.getInnerAppend())),void 0!==t.getControlChild&&a.push(t.getControlChild()),a}function R(){let a,r;d.value?null===h.value?(a=Ae(i.error),r="q--slot-error"):(a=[(0,e.h)("div",{role:"alert"},h.value)],r=`q--slot-error-${h.value}`):(!n.hideHint||t.focused.value)&&(void 0===n.hint?(a=Ae(i.hint),r="q--slot-hint"):(a=[(0,e.h)("div",n.hint)],r=`q--slot-hint-${n.hint}`));let o=n.counter||void 0!==i.counter;if(n.hideBottomSpace&&!o&&void 0===a)return;let s=(0,e.h)("div",{key:r,class:"q-field__messages col"},a);return(0,e.h)("div",{class:"q-field__bottom row items-start q-field__bottom--"+(n.hideBottomSpace?"stale":"animated"),onClick:y},[n.hideBottomSpace?s:(0,e.h)(e.Transition,{name:"q-transition--field-message"},()=>s),o?(0,e.h)("div",{class:"q-field__counter"},void 0===i.counter?t.computedCounter.value:i.counter()):null])}let z=!1;return(0,e.onDeactivated)(()=>{z=!0}),(0,e.onActivated)(()=>{z&&n.autofocus&&o.focus()}),n.autofocus&&(0,e.onMounted)(()=>{o.focus()}),(0,e.onBeforeUnmount)(()=>{null!==l&&clearTimeout(l)}),Object.assign(o,{focus:T,blur:function(){!function(e){sn=sn.filter(t=>t!==e)}(C);let e=document.activeElement;null!==e&&t.rootRef.value.contains(e)&&e.blur()}}),function(){let a=void 0===t.getControl&&void 0===i.control?{...t.splitAttrs.attributes.value,"data-autofocus":n.autofocus||void 0,...S.value}:S.value;return(0,e.h)(t.tag.value,{ref:t.rootRef,class:[g.value,r.class],style:r.style,...a},[void 0===i.before?null:(0,e.h)("div",{class:"q-field__before q-field__marginal row no-wrap items-center",onClick:y},i.before()),(0,e.h)("div",{class:"q-field__inner relative-position col self-stretch"},[(0,e.h)("div",{ref:t.controlRef,class:v.value,tabindex:-1,...t.controlEvents},M()),m.value?R():null]),void 0===i.after?null:(0,e.h)("div",{class:"q-field__after q-field__marginal row no-wrap items-center",onClick:y},i.after())])}}var Es=h({name:"QField",inheritAttrs:!1,props:{...xs,tag:{type:String,default:"label"}},emits:Ss,setup:()=>Ps(Cs({tagProp:!0}))});function As(e,t,n,a){let i=[];return e.forEach(e=>{a(e)?i.push(e):t.push({failedPropValidation:n,file:e})}),i}function Ls(e){e?.dataTransfer&&(e.dataTransfer.dropEffect="copy"),w(e)}let Ms={multiple:Boolean,accept:String,capture:String,maxFileSize:[Number,String],maxTotalSize:[Number,String],maxFiles:[Number,String],filter:Function},Rs=["rejected"];function zs({editable:t,dnd:n,getFileInput:a,addFilesToQueue:i}){let{props:r,emit:o,proxy:s}=(0,e.getCurrentInstance)(),l=(0,e.ref)(null),u=(0,e.computed)(()=>void 0===r.accept?null:r.accept.split(",").map(e=>"*"===(e=e.trim())?"*/":(e.endsWith("/*")&&(e=e.slice(0,-1)),e.toUpperCase()))),d=(0,e.computed)(()=>Number.parseInt(r.maxFiles,10)),h=(0,e.computed)(()=>Number.parseInt(r.maxTotalSize,10));function p(e){if(t.value)if(e!==Object(e)&&(e={target:null}),!0===e.target?.matches('input[type="file"]'))0===e.clientX&&0===e.clientY&&b(e);else{let t=a();t!==e.target&&t?.click(e)}}function f(e){t.value&&e&&i(null,e)}function m(e){w(e),(null===e.relatedTarget&&c.is.safari?!document.elementsFromPoint(e.clientX,e.clientY).includes(l.value):e.relatedTarget!==l.value)&&(n.value=!1)}function _(e){Ls(e);let t=e.dataTransfer.files;0!==t.length&&i(null,t),n.value=!1}return Object.assign(s,{pickFiles:p,addFiles:f}),{pickFiles:p,addFiles:f,onDragover:function(e){Ls(e),n.value||=!0},onDragleave:m,processFiles:function(e,t,n,a){let i=[...t||e.target.files],s=[],l=()=>{0!==s.length&&o("rejected",s)};if(void 0!==r.accept&&!u.value.includes("*/")&&(i=As(i,s,"accept",e=>u.value.some(t=>(t.endsWith("/")?e.type.toUpperCase().startsWith(t):e.type.toUpperCase()===t)||e.name.toUpperCase().endsWith(t))),0===i.length))return l();if(void 0!==r.maxFileSize){let e=Number.parseInt(r.maxFileSize,10);if(i=As(i,s,"max-file-size",t=>t.size<=e),0===i.length)return l()}if(!r.multiple&&0!==i.length&&(i=[i[0]]),i.forEach(e=>{e.__key=JSON.stringify([e.webkitRelativePath,e.lastModified,e.name,e.size])}),a){let e=new Set(n.map(e=>e.__key));i=As(i,s,"duplicate",t=>!e.has(t.__key)&&(e.add(t.__key),!0))}if(0===i.length)return l();if(void 0!==r.maxTotalSize){let e=a?n.reduce((e,t)=>e+t.size,0):0;if(i=As(i,s,"max-total-size",t=>{let n=e+t.size;return!(n>h.value)&&(e=n,!0)}),0===i.length)return l()}if("function"==typeof r.filter){let e=r.filter(i);i=As(i,s,"filter",t=>e.includes(t))}if(void 0!==r.maxFiles){let e=a?n.length:0;if(i=As(i,s,"max-files",()=>(e++,e<=d.value)),0===i.length)return l()}return l(),0!==i.length?i:void 0},getDndNode:function(t){if(n.value)return(0,e.h)("div",{ref:l,class:`q-${t}__dnd absolute-full`,onDragenter:Ls,onDragover:Ls,onDragleave:m,onDrop:_})},maxFilesNumber:d,maxTotalSizeNumber:h}}function Is(t,n){function a(){let e=t.modelValue;try{let t="DataTransfer"in window?new DataTransfer:"ClipboardEvent"in window?new ClipboardEvent("").clipboardData:void 0;return Object(e)===e&&("length"in e?[...e]:[e]).forEach(e=>{t.items.add(e)}),{files:t.files}}catch{return{files:void 0}}}return n?(0,e.computed)(()=>{if("file"===t.type)return a()}):(0,e.computed)(a)}function Ns(e){13===e.keyCode&&y(e)}var Os=h({name:"QFile",inheritAttrs:!1,props:{...ks,...wa,...Ms,modelValue:[File,FileList,Array],append:Boolean,useChips:Boolean,displayValue:[String,Number],tabindex:{type:[String,Number],default:0},counterLabel:Function,inputClass:[Array,String,Object],inputStyle:[Array,String,Object]},emits:[...Ss,...Rs],setup(t,{slots:n,emit:i,attrs:r}){let{proxy:o}=(0,e.getCurrentInstance)(),s=Cs(),l=(0,e.ref)(null),u=(0,e.ref)(!1),c=Sa(t),{pickFiles:d,onDragover:h,onDragleave:p,processFiles:f,getDndNode:m}=zs({editable:s.editable,dnd:u,getFileInput:E,addFilesToQueue:A}),_=Is(t),g=(0,e.computed)(()=>Object(t.modelValue)===t.modelValue?"length"in t.modelValue?[...t.modelValue]:[t.modelValue]:[]),v=(0,e.computed)(()=>ws(g.value)),b=(0,e.computed)(()=>g.value.map(e=>e.name).join(", ")),y=(0,e.computed)(()=>fe(g.value.reduce((e,t)=>e+t.size,0))),w=(0,e.computed)(()=>({totalSize:y.value,filesNumber:g.value.length,maxFiles:t.maxFiles})),k=(0,e.computed)(()=>({tabindex:-1,type:"file",title:"",accept:t.accept,capture:t.capture,name:c.value,...r,id:s.targetUid.value,disabled:!s.editable.value})),x=(0,e.computed)(()=>"q-file q-field--auto-height"+(u.value?" q-file--dnd":"")),S=(0,e.computed)(()=>t.multiple&&t.append);function C(e){let t=[...g.value];t.splice(e,1),T(t)}function T(e){i("update:modelValue",t.multiple?e:e[0])}function P(e){(13===e.keyCode||32===e.keyCode)&&d(e)}function E(){return l.value}function A(e,n){let a=f(e,n,g.value,S.value),i=E();null!=i&&(i.value=""),void 0!==a&&((t.multiple?t.modelValue&&a.every(e=>g.value.includes(e)):t.modelValue===a[0])||T(S.value?[...g.value,...a]:a))}function L(){return[(0,e.h)("input",{class:[t.inputClass,"q-file__filler"],style:t.inputStyle})]}function M(){if(void 0!==n.file)return 0===g.value.length?L():g.value.map((e,t)=>n.file({index:t,file:e,ref:this}));if(void 0!==n.selected)return 0===g.value.length?L():n.selected({files:g.value,ref:this});if(t.useChips)return 0===g.value.length?L():g.value.map((n,a)=>(0,e.h)(ui,{key:"file-"+a,removable:s.editable.value,dense:!0,textColor:t.color,tabindex:t.tabindex,onRemove:()=>{C(a)}},()=>(0,e.h)("span",{class:"ellipsis",textContent:n.name})));let a=void 0===t.displayValue?b.value:t.displayValue;return 0===a.length?L():[(0,e.h)("div",{class:t.inputClass,style:t.inputStyle,textContent:a})]}function R(){let n={ref:l,...k.value,..._.value,class:"q-field__input fit absolute-full cursor-pointer",onChange:A};return t.multiple&&(n.multiple=!0),(0,e.h)("input",n)}return Object.assign(s,{fieldClass:x,emitValue:T,hasValue:v,inputRef:l,innerValue:g,floatingLabel:(0,e.computed)(()=>v.value||ws(t.displayValue)),computedCounter:(0,e.computed)(()=>{if(void 0!==t.counterLabel)return t.counterLabel(w.value);let e=t.maxFiles;return`${g.value.length}${void 0===e?"":" / "+e} (${y.value})`}),getControlChild:()=>m("file"),getControl:()=>{let n={ref:s.targetRef,class:"q-field__native row items-center cursor-pointer",tabindex:t.tabindex};return s.editable.value&&Object.assign(n,{onDragover:h,onDragleave:p,onKeydown:Ns,onKeyup:P}),(0,e.h)("div",n,[R()].concat(M()))}}),Object.assign(o,{removeAtIndex:C,removeFile:function(e){let t=g.value.indexOf(e);-1!==t&&C(t)},getNativeElement:()=>l.value}),a(o,"nativeEl",()=>l.value),Ps(s)}});function js(e,t){e.value!==t&&(e.value=t)}var Ds=h({name:"QFooter",props:{modelValue:{type:Boolean,default:!0},reveal:Boolean,bordered:Boolean,elevated:Boolean,heightHint:{type:[String,Number],default:50}},emits:["reveal","focusin"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=(0,e.inject)(Y,ee);if(r===ee)return console.error("QFooter needs to be child of QLayout"),ee;let s=(0,e.ref)(Number.parseInt(t.heightHint,10)),l=(0,e.ref)(!0),u=(0,e.ref)(o.value||r.isContainer.value?0:window.innerHeight),c=(0,e.computed)(()=>t.reveal||r.view.value.includes("F")||i.platform.is.ios&&r.isContainer.value),d=(0,e.computed)(()=>r.isContainer.value?r.containerHeight.value:u.value),h=(0,e.computed)(()=>{if(!t.modelValue)return 0;if(c.value)return l.value?s.value:0;let e=r.scroll.value.position+d.value+s.value-r.height.value;return Math.max(e,0)}),p=(0,e.computed)(()=>!t.modelValue||c.value&&!l.value),f=(0,e.computed)(()=>t.modelValue&&p.value&&t.reveal),m=(0,e.computed)(()=>"q-footer q-layout__section--marginal "+(c.value?"fixed":"absolute")+"-bottom"+(t.bordered?" q-footer--bordered":"")+(p.value?" q-footer--hidden":"")+(t.modelValue?"":" q-layout--prevent-focus"+(c.value?"":" hidden"))),_=(0,e.computed)(()=>{let e=r.rows.value.bottom,t={};return"l"===e[0]&&r.left.space&&(t[i.lang.rtl?"right":"left"]=`${r.left.size}px`),"r"===e[2]&&r.right.space&&(t[i.lang.rtl?"left":"right"]=`${r.right.size}px`),t});function g(e,t){r.update("footer",e,t)}function v({height:e}){js(s,e),g("size",e)}function b(e){f.value&&js(l,!0),a("focusin",e)}(0,e.watch)(()=>t.modelValue,e=>{g("space",e),js(l,!0),r.animate()}),(0,e.watch)(h,e=>{g("offset",e)}),(0,e.watch)(()=>t.reveal,e=>{e||js(l,t.modelValue)}),(0,e.watch)(l,e=>{r.animate(),a("reveal",e)}),(0,e.watch)([s,r.scroll,r.height],function(){if(!t.reveal)return;let{direction:e,position:n,inflectionPoint:a}=r.scroll.value;js(l,"up"===e||n-a<100||r.height.value-d.value-n-s.value<300)}),(0,e.watch)(()=>i.screen.height,e=>{r.isContainer.value||js(u,e)});let y={};return r.instances.footer=y,t.modelValue&&g("size",s.value),g("space",t.modelValue),g("offset",h.value),(0,e.onBeforeUnmount)(()=>{r.instances.footer===y&&(r.instances.footer=void 0,g("size",0),g("offset",0),g("space",!1))}),()=>{let a=Me(n.default,[(0,e.h)(Ai,{debounce:0,onResize:v})]);return t.elevated&&a.push((0,e.h)("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),(0,e.h)("footer",{class:m.value,style:_.value,onFocusin:b},a)}}});function qs(e){let t=e.validate();return"function"==typeof t.then?t.then(t=>({valid:t,comp:e}),t=>({valid:!1,comp:e,err:t})):Promise.resolve({valid:t,comp:e})}var Bs=h({name:"QForm",props:{autofocus:Boolean,noErrorFocus:Boolean,noResetFocus:Boolean,greedy:Boolean,onSubmit:Function},emits:["reset","validationSuccess","validationError"],setup(t,{slots:n,emit:a}){let i=(0,e.getCurrentInstance)(),r=(0,e.ref)(null),o=0,s=[];function l(e){let n="boolean"==typeof e?e:!t.noErrorFocus,i=++o,r=(e,t)=>{a("validation"+(e?"Success":"Error"),t)};return(t.greedy?Promise.all(s.map(qs)).then(e=>e.filter(e=>!e.valid)):s.reduce((e,t)=>e.then(()=>qs(t)).then(e=>{if(!e.valid)throw e}),Promise.resolve()).catch(e=>[e])).then(e=>{if(void 0===e||0===e.length)return i===o&&r(!0),!0;if(i===o){let{comp:t,err:a}=e[0];if(void 0!==a&&console.error(a),r(!1,t),n){let t=e.find(({comp:e})=>"function"==typeof e.focus&&!ct(e.$));void 0!==t&&t.comp.focus()}}return!1})}function u(){o++,s.forEach(e=>{"function"==typeof e.resetValidation&&e.resetValidation()})}function c(e){void 0!==e&&w(e);let n=o+1;l().then(i=>{n===o&&i&&(void 0===t.onSubmit?void 0!==e?.target&&"function"==typeof e.target.submit&&e.target.submit():a("submit",e))})}function d(n){void 0!==n&&w(n),a("reset"),(0,e.nextTick)(()=>{u(),t.autofocus&&!t.noResetFocus&&h()})}function h(){dn(()=>{null!==r.value&&(r.value.querySelector("[autofocus][tabindex], [data-autofocus][tabindex]")||r.value.querySelector("[autofocus] [tabindex], [data-autofocus] [tabindex]")||r.value.querySelector("[autofocus], [data-autofocus]")||Array.prototype.find.call(r.value.querySelectorAll("[tabindex]"),e=>-1!==e.tabIndex))?.focus({preventScroll:!0})})}(0,e.provide)(Z,{bindComponent(e){s.push(e)},unbindComponent(e){let t=s.indexOf(e);-1!==t&&s.splice(t,1)}});let p=!1;return(0,e.onDeactivated)(()=>{p=!0}),(0,e.onActivated)(()=>{p&&t.autofocus&&h()}),(0,e.onMounted)(()=>{t.autofocus&&h()}),Object.assign(i.proxy,{validate:l,resetValidation:u,submit:c,reset:d,focus:h,getValidationComponents:()=>s}),()=>(0,e.h)("form",{class:"q-form",ref:r,onSubmit:c,onReset:d},Ae(n.default))}}),Fs={inject:{[Z]:{default:_}},watch:{disable(e){let t=this.$.provides[Z];void 0!==t&&(e?(this.resetValidation(),t.unbindComponent(this)):t.bindComponent(this))}},methods:{validate(){},resetValidation(){}},mounted(){this.disable||this.$.provides[Z]?.bindComponent(this)},beforeUnmount(){this.disable||this.$.provides[Z]?.unbindComponent(this)}};function Vs(e,t){e.value!==t&&(e.value=t)}var Us=h({name:"QHeader",props:{modelValue:{type:Boolean,default:!0},reveal:Boolean,revealOffset:{type:Number,default:250},bordered:Boolean,elevated:Boolean,heightHint:{type:[String,Number],default:50}},emits:["reveal","focusin"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=(0,e.inject)(Y,ee);if(r===ee)return console.error("QHeader needs to be child of QLayout"),ee;let o=(0,e.ref)(Number.parseInt(t.heightHint,10)),s=(0,e.ref)(!0),l=(0,e.computed)(()=>t.reveal||r.view.value.includes("H")||i.platform.is.ios&&r.isContainer.value),u=(0,e.computed)(()=>{if(!t.modelValue)return 0;if(l.value)return s.value?o.value:0;let e=o.value-r.scroll.value.position;return Math.max(e,0)}),c=(0,e.computed)(()=>!t.modelValue||l.value&&!s.value),d=(0,e.computed)(()=>t.modelValue&&c.value&&t.reveal),h=(0,e.computed)(()=>"q-header q-layout__section--marginal "+(l.value?"fixed":"absolute")+"-top"+(t.bordered?" q-header--bordered":"")+(c.value?" q-header--hidden":"")+(t.modelValue?"":" q-layout--prevent-focus")),p=(0,e.computed)(()=>{let e=r.rows.value.top,t={};return"l"===e[0]&&r.left.space&&(t[i.lang.rtl?"right":"left"]=`${r.left.size}px`),"r"===e[2]&&r.right.space&&(t[i.lang.rtl?"left":"right"]=`${r.right.size}px`),t});function f(e,t){r.update("header",e,t)}function m({height:e}){Vs(o,e),f("size",e)}function _(e){d.value&&Vs(s,!0),a("focusin",e)}(0,e.watch)(()=>t.modelValue,e=>{f("space",e),Vs(s,!0),r.animate()}),(0,e.watch)(u,e=>{f("offset",e)}),(0,e.watch)(()=>t.reveal,e=>{e||Vs(s,t.modelValue)}),(0,e.watch)(s,e=>{r.animate(),a("reveal",e)}),(0,e.watch)(r.scroll,e=>{t.reveal&&Vs(s,"up"===e.direction||e.position<=t.revealOffset||e.position-e.inflectionPoint<100)});let g={};return r.instances.header=g,t.modelValue&&f("size",o.value),f("space",t.modelValue),f("offset",u.value),(0,e.onBeforeUnmount)(()=>{r.instances.header===g&&(r.instances.header=void 0,f("size",0),f("offset",0),f("space",!1))}),()=>{let a=Le(n.default,[]);return t.elevated&&a.push((0,e.h)("div",{class:"q-layout__shadow absolute-full overflow-hidden no-pointer-events"})),a.push((0,e.h)(Ai,{debounce:0,onResize:m})),(0,e.h)("header",{class:h.value,style:p.value,onFocusin:_},a)}}});let $s={ratio:[String,Number]};function Hs(t,n){return(0,e.computed)(()=>{let e=t.ratio||n?.value;if("string"==typeof e&&""===e.trim())return null;let a=Number(e);return Number.isFinite(a)&&a>0?{paddingBottom:100/a+"%"}:null})}var Ws=h({name:"QImg",props:{...$s,src:String,srcset:String,sizes:String,alt:String,crossorigin:String,decoding:String,referrerpolicy:String,draggable:Boolean,loading:{type:String,default:"lazy"},loadingShowDelay:{type:[Number,String],default:0},fetchpriority:{type:String,default:"auto"},width:String,height:String,initialRatio:{type:[Number,String],default:1.7778},placeholderSrc:String,errorSrc:String,fit:{type:String,default:"cover"},position:{type:String,default:"50% 50%"},imgClass:String,imgStyle:Object,noSpinner:Boolean,noNativeMenu:Boolean,noTransition:Boolean,spinnerColor:String,spinnerSize:String},emits:["load","error"],setup(t,{slots:n,emit:a}){let i=(0,e.ref)(t.initialRatio),r=Hs(t,i),s=(0,e.getCurrentInstance)(),{registerTimeout:l,removeTimeout:u}=xn(),{registerTimeout:c,removeTimeout:d}=xn(),h=(0,e.computed)(()=>void 0===t.placeholderSrc?null:{src:t.placeholderSrc}),p=(0,e.computed)(()=>void 0===t.errorSrc?null:{src:t.errorSrc,__qerror:!0}),f=[(0,e.ref)(null),(0,e.ref)(h.value)],m=(0,e.ref)(0),_=(0,e.ref)(!1),g=(0,e.ref)(!1),v=(0,e.computed)(()=>`q-img q-img--${t.noNativeMenu?"no-":""}menu`),b=(0,e.computed)(()=>({width:t.width,height:t.height})),y=(0,e.computed)(()=>`q-img__image ${void 0===t.imgClass?"":t.imgClass+" "}q-img__image--with${t.noTransition?"out":""}-transition q-img__image--`),w=(0,e.computed)(()=>({...t.imgStyle,objectFit:t.fit,objectPosition:t.position}));function k(){d(),_.value=!1}function x({target:e}){ct(s)||(u(),i.value=0===e.naturalHeight?.5:e.naturalWidth/e.naturalHeight,S(e,1))}function S(e,t){1e3===t||ct(s)||(e.complete?function(e){ct(s)||(m.value^=1,f[m.value].value=null,k(),"true"!==e.getAttribute("__qerror")&&(g.value=!1),a("load",e.currentSrc||e.src))}(e):l(()=>{S(e,t+1)},50))}function C(e){u(),k(),g.value=!0,f[m.value].value=p.value,f[1^m.value].value=h.value,a("error",e)}function T(n){let a=f[n].value,i={key:"img_"+n,class:y.value,style:w.value,alt:t.alt,crossorigin:t.crossorigin,decoding:t.decoding,referrerpolicy:t.referrerpolicy,height:t.height,width:t.width,loading:t.loading,fetchpriority:t.fetchpriority,"aria-hidden":"true",draggable:t.draggable,...a};return m.value===n?Object.assign(i,{class:i.class+"current",onLoad:x,onError:C}):i.class+="loaded",(0,e.h)("div",{class:"q-img__container absolute-full",key:"img"+n},(0,e.h)("img",i))}function P(){return _.value?(0,e.h)("div",{key:"loading",class:"q-img__loading absolute-full flex flex-center"},void 0===n.loading?t.noSpinner?void 0:[(0,e.h)(xt,{color:t.spinnerColor,size:t.spinnerSize})]:n.loading()):(0,e.h)("div",{key:"content",class:"q-img__content absolute-full q-anchor--skip"},Ae(n[g.value?"error":"default"]))}{let n=()=>{(0,e.watch)(()=>t.src||t.srcset||t.sizes?{src:t.src,srcset:t.srcset,sizes:t.sizes}:null,e=>{u(),g.value=!1,null===e?(k(),f[1^m.value].value=h.value):(d(),0!==t.loadingShowDelay?c(()=>{_.value=!0},t.loadingShowDelay):_.value=!0),f[m.value].value=e},{immediate:!0})};o.value?(0,e.onMounted)(n):n()}return()=>{let n=[];return null!==r.value&&n.push((0,e.h)("div",{key:"filler",style:r.value})),null!==f[0].value&&n.push(T(0)),null!==f[1].value&&n.push(T(1)),n.push((0,e.h)(e.Transition,{name:"q-transition--fade"},P)),(0,e.h)("div",{key:"main",class:v.value,style:b.value,role:"img","aria-label":t.alt},n)}}});let{passive:Gs}=m;var Ks=h({name:"QInfiniteScroll",props:{offset:{type:Number,default:500},debounce:{type:[String,Number],default:100},scrollTarget:Cn,initialIndex:{type:Number,default:0},disable:Boolean,reverse:Boolean},emits:["load"],setup(t,{slots:n,emit:a}){let i,r,o=(0,e.ref)(!1),s=(0,e.ref)(!0),l=(0,e.ref)(null),u=(0,e.ref)(null),c=t.initialIndex,d=(0,e.computed)(()=>"q-infinite-scroll__loading"+(o.value?"":" invisible"));function h(){if(t.disable||o.value||!s.value)return;let e=En(i),n=An(i),a=Ct(i);t.reverse?Math.round(n)<=t.offset&&p():Math.round(n+a+t.offset)>=Math.round(e)&&p()}function p(){if(t.disable||o.value||!s.value)return;c++,o.value=!0;let n=En(i);a("load",c,a=>{s.value&&(o.value=!1,(0,e.nextTick)(()=>{if(t.reverse){let e=En(i),t=An(i);Nn(i,t+(e-n))}!0===a?m():l.value?.closest("body")&&r()}))})}function f(){s.value||(s.value=!0,i.addEventListener("scroll",r,Gs)),h()}function m(){s.value&&(s.value=!1,o.value=!1,i.removeEventListener("scroll",r,Gs),r?.cancel?.())}function _(){if(i&&s.value&&i.removeEventListener("scroll",r,Gs),i=Pn(l.value,t.scrollTarget),s.value){if(i.addEventListener("scroll",r,Gs),t.reverse){let e=En(i),t=Ct(i);Nn(i,e-t)}h()}}function g(e){e=Number.parseInt(e,10);let t=r;r=e<=0?h:T(h,Number.isNaN(e)?100:e),i&&s.value&&(void 0!==t&&i.removeEventListener("scroll",t,Gs),i.addEventListener("scroll",r,Gs))}function v(t){if(b.value){if(null===u.value)return void(t||(0,e.nextTick)(()=>{v(!0)}));let n=(o.value?"un":"")+"pauseAnimations";[...u.value.getElementsByTagName("svg")].forEach(e=>{e[n]()})}}let b=(0,e.computed)(()=>!t.disable&&s.value);(0,e.watch)([o,b],()=>{v()}),(0,e.watch)(()=>t.disable,e=>{e?m():f()}),(0,e.watch)(()=>t.reverse,()=>{!o.value&&s.value&&h()}),(0,e.watch)(()=>t.scrollTarget,_),(0,e.watch)(()=>t.debounce,g);let y=!1;(0,e.onActivated)(()=>{!1!==y&&i&&Nn(i,y)}),(0,e.onDeactivated)(()=>{y=!!i&&An(i)}),(0,e.onBeforeUnmount)(()=>{s.value&&i.removeEventListener("scroll",r,Gs)}),(0,e.onMounted)(()=>{g(t.debounce),_(),o.value||v()});let w=(0,e.getCurrentInstance)();return Object.assign(w.proxy,{poll:()=>{r?.()},trigger:p,stop:m,reset:function(){c=0},resume:f,setIndex:function(e){c=e},updateScrollTarget:_}),()=>{let a=Le(n.default,[]);return b.value&&a[t.reverse?"unshift":"push"]((0,e.h)("div",{ref:u,class:d.value},Ae(n.loading))),(0,e.h)("div",{class:"q-infinite-scroll",ref:l},a)}}}),Ys=h({name:"QInnerLoading",props:{...Je,...yn,showing:Boolean,color:String,size:{type:[String,Number],default:"42px"},label:String,labelClass:String,labelStyle:[String,Array,Object]},setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),{transitionProps:i,transitionStyle:r}=wn(t),o=(0,e.computed)(()=>"q-inner-loading q--avoid-card-border absolute-full column flex-center"+(a.value?" q-inner-loading--dark":"")),s=(0,e.computed)(()=>"q-inner-loading__label"+(void 0===t.labelClass?"":` ${t.labelClass}`));function l(){return t.showing?(0,e.h)("div",{class:o.value,style:r.value},void 0===n.default?function(){let n=[(0,e.h)(xt,{size:t.size,color:t.color})];return void 0!==t.label&&n.push((0,e.h)("div",{class:s.value,style:t.labelStyle},[t.label])),n}():n.default()):null}return()=>(0,e.h)(e.Transition,i.value,l)}});let Qs={date:"####/##/##",datetime:"####/##/## ##:##",time:"##:##",fulltime:"##:##:##",phone:"(###) ### - ####",card:"#### #### #### ####"},{tokenMap:Zs,tokenKeys:Js}=Xs({"#":{pattern:"[\\d]",negate:"[^\\d]"},S:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]"},N:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]"},A:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]",transform:e=>e.toLocaleUpperCase()},a:{pattern:"[a-zA-Z]",negate:"[^a-zA-Z]",transform:e=>e.toLocaleLowerCase()},X:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]",transform:e=>e.toLocaleUpperCase()},x:{pattern:"[0-9a-zA-Z]",negate:"[^0-9a-zA-Z]",transform:e=>e.toLocaleLowerCase()}});function Xs(e){let t=Object.keys(e),n={};return t.forEach(t=>{let a=e[t];n[t]={...a,regex:new RegExp(a.pattern)}}),{tokenMap:n,tokenKeys:t}}function el(e){return RegExp("\\\\([^.*+?^${}()|([\\]])|([.*+?^${}()|[\\]])|(["+e.join("")+"])|(.)","g")}let tl=/[.*+?^${}()|[\]\\]/g,nl=el(Js),al=String.fromCodePoint(1),il={mask:String,reverseFillMask:Boolean,fillMask:[Boolean,String],unmaskedValue:Boolean,maskTokens:Object};function rl(t,n,a,i){let r,o,s,l,u,c,d=(0,e.computed)(()=>{if(void 0===t.maskTokens||null===t.maskTokens)return{tokenMap:Zs,tokenRegexMask:nl};let{tokenMap:e}=Xs(t.maskTokens),n={...Zs,...e};return{tokenMap:n,tokenRegexMask:el(Object.keys(n))}}),h=(0,e.ref)(null),p=(0,e.ref)(function(){if(m(),h.value){let e=v(y(t.modelValue));return!1===t.fillMask?e:w(e)}return t.modelValue}());function f(e){if(e0;a--)t+=al;n=n.slice(0,a)+t+n.slice(a)}return n}function m(){if(h.value=void 0!==t.mask&&0!==t.mask.length&&(t.autogrow||["textarea","text","search","url","tel","password"].includes(t.type)),!h.value)return l=void 0,r="",void(o="");let e=void 0===Qs[t.mask]?t.mask:Qs[t.mask],n="string"==typeof t.fillMask&&0!==t.fillMask.length?t.fillMask.slice(0,1):"_",a=n.replace(tl,String.raw`\$&`),i=[],u=[],c=[],p=t.reverseFillMask,f="",m="";e.replace(d.value.tokenRegexMask,(e,t,n,a,r)=>{if(void 0!==a){let e=d.value.tokenMap[a];return c.push(e),m=e.negate,p&&=(u.push("(?:"+m+"+)?("+e.pattern+"+)?(?:"+m+"+)?("+e.pattern+"+)?"),!1),void u.push("(?:"+m+"+)?("+e.pattern+")?")}if(void 0!==n)f="\\"+("\\"===n?"":n),c.push(n);else{let e=void 0===t?r:t;f="\\"===e?String.raw`\\\\`:e.replace(tl,String.raw`\\$&`),c.push(e)}i.push("([^"+f+"]+)?"+f+"?")});let _=RegExp("^"+i.join("")+"("+(""===f?".":"[^"+f+"]")+"+)?"+(""===f?"":"["+f+"]*")+"$"),g=u.length-1,v=u.map((e,n)=>0===n&&t.reverseFillMask?RegExp("^"+a+"*"+e):RegExp(n===g?"^"+e+"("+(""===m?".":m)+"+)?"+(t.reverseFillMask?"$":a+"*"):"^"+e));s=c,l=e=>{let n=_.exec(t.reverseFillMask?e:e.slice(0,c.length+1));null!==n&&(e=n.slice(1).join(""));let a=[],i=v.length;for(let t=0,n=e;t"string"==typeof e?e:al).join(""),o=r.split(al).join(n)}function _(n,s,l){let c=i.value,d=c?.selectionEnd??0,h=null===c?0:c.value.length-d,f=y(n);!0===s&&m();let _=v(f,s),b=!1===t.fillMask?_:w(_),k=p.value!==b;null!==c&&c.value!==b&&(c.value=b),k&&(p.value=b),null!==c&&document.activeElement===c&&(0,e.nextTick)(()=>{if(b===o){let e=t.reverseFillMask?o.length:0;return void c.setSelectionRange(e,e,"forward")}if("insertFromPaste"===l&&!t.reverseFillMask){let e=c.selectionEnd,t=d-1;for(let n=u;n<=t&&n_.length):Math.max(0,b.length-(b===o?0:Math.min(_.length,h)+1))+1:d;return void c.setSelectionRange(e,e,"forward")}if(t.reverseFillMask)if(k){let e=Math.max(0,b.length-(b===o?0:Math.min(_.length,h+1)));1===e&&1===d?c.setSelectionRange(e,e,"forward"):g.rightReverse(c,e)}else{let e=b.length-h;c.setSelectionRange(e,e,"backward")}else if(k){let e=Math.max(0,r.indexOf(al),Math.min(_.length,d)-1);g.right(c,e)}else{let e=d-1;g.right(c,e)}});let x=t.unmaskedValue?y(b):b;String(t.modelValue)!==x&&(null!==t.modelValue||""!==x)&&a(x,!0)}(0,e.watch)(()=>t.type+t.autogrow,m),(0,e.watch)(()=>t.mask,e=>{if(void 0!==e)_(p.value,!0);else{let e=y(p.value);m(),t.modelValue!==e&&n("update:modelValue",e)}}),(0,e.watch)(()=>t.fillMask+t.reverseFillMask,()=>{h.value&&_(p.value,!0)}),(0,e.watch)(()=>t.unmaskedValue,()=>{h.value&&_(p.value)}),(0,e.watch)(()=>t.maskTokens,()=>{h.value&&_(p.value,!0)},{deep:!0});let g={left(e,t){let n=!r.slice(t-1).includes(al),a=Math.max(0,t-1);for(;a>=0;a--)if(r[a]===al){t=a,n&&t++;break}if(a<0&&void 0!==r[t]&&r[t]!==al)return g.right(e,0);t>=0&&e.setSelectionRange(t,t,"backward")},right(e,t){let n=e.value.length,a=Math.min(n,t+1);for(;a<=n;a++){if(r[a]===al){t=a;break}r[a-1]===al&&(t=a)}if(a>n&&void 0!==r[t-1]&&r[t-1]!==al)return g.left(e,n);e.setSelectionRange(t,t,"forward")},leftReverse(e,t){let n=f(e.value.length),a=Math.max(0,t-1);for(;a>=0;a--){if(n[a-1]===al){t=a;break}if(n[a]===al&&(t=a,0===a))break}if(a<0&&void 0!==n[t]&&n[t]!==al)return g.rightReverse(e,0);t>=0&&e.setSelectionRange(t,t,"backward")},rightReverse(e,t){let n=e.value.length,a=f(n),i=!a.slice(0,t+1).includes(al),r=Math.min(n,t+1);for(;r<=n;r++)if(a[r-1]===al){(t=r)>0&&i&&t--;break}if(r>n&&void 0!==a[t-1]&&a[t-1]!==al)return g.leftReverse(e,n);e.setSelectionRange(t,t,"forward")}};function v(e,n){if(null==e||""===e)return"";if(t.reverseFillMask)return b(e,n);let a=s,i=0,r="";for(let t=0;t=0&&-1!==i;r--){let s=n[r],l=e[i];if("string"==typeof s)o=s+o,!0===t&&l===s&&i--;else{if(void 0===l||!s.regex.test(l))return o;do{o=(void 0===s.transform?l:s.transform(l))+o,i--,l=e[i]}while(a===r&&void 0!==l&&s.regex.test(l))}}return o}function y(e){return"string"!=typeof e||void 0===l?"number"==typeof e?l(String(e)):e:l(e)}function w(e){return o.length-e.length<=0?e:t.reverseFillMask&&0!==e.length?o.slice(0,-e.length)+e:e+o.slice(e.length)}return{innerValue:p,hasMask:h,moveCursorForPaste:function(e,t,n){let a=v(y(e.value));t=Math.max(0,r.indexOf(al),Math.min(a.length,t)),u=t,e.setSelectionRange(t,n,"forward")},updateMaskValue:_,onMaskedKeydown:function(e){if(n("keydown",e),I(e)||e.altKey)return;let a=i.value,r=a.selectionStart,o=a.selectionEnd;if(e.shiftKey||(c=void 0),37===e.keyCode||39===e.keyCode){e.shiftKey&&void 0===c&&(c="forward"===a.selectionDirection?r:o);let n=g[(39===e.keyCode?"right":"left")+(t.reverseFillMask?"Reverse":"")];if(e.preventDefault(),n(a,c===r?o:r),e.shiftKey){let e=a.selectionStart;a.setSelectionRange(Math.min(c,e),Math.max(c,e),"forward")}}else 8!==e.keyCode||t.reverseFillMask||r!==o?46===e.keyCode&&t.reverseFillMask&&r===o&&(g.rightReverse(a,o),a.setSelectionRange(r,a.selectionEnd,"forward")):(g.left(a,r),a.setSelectionRange(a.selectionStart,o,"backward"))},onMaskedClick:function(e){n("click",e),c=void 0}}}let ol=/[\u3000-\u303F\u3040-\u309F\u30A0-\u30FF\uFF00-\uFF9F\u4E00-\u9FAF\u3400-\u4DBF]/,sl=/[\u4E00-\u9FFF\u3400-\u4DBF\u{20000}-\u{2A6DF}\u{2A700}-\u{2B73F}\u{2B740}-\u{2B81F}\u{2B820}-\u{2CEAF}\uF900-\uFAFF\u3300-\u33FF\uFE30-\uFE4F\uF900-\uFAFF\u{2F800}-\u{2FA1F}]/u,ll=/[\u3131-\u314E\u314F-\u3163\uAC00-\uD7A3]/,ul=/[a-z0-9_ -]$/i;function cl(e){return function(t){if("compositionend"===t.type||"change"===t.type){if(!t.target.qComposing)return;t.target.qComposing=!1,e(t)}else"compositionupdate"===t.type&&!t.target.qComposing&&"string"==typeof t.data&&(c.is.firefox?!ul.test(t.data):ol.test(t.data)||sl.test(t.data)||ll.test(t.data))&&(t.target.qComposing=!0)}}var dl=h({name:"QInput",inheritAttrs:!1,props:{...xs,...il,...wa,modelValue:[String,Number,FileList],modelModifiers:Object,shadowText:String,type:{type:String,default:"text"},debounce:[String,Number],autogrow:Boolean,inputClass:[Array,String,Object],inputStyle:[Array,String,Object]},emits:[...Ss,"paste","change","keydown","click","animationend"],setup(t,{emit:n,attrs:i}){let r,{proxy:o}=(0,e.getCurrentInstance)(),{$q:s}=o,l={},u=NaN,c=!1,d=!1,h=null,p=(0,e.ref)(null),f=Sa(t),{innerValue:m,hasMask:_,moveCursorForPaste:g,updateMaskValue:v,onMaskedKeydown:y,onMaskedClick:w}=rl(t,n,z,p),k=Is(t,!0),x=(0,e.computed)(()=>ws(m.value)),S=cl(M),C=Cs({changeEvent:!0}),T=(0,e.computed)(()=>"textarea"===t.type||t.autogrow),P=(0,e.computed)(()=>T.value||["text","search","url","tel","password"].includes(t.type)),E=(0,e.computed)(()=>{let e={...C.splitAttrs.listeners.value,onInput:M,onPaste:L,onChange:O,onBlur:j,onFocus:b};return e.onCompositionstart=e.onCompositionupdate=e.onCompositionend=S,_.value&&(e.onKeydown=y,e.onClick=w),t.autogrow&&(e.onAnimationend=R),e}),A=(0,e.computed)(()=>{let e={tabindex:0,"data-autofocus":t.autofocus||void 0,rows:"textarea"===t.type?6:void 0,"aria-label":t.label,name:f.value,...C.splitAttrs.attributes.value,id:C.targetUid.value,maxlength:t.maxlength,disabled:t.disable,readonly:t.readonly};return T.value||(e.type=t.type),t.autogrow&&(e.rows=1),e});function L(e){if(_.value&&!0!==t.reverseFillMask){let t=e.target;g(t,t.selectionStart,t.selectionEnd)}n("paste",e)}function M(a){if(!a||!a.target)return;if("file"===t.type)return void n("update:modelValue",a.target.files);let i=a.target.value;if(a.target.qComposing)l.value=i;else{if(_.value)v(i,!1,a.inputType);else if(!0===t.modelModifiers?.trim&&(l.value=i),z(i),P.value&&a.target===document.activeElement){let{selectionStart:t,selectionEnd:n}=a.target;void 0!==t&&void 0!==n&&(0,e.nextTick)(()=>{a.target===document.activeElement&&0===i.indexOf(a.target.value)&&a.target.setSelectionRange(t,n)})}t.autogrow&&N()}}function R(e){n("animationend",e),N()}function z(a,i){r=()=>{h=null,"number"!==t.type&&(!0!==t.modelModifiers?.trim||_.value)&&Object.hasOwn(l,"value")&&delete l.value,t.modelValue!==a&&u!==a&&(u=a,!0===i&&(d=!0),n("update:modelValue",a),(0,e.nextTick)(()=>{u===a&&(u=NaN)})),r=void 0},"number"===t.type&&(c=!0,l.value=a),void 0===t.debounce?r():(null!==h&&clearTimeout(h),l.value=a,h=setTimeout(r,t.debounce))}function I(){null!==h&&(clearTimeout(h),h=null),r=void 0}function N(){requestAnimationFrame(()=>{let e=p.value;if(null!==e){let t=e.parentNode.style,{scrollTop:n}=e,{overflowY:a,maxHeight:i}=s.platform.is.firefox?{}:window.getComputedStyle(e),r=void 0!==a&&"scroll"!==a;r&&(e.style.overflowY="hidden"),t.marginBottom=e.scrollHeight-1+"px",e.style.height="1px",e.style.height=e.scrollHeight+"px",r&&(e.style.overflowY=Number.parseInt(i,10){null!==p.value&&(p.value.value=void 0===m.value?"":m.value)},0)}function D(){return Object.hasOwn(l,"value")?l.value:void 0===m.value?"":m.value}(0,e.watch)(()=>t.type,()=>{p.value&&(p.value.value=t.modelValue)}),(0,e.watch)(()=>t.modelValue,n=>{if(null!==h&&(I(),c=!1,d=!1,delete l.value),_.value){if(d&&(d=!1,String(n)===u))return;v(n)}else m.value!==n&&(m.value=n,"number"===t.type&&Object.hasOwn(l,"value")&&(c?c=!1:delete l.value),!0===t.modelModifiers?.trim&&Object.hasOwn(l,"value")&&("string"!=typeof l.value||l.value.trim()!==n)&&delete l.value);t.autogrow&&(0,e.nextTick)(N)}),(0,e.watch)(()=>t.autogrow,t=>{t?(0,e.nextTick)(N):null!==p.value&&i.rows>0&&(p.value.style.height="auto")}),(0,e.watch)(()=>t.dense,()=>{t.autogrow&&(0,e.nextTick)(N)}),(0,e.onBeforeUnmount)(()=>{j()}),(0,e.onMounted)(()=>{t.autogrow&&N()}),Object.assign(C,{innerValue:m,fieldClass:(0,e.computed)(()=>"q-"+(T.value?"textarea":"input")+(t.autogrow?" q-textarea--autogrow":"")),hasShadow:(0,e.computed)(()=>"file"!==t.type&&"string"==typeof t.shadowText&&0!==t.shadowText.length),inputRef:p,emitValue:z,onClear:function(){I(),c=!1,d=!1,delete l.value},hasValue:x,floatingLabel:(0,e.computed)(()=>x.value&&("number"!==t.type||Number.isFinite(Number(m.value)))||ws(t.displayValue)),getControl:()=>(0,e.h)(T.value?"textarea":"input",{ref:p,class:["q-field__native q-placeholder",t.inputClass],style:t.inputStyle,...A.value,...E.value,..."file"===t.type?k.value:{value:D()}}),getShadowControl:()=>(0,e.h)("div",{class:"q-field__native q-field__shadow absolute-bottom no-pointer-events"+(T.value?"":" text-no-wrap")},[(0,e.h)("span",{class:"invisible"},D()),(0,e.h)("span",t.shadowText)])});let q=Ps(C);return Object.assign(o,{focus:function(){dn(()=>{let e=document.activeElement;null!==p.value&&p.value!==e&&(null===e||e.id!==C.targetUid.value)&&p.value.focus({preventScroll:!0})})},select:function(){p.value?.select()},getNativeElement:()=>p.value}),a(o,"nativeEl",()=>p.value),q}});let hl={threshold:0,root:null,rootMargin:"0px"};function pl(e,t,n){let a,i,r;"function"==typeof n?(a=n,i=hl,r=void 0===t.cfg):(a=n.handler,i={...hl,...n.cfg},r=void 0===t.cfg||!te(t.cfg,i)),t.handler!==a&&(t.handler=a),r&&(t.cfg=i,t.observer?.disconnect(),t.observer=new IntersectionObserver(([n])=>{if("function"==typeof t.handler){if(null===n.rootBounds&&document.body.contains(e))return t.observer.unobserve(e),void t.observer.observe(e);(!1===t.handler(n,t.observer)||t.once&&n.isIntersecting)&&fl(e)}},i),t.observer.observe(e))}function fl(e){let t=e.__qvisible;void 0!==t&&(t.observer?.disconnect(),delete e.__qvisible)}var ml=p({name:"intersection",mounted(e,{modifiers:t,value:n}){let a={once:!0===t.once};pl(e,a,n),e.__qvisible=a},updated(e,t){let n=e.__qvisible;void 0!==n&&pl(e,n,t.value)},beforeUnmount:fl}),_l=h({name:"QIntersection",props:{tag:{type:String,default:"div"},once:Boolean,transition:String,transitionDuration:{type:[String,Number],default:300},ssrPrerender:Boolean,margin:String,threshold:[Number,Array],root:{default:null},disable:Boolean,onVisibility:Function},setup(t,{slots:n,emit:a}){let i=(0,e.ref)(!!o.value&&t.ssrPrerender),r=(0,e.computed)(()=>void 0!==t.root||void 0!==t.margin||void 0!==t.threshold?{handler:c,cfg:{root:t.root,rootMargin:t.margin,threshold:t.threshold}}:c),s=(0,e.computed)(()=>!(t.disable||o.value&&t.once&&t.ssrPrerender)),l=(0,e.computed)(()=>[[ml,r.value,void 0,{once:t.once}]]),u=(0,e.computed)(()=>`--q-transition-duration: ${t.transitionDuration}ms`);function c(e){i.value!==e.isIntersecting&&(i.value=e.isIntersecting,void 0!==t.onVisibility&&a("visibility",i.value))}function d(){return i.value?[(0,e.h)("div",{key:"content",style:u.value},Ae(n.default))]:void 0!==n.hidden?[(0,e.h)("div",{key:"hidden",style:u.value},n.hidden())]:void 0}return()=>{let n=t.transition?[(0,e.h)(e.Transition,{name:"q-transition--"+t.transition},d)]:d();return ze(t.tag,{class:"q-intersection"},n,"main",s.value,()=>l.value)}}});let gl=["ul","ol"];var vl=h({name:"QList",props:{...Je,bordered:Boolean,dense:Boolean,separator:Boolean,padding:Boolean,tag:{type:String,default:"div"}},setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),i=(0,e.computed)(()=>gl.includes(t.tag)?null:"list"),r=(0,e.computed)(()=>"q-list"+(t.bordered?" q-list--bordered":"")+(t.dense?" q-list--dense":"")+(t.separator?" q-list--separator":"")+(a.value?" q-list--dark":"")+(t.padding?" q-list--padding":""));return()=>(0,e.h)(t.tag,{class:r.value,role:i.value},Ae(n.default))}});let bl=[34,37,40,33,39,38],yl=Object.keys(ci);var wl=h({name:"QKnob",props:{...wa,...ci,modelValue:{type:Number,required:!0},innerMin:Number,innerMax:Number,step:{type:Number,default:1,validator:e=>e>=0},tabindex:{type:[Number,String],default:0},disable:Boolean,readonly:Boolean},emits:["update:modelValue","change","dragValue"],setup(t,{slots:n,emit:a}){let i,{proxy:r}=(0,e.getCurrentInstance)(),{$q:o}=r,s=(0,e.ref)(t.modelValue),l=(0,e.ref)(!1),u=(0,e.computed)(()=>!Number.isFinite(t.innerMin)||t.innerMin!Number.isFinite(t.innerMax)||t.innerMax>t.max?t.max:t.innerMax);function d(){s.value=null===t.modelValue?u.value:_e(t.modelValue,u.value,c.value),L(!0)}(0,e.watch)(()=>`${t.modelValue}|${u.value}|${c.value}`,d),d();let h=(0,e.computed)(()=>!t.disable&&!t.readonly),p=(0,e.computed)(()=>"q-knob non-selectable"+(h.value?" q-knob--editable":t.disable?" disabled":"")),f=(0,e.computed)(()=>(String(t.step).trim().split(".")[1]||"").length),m=(0,e.computed)(()=>0===t.step?1:t.step),_=(0,e.computed)(()=>t.instantFeedback||l.value),g=o.platform.is.mobile?(0,e.computed)(()=>h.value?{onClick:T}:{}):(0,e.computed)(()=>h.value?{onMousedown:C,onClick:T,onKeydown:P,onKeyup:A}:{}),b=(0,e.computed)(()=>h.value?{tabindex:t.tabindex}:{["aria-"+(t.disable?"disabled":"readonly")]:"true"}),y=(0,e.computed)(()=>{let e={};return yl.forEach(n=>{e[n]=t[n]}),e});function k(e){if(e.isFinal)return E(e.evt,!0),void(l.value=!1);e.isFirst&&(S(),l.value=!0),E(e.evt,!1)}let x=(0,e.computed)(()=>[[gi,k,void 0,{prevent:!0,stop:!0,mouse:!0}]]);function S(){let{top:e,left:t,width:n,height:a}=r.$el.getBoundingClientRect();i={top:e+a/2,left:t+n/2}}function C(e){S(),E(e,!1)}function T(e){S(),E(e,!0)}function P(e){if(!bl.includes(e.keyCode))return;w(e);let t=([34,33].includes(e.keyCode)?10:1)*m.value,n=[34,37,40].includes(e.keyCode)?-t:t;s.value=_e(Number.parseFloat((s.value+n).toFixed(f.value)),u.value,c.value),L(!1)}function E(e,n){let r=v(e),l=Math.abs(r.top-i.top),d=Math.hypot(l,r.left-i.left),h=Math.asin(l/d)*(180/Math.PI);h=r.top=m.value/2?(e<0?-1:1)*m.value:0),p=Number.parseFloat(p.toFixed(f.value))}p=_e(p,u.value,c.value),a("dragValue",p),s.value!==p&&(s.value=p),L(n)}function A(e){bl.includes(e.keyCode)&&L(!0)}function L(e){t.modelValue!==s.value&&a("update:modelValue",s.value),e&&a("change",s.value)}let M=ka(t);function R(){return(0,e.h)("input",M.value)}return()=>{let e={class:p.value,role:"slider","aria-valuemin":u.value,"aria-valuemax":c.value,"aria-valuenow":t.modelValue,...b.value,...y.value,value:s.value,instantFeedback:_.value,...g.value},a={default:n.default};return h.value&&void 0!==t.name&&(a.internal=R),ze(pi,e,a,"knob",h.value,()=>x.value)}}});let{passive:kl}=m,xl=["both","horizontal","vertical"];var Sl=h({name:"QScrollObserver",props:{axis:{type:String,validator:e=>xl.includes(e),default:"vertical"},debounce:[String,Number],scrollTarget:Cn},emits:["scroll"],setup(t,{emit:n}){let a,i,r={position:{top:0,left:0},direction:"down",directionChanged:!1,delta:{top:0,left:0},inflectionPoint:{top:0,left:0}},o=null;function s(){o?.();let e=Math.max(0,An(a)),i=Ln(a),s={top:e-r.position.top,left:i-r.position.left};if("vertical"===t.axis&&0===s.top||"horizontal"===t.axis&&0===s.left)return;let l=Math.abs(s.top)>=Math.abs(s.left)?s.top<0?"up":"down":s.left<0?"left":"right";r.position={top:e,left:i},r.directionChanged=r.direction!==l,r.delta=s,r.directionChanged&&(r.direction=l,r.inflectionPoint=r.position),n("scroll",{...r})}function l(){a=Pn(i,t.scrollTarget),a.addEventListener("scroll",c,kl),c(!0)}function u(){void 0!==a&&(a.removeEventListener("scroll",c,kl),a=void 0)}function c(e){if(!0===e||0===t.debounce||"0"===t.debounce)s();else if(null===o){let[e,n]=t.debounce?[setTimeout(s,t.debounce),clearTimeout]:[requestAnimationFrame(s),cancelAnimationFrame];o=()=>{n(e),o=null}}}(0,e.watch)(()=>t.scrollTarget,()=>{u(),l()});let{proxy:d}=(0,e.getCurrentInstance)();return(0,e.watch)(()=>d.$q.lang.rtl,s),(0,e.onMounted)(()=>{i=d.$el.parentNode,l()}),(0,e.onBeforeUnmount)(()=>{o?.(),u()}),Object.assign(d,{trigger:c,getPosition:()=>r}),_}});let Cl=/^(h|l)h(h|r) lpr (f|l)f(f|r)$/;var Tl=h({name:"QLayout",props:{container:Boolean,view:{type:String,default:"hhh lpr fff",validator:e=>Cl.test(e.toLowerCase())},onScroll:Function,onScrollHeight:Function,onResize:Function},setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=(0,e.ref)(null),s=(0,e.ref)(i.screen.height),l=(0,e.ref)(t.container?0:i.screen.width),u=(0,e.ref)({position:0,direction:"down",inflectionPoint:0}),c=(0,e.ref)(0),d=(0,e.ref)(o.value?0:jn()),h=(0,e.computed)(()=>"q-layout q-layout--"+(t.container?"containerized":"standard")),p=(0,e.computed)(()=>t.container?null:{minHeight:i.screen.height+"px"}),f=(0,e.computed)(()=>0===d.value?null:{[i.lang.rtl?"left":"right"]:`${d.value}px`}),m=(0,e.computed)(()=>0===d.value?null:{[i.lang.rtl?"right":"left"]:0,[i.lang.rtl?"left":"right"]:`-${d.value}px`,width:`calc(100% + ${d.value}px)`});function _(e){if(t.container||!document.qScrollPrevented){let n={position:e.position.top,direction:e.direction,directionChanged:e.directionChanged,inflectionPoint:e.inflectionPoint.top,delta:e.delta.top};u.value=n,void 0!==t.onScroll&&a("scroll",n)}}function g(e){let{height:n,width:i}=e,r=!1;s.value!==n&&(r=!0,s.value=n,void 0!==t.onScrollHeight&&a("scrollHeight",n),b()),l.value!==i&&(r=!0,l.value=i),r&&void 0!==t.onResize&&a("resize",e)}function v({height:e}){c.value!==e&&(c.value=e,b())}function b(){if(t.container){let e=s.value>c.value?jn():0;d.value!==e&&(d.value=e)}}let y=null,w={instances:{},view:(0,e.computed)(()=>t.view),isContainer:(0,e.computed)(()=>t.container),rootRef:r,height:s,containerHeight:c,scrollbarWidth:d,totalWidth:(0,e.computed)(()=>l.value+d.value),rows:(0,e.computed)(()=>{let e=t.view.toLowerCase().split(" ");return{top:[...e[0]],middle:[...e[1]],bottom:[...e[2]]}}),header:(0,e.reactive)({size:0,offset:0,space:!1}),right:(0,e.reactive)({size:300,offset:0,space:!1}),footer:(0,e.reactive)({size:0,offset:0,space:!1}),left:(0,e.reactive)({size:300,offset:0,space:!1}),scroll:u,animate(){null===y?document.body.classList.add("q-body--layout-animate"):clearTimeout(y),y=setTimeout(()=>{y=null,document.body.classList.remove("q-body--layout-animate")},155)},update(e,t,n){w[e][t]=n}};if((0,e.provide)(Y,w),jn()>0){let n=null,a=document.body,r=()=>{n=null,a.classList.remove("hide-scrollbar")},o=()=>{if(null===n){if(a.scrollHeight>i.screen.height)return;a.classList.add("hide-scrollbar")}else clearTimeout(n);n=setTimeout(r,300)},s=e=>{null!==n&&"remove"===e&&(clearTimeout(n),r()),window[`${e}EventListener`]("resize",o)};(0,e.watch)(()=>t.container?"remove":"add",s),t.container||s("add"),(0,e.onUnmounted)(()=>{s("remove")})}return()=>{let a=Me(n.default,[(0,e.h)(Sl,{onScroll:_}),(0,e.h)(Ai,{onResize:g})]),i=(0,e.h)("div",{class:h.value,style:p.value,ref:t.container?void 0:r,tabindex:-1},a);return t.container?(0,e.h)("div",{class:"q-layout-container overflow-hidden",ref:r},[(0,e.h)(Ai,{onResize:v}),(0,e.h)("div",{class:"absolute-full",style:f.value},[(0,e.h)("div",{class:"scroll",style:m.value},[i])])]):i}}});let Pl={xs:2,sm:4,md:6,lg:10,xl:14};function El(e,t,n){return{transform:t?`translateX(${n.lang.rtl?"-":""}100%) scale3d(${-e},1,1)`:`scale3d(${e},1,1)`}}var Al=h({name:"QLinearProgress",props:{...Je,...Pe,value:{type:Number,default:0},buffer:Number,color:String,trackColor:String,reverse:Boolean,stripe:Boolean,indeterminate:Boolean,query:Boolean,rounded:Boolean,animationSpeed:{type:[String,Number],default:2100},instantFeedback:Boolean},setup(t,{slots:n}){let{proxy:a}=(0,e.getCurrentInstance)(),i=Xe(t,a.$q),r=Ee(t,Pl),o=(0,e.computed)(()=>t.indeterminate||t.query),s=(0,e.computed)(()=>t.reverse!==t.query),l=(0,e.computed)(()=>({...null===r.value?{}:r.value,"--q-linear-progress-speed":`${t.animationSpeed}ms`})),u=(0,e.computed)(()=>"q-linear-progress"+(void 0===t.color?"":` text-${t.color}`)+(t.reverse||t.query?" q-linear-progress--reverse":"")+(t.rounded?" rounded-borders":"")),c=(0,e.computed)(()=>El(void 0===t.buffer?1:t.buffer,s.value,a.$q)),d=(0,e.computed)(()=>`with${t.instantFeedback?"out":""}-transition`),h=(0,e.computed)(()=>`q-linear-progress__track absolute-full q-linear-progress__track--${d.value} q-linear-progress__track--${i.value?"dark":"light"}`+(void 0===t.trackColor?"":` bg-${t.trackColor}`)),p=(0,e.computed)(()=>El(o.value?1:t.value,s.value,a.$q)),f=(0,e.computed)(()=>`q-linear-progress__model absolute-full q-linear-progress__model--${d.value} q-linear-progress__model--${o.value?"in":""}determinate`),m=(0,e.computed)(()=>({width:100*t.value+"%"})),_=(0,e.computed)(()=>`q-linear-progress__stripe absolute-${t.reverse?"right":"left"} q-linear-progress__stripe--${d.value}`);return()=>{let a=[(0,e.h)("div",{class:h.value,style:c.value}),(0,e.h)("div",{class:f.value,style:p.value})];return t.stripe&&!o.value&&a.push((0,e.h)("div",{class:_.value,style:m.value})),(0,e.h)("div",{class:u.value,style:l.value,role:"progressbar","aria-valuemin":0,"aria-valuemax":1,"aria-valuenow":t.indeterminate?void 0:t.value},Me(n.default,a))}}});let Ll=["horizontal","vertical","cell","none"];var Ml=h({name:"QMarkupTable",props:{...Je,dense:Boolean,flat:Boolean,bordered:Boolean,square:Boolean,wrapCells:Boolean,separator:{type:String,default:"horizontal",validator:e=>Ll.includes(e)}},setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),i=(0,e.computed)(()=>`q-markup-table q-table__container q-table__card q-table--${t.separator}-separator`+(a.value?" q-table--dark q-table__card--dark q-dark":"")+(t.dense?" q-table--dense":"")+(t.flat?" q-table--flat":"")+(t.bordered?" q-table--bordered":"")+(t.square?" q-table--square":"")+(t.wrapCells?"":" q-table--no-wrap"));return()=>(0,e.h)("div",{class:i.value},[(0,e.h)("table",{class:"q-table"},Ae(n.default))])}}),Rl=h({name:"QNoSsr",props:{tag:{type:String,default:"div"},placeholder:String},setup(t,{slots:n}){let{isHydrated:a}=Ti();return()=>{if(a.value){let a=Ae(n.default);return void 0===a?a:a.length>1?(0,e.h)(t.tag,{},a):a[0]}let i={class:"q-no-ssr-placeholder"},r=Ae(n.placeholder);return void 0!==r?r.length>1?(0,e.h)(t.tag,i,r):r[0]:void 0!==t.placeholder?(0,e.h)(t.tag,i,t.placeholder):void 0}}});function zl(e){(13===e.keyCode||32===e.keyCode)&&w(e)}var Il=h({name:"QRadio",props:{...Je,...Pe,...wa,modelValue:{required:!0},val:{required:!0},label:String,leftLabel:Boolean,checkedIcon:String,uncheckedIcon:String,color:String,keepColor:Boolean,dense:Boolean,disable:Boolean,tabindex:[String,Number]},emits:["update:modelValue"],setup(t,{slots:n,emit:a}){let{proxy:i}=(0,e.getCurrentInstance)(),r=Xe(t,i.$q),o=Ee(t,ti),s=(0,e.ref)(null),{refocusTargetEl:l,refocusTarget:u}=ei(t,s),c=(0,e.computed)(()=>(0,e.toRaw)(t.modelValue)===(0,e.toRaw)(t.val)),d=(0,e.computed)(()=>"q-radio cursor-pointer no-outline row inline no-wrap items-center"+(t.disable?" disabled":"")+(r.value?" q-radio--dark":"")+(t.dense?" q-radio--dense":"")+(t.leftLabel?" reverse":"")),h=(0,e.computed)(()=>{let e=void 0!==t.color&&(t.keepColor||c.value)?` text-${t.color}`:"";return`q-radio__inner relative-position q-radio__inner--${c.value?"truthy":"falsy"}${e}`}),p=(0,e.computed)(()=>(c.value?t.checkedIcon:t.uncheckedIcon)||null),f=(0,e.computed)(()=>t.disable?-1:t.tabindex||0),m=xa((0,e.computed)(()=>{let e={type:"radio"};return void 0!==t.name&&Object.assign(e,{".checked":c.value,"^checked":c.value?"checked":void 0,name:t.name,value:t.val}),e}));function _(e){void 0!==e&&(w(e),u(e)),!t.disable&&!c.value&&a("update:modelValue",t.val,e)}function g(e){(13===e.keyCode||32===e.keyCode)&&_(e)}Object.assign(i,{set:_});let v=(0,e.h)("svg",{key:"svg",class:"q-radio__bg absolute non-selectable",viewBox:"0 0 24 24"},[(0,e.h)("path",{d:"M12,22a10,10 0 0 1 -10,-10a10,10 0 0 1 10,-10a10,10 0 0 1 10,10a10,10 0 0 1 -10,10m0,-22a12,12 0 0 0 -12,12a12,12 0 0 0 12,12a12,12 0 0 0 12,-12a12,12 0 0 0 -12,-12"}),(0,e.h)("path",{class:"q-radio__check",d:"M12,6a6,6 0 0 0 -6,6a6,6 0 0 0 6,6a6,6 0 0 0 6,-6a6,6 0 0 0 -6,-6"})]);return()=>{let a=null===p.value?[v]:[(0,e.h)("div",{key:"icon",class:"q-radio__icon-container absolute-full flex flex-center no-wrap"},[(0,e.h)(Ke,{class:"q-radio__icon",name:p.value})])];t.disable||m(a,"unshift"," q-radio__native q-ma-none q-pa-none");let i=[(0,e.h)("div",{class:h.value,style:o.value,"aria-hidden":"true"},a)];null!==l.value&&i.push(l.value);let r=void 0===t.label?Ae(n.default):Me(n.default,[t.label]);return void 0!==r&&i.push((0,e.h)("div",{class:"q-radio__label q-anchor--skip"},r)),(0,e.h)("div",{ref:s,class:d.value,tabindex:f.value,role:"radio","aria-label":t.label,"aria-checked":c.value?"true":"false","aria-disabled":t.disable?"true":void 0,onClick:_,onKeydown:zl,onKeyup:g},i)}}}),Nl=h({name:"QToggle",props:{...ni,icon:String,iconColor:String},emits:ai,setup:t=>ri("toggle",function(n,a){let i=(0,e.computed)(()=>(n.value?t.checkedIcon:a.value?t.indeterminateIcon:t.uncheckedIcon)||t.icon),r=(0,e.computed)(()=>n.value?t.iconColor:null);return()=>[(0,e.h)("div",{class:"q-toggle__track"}),(0,e.h)("div",{class:"q-toggle__thumb absolute flex flex-center no-wrap"},void 0===i.value?void 0:[(0,e.h)(Ke,{name:i.value,color:r.value})])]})});let Ol={radio:Il,checkbox:oi,toggle:Nl},jl=Object.keys(Ol);function Dl(e,t){if("function"==typeof e)return e;let n=void 0===e?t:e;return e=>e[n]}var ql=h({name:"QOptionGroup",props:{...Je,modelValue:{required:!0},options:{type:Array,validator:e=>e.every(ne),default:()=>[]},optionValue:[Function,String],optionLabel:[Function,String],optionDisable:[Function,String],name:String,type:{type:String,default:"radio",validator:e=>jl.includes(e)},color:String,keepColor:Boolean,dense:Boolean,size:String,leftLabel:Boolean,inline:Boolean,disable:Boolean},emits:["update:modelValue"],setup(t,{emit:n,slots:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Array.isArray(t.modelValue);"radio"===t.type?r&&console.error("q-option-group: model should not be array"):r||console.error("q-option-group: model should be array in your case");let o=Xe(t,i),s=(0,e.computed)(()=>Ol[t.type]),l=(0,e.computed)(()=>Dl(t.optionValue,"value")),u=(0,e.computed)(()=>Dl(t.optionLabel,"label")),c=(0,e.computed)(()=>Dl(t.optionDisable,"disable")),d=(0,e.computed)(()=>t.options.map(e=>({val:l.value(e),name:void 0===e.name?t.name:e.name,disable:t.disable||c.value(e),leftLabel:void 0===e.leftLabel?t.leftLabel:e.leftLabel,color:void 0===e.color?t.color:e.color,checkedIcon:e.checkedIcon,uncheckedIcon:e.uncheckedIcon,dark:void 0===e.dark?o.value:e.dark,size:void 0===e.size?t.size:e.size,dense:t.dense,keepColor:void 0===e.keepColor?t.keepColor:e.keepColor}))),h=(0,e.computed)(()=>"q-option-group q-gutter-x-sm"+(t.inline?" q-option-group--inline":"")),p=(0,e.computed)(()=>{let e={role:"group"};return"radio"===t.type&&(e.role="radiogroup",t.disable&&(e["aria-disabled"]="true")),e});function f(e){n("update:modelValue",e)}return()=>(0,e.h)("div",{class:h.value,...p.value},t.options.map((n,i)=>{let r=void 0===a["label-"+i]?void 0===a.label?void 0:()=>a.label(n):()=>a["label-"+i](n);return(0,e.h)("div",[(0,e.h)(s.value,{label:void 0===r?u.value(n):null,modelValue:t.modelValue,"onUpdate:modelValue":f,...d.value[i]},r)])}))}}),Bl=h({name:"QPage",props:{padding:Boolean,styleFn:Function},setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=(0,e.inject)(Y,ee);if(i===ee)return console.error("QPage needs to be a deep child of QLayout"),ee;if((0,e.inject)("_q_pc_",ee)===ee)return console.error("QPage needs to be child of QPageContainer"),ee;let r=(0,e.computed)(()=>{let e=(i.header.space?i.header.size:0)+(i.footer.space?i.footer.size:0);if("function"==typeof t.styleFn){let n=i.isContainer.value?i.containerHeight.value:a.screen.height;return t.styleFn(e,n)}return{minHeight:i.isContainer.value?i.containerHeight.value-e+"px":0===a.screen.height?0===e?"100vh":`calc(100vh - ${e}px)`:a.screen.height-e+"px"}}),o=(0,e.computed)(()=>"q-page"+(t.padding?" q-layout-padding":""));return()=>(0,e.h)("main",{class:o.value,style:r.value},Ae(n.default))}}),Fl=h({name:"QPageContainer",setup(t,{slots:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=(0,e.inject)(Y,ee);if(i===ee)return console.error("QPageContainer needs to be child of QLayout"),ee;(0,e.provide)("_q_pc_",!0);let r=(0,e.computed)(()=>{let e={};return i.header.space&&(e.paddingTop=`${i.header.size}px`),i.right.space&&(e["padding"+(a.lang.rtl?"Left":"Right")]=`${i.right.size}px`),i.footer.space&&(e.paddingBottom=`${i.footer.size}px`),i.left.space&&(e["padding"+(a.lang.rtl?"Right":"Left")]=`${i.left.size}px`),e});return()=>(0,e.h)("div",{class:"q-page-container",style:r.value},Ae(n.default))}});let Vl={position:{type:String,default:"bottom-right",validator:e=>["top-right","top-left","bottom-right","bottom-left","top","right","bottom","left"].includes(e)},offset:{type:Array,validator:e=>2===e.length},expand:Boolean};function Ul(){let{props:t,proxy:{$q:n}}=(0,e.getCurrentInstance)(),a=(0,e.inject)(Y,ee);if(a===ee)return console.error("QPageSticky needs to be child of QLayout"),ee;let i=(0,e.computed)(()=>{let e=t.position;return{top:e.includes("top"),right:e.includes("right"),bottom:e.includes("bottom"),left:e.includes("left"),vertical:"top"===e||"bottom"===e,horizontal:"left"===e||"right"===e}}),r=(0,e.computed)(()=>a.header.offset),o=(0,e.computed)(()=>a.right.offset),s=(0,e.computed)(()=>a.footer.offset),l=(0,e.computed)(()=>a.left.offset),u=(0,e.computed)(()=>{let e=0,a=0,u=i.value,c=n.lang.rtl?-1:1;u.top&&0!==r.value?a=`${r.value}px`:u.bottom&&0!==s.value&&(a=-s.value+"px"),u.left&&0!==l.value?e=c*l.value+"px":u.right&&0!==o.value&&(e=-c*o.value+"px");let d={transform:`translate(${e}, ${a})`};return t.offset&&(d.margin=`${t.offset[1]}px ${t.offset[0]}px`),u.vertical?(0!==l.value&&(d[n.lang.rtl?"right":"left"]=`${l.value}px`),0!==o.value&&(d[n.lang.rtl?"left":"right"]=`${o.value}px`)):u.horizontal&&(0!==r.value&&(d.top=`${r.value}px`),0!==s.value&&(d.bottom=`${s.value}px`)),d}),c=(0,e.computed)(()=>`q-page-sticky row flex-center fixed-${t.position} q-page-sticky--${t.expand?"expand":"shrink"}`);return{$layout:a,getStickyContent:function(n){let a=Ae(n.default);return(0,e.h)("div",{class:c.value,style:u.value},t.expand?a:[(0,e.h)("div",a)])}}}var $l=h({name:"QPageScroller",props:{...Vl,scrollOffset:{type:Number,default:1e3},reverse:Boolean,duration:{type:Number,default:300},offset:{...Vl.offset,default:()=>[18,18]}},emits:["click"],setup(t,{slots:n,emit:a}){let i,{proxy:{$q:r}}=(0,e.getCurrentInstance)(),{$layout:o,getStickyContent:s}=Ul(),l=(0,e.ref)(null),u=(0,e.computed)(()=>o.height.value-(o.isContainer.value?o.containerHeight.value:r.screen.height));function c(){return t.reverse?u.value-o.scroll.value.position>t.scrollOffset:o.scroll.value.position>t.scrollOffset}let d=(0,e.ref)(c());function h(){let e=c();d.value!==e&&(d.value=e)}function p(){t.reverse?void 0===i&&(i=(0,e.watch)(u,h)):f()}function f(){void 0!==i&&(i(),i=void 0)}function m(e){Nn(Pn(o.isContainer.value?l.value:o.rootRef.value),t.reverse?o.height.value:0,t.duration),a("click",e)}function _(){return d.value?(0,e.h)("div",{ref:l,class:"q-page-scroller",onClick:m},s(n)):null}return(0,e.watch)(o.scroll,h),(0,e.watch)(()=>t.reverse,p),p(),(0,e.onBeforeUnmount)(f),()=>(0,e.h)(e.Transition,{name:"q-transition--fade"},_)}}),Hl=h({name:"QPageSticky",props:Vl,setup(e,{slots:t}){let{getStickyContent:n}=Ul();return()=>n(t)}});function Wl(e,t){return!0===e||!1===e?e:t}var Gl=h({name:"QPagination",props:{...Je,modelValue:{type:Number,required:!0},min:{type:[Number,String],default:1},max:{type:[Number,String],required:!0},maxPages:{type:[Number,String],default:0,validator:e=>("string"==typeof e?Number.parseInt(e,10):e)>=0},inputStyle:[Array,String,Object],inputClass:[Array,String,Object],size:String,disable:Boolean,input:Boolean,iconPrev:String,iconNext:String,iconFirst:String,iconLast:String,toFn:Function,boundaryLinks:{type:Boolean,default:null},boundaryNumbers:{type:Boolean,default:null},directionLinks:{type:Boolean,default:null},ellipses:{type:Boolean,default:null},ripple:{type:[Boolean,Object],default:null},round:Boolean,rounded:Boolean,flat:Boolean,outline:Boolean,unelevated:Boolean,push:Boolean,glossy:Boolean,color:{type:String,default:"primary"},textColor:String,activeDesign:{type:String,default:"",values:e=>""===e||Dt.includes(e)},activeColor:String,activeTextColor:String,gutter:String,padding:{type:String,default:"3px 2px"}},emits:["update:modelValue"],setup(t,{emit:n}){let{proxy:a}=(0,e.getCurrentInstance)(),{$q:i}=a,r=Xe(t,i),o=(0,e.computed)(()=>Number.parseInt(t.min,10)),s=(0,e.computed)(()=>Number.parseInt(t.max,10)),l=(0,e.computed)(()=>Number.parseInt(t.maxPages,10)),u=(0,e.computed)(()=>m.value+" / "+s.value),c=(0,e.computed)(()=>Wl(t.boundaryLinks,t.input)),d=(0,e.computed)(()=>Wl(t.boundaryNumbers,!t.input)),h=(0,e.computed)(()=>Wl(t.directionLinks,t.input)),p=(0,e.computed)(()=>Wl(t.ellipses,!t.input)),f=(0,e.ref)(null),m=(0,e.computed)({get:()=>t.modelValue,set:e=>{if(e=Number.parseInt(e,10),t.disable||!Number.isFinite(e))return;let a=_e(e,o.value,s.value);t.modelValue!==a&&n("update:modelValue",a)}});(0,e.watch)(()=>`${o.value}|${s.value}`,()=>{m.value=t.modelValue});let _=(0,e.computed)(()=>"q-pagination row no-wrap items-center"+(t.disable?" disabled":"")),g=(0,e.computed)(()=>t.gutter in It?`${It[t.gutter]}px`:t.gutter||null),v=(0,e.computed)(()=>null===g.value?null:`--q-pagination-gutter-parent:-${g.value};--q-pagination-gutter-child:${g.value}`),b=(0,e.computed)(()=>{let e=[t.iconFirst||i.iconSet.pagination.first,t.iconPrev||i.iconSet.pagination.prev,t.iconNext||i.iconSet.pagination.next,t.iconLast||i.iconSet.pagination.last];return i.lang.rtl?e.reverse():e}),y=(0,e.computed)(()=>({"aria-disabled":t.disable?"true":"false",role:"navigation"})),w=(0,e.computed)(()=>qt(t,"flat")),k=(0,e.computed)(()=>({[w.value]:!0,round:t.round,rounded:t.rounded,padding:t.padding,color:t.color,textColor:t.textColor,size:t.size,ripple:null===t.ripple||t.ripple})),x=(0,e.computed)(()=>{let e={[w.value]:!1};return""!==t.activeDesign&&(e[t.activeDesign]=!0),e}),S=(0,e.computed)(()=>({...x.value,color:t.activeColor||t.color,textColor:t.activeTextColor||t.textColor})),C=(0,e.computed)(()=>{let e=Math.max(l.value,1+(p.value?2:0)+(d.value?2:0)),n={pgFrom:o.value,pgTo:s.value,ellipsesStart:!1,ellipsesEnd:!1,boundaryStart:!1,boundaryEnd:!1,marginalStyle:{minWidth:`${Math.max(2,String(s.value).length)}em`}};return l.value&&eo.value+ +!!d.value&&(n.ellipsesStart=!0,n.pgFrom++),d.value&&(n.boundaryEnd=!0,n.pgTo--),p.value&&n.pgTo{T(a)}:r.to=t.toFn(a)),(0,e.h)(Kt,r)}return Object.assign(a,{set:T,setByOffset:function(e){m.value+=e}}),()=>{let n,a=[],l=[];if(c.value&&(a.push(L({key:"bls",disable:t.disable||t.modelValue<=o.value,icon:b.value[0],"aria-label":i.lang.pagination.first},o.value)),l.unshift(L({key:"ble",disable:t.disable||t.modelValue>=s.value,icon:b.value[3],"aria-label":i.lang.pagination.last},s.value))),h.value&&(a.push(L({key:"bdp",disable:t.disable||t.modelValue<=o.value,icon:b.value[1],"aria-label":i.lang.pagination.prev},t.modelValue-1)),l.unshift(L({key:"bdn",disable:t.disable||t.modelValue>=s.value,icon:b.value[2],"aria-label":i.lang.pagination.next},t.modelValue+1))),!t.input){n=[];let{pgFrom:e,pgTo:i,marginalStyle:r}=C.value;C.value.boundaryStart&&a.push(L({key:"bns",style:r,disable:t.disable,label:o.value},o.value,o.value===t.modelValue)),C.value.boundaryEnd&&l.unshift(L({key:"bne",style:r,disable:t.disable,label:s.value},s.value,s.value===t.modelValue)),C.value.ellipsesStart&&a.push(L({key:"bes",style:r,disable:t.disable,label:"…",ripple:!1},e-1)),C.value.ellipsesEnd&&l.unshift(L({key:"bee",style:r,disable:t.disable,label:"…",ripple:!1},i+1));for(let a=e;a<=i;a++)n.push(L({key:`bpg${a}`,style:r,disable:t.disable,label:a},a,a===t.modelValue))}return(0,e.h)("div",{class:_.value,...y.value},[(0,e.h)("div",{class:"q-pagination__content row no-wrap items-center",style:v.value},[...a,t.input?(0,e.h)(dl,{class:"inline",style:{width:u.value.length/1.5+"em"},type:"number",dense:!0,value:f.value,disable:t.disable,dark:r.value,borderless:!0,inputClass:t.inputClass,inputStyle:t.inputStyle,placeholder:u.value,min:o.value,max:s.value,"onUpdate:modelValue":E,onKeyup:A,onBlur:P}):(0,e.h)("div",{class:"q-pagination__middle row justify-center"},n),...l])])}}});function Kl(e){let t=null,n=null,a=null;function i(...i){n=i,a=this,null===t&&(t=window.requestAnimationFrame(()=>{e.apply(a,n),t=null,n=null,a=null}))}return i.cancel=()=>{null!==t&&(window.cancelAnimationFrame(t),t=null),n=null,a=null},i}let{passive:Yl}=m,Ql=["load","loadstart","loadedmetadata"];var Zl=h({name:"QParallax",props:{src:String,height:{type:Number,default:500},speed:{type:Number,default:1,validator:e=>e>=0&&e<=1},scrollTarget:Cn,onScroll:Function},setup(t,{slots:n,emit:a}){let i,r,o,s,l,u=(0,e.ref)(0),c=(0,e.ref)(null),d=(0,e.ref)(null),h=(0,e.ref)(null),p=!1;(0,e.watch)(()=>t.height,()=>{p&&m()}),(0,e.watch)(()=>t.scrollTarget,()=>{p&&(b(),v())});let f=e=>{u.value=e,void 0!==t.onScroll&&a("scroll",e)};function m(){let e,n,a;l===window?(e=0,a=n=window.innerHeight):(e=St(l).top,n=Ct(l),a=e+n);let i=St(c.value).top,o=i+t.height;if(void 0!==s||o>e&&i{i.style.transform=`translate3d(-50%,${Math.round(e)}px,0)`};function g(){r=i.naturalHeight||i.videoHeight||Ct(i),p&&m()}function v(){p=!0,l=Pn(c.value,t.scrollTarget),l.addEventListener("scroll",m,Yl),window.addEventListener("resize",o,Yl),m()}function b(){p&&(p=!1,l.removeEventListener("scroll",m,Yl),window.removeEventListener("resize",o,Yl),l=void 0,_.cancel(),f.cancel(),o.cancel())}return(0,e.onMounted)(()=>{_=Kl(_),f=Kl(f),o=Kl(g),i=void 0===n.media?h.value:d.value.children[0],Ql.forEach(e=>{i.addEventListener(e,g)}),g(),i.style.display="initial",void 0===window.IntersectionObserver?v():(s=new IntersectionObserver(e=>{(e[0].isIntersecting?v:b)()}),s.observe(c.value))}),(0,e.onBeforeUnmount)(()=>{b(),s?.disconnect(),Ql.forEach(e=>{i.removeEventListener(e,g)})}),()=>(0,e.h)("div",{ref:c,class:"q-parallax",style:{height:`${t.height}px`}},[(0,e.h)("div",{ref:d,class:"q-parallax__media absolute-full"},void 0===n.media?[(0,e.h)("img",{ref:h,src:t.src})]:n.media()),(0,e.h)("div",{class:"q-parallax__content absolute-full column flex-center"},void 0===n.content?Ae(n.default):n.content({percentScrolled:u.value}))])}});function Jl(e,t=new WeakMap){if(Object(e)!==e)return e;if(t.has(e))return t.get(e);let n=e instanceof Date?new Date(e):e instanceof RegExp?new RegExp(e.source,e.flags):e instanceof Set?new Set:e instanceof Map?new Map:"function"==typeof e.constructor?void 0!==e.prototype&&"function"==typeof e.prototype.constructor?e:new e.constructor:Object.create(null);if("function"==typeof e.constructor&&"function"==typeof e.valueOf){let n=e.valueOf();if(Object(n)!==n){let a=new e.constructor(n);return t.set(e,a),a}}return t.set(e,n),e instanceof Set?e.forEach(e=>{n.add(Jl(e,t))}):e instanceof Map&&e.forEach((e,a)=>{n.set(a,Jl(e,t))}),Object.assign(n,...Object.keys(e).map(n=>({[n]:Jl(e[n],t)})))}var Xl=h({name:"QPopupEdit",props:{modelValue:{required:!0},title:String,buttons:Boolean,labelSet:String,labelCancel:String,color:{type:String,default:"primary"},validate:{type:Function,default:()=>!0},autoSave:Boolean,cover:{type:Boolean,default:!0},disable:Boolean},emits:["update:modelValue","save","cancel","beforeShow","show","beforeHide","hide"],setup(t,{slots:n,emit:i}){let{proxy:r}=(0,e.getCurrentInstance)(),{$q:o}=r,s=(0,e.ref)(null),l=(0,e.ref)(""),u=(0,e.ref)(""),c=!1,d=(0,e.computed)(()=>a({initialValue:l.value,validate:t.validate,set:h,cancel:p,updatePosition:f},"value",()=>u.value,e=>{u.value=e}));function h(){t.validate(u.value)&&(m()&&(i("save",u.value,l.value),i("update:modelValue",u.value)),_())}function p(){m()&&i("cancel",u.value,l.value),_()}function f(){(0,e.nextTick)(()=>{s.value.updatePosition()})}function m(){return!te(u.value,l.value)}function _(){c=!0,s.value.hide()}function g(){c=!1,l.value=Jl(t.modelValue),u.value=Jl(t.modelValue),i("beforeShow")}function v(){i("show")}function b(){!c&&m()&&(t.autoSave&&t.validate(u.value)?(i("save",u.value,l.value),i("update:modelValue",u.value)):i("cancel",u.value,l.value)),i("beforeHide")}function y(){i("hide")}function w(){let a=void 0===n.default?[]:[n.default(d.value)].flat();return t.title&&a.unshift((0,e.h)("div",{class:"q-dialog__title q-mt-sm q-mb-sm"},t.title)),t.buttons&&a.push((0,e.h)("div",{class:"q-popup-edit__buttons row justify-center no-wrap"},[(0,e.h)(Kt,{flat:!0,color:t.color,label:t.labelCancel||o.lang.label.cancel,onClick:p}),(0,e.h)(Kt,{flat:!0,color:t.color,label:t.labelSet||o.lang.label.set,onClick:h})])),a}return Object.assign(r,{set:h,cancel:p,show(e){s.value?.show(e)},hide(e){s.value?.hide(e)},updatePosition:f}),()=>{if(!t.disable)return(0,e.h)(ma,{ref:s,class:"q-popup-edit",cover:t.cover,onBeforeShow:g,onShow:v,onBeforeHide:b,onHide:y,onEscapeKey:p},w)}}}),eu=h({name:"QPopupProxy",props:{...Jt,breakpoint:{type:[String,Number],default:450}},emits:["show","hide"],setup(t,{slots:n,emit:i,attrs:r}){let{proxy:o}=(0,e.getCurrentInstance)(),{$q:s}=o,l=(0,e.ref)(!1),u=(0,e.ref)(null),c=(0,e.computed)(()=>Number.parseInt(t.breakpoint,10)),{canShow:d}=Xt({showing:l,avoidEmit:!0});function h(){return s.screen.width"menu"===p.value?{maxHeight:"99vh"}:{});function m(e){l.value=!0,i("show",e)}function _(e){l.value=!1,p.value=h(),i("hide",e)}return(0,e.watch)(()=>h(),e=>{l.value||(p.value=e)}),Object.assign(o,{show(e){d(e)&&u.value.show(e)},hide(e){u.value.hide(e)},toggle(e){u.value.toggle(e)}}),a(o,"currentComponent",()=>({type:p.value,ref:u.value})),()=>{let a,i={ref:u,...f.value,...r,onShow:m,onHide:_};return"dialog"===p.value?a=Po:(a=ma,Object.assign(i,{target:t.target,contextMenu:t.contextMenu,noParentEvent:!0,separateClosePopup:!0})),(0,e.h)(a,i,n.default)}}}),tu=h({name:"QPullToRefresh",props:{color:String,bgColor:String,icon:String,noMouse:Boolean,disable:Boolean,scrollTarget:Cn},emits:["refresh"],setup(t,{slots:n,emit:a}){let{proxy:i}=(0,e.getCurrentInstance)(),{$q:r}=i,o=(0,e.ref)("pull"),s=(0,e.ref)(0),l=(0,e.ref)(!1),u=(0,e.ref)(-40),c=(0,e.ref)(!1),d=(0,e.ref)({}),h=(0,e.computed)(()=>({opacity:s.value,transform:`translateY(${u.value}px) rotate(${360*s.value}deg)`})),p=(0,e.computed)(()=>"q-pull-to-refresh__puller row flex-center"+(c.value?" q-pull-to-refresh__puller--animating":"")+(void 0===t.bgColor?"":` bg-${t.bgColor}`));function f(e){if(e.isFinal)return void(l.value&&(l.value=!1,"pulled"===o.value?(o.value="refreshing",w({pos:20}),g()):"pull"===o.value&&w({pos:-40,ratio:0})));if(c.value||"refreshing"===o.value)return!1;if(e.isFirst){if(0!==An(v)||"down"!==e.direction)return l.value&&(l.value=!1,o.value="pull",w({pos:-40,ratio:0})),!1;l.value=!0;let{top:t,left:n}=i.$el.getBoundingClientRect();d.value={top:t+"px",left:n+"px",width:window.getComputedStyle(i.$el).getPropertyValue("width")}}y(e.evt);let t=Math.min(140,Math.max(0,e.distance.y));u.value=t-40,s.value=_e(t/60,0,1);let n=u.value>20?"pulled":"pull";o.value!==n&&(o.value=n)}let m=(0,e.computed)(()=>{let e={down:!0};return t.noMouse||(e.mouse=!0),[[gi,f,void 0,e]]}),_=(0,e.computed)(()=>"q-pull-to-refresh__content"+(l.value?" no-pointer-events":""));function g(){a("refresh",()=>{w({pos:-40,ratio:0},()=>{o.value="pull"})})}let v,b=null;function w({pos:e,ratio:t},n){c.value=!0,u.value=e,void 0!==t&&(s.value=t),null!==b&&clearTimeout(b),b=setTimeout(()=>{b=null,c.value=!1,n?.()},300)}function k(){v=Pn(i.$el,t.scrollTarget)}return(0,e.watch)(()=>t.scrollTarget,k),(0,e.onMounted)(k),(0,e.onBeforeUnmount)(()=>{null!==b&&clearTimeout(b)}),Object.assign(i,{trigger:g,updateScrollTarget:k}),()=>ze("div",{class:"q-pull-to-refresh"},[(0,e.h)("div",{class:_.value},Ae(n.default)),(0,e.h)("div",{class:"q-pull-to-refresh__puller-container fixed row flex-center no-pointer-events z-top",style:d.value},[(0,e.h)("div",{class:p.value,style:h.value},["refreshing"===o.value?(0,e.h)(xt,{size:"24px",color:t.color}):(0,e.h)(Ke,{name:t.icon||r.iconSet.pullToRefresh.icon,color:t.color,size:"32px"})])])],"main",!t.disable,()=>m.value)}});let nu=0,au=1,iu=2;var ru=h({name:"QRange",props:{...wi,modelValue:{type:Object,default:()=>({min:null,max:null}),validator:e=>"min"in e&&"max"in e},dragRange:Boolean,dragOnlyRange:Boolean,leftLabelColor:String,leftLabelTextColor:String,rightLabelColor:String,rightLabelTextColor:String,leftLabelValue:[String,Number],rightLabelValue:[String,Number],leftThumbColor:String,rightThumbColor:String},emits:ki,setup(t,{emit:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),{state:i,methods:r}=xi({updateValue:T,updatePosition:function(e,n=i.dragging.value){let a,o=r.getDraggingRatio(e,n),c=r.convertRatioToModel(o);switch(n.type){case nu:o<=n.ratioMax?(a={minR:o,maxR:n.ratioMax,min:c,max:n.valueMax},i.focus.value="min"):(a={minR:n.ratioMax,maxR:o,min:n.valueMax,max:c},i.focus.value="max");break;case iu:o>=n.ratioMin?(a={minR:n.ratioMin,maxR:o,min:n.valueMin,max:c},i.focus.value="max"):(a={minR:o,maxR:n.ratioMin,min:c,max:n.valueMin},i.focus.value="min");break;case au:{let e=o-n.offsetRatio,t=_e(n.ratioMin+e,i.innerMinRatio.value,i.innerMaxRatio.value-n.rangeRatio),r=c-n.offsetModel,s=_e(n.valueMin+r,i.innerMin.value,i.innerMax.value-n.rangeValue);a={minR:t,maxR:t+n.rangeRatio,min:i.roundValueFn.value(s),max:i.roundValueFn.value(s+n.rangeValue)},i.focus.value="both";break}}u.value=null===u.value.min||null===u.value.max?{min:a.min??t.min,max:a.max??t.max}:{min:a.min,max:a.max},t.snap&&0!==t.step?(s.value=r.convertModelToRatio(u.value.min),l.value=r.convertModelToRatio(u.value.max)):(s.value=a.minR,l.value=a.maxR)},getDragging:function(e){let{left:n,top:a,width:i,height:s}=o.value.getBoundingClientRect(),l=t.dragOnlyRange?0:t.vertical?y.value.offsetHeight/(2*s):y.value.offsetWidth/(2*i),c={left:n,top:a,width:i,height:s,valueMin:u.value.min,valueMax:u.value.max,ratioMin:d.value,ratioMax:h.value},p=r.getDraggingRatio(e,c);return!t.dragOnlyRange&&p({type:"hidden",name:t.name,value:`${t.modelValue.min}|${t.modelValue.max}`}))}),o=(0,e.ref)(null),s=(0,e.ref)(0),l=(0,e.ref)(0),u=(0,e.ref)({min:0,max:0});function c(){u.value.min=null===t.modelValue.min?i.innerMin.value:_e(t.modelValue.min,i.innerMin.value,i.innerMax.value),u.value.max=null===t.modelValue.max?i.innerMax.value:_e(t.modelValue.max,i.innerMin.value,i.innerMax.value)}(0,e.watch)(()=>`${t.modelValue.min}|${t.modelValue.max}|${i.innerMin.value}|${i.innerMax.value}`,c),c();let d=(0,e.computed)(()=>r.convertModelToRatio(u.value.min)),h=(0,e.computed)(()=>r.convertModelToRatio(u.value.max)),p=(0,e.computed)(()=>i.active.value?s.value:d.value),f=(0,e.computed)(()=>i.active.value?l.value:h.value),m=(0,e.computed)(()=>{let e={[i.positionProp.value]:100*p.value+"%",[i.sizeProp.value]:100*(f.value-p.value)+"%"};return void 0!==t.selectionImg&&(e.backgroundImage=`url(${t.selectionImg}) !important`),e}),_=(0,e.computed)(()=>{if(!i.editable.value)return{};if(a.platform.is.mobile)return{onClick:r.onMobileClick};let e={onMousedown:r.onActivate};return(t.dragRange||t.dragOnlyRange)&&Object.assign(e,{onFocus:()=>{i.focus.value="both"},onBlur:r.onBlur,onKeydown:P,onKeyup:r.onKeyup}),e});function g(e){return a.platform.is.mobile||!i.editable.value||t.dragOnlyRange?{}:{onFocus:()=>{i.focus.value=e},onBlur:r.onBlur,onKeydown:P,onKeyup:r.onKeyup}}let v=(0,e.computed)(()=>t.dragOnlyRange?null:i.tabindex.value),b=(0,e.computed)(()=>a.platform.is.mobile||!t.dragRange&&!t.dragOnlyRange?null:i.tabindex.value),y=(0,e.ref)(null),k=(0,e.computed)(()=>g("min")),x=r.getThumbRenderFn({focusValue:"min",getNodeData:()=>({ref:y,key:"tmin",...k.value,tabindex:v.value}),ratio:p,label:(0,e.computed)(()=>void 0===t.leftLabelValue?u.value.min:t.leftLabelValue),thumbColor:(0,e.computed)(()=>t.leftThumbColor||t.thumbColor||t.color),labelColor:(0,e.computed)(()=>t.leftLabelColor||t.labelColor),labelTextColor:(0,e.computed)(()=>t.leftLabelTextColor||t.labelTextColor)}),S=(0,e.computed)(()=>g("max")),C=r.getThumbRenderFn({injectFormInput:!1,focusValue:"max",getNodeData:()=>({...S.value,key:"tmax",tabindex:v.value}),ratio:f,label:(0,e.computed)(()=>void 0===t.rightLabelValue?u.value.max:t.rightLabelValue),thumbColor:(0,e.computed)(()=>t.rightThumbColor||t.thumbColor||t.color),labelColor:(0,e.computed)(()=>t.rightLabelColor||t.labelColor),labelTextColor:(0,e.computed)(()=>t.rightLabelTextColor||t.labelTextColor)});function T(e){(u.value.min!==t.modelValue.min||u.value.max!==t.modelValue.max)&&n("update:modelValue",{...u.value}),e&&n("change",{...u.value})}function P(e){if(!yi.includes(e.keyCode))return;w(e);let n=([34,33].includes(e.keyCode)?10:1)*i.keyStep.value,a=([34,37,40].includes(e.keyCode)?-1:1)*(i.isReversed.value?-1:1)*(t.vertical?-1:1)*n;if("both"===i.focus.value){let e=u.value.max-u.value.min,t=_e(i.roundValueFn.value(u.value.min+a),i.innerMin.value,i.innerMax.value-e);u.value={min:t,max:i.roundValueFn.value(t+e)}}else{if(!i.focus.value)return;{let e=i.focus.value;u.value={...u.value,[e]:_e(i.roundValueFn.value(u.value[e]+a),"min"===e?i.innerMin.value:u.value.min,"max"===e?i.innerMax.value:u.value.max)}}}T()}return()=>{let n=r.getContent(m,b,_,e=>{e.push(x(),C())});return(0,e.h)("div",{ref:o,class:"q-range "+i.classes.value+(null===t.modelValue.min||null===t.modelValue.max?" q-slider--no-value":""),...i.attributes.value,"aria-valuenow":t.modelValue.min+"|"+t.modelValue.max},n)}}}),ou=h({name:"QRating",props:{...Pe,...wa,modelValue:{type:Number,required:!0},max:{type:[String,Number],default:5},icon:[String,Array],iconHalf:[String,Array],iconSelected:[String,Array],iconAriaLabel:[String,Array],color:[String,Array],colorHalf:[String,Array],colorSelected:[String,Array],noReset:Boolean,noDimming:Boolean,readonly:Boolean,disable:Boolean},emits:["update:modelValue"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Ee(t),o=xa(ka(t)),s=(0,e.ref)(0),l={},u=(0,e.computed)(()=>!t.readonly&&!t.disable),c=(0,e.computed)(()=>`q-rating row inline items-center q-rating--${u.value?"":"non-"}editable`+(t.noDimming?" q-rating--no-dimming":"")+(t.disable?" disabled":"")+(void 0===t.color||Array.isArray(t.color)?"":` text-${t.color}`)),d=(0,e.computed)(()=>{let e=Array.isArray(t.icon)?t.icon.length:0,n=Array.isArray(t.iconSelected)?t.iconSelected.length:0,a=Array.isArray(t.iconHalf)?t.iconHalf.length:0,i=Array.isArray(t.color)?t.color.length:0,r=Array.isArray(t.colorSelected)?t.colorSelected.length:0,o=Array.isArray(t.colorHalf)?t.colorHalf.length:0;return{iconLen:e,icon:e>0?t.icon[e-1]:t.icon,selIconLen:n,selIcon:n>0?t.iconSelected[n-1]:t.iconSelected,halfIconLen:a,halfIcon:a>0?t.iconHalf[a-1]:t.iconHalf,colorLen:i,color:i>0?t.color[i-1]:t.color,selColorLen:r,selColor:r>0?t.colorSelected[r-1]:t.colorSelected,halfColorLen:o,halfColor:o>0?t.colorHalf[o-1]:t.colorHalf}}),h=(0,e.computed)(()=>{if("string"==typeof t.iconAriaLabel){let e=0===t.iconAriaLabel.length?"":`${t.iconAriaLabel} `;return t=>`${e}${t}`}if(Array.isArray(t.iconAriaLabel)){let e=t.iconAriaLabel.length;if(e>0)return n=>t.iconAriaLabel[Math.min(n,e)-1]}return(e,t)=>`${t} ${e}`}),p=(0,e.computed)(()=>{let e=[],n=d.value,a=Math.ceil(t.modelValue),r=Number.isInteger(t.modelValue)&&t.modelValue>=1&&t.modelValue<=t.max?t.modelValue:1,o=void 0===t.iconHalf||a===t.modelValue?-1:a;for(let l=1;l<=t.max;l++){let c=0===s.value&&t.modelValue>=l||s.value>0&&s.value>=l,d=o===l&&s.value0&&(d?a:t.modelValue)>=l&&s.value{let e={role:"radiogroup"};return t.disable&&(e["aria-disabled"]="true"),t.readonly&&(e["aria-readonly"]="true"),e});function m(e){if(u.value){let n=_e(Number.parseInt(e,10),1,Number.parseInt(t.max,10)),i=t.noReset||t.modelValue!==n?n:0;i!==t.modelValue&&a("update:modelValue",i),s.value=0}}function _(e){u.value&&(s.value=e)}function g(e,t){switch(e.keyCode){case 13:case 32:return m(t),w(e);case 37:{let n=t+(i.lang.rtl?1:-1);return l[`rt${n}`]&&l[`rt${n}`].focus(),w(e)}case 39:{let n=t+(i.lang.rtl?-1:1);return l[`rt${n}`]&&l[`rt${n}`].focus(),w(e)}case 40:return l["rt"+(t-1)]&&l["rt"+(t-1)].focus(),w(e);case 38:return l[`rt${t+1}`]&&l[`rt${t+1}`].focus(),w(e)}}function v(){s.value=0}return(0,e.onBeforeUpdate)(()=>{l={}}),()=>{let a=[];return p.value.forEach(({iconClass:t,name:i,attrs:r},o)=>{let s=o+1;a.push((0,e.h)("div",{key:s,ref:e=>{l[`rt${s}`]=e},class:"q-rating__icon-container flex flex-center",...r,onClick(){m(s)},onMouseover(){_(s)},onMouseout:v,onFocus(){_(s)},onBlur:v,onKeydown(e){g(e,s)}},Me(n[`tip-${s}`],[(0,e.h)(Ke,{class:t,name:i})])))}),void 0!==t.name&&!t.disable&&o(a,"push"),(0,e.h)("div",{class:c.value,style:r.value,...f.value},a)}}}),su=h({name:"QResponsive",props:$s,setup(t,{slots:n}){let a=Hs(t);return()=>(0,e.h)("div",{class:"q-responsive"},[(0,e.h)("div",{class:"q-responsive__filler overflow-hidden"},[(0,e.h)("div",{style:a.value})]),(0,e.h)("div",{class:"q-responsive__content absolute-full fit"},Ae(n.default))])}}),lu=h({props:["store","barStyle","verticalBarStyle","horizontalBarStyle"],setup:t=>()=>[(0,e.h)("div",{class:t.store.scroll.vertical.barClass.value,style:[t.barStyle,t.verticalBarStyle],"aria-hidden":"true",onMousedown:t.store.onVerticalMousedown}),(0,e.h)("div",{class:t.store.scroll.horizontal.barClass.value,style:[t.barStyle,t.horizontalBarStyle],"aria-hidden":"true",onMousedown:t.store.onHorizontalMousedown}),(0,e.withDirectives)((0,e.h)("div",{ref:t.store.scroll.vertical.ref,class:t.store.scroll.vertical.thumbClass.value,style:t.store.scroll.vertical.style.value,"aria-hidden":"true"}),t.store.thumbVertDir),(0,e.withDirectives)((0,e.h)("div",{ref:t.store.scroll.horizontal.ref,class:t.store.scroll.horizontal.thumbClass.value,style:t.store.scroll.horizontal.style.value,"aria-hidden":"true"}),t.store.thumbHorizDir)]});let uu=["vertical","horizontal"],cu={vertical:{offset:"offsetY",scroll:"scrollTop",dir:"down",dist:"y"},horizontal:{offset:"offsetX",scroll:"scrollLeft",dir:"right",dist:"x"}},du={prevent:!0,mouse:!0,mouseAllDir:!0},hu=e=>e>=250?50:Math.ceil(e/5);var pu=h({name:"QScrollArea",props:{...Je,thumbStyle:Object,verticalThumbStyle:Object,horizontalThumbStyle:Object,barStyle:[Array,String,Object],verticalBarStyle:[Array,String,Object],horizontalBarStyle:[Array,String,Object],verticalOffset:{type:Array,default:()=>[0,0]},horizontalOffset:{type:Array,default:()=>[0,0]},contentStyle:[Array,String,Object],contentActiveStyle:[Array,String,Object],delay:{type:[String,Number],default:1e3},visible:{type:Boolean,default:null},tabindex:[String,Number],onScroll:Function},setup(t,{slots:n,emit:a}){let i,r=(0,e.ref)(!1),o=(0,e.ref)(!1),s=(0,e.ref)(!1),l={vertical:(0,e.ref)(0),horizontal:(0,e.ref)(0)},u={vertical:{ref:(0,e.ref)(null),position:(0,e.ref)(0),size:(0,e.ref)(0)},horizontal:{ref:(0,e.ref)(null),position:(0,e.ref)(0),size:(0,e.ref)(0)}},{proxy:c}=(0,e.getCurrentInstance)(),d=Xe(t,c.$q),h=null,p=(0,e.ref)(null),f=(0,e.computed)(()=>"q-scrollarea"+(d.value?" q-scrollarea--dark":""));Object.assign(l,{verticalInner:(0,e.computed)(()=>l.vertical.value-t.verticalOffset[0]-t.verticalOffset[1]),horizontalInner:(0,e.computed)(()=>l.horizontal.value-t.horizontalOffset[0]-t.horizontalOffset[1])}),u.vertical.percentage=(0,e.computed)(()=>{let e=u.vertical.size.value-l.vertical.value;if(e<=0)return 0;let t=_e(u.vertical.position.value/e,0,1);return Math.round(1e4*t)/1e4}),u.vertical.thumbHidden=(0,e.computed)(()=>!(null===t.visible?s.value:t.visible)&&!r.value&&!o.value||u.vertical.size.value<=l.vertical.value+1),u.vertical.thumbStart=(0,e.computed)(()=>t.verticalOffset[0]+u.vertical.percentage.value*(l.verticalInner.value-u.vertical.thumbSize.value)),u.vertical.thumbSize=(0,e.computed)(()=>Math.round(_e(l.verticalInner.value*l.verticalInner.value/u.vertical.size.value,hu(l.verticalInner.value),l.verticalInner.value))),u.vertical.style=(0,e.computed)(()=>({...t.thumbStyle,...t.verticalThumbStyle,top:`${u.vertical.thumbStart.value}px`,height:`${u.vertical.thumbSize.value}px`,right:`${t.horizontalOffset[1]}px`})),u.vertical.thumbClass=(0,e.computed)(()=>"q-scrollarea__thumb q-scrollarea__thumb--v absolute-right"+(u.vertical.thumbHidden.value?" q-scrollarea__thumb--invisible":"")),u.vertical.barClass=(0,e.computed)(()=>"q-scrollarea__bar q-scrollarea__bar--v absolute-right"+(u.vertical.thumbHidden.value?" q-scrollarea__bar--invisible":"")),u.horizontal.percentage=(0,e.computed)(()=>{let e=u.horizontal.size.value-l.horizontal.value;if(e<=0)return 0;let t=_e(P(u.horizontal.position.value)/e,0,1);return Math.round(1e4*t)/1e4}),u.horizontal.thumbHidden=(0,e.computed)(()=>!(null===t.visible?s.value:t.visible)&&!r.value&&!o.value||u.horizontal.size.value<=l.horizontal.value+1),u.horizontal.thumbStart=(0,e.computed)(()=>t.horizontalOffset[+!!c.$q.lang.rtl]+u.horizontal.percentage.value*(l.horizontalInner.value-u.horizontal.thumbSize.value)),u.horizontal.thumbSize=(0,e.computed)(()=>Math.round(_e(l.horizontalInner.value*l.horizontalInner.value/u.horizontal.size.value,hu(l.horizontalInner.value),l.horizontalInner.value))),u.horizontal.style=(0,e.computed)(()=>({...t.thumbStyle,...t.horizontalThumbStyle,[c.$q.lang.rtl?"right":"left"]:`${u.horizontal.thumbStart.value}px`,width:`${u.horizontal.thumbSize.value}px`,bottom:`${t.verticalOffset[1]}px`})),u.horizontal.thumbClass=(0,e.computed)(()=>"q-scrollarea__thumb q-scrollarea__thumb--h absolute-bottom"+(u.horizontal.thumbHidden.value?" q-scrollarea__thumb--invisible":"")),u.horizontal.barClass=(0,e.computed)(()=>"q-scrollarea__bar q-scrollarea__bar--h absolute-bottom"+(u.horizontal.thumbHidden.value?" q-scrollarea__bar--invisible":""));let m=(0,e.computed)(()=>u.vertical.thumbHidden.value&&u.horizontal.thumbHidden.value?t.contentStyle:t.contentActiveStyle);function _(){let e={};return uu.forEach(t=>{let n=u[t];Object.assign(e,{[t+"Position"]:n.position.value,[t+"Percentage"]:n.percentage.value,[t+"Size"]:n.size.value,[t+"ContainerSize"]:l[t].value,[t+"ContainerInnerSize"]:l[t+"Inner"].value})}),e}let g=T(()=>{let e=_();e.ref=c,a("scroll",e)},0);function v(e,t,n){uu.includes(e)?("vertical"===e?Nn:On)(p.value,t,n):console.error("[QScrollArea]: wrong first param of setScrollPosition (vertical/horizontal)")}function b({height:e,width:t}){let n=!1;l.vertical.value!==e&&(l.vertical.value=e,n=!0),l.horizontal.value!==t&&(l.horizontal.value=t,n=!0),n&&S()}function y({position:e}){let t=!1;u.vertical.position.value!==e.top&&(u.vertical.position.value=e.top,t=!0),u.horizontal.position.value!==e.left&&(u.horizontal.position.value=e.left,t=!0),t&&S()}function w({height:e,width:t}){u.horizontal.size.value!==t&&(u.horizontal.size.value=t,S()),u.vertical.size.value!==e&&(u.vertical.size.value=e,S())}function k(e,t){let n=u[t];if(e.isFirst){if(n.thumbHidden.value)return;i="horizontal"===t?P(n.position.value):n.position.value,o.value=!0}else if(!o.value)return;e.isFinal&&(o.value=!1);let a=cu[t],r=(n.size.value-l[t].value)/(l[t+"Inner"].value-n.thumbSize.value),s=e.distance[a.dist],d=(e.direction===a.dir?1:-1)*("horizontal"===t&&c.$q.lang.rtl?-1:1),h=i+d*s*r;C("horizontal"===t?E(h):h,t)}function x(e,n){let a=u[n];if(!a.thumbHidden.value){let i="horizontal"===n&&c.$q.lang.rtl,r="vertical"===n?t.verticalOffset[0]:t.horizontalOffset[+!!i],o=(i?l.horizontal.value-e.offsetX:e[cu[n].offset])-r,s=a.thumbStart.value-r;if(os+a.thumbSize.value){let e=_e((o-a.thumbSize.value/2)/(l[n+"Inner"].value-a.thumbSize.value),0,1);C(i?E(e*Math.max(0,a.size.value-l[n].value)):e*Math.max(0,a.size.value-l[n].value),n)}null!==a.ref.value&&a.ref.value.dispatchEvent(new MouseEvent(e.type,e))}}function S(){r.value=!0,null!==h&&clearTimeout(h),h=setTimeout(()=>{h=null,r.value=!1},t.delay),void 0!==t.onScroll&&g()}function C(e,t){p.value[cu[t].scroll]=e}function P(e,t=c.$q.lang.rtl){return t?Li?Math.max(0,u.horizontal.size.value-l.horizontal.value)-e:-e:e}function E(e,t=c.$q.lang.rtl){return t?Li?Math.max(0,u.horizontal.size.value-l.horizontal.value)-e:-e:e}let A=null;function L(){null!==A&&clearTimeout(A),A=setTimeout(()=>{A=null,s.value=!0},c.$q.platform.is.ios?50:0)}function M(){null!==A&&(clearTimeout(A),A=null),s.value=!1}let R=null;(0,e.watch)(()=>c.$q.lang.rtl,(e,t)=>{null!==p.value&&On(p.value,E(P(u.horizontal.position.value,t),e))}),(0,e.onDeactivated)(()=>{R={top:u.vertical.position.value,left:u.horizontal.position.value}}),(0,e.onActivated)(()=>{if(null===R)return;let e=p.value;null!==e&&(On(e,R.left),Nn(e,R.top))}),(0,e.onBeforeUnmount)(g.cancel),Object.assign(c,{getScrollTarget:()=>p.value,getScroll:_,getScrollPosition:()=>({top:u.vertical.position.value,left:u.horizontal.position.value}),getScrollPercentage:()=>({top:u.vertical.percentage.value,left:u.horizontal.percentage.value}),setScrollPosition:v,setScrollPercentage(e,t,n){let a=t*(u[e].size.value-l[e].value);v(e,"horizontal"===e?E(a):a,n)}});let z={scroll:u,thumbVertDir:[[gi,e=>{k(e,"vertical")},void 0,{vertical:!0,...du}]],thumbHorizDir:[[gi,e=>{k(e,"horizontal")},void 0,{horizontal:!0,...du}]],onVerticalMousedown(e){x(e,"vertical")},onHorizontalMousedown(e){x(e,"horizontal")}};return()=>(0,e.h)("div",{class:f.value,onMouseenter:L,onMouseleave:M},[(0,e.h)("div",{ref:p,class:"q-scrollarea__container scroll relative-position fit hide-scrollbar",tabindex:void 0===t.tabindex?void 0:t.tabindex},[(0,e.h)("div",{class:"q-scrollarea__content absolute",style:m.value},Me(n.default,[(0,e.h)(Ai,{debounce:0,onResize:w})])),(0,e.h)(Sl,{axis:"both",onScroll:y})]),(0,e.h)(Ai,{debounce:0,onResize:b}),(0,e.h)(lu,{store:z,barStyle:t.barStyle,verticalBarStyle:t.verticalBarStyle,horizontalBarStyle:t.horizontalBarStyle})])}});let fu=1e3,mu=["start","center","end","start-force","center-force","end-force"],_u=Array.prototype.filter,gu=void 0===window.getComputedStyle(document.body).overflowAnchor?_:function(e,t){null!==e&&(void 0!==e._qOverflowAnimationFrame&&cancelAnimationFrame(e._qOverflowAnimationFrame),e._qOverflowAnimationFrame=requestAnimationFrame(()=>{if(null===e)return;e._qOverflowAnimationFrame=void 0;let n=e.children||[];_u.call(n,e=>e.dataset&&void 0!==e.dataset.qVsAnchor).forEach(e=>{delete e.dataset.qVsAnchor});let a=n[t];a?.dataset&&(a.dataset.qVsAnchor="")}))};function vu(e,t){return e+t}function bu(e,t,n,a,i,r,o,s){let l=e===window?document.scrollingElement||document.documentElement:e,u=i?"offsetWidth":"offsetHeight",c={scrollStart:0,scrollViewSize:-o-s,scrollMaxSize:0,offsetStart:-o,offsetEnd:-s};if(i?(e===window?(c.scrollStart=window.pageXOffset||window.scrollX||document.body.scrollLeft||0,c.scrollViewSize+=document.documentElement.clientWidth):(c.scrollStart=l.scrollLeft,c.scrollViewSize+=l.clientWidth),c.scrollMaxSize=l.scrollWidth,r&&(c.scrollStart=(Li?c.scrollMaxSize-c.scrollViewSize:0)-c.scrollStart)):(e===window?(c.scrollStart=window.pageYOffset||window.scrollY||document.body.scrollTop||0,c.scrollViewSize+=document.documentElement.clientHeight):(c.scrollStart=l.scrollTop,c.scrollViewSize+=l.clientHeight),c.scrollMaxSize=l.scrollHeight),null!==n)for(let e=n.previousElementSibling;null!==e;e=e.previousElementSibling)e.classList.contains("q-virtual-scroll--skip")||(c.offsetStart+=e[u]);if(null!==a)for(let e=a.nextElementSibling;null!==e;e=e.nextElementSibling)e.classList.contains("q-virtual-scroll--skip")||(c.offsetEnd+=e[u]);if(t!==e){let n=l.getBoundingClientRect(),a=t.getBoundingClientRect();i?(c.offsetStart+=a.left-n.left,c.offsetEnd-=a.width):(c.offsetStart+=a.top-n.top,c.offsetEnd-=a.height),e!==window&&(c.offsetStart+=c.scrollStart),c.offsetEnd+=c.scrollMaxSize-c.offsetStart}return c}function yu(e,t,n,a){"end"===t&&(t=(e===window?document.body:e)[n?"scrollWidth":"scrollHeight"]),e===window?n?(a&&(t=(Li?document.body.scrollWidth-document.documentElement.clientWidth:0)-t),window.scrollTo(t,window.pageYOffset||window.scrollY||document.body.scrollTop||0)):window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,t):n?(a&&(t=(Li?e.scrollWidth-e.offsetWidth:0)-t),e.scrollLeft=t):e.scrollTop=t}function wu(e,t,n,a){if(n>=a)return 0;let i=t.length,r=Math.floor(n/fu),o=Math.floor((a-1)/fu)+1,s=e.slice(r,o).reduce(vu,0);return n%fu!=0&&(s-=t.slice(r*fu,n).reduce(vu,0)),a%fu!=0&&a!==i&&(s-=t.slice(a,o*fu).reduce(vu,0)),s}let ku={virtualScrollSliceSize:{type:[Number,String],default:10},virtualScrollSliceRatioBefore:{type:[Number,String],default:1},virtualScrollSliceRatioAfter:{type:[Number,String],default:1},virtualScrollItemSize:{type:[Number,String],default:24},virtualScrollStickySizeStart:{type:[Number,String],default:0},virtualScrollStickySizeEnd:{type:[Number,String],default:0},tableColspan:[Number,String]},xu=Object.keys(ku),Su={virtualScrollHorizontal:Boolean,onVirtualScroll:Function,...ku};function Cu({virtualScrollLength:t,getVirtualScrollTarget:n,getVirtualScrollEl:a,virtualScrollItemSizeComputed:i}){let r,o,s,l,{props:u,emit:c,proxy:d}=(0,e.getCurrentInstance)(),{$q:h}=d,p=[],f=(0,e.ref)(0),m=(0,e.ref)(0),_=(0,e.ref)({}),g=(0,e.ref)(null),v=(0,e.ref)(null),b=(0,e.ref)(null),y=(0,e.ref)({from:0,to:0}),w=(0,e.computed)(()=>void 0===u.tableColspan?100:u.tableColspan);void 0===i&&(i=(0,e.computed)(()=>u.virtualScrollItemSize));let k=(0,e.computed)(()=>i.value+";"+u.virtualScrollHorizontal);function x(){L(o,!0)}function S(e){L(void 0===e?o:e)}function C(e,i){let r=n();if(null==r||8===r.nodeType)return;let l=bu(r,a(),g.value,v.value,u.virtualScrollHorizontal,h.lang.rtl,u.virtualScrollStickySizeStart,u.virtualScrollStickySizeEnd);s!==l.scrollViewSize&&M(l.scrollViewSize),P(r,l,Math.min(t.value-1,Math.max(0,Number.parseInt(e,10)||0)),0,mu.includes(i)?i:-1!==o&&e>o?"end":"start")}function P(e,n,a,i,o){let s="string"==typeof o&&o.includes("-force"),c=s?o.replace("-force",""):o,d=void 0===c?"start":c,g=Math.max(0,a-_.value[d]),v=g+_.value.total;v>t.value&&(v=t.value,g=Math.max(0,v-_.value.total)),r=n.scrollStart;let w=g!==y.value.from||v!==y.value.to;if(!w&&void 0===c)return void R(a);let{activeElement:k}=document,x=b.value;w&&null!==x&&x!==k&&x.contains(k)&&(x.addEventListener("focusout",A),setTimeout(()=>{x?.removeEventListener("focusout",A)},0)),gu(x,a-g);let S=void 0===c?0:l.slice(g,a).reduce(vu,0);if(w){let e=v>=y.value.from&&g<=y.value.to?y.value.to:v;y.value={from:g,to:e},f.value=wu(p,l,0,g),m.value=wu(p,l,v,t.value),requestAnimationFrame(()=>{y.value.to!==v&&r===n.scrollStart&&(y.value={from:y.value.from,to:v},m.value=wu(p,l,v,t.value))})}requestAnimationFrame(()=>{if(r!==n.scrollStart)return;w&&E(g);let t=l.slice(g,a).reduce(vu,0),o=t+n.offsetStart+f.value,d=o+l[a],p=o+i;if(void 0!==c){let e=t-S,i=n.scrollStart+e;p=!s&&ie.classList&&!e.classList.contains("q-virtual-scroll--skip")),r=i.length,o=u.virtualScrollHorizontal?e=>e.getBoundingClientRect().width:e=>e.offsetHeight,s=e;for(let e=0;e=u;e--)l[e]=s;let c=Math.floor((t.value-1)/fu);p=[];for(let e=0;e<=c;e++){let n=0,a=Math.min((e+1)*fu,t.value);for(let t=e*fu;t=0?(E(y.value.from),(0,e.nextTick)(()=>{C(n)})):z()}function M(e){if(void 0===e&&typeof window<"u"){let t=n();null!=t&&8!==t.nodeType&&(e=bu(t,a(),g.value,v.value,u.virtualScrollHorizontal,h.lang.rtl,u.virtualScrollStickySizeStart,u.virtualScrollStickySizeEnd).scrollViewSize)}s=e;let t=Number.parseFloat(u.virtualScrollSliceRatioBefore)||0,r=1+t+(Number.parseFloat(u.virtualScrollSliceRatioAfter)||0),o=void 0===e||e<=0?1:Math.ceil(e/i.value),l=Math.max(1,o,Math.ceil((u.virtualScrollSliceSize>0?u.virtualScrollSliceSize:10)/r));_.value={total:Math.ceil(l*r),start:Math.ceil(l*t),center:Math.ceil(l*(.5+t)),end:Math.ceil(l*(1+t)),view:o}}function R(e){o!==e&&(void 0!==u.onVirtualScroll&&c("virtualScroll",{index:e,from:y.value.from,to:y.value.to-1,direction:ek.value+";"+u.virtualScrollSliceRatioBefore+";"+u.virtualScrollSliceRatioAfter),()=>{M()}),(0,e.watch)(k,x),M();let z=T(function(){let e=n();if(null==e||8===e.nodeType)return;let i=bu(e,a(),g.value,v.value,u.virtualScrollHorizontal,h.lang.rtl,u.virtualScrollStickySizeStart,u.virtualScrollStickySizeEnd),o=t.value-1,c=i.scrollMaxSize-i.offsetStart-i.offsetEnd-m.value;if(r===i.scrollStart)return;if(i.scrollMaxSize<=0)return void P(e,i,0,0);s!==i.scrollViewSize&&M(i.scrollViewSize),E(y.value.from);let d=Math.floor(i.scrollMaxSize-Math.max(i.scrollViewSize,i.offsetEnd)-Math.min(l[o],i.scrollViewSize/2));if(d>0&&Math.ceil(i.scrollStart)>=d)return void P(e,i,o,i.scrollMaxSize-i.offsetEnd-p.reduce(vu,0));let _=0,b=i.scrollStart-i.offsetStart,w=b;if(b<=c&&b+i.scrollViewSize>=f.value)b-=f.value,_=y.value.from,w=b;else for(let e=0;b>=p[e]&&_0&&_-i.scrollViewSize?(_++,w=b):w=l[_]+b;P(e,i,_,w)},h.platform.is.ios?120:35);(0,e.onBeforeMount)(()=>{M()});let I=!1;return(0,e.onDeactivated)(()=>{I=!0}),(0,e.onActivated)(()=>{if(!I)return;let e=n();void 0!==r&&null!=e&&8!==e.nodeType?yu(e,r,u.virtualScrollHorizontal,h.lang.rtl):C(o)}),(0,e.onBeforeUnmount)(()=>{z.cancel()}),Object.assign(d,{scrollTo:C,reset:x,refresh:S}),{virtualScrollSliceRange:y,virtualScrollSliceSizeComputed:_,setVirtualScrollSize:M,onVirtualScrollEvt:z,localResetVirtualScroll:L,padVirtualScroll:function(t,n){let a=u.virtualScrollHorizontal?"width":"height",r={["--q-virtual-scroll-item-"+a]:i.value+"px"};return["tbody"===t?(0,e.h)(t,{class:"q-virtual-scroll__padding",key:"before",ref:g},[(0,e.h)("tr",[(0,e.h)("td",{style:{[a]:`${f.value}px`,...r},colspan:w.value})])]):(0,e.h)(t,{class:"q-virtual-scroll__padding",key:"before",ref:g,style:{[a]:`${f.value}px`,...r}}),(0,e.h)(t,{class:"q-virtual-scroll__content",key:"content",ref:b,tabindex:-1},n.flat()),"tbody"===t?(0,e.h)(t,{class:"q-virtual-scroll__padding",key:"after",ref:v},[(0,e.h)("tr",[(0,e.h)("td",{style:{[a]:`${m.value}px`,...r},colspan:w.value})])]):(0,e.h)(t,{class:"q-virtual-scroll__padding",key:"after",ref:v,style:{[a]:`${m.value}px`,...r}})]},scrollTo:C,reset:x,refresh:S}}let Tu=e=>["add","add-unique","toggle"].includes(e),Pu=Object.keys(xs);function Eu(e,t){if("function"==typeof e)return e;let n=void 0===e?t:e;return e=>"object"==typeof e&&e&&n in e?e[n]:e}var Au=h({name:"QSelect",inheritAttrs:!1,props:{...Su,...wa,...xs,modelValue:{required:!0},multiple:Boolean,displayValue:[String,Number],displayValueHtml:Boolean,dropdownIcon:String,options:{type:Array,default:()=>[]},optionValue:[Function,String],optionLabel:[Function,String],optionDisable:[Function,String],hideSelected:Boolean,hideDropdownIcon:Boolean,fillInput:Boolean,maxValues:[Number,String],optionsDense:Boolean,optionsDark:{type:Boolean,default:null},optionsSelectedClass:String,optionsHtml:Boolean,optionsCover:Boolean,menuShrink:Boolean,menuAnchor:String,menuSelf:String,menuOffset:Array,popupContentClass:String,popupContentStyle:[String,Array,Object],popupNoRouteDismiss:Boolean,useInput:Boolean,useChips:Boolean,newValueMode:{type:String,validator:Tu},mapOptions:Boolean,emitValue:Boolean,disableTabSelection:Boolean,inputDebounce:{type:[Number,String],default:500},inputClass:[Array,String,Object],inputStyle:[Array,String,Object],tabindex:{type:[String,Number],default:0},autocomplete:String,transitionShow:{},transitionHide:{},transitionDuration:{},behavior:{type:String,validator:e=>["default","menu","dialog"].includes(e),default:"default"},virtualScrollItemSize:Su.virtualScrollItemSize.type,onNewValue:Function,onFilter:Function},emits:[...Ss,"add","remove","inputValue","keyup","keypress","keydown","popupShow","popupHide","filterAbort"],setup(t,{slots:n,emit:a}){let i,r,o,s,l,u,c,{proxy:d}=(0,e.getCurrentInstance)(),{$q:h}=d,p=(0,e.ref)(!1),f=(0,e.ref)(!1),m=(0,e.ref)(-1),_=(0,e.ref)(""),g=(0,e.ref)(!1),v=(0,e.ref)(!1),k=null,x=null,S=null,C=(0,e.ref)(null),T=(0,e.ref)(null),P=(0,e.ref)(null),E=(0,e.ref)(null),A=(0,e.ref)(null),L=Sa(t),M=cl(Re),R=(0,e.computed)(()=>Array.isArray(t.options)?t.options.length:0),{virtualScrollSliceRange:z,virtualScrollSliceSizeComputed:O,localResetVirtualScroll:j,padVirtualScroll:D,onVirtualScrollEvt:q,scrollTo:B,setVirtualScrollSize:F}=Cu({virtualScrollLength:R,getVirtualScrollTarget:function(){return Ee()},getVirtualScrollEl:Ee,virtualScrollItemSizeComputed:(0,e.computed)(()=>void 0===t.virtualScrollItemSize?t.optionsDense?24:48:t.virtualScrollItemSize)}),V=Cs(),U=(0,e.computed)(()=>{let e=t.mapOptions&&!t.multiple,n=void 0===t.modelValue||null===t.modelValue&&!e?[]:t.multiple&&Array.isArray(t.modelValue)?t.modelValue:[t.modelValue];if(t.mapOptions&&Array.isArray(t.options)){let a=t.mapOptions&&void 0!==i?i:[],r=n.map(e=>function(e,n){let a=t=>te(ue.value(t),e);return t.options.find(a)||n.find(a)||e}(e,a));return null===t.modelValue&&e?r.filter(e=>null!==e):r}return n}),$=(0,e.computed)(()=>{let e={};return Pu.forEach(n=>{let a=t[n];void 0!==a&&(e[n]=a)}),e}),H=(0,e.computed)(()=>null===t.optionsDark?V.isDark.value:t.optionsDark),W=(0,e.computed)(()=>ws(U.value)),G=(0,e.computed)(()=>{let e="q-field__input q-placeholder col";return t.hideSelected||0===U.value.length?[e,t.inputClass]:(e+=" q-field__input--padding",void 0===t.inputClass?e:[e,t.inputClass])}),K=(0,e.computed)(()=>(t.virtualScrollHorizontal?"q-virtual-scroll--horizontal":"")+(t.popupContentClass?" "+t.popupContentClass:"")),Y=(0,e.computed)(()=>0===R.value),Q=(0,e.computed)(()=>U.value.map(e=>ce.value(e)).join(", ")),Z=(0,e.computed)(()=>void 0===t.displayValue?Q.value:t.displayValue),J=(0,e.computed)(()=>t.optionsHtml?()=>!0:e=>!0===e?.html),X=(0,e.computed)(()=>t.displayValueHtml||void 0===t.displayValue&&(t.optionsHtml||U.value.some(J.value))),ee=(0,e.computed)(()=>V.focused.value?t.tabindex:-1),ne=(0,e.computed)(()=>{let e={tabindex:t.tabindex,role:"combobox","aria-label":t.label,"aria-readonly":t.readonly?"true":"false","aria-autocomplete":t.useInput?"list":"none","aria-expanded":p.value?"true":"false","aria-controls":`${V.targetUid.value}_lb`};return m.value>=0&&(e["aria-activedescendant"]=`${V.targetUid.value}_${m.value}`),e}),ae=(0,e.computed)(()=>({id:`${V.targetUid.value}_lb`,role:"listbox","aria-multiselectable":t.multiple?"true":"false"})),ie=(0,e.computed)(()=>U.value.map((e,t)=>({index:t,opt:e,html:J.value(e),selected:!0,removeAtIndex:_e,toggleOption:be,tabindex:ee.value}))),re=(0,e.computed)(()=>{if(0===R.value)return[];let{from:e,to:n}=z.value;return t.options.slice(e,n).map((n,a)=>{let i=!0===de.value(n),r=ke(n),o=e+a,s={clickable:!0,active:r,activeClass:le.value,manualFocus:!0,focused:!1,disable:i,tabindex:-1,dense:t.optionsDense,dark:H.value,role:"option","aria-selected":r?"true":"false",id:`${V.targetUid.value}_${o}`,onClick:()=>{be(n)}};return i||(m.value===o&&(s.focused=!0),h.platform.is.desktop&&(s.onMousemove=()=>{p.value&&ye(o)})),{index:o,opt:n,html:J.value(n),label:ce.value(n),selected:s.active,focused:s.focused,toggleOption:be,setOptionIndex:ye,itemProps:s}})}),oe=(0,e.computed)(()=>void 0===t.dropdownIcon?h.iconSet.arrow.dropdown:t.dropdownIcon),se=(0,e.computed)(()=>!(t.optionsCover||t.outlined||t.standout||t.borderless||t.rounded)),le=(0,e.computed)(()=>void 0===t.optionsSelectedClass?void 0===t.color?"":`text-${t.color}`:t.optionsSelectedClass),ue=(0,e.computed)(()=>Eu(t.optionValue,"value")),ce=(0,e.computed)(()=>Eu(t.optionLabel,"label")),de=(0,e.computed)(()=>Eu(t.optionDisable,"disable")),he=(0,e.computed)(()=>U.value.map(ue.value)),pe=(0,e.computed)(()=>{let e={onInput:Re,onChange:M,onKeydown:Pe,onKeyup:Ce,onKeypress:Te,onFocus:xe,onClick(e){r&&b(e)}};return e.onCompositionstart=e.onCompositionupdate=e.onCompositionend=M,e});function fe(e){return t.emitValue?ue.value(e):e}function me(e){if(-1!==e&&e=t.maxValues)return;let r=[...t.modelValue];a("add",{index:r.length,value:i}),r.push(i),a("update:modelValue",r)}function be(e,n){if(!V.editable.value||void 0===e||!0===de.value(e))return;let i=ue.value(e);if(!t.multiple)return n||(Ie(t.fillInput?ce.value(e):"",!0,!0),He()),T.value?.focus(),void((0===U.value.length||!te(ue.value(U.value[0]),i))&&a("update:modelValue",t.emitValue?i:e));if((!r||g.value)&&V.focus(),xe(),0===U.value.length){let n=t.emitValue?i:e;return a("add",{index:0,value:n}),void a("update:modelValue",t.multiple?[n]:n)}let o=[...t.modelValue],s=he.value.findIndex(e=>te(e,i));if(-1!==s)a("remove",{index:s,value:o.splice(s,1)[0]});else{if(void 0!==t.maxValues&&o.length>=t.maxValues)return;let n=t.emitValue?i:e;a("add",{index:o.length,value:n}),o.push(n)}a("update:modelValue",o)}function ye(e){if(!h.platform.is.desktop)return;let t=-1!==e&&e=0?ce.value(t.options[a]):s,!0))}}function ke(e){let t=ue.value(e);return void 0!==he.value.find(e=>te(e,t))}function xe(e){t.useInput&&null!==T.value&&(void 0===e||T.value===e.target&&e.target.value===Q.value)&&T.value.select()}function Se(e){N(e,27)&&p.value&&(b(e),He(),We()),a("keyup",e)}function Ce(e){let{value:n}=e.target;if(void 0===e.keyCode)if(e.target.value="",null!==k&&(clearTimeout(k),k=null),null!==x&&(clearTimeout(x),x=null),We(),"string"==typeof n&&0!==n.length){let e=n.toLocaleLowerCase(),a=n=>{let a=t.options.find(t=>String(n.value(t)).toLocaleLowerCase()===e);return void 0!==a&&(U.value.includes(a)?He():be(a),!0)},i=e=>{!a(ue)&&!e&&!a(ce)&&Ne(n,!0,()=>i(!0))};i()}else V.clearValue(e);else Se(e)}function Te(e){a("keypress",e)}function Pe(n){if(a("keydown",n),I(n))return;let i=0!==_.value.length&&(void 0!==t.newValueMode||void 0!==t.onNewValue),r=!n.shiftKey&&!t.disableTabSelection&&!t.multiple&&(-1!==m.value||i);if(27===n.keyCode)return void y(n);if(9===n.keyCode&&!r)return void Ue();if(void 0===n.target||n.target.id!==V.targetUid.value||!V.editable.value)return;if(40===n.keyCode&&!V.innerLoading.value&&!p.value)return w(n),void $e();if(8===n.keyCode&&(t.useChips||t.clearable)&&!t.hideSelected&&0===_.value.length)return void(t.multiple&&Array.isArray(t.modelValue)?me(t.modelValue.length-1):!t.multiple&&null!==t.modelValue&&a("update:modelValue",null));(35===n.keyCode||36===n.keyCode)&&("string"!=typeof _.value||0===_.value.length)&&(w(n),m.value=-1,we(36===n.keyCode?1:-1,t.multiple)),(33===n.keyCode||34===n.keyCode)&&void 0!==O.value&&(w(n),m.value=Math.max(-1,Math.min(R.value,m.value+(33===n.keyCode?-1:1)*O.value.view)),we(33===n.keyCode?1:-1,t.multiple)),(38===n.keyCode||40===n.keyCode)&&(w(n),we(38===n.keyCode?-1:1,t.multiple));let o=R.value;if((void 0===u||c0&&!t.useInput&&void 0!==n.key&&1===n.key.length&&!n.altKey&&!n.ctrlKey&&!n.metaKey&&(32!==n.keyCode||0!==u.length)){p.value||$e(n);let a=n.key.toLocaleLowerCase(),i=1===u.length&&u[0]===a;c=Date.now()+1500,i||(w(n),u+=a);let r=RegExp("^"+[...u].map(e=>".*+?^${}()|[]\\".includes(e)?"\\"+e:e).join(".*"),"i"),s=m.value;if(i||s<0||!r.test(ce.value(t.options[s])))do{s=ge(s+1,-1,o-1)}while(s!==m.value&&(!0===de.value(t.options[s])||!r.test(ce.value(t.options[s]))));return void(m.value!==s&&(0,e.nextTick)(()=>{ye(s),B(s),s>=0&&t.useInput&&t.fillInput&&ze(ce.value(t.options[s]),!0)}))}if(13===n.keyCode||32===n.keyCode&&!t.useInput&&""===u||9===n.keyCode&&r){if(9!==n.keyCode&&w(n),-1!==m.value&&m.value{if(n){if(!Tu(n))return}else n=t.newValueMode;Ie("",!t.multiple,!0),null!=e&&(("toggle"===n?be:ve)(e,"add-unique"===n),t.multiple||(T.value?.focus(),He()))};if(void 0===t.onNewValue?e(_.value):a("newValue",_.value,e),!t.multiple)return}p.value?Ue():V.innerLoading.value||$e()}}function Ee(){return r?A.value:null!==P.value&&null!==P.value.contentEl?P.value.contentEl:void 0}function Ae(){return t.hideSelected?[]:void 0===n["selected-item"]?void 0===n.selected?t.useChips?ie.value.map((n,a)=>(0,e.h)(ui,{key:"option-"+a,removable:V.editable.value&&!0!==de.value(n.opt),dense:!0,textColor:t.color,tabindex:ee.value,onRemove(){n.removeAtIndex(a)}},()=>(0,e.h)("span",{class:"ellipsis",[n.html?"innerHTML":"textContent"]:ce.value(n.opt)}))):[(0,e.h)("span",{class:"ellipsis",[X.value?"innerHTML":"textContent"]:Z.value})]:[n.selected()].flat():ie.value.map(e=>n["selected-item"](e))}function Le(){if(Y.value)return void 0===n["no-option"]?void 0:n["no-option"]({inputValue:_.value});let t=void 0===n.option?t=>(0,e.h)(jo,{key:t.index,...t.itemProps},()=>(0,e.h)(Do,()=>(0,e.h)(Xo,()=>(0,e.h)("span",{[t.html?"innerHTML":"textContent"]:t.label})))):n.option,a=D("div",re.value.map(t));return void 0!==n["before-options"]&&(a=[n["before-options"](),...a].flat()),Me(n["after-options"],a)}function Re(e){null!==k&&(clearTimeout(k),k=null),null!==x&&(clearTimeout(x),x=null),!e?.target?.qComposing&&(ze(e.target.value||""),o=!0,s=_.value,!V.focused.value&&(!r||g.value)&&V.focus(),void 0!==t.onFilter&&(k=setTimeout(()=>{k=null,Ne(_.value)},t.inputDebounce)))}function ze(e,n){_.value!==e&&(_.value=e,n||0===t.inputDebounce||"0"===t.inputDebounce?a("inputValue",e):x=setTimeout(()=>{x=null,a("inputValue",e)},t.inputDebounce))}function Ie(e,n,a){o=!0!==a,t.useInput&&(ze(e,!0),(n||o)&&(s=e),n||Ne(e))}function Ne(n,i,r){if(void 0===t.onFilter||!i&&!V.focused.value)return;V.innerLoading.value?a("filterAbort"):(V.innerLoading.value=!0,v.value=!0),""!==n&&!t.multiple&&0!==U.value.length&&!o&&n===ce.value(U.value[0])&&(n="");let s=setTimeout(()=>{p.value&&=!1},10);null!==S&&clearTimeout(S),S=s,a("filter",n,(t,n)=>{(i||V.focused.value)&&S===s&&(clearTimeout(S),"function"==typeof t&&t(),v.value=!1,(0,e.nextTick)(()=>{V.innerLoading.value=!1,V.editable.value&&(i?p.value&&He():p.value?Ge(!0):p.value=!0),"function"==typeof n&&(0,e.nextTick)(()=>{n(d)}),"function"==typeof r&&(0,e.nextTick)(()=>{r(d)})}))},()=>{V.focused.value&&S===s&&(clearTimeout(S),V.innerLoading.value=!1,v.value=!1),p.value&&=!1})}function Oe(e){Ze(e),Ue()}function je(){F()}function De(e){b(e),T.value?.focus(),g.value=!0,window.scrollTo(window.pageXOffset||window.scrollX||document.body.scrollLeft||0,0)}function qe(t){b(t),(0,e.nextTick)(()=>{g.value=!1})}function Be(e){Ze(e),null!==E.value&&E.value.__updateRefocusTarget(V.rootRef.value.querySelector(".q-field__native > [tabindex]:last-child")),V.focused.value=!1}function Fe(e){He(),V.focused.value||a("blur",e),We()}function Ve(){let e=document.activeElement;(null===e||e.id!==V.targetUid.value)&&null!==T.value&&T.value!==e&&T.value.focus(),F()}function Ue(){f.value||(m.value=-1,p.value&&=!1,V.focused.value||(null!==S&&(clearTimeout(S),S=null),V.innerLoading.value&&(a("filterAbort"),V.innerLoading.value=!1,v.value=!1)))}function $e(a){V.editable.value&&(r?(V.onControlFocusin(a),f.value=!0,(0,e.nextTick)(()=>{V.focus()})):V.focus(),void 0===t.onFilter?(!Y.value||void 0!==n["no-option"])&&(p.value=!0):Ne(_.value))}function He(){f.value=!1,Ue()}function We(){t.useInput&&Ie(!t.multiple&&t.fillInput&&0!==U.value.length&&ce.value(U.value[0])||"",!0,!0)}function Ge(e){let n=-1;if(e){if(0!==U.value.length){let e=ue.value(U.value[0]);n=t.options.findIndex(t=>te(ue.value(t),e))}j(n)}ye(n)}function Ye(){f.value||P.value?.updatePosition()}function Qe(e){void 0!==e&&b(e),a("popupShow",e),V.hasPopupOpen=!0,V.onControlFocusin(e)}function Ze(e){void 0!==e&&b(e),a("popupHide",e),V.hasPopupOpen=!1,V.onControlFocusout(e)}function Je(){r=!(!h.platform.is.mobile&&"dialog"!==t.behavior)&&!("menu"===t.behavior||t.useInput&&void 0===n["no-option"]&&void 0===t.onFilter&&Y.value),l=h.platform.is.ios&&r&&t.useInput?"fade":t.transitionShow}return(0,e.watch)(U,e=>{i=e,t.useInput&&t.fillInput&&!t.multiple&&!V.innerLoading.value&&(!f.value&&!p.value||!W.value)&&(o||We(),(f.value||p.value)&&Ne(""))},{immediate:!0}),(0,e.watch)(()=>t.fillInput,We),(0,e.watch)(p,Ge),(0,e.watch)(R,function(t,n){p.value&&!V.innerLoading.value&&(j(-1,!0),(0,e.nextTick)(()=>{p.value&&!V.innerLoading.value&&(t>n?j():Ge(!0))}))}),(0,e.onBeforeUpdate)(Je),(0,e.onUpdated)(Ye),Je(),(0,e.onBeforeUnmount)(()=>{null!==k&&clearTimeout(k),null!==x&&clearTimeout(x)}),Object.assign(d,{showPopup:$e,hidePopup:He,removeAtIndex:me,add:ve,toggleOption:be,getOptionIndex:()=>m.value,setOptionIndex:ye,moveOptionSelection:we,filter:Ne,updateMenuPosition:Ye,updateInputValue:Ie,isOptionSelected:ke,getEmittingOptionValue:fe,isOptionDisabled:(...e)=>!0===de.value(...e),getOptionValue:(...e)=>ue.value(...e),getOptionLabel:(...e)=>ce.value(...e)}),Object.assign(V,{innerValue:U,fieldClass:(0,e.computed)(()=>`q-select q-field--auto-height q-select--with${t.useInput?"":"out"}-input q-select--with${t.useChips?"":"out"}-chips q-select--${t.multiple?"multiple":"single"}`),inputRef:C,targetRef:T,hasValue:W,showPopup:$e,floatingLabel:(0,e.computed)(()=>!t.hideSelected&&W.value||"number"==typeof _.value||0!==_.value.length||ws(t.displayValue)),getControlChild:()=>{if(V.editable.value&&(f.value||!Y.value||void 0!==n["no-option"]))return r?function(){let a=[(0,e.h)(Es,{class:`col-auto ${V.fieldClass.value}`,...$.value,for:V.targetUid.value,dark:H.value,square:!0,loading:v.value,itemAligned:!1,filled:!0,stackLabel:0!==_.value.length,...V.splitAttrs.listeners.value,onFocus:De,onBlur:qe},{...n,rawControl:()=>V.getControl(!0),before:void 0,after:void 0})];return p.value&&a.push((0,e.h)("div",{ref:A,class:K.value+" scroll",style:t.popupContentStyle,...ae.value,onClick:y,onScrollPassive:q},Le())),(0,e.h)(Po,{ref:E,modelValue:f.value,position:t.useInput?"top":void 0,transitionShow:l,transitionHide:t.transitionHide,transitionDuration:t.transitionDuration,noRouteDismiss:t.popupNoRouteDismiss,onBeforeShow:Qe,onBeforeHide:Be,onHide:Fe,onShow:Ve},()=>(0,e.h)("div",{class:"q-select__dialog"+(H.value?" q-select__dialog--dark q-dark":"")+(g.value?" q-select__dialog--focused":"")},a))}():(0,e.h)(ma,{ref:P,class:K.value,style:t.popupContentStyle,modelValue:p.value,fit:!t.menuShrink,cover:t.optionsCover&&!Y.value&&!t.useInput,anchor:t.menuAnchor,self:t.menuSelf,offset:t.menuOffset,dark:H.value,noParentEvent:!0,noRefocus:!0,noFocus:!0,noRouteDismiss:t.popupNoRouteDismiss,square:se.value,transitionShow:t.transitionShow,transitionHide:t.transitionHide,transitionDuration:t.transitionDuration,separateClosePopup:!0,...ae.value,onScrollPassive:q,onBeforeShow:Qe,onBeforeHide:Oe,onShow:je},Le);V.hasPopupOpen&&=!1},controlEvents:{onFocusin(e){V.onControlFocusin(e)},onFocusout(e){V.onControlFocusout(e,()=>{We(),Ue()})},onClick(e){if(y(e),!r&&p.value)return Ue(),void T.value?.focus();$e(e)}},getControl:n=>{let a=Ae(),i=!0===n||!f.value||!r;if(t.useInput)a.push(function(n,a){let i=a?{...ne.value,...V.splitAttrs.attributes.value}:void 0,o={ref:a?T:void 0,key:"i_t",class:G.value,style:t.inputStyle,value:void 0===_.value?"":_.value,type:"search",...i,id:a?V.targetUid.value:void 0,maxlength:t.maxlength,autocomplete:t.autocomplete,"data-autofocus":!0===n||t.autofocus||void 0,disabled:t.disable,readonly:t.readonly,...pe.value};return!n&&r&&(Array.isArray(o.class)?o.class=[...o.class,"no-pointer-events"]:o.class+=" no-pointer-events"),(0,e.h)("input",o)}(n,i));else if(V.editable.value){let r=i?ne.value:void 0;a.push((0,e.h)("input",{ref:i?T:void 0,key:"d_t",class:"q-select__focus-target",id:i?V.targetUid.value:void 0,value:Z.value,readonly:!0,"data-autofocus":!0===n||t.autofocus||void 0,...r,onKeydown:Pe,onKeyup:Se,onKeypress:Te})),i&&"string"==typeof t.autocomplete&&0!==t.autocomplete.length&&a.push((0,e.h)("input",{class:"q-select__autocomplete-input",autocomplete:t.autocomplete,tabindex:-1,onKeyup:Ce}))}if(void 0!==L.value&&!t.disable&&0!==he.value.length){let n=he.value.map(t=>(0,e.h)("option",{value:t,selected:!0}));a.push((0,e.h)("select",{class:"hidden",name:L.value,multiple:t.multiple},n))}return(0,e.h)("div",{class:"q-field__native row items-center",...t.useInput||!i?void 0:V.splitAttrs.attributes.value,...V.splitAttrs.listeners.value},a)},getInnerAppend:()=>t.loading||v.value||t.hideDropdownIcon?null:[(0,e.h)(Ke,{class:"q-select__dropdown-icon"+(p.value?" rotate-180":""),name:oe.value})]}),Ps(V)}});let Lu=["text","rect","circle","QBtn","QBadge","QChip","QToolbar","QCheckbox","QRadio","QToggle","QSlider","QRange","QInput","QAvatar"],Mu=["wave","pulse","pulse-x","pulse-y","fade","blink","none"];var Ru=h({name:"QSkeleton",props:{...Je,tag:{type:String,default:"div"},type:{type:String,validator:e=>Lu.includes(e),default:"rect"},animation:{type:String,validator:e=>Mu.includes(e),default:"wave"},animationSpeed:{type:[String,Number],default:1500},square:Boolean,bordered:Boolean,size:String,width:String,height:String},setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),i=(0,e.computed)(()=>{let e=void 0===t.size?[t.width,t.height]:[t.size,t.size];return{"--q-skeleton-speed":`${t.animationSpeed}ms`,width:e[0],height:e[1]}}),r=(0,e.computed)(()=>`q-skeleton q-skeleton--${a.value?"dark":"light"} q-skeleton--type-${t.type}`+("none"===t.animation?"":` q-skeleton--anim q-skeleton--anim-${t.animation}`)+(t.square?" q-skeleton--square":"")+(t.bordered?" q-skeleton--bordered":""));return()=>(0,e.h)(t.tag,{class:r.value,style:i.value},Ae(n.default))}});let zu=[["left","center","start","width"],["right","center","end","width"],["top","start","center","height"],["bottom","end","center","height"]];var Iu=h({name:"QSlideItem",props:{...Je,leftColor:String,rightColor:String,topColor:String,bottomColor:String,onSlide:Function},emits:["action","top","right","bottom","left"],setup(t,{slots:n,emit:a}){let{proxy:i}=(0,e.getCurrentInstance)(),{$q:r}=i,o=Xe(t,r),{getCache:s}=ja(),l=(0,e.ref)(null),u=null,c={},d={},h={},p=(0,e.computed)(()=>r.lang.rtl?{left:"right",right:"left"}:{left:"left",right:"right"}),f=(0,e.computed)(()=>"q-slide-item q-item-type overflow-hidden"+(o.value?" q-slide-item--dark q-dark":""));function m(){l.value.style.transform="translate(0,0)"}function _(e,n,i){void 0!==t.onSlide&&a("slide",{side:e,ratio:n,isReset:i})}function g(e){let t,i,r,o=l.value;if(e.isFirst)c={dir:null,size:{left:0,right:0,top:0,bottom:0},scale:0},o.classList.add("no-transition"),zu.forEach(e=>{if(void 0!==n[e[0]]){let t=h[e[0]];t.style.transform="scale(1)",c.size[e[0]]=t.getBoundingClientRect()[e[3]]}}),c.axis="up"===e.direction||"down"===e.direction?"Y":"X";else{if(e.isFinal){if(o.classList.remove("no-transition"),1===c.scale){o.style.transform=`translate${c.axis}(${100*c.dir}%)`,null!==u&&clearTimeout(u);let e=c.showing;u=setTimeout(()=>{u=null,a(e,{reset:m}),a("action",{side:e,reset:m})},230)}else o.style.transform="translate(0,0)",_(c.showing,0,!0);return}e.direction="X"===c.axis?e.offset.x<0?"left":"right":e.offset.y<0?"up":"down"}void 0===n.left&&e.direction===p.value.right||void 0===n.right&&e.direction===p.value.left||void 0===n.top&&"down"===e.direction||void 0===n.bottom&&"up"===e.direction?o.style.transform="translate(0,0)":("X"===c.axis?(i="left"===e.direction?-1:1,t=1===i?p.value.left:p.value.right,r=e.distance.x):(i="up"===e.direction?-2:2,t=2===i?"top":"bottom",r=e.distance.y),(null===c.dir||Math.abs(i)===Math.abs(c.dir))&&(c.dir!==i&&(["left","right","top","bottom"].forEach(e=>{d[e]&&(d[e].style.visibility=t===e?"visible":"hidden")}),c.showing=t,c.dir=i),c.scale=Math.max(0,Math.min(1,(r-40)/c.size[t])),o.style.transform=`translate${c.axis}(${r*i/Math.abs(i)}px)`,h[t].style.transform=`scale(${c.scale})`,_(t,c.scale,!1)))}return(0,e.onBeforeUpdate)(()=>{d={},h={}}),(0,e.onBeforeUnmount)(()=>{null!==u&&clearTimeout(u)}),Object.assign(i,{reset:m}),()=>{let a=[],i={left:void 0!==n[p.value.right],right:void 0!==n[p.value.left],up:void 0!==n.bottom,down:void 0!==n.top},r=Object.keys(i).filter(e=>i[e]);zu.forEach(i=>{let r=i[0];void 0!==n[r]&&a.push((0,e.h)("div",{key:r,ref:e=>{d[r]=e},class:`q-slide-item__${r} absolute-full row no-wrap items-${i[1]} justify-${i[2]}`+(void 0===t[r+"Color"]?"":` bg-${t[r+"Color"]}`)},[(0,e.h)("div",{ref:e=>{h[r]=e}},n[r]())]))});let o=(0,e.h)("div",{key:(0===r.length?"only-":"")+" content",ref:l,class:"q-slide-item__content"},Ae(n.default));return 0===r.length?a.push(o):a.push((0,e.withDirectives)(o,s("dir#"+r.join(""),()=>{let e={prevent:!0,stop:!0,mouse:!0};return r.forEach(t=>{e[t]=!0}),[[gi,g,void 0,e]]}))),(0,e.h)("div",{class:f.value},a)}}}),Nu=h({name:"QSpace",setup(){let t=(0,e.h)("div",{class:"q-space"});return()=>t}}),Ou=h({name:"QSpinnerAudio",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,fill:"currentColor",width:n.value,height:n.value,viewBox:"0 0 55 80",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ju=h({name:"QSpinnerBall",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,stroke:"currentColor",width:n.value,height:n.value,viewBox:"0 0 57 57",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Du=h({name:"QSpinnerBars",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,fill:"currentColor",width:n.value,height:n.value,viewBox:"0 0 135 140",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),qu=h({name:"QSpinnerBox",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Bu=h({name:"QSpinnerClock",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Fu=h({name:"QSpinnerComment",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Vu=h({name:"QSpinnerCube",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Uu=h({name:"QSpinnerDots",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,fill:"currentColor",width:n.value,height:n.value,viewBox:"0 0 120 30",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),$u=h({name:"QSpinnerFacebook",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",xmlns:"http://www.w3.org/2000/svg",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Hu=h({name:"QSpinnerGears",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Wu=h({name:"QSpinnerGrid",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,fill:"currentColor",width:n.value,height:n.value,viewBox:"0 0 105 105",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Gu=h({name:"QSpinnerHearts",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,fill:"currentColor",width:n.value,height:n.value,viewBox:"0 0 140 64",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Ku=h({name:"QSpinnerHourglass",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Yu=h({name:"QSpinnerInfinity",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",innerHTML:''})}}),Qu=h({name:"QSpinnerIos",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,stroke:"currentColor",fill:"currentColor",viewBox:"0 0 64 64",innerHTML:''})}}),Zu=h({name:"QSpinnerOrbit",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Ju=h({name:"QSpinnerOval",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,stroke:"currentColor",width:n.value,height:n.value,viewBox:"0 0 38 38",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),Xu=h({name:"QSpinnerPie",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ec=h({name:"QSpinnerPuff",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,stroke:"currentColor",width:n.value,height:n.value,viewBox:"0 0 44 44",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),tc=h({name:"QSpinnerRadio",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 100 100",preserveAspectRatio:"xMidYMid",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),nc=h({name:"QSpinnerRings",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,stroke:"currentColor",width:n.value,height:n.value,viewBox:"0 0 45 45",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ac=h({name:"QSpinnerTail",props:wt,setup(t){let{cSize:n,classes:a}=kt(t);return()=>(0,e.h)("svg",{class:a.value,width:n.value,height:n.value,viewBox:"0 0 38 38",xmlns:"http://www.w3.org/2000/svg",innerHTML:''})}}),ic=h({name:"QSplitter",props:{...Je,modelValue:{type:Number,required:!0},reverse:Boolean,unit:{type:String,default:"%",validator:e=>["%","px"].includes(e)},limits:{type:Array,validator:e=>2===e.length&&"number"==typeof e[0]&&"number"==typeof e[1]&&(e[0]>=0&&e[0]<=e[1])},emitImmediately:Boolean,horizontal:Boolean,disable:Boolean,beforeClass:[Array,String,Object],afterClass:[Array,String,Object],separatorClass:[Array,String,Object],separatorStyle:[Array,String,Object]},emits:["update:modelValue"],setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=Xe(t,i),o=(0,e.ref)(null),s={before:(0,e.ref)(null),after:(0,e.ref)(null)},l=(0,e.computed)(()=>`q-splitter no-wrap ${t.horizontal?"q-splitter--horizontal column":"q-splitter--vertical row"} q-splitter--${t.disable?"disabled":"workable"}`+(r.value?" q-splitter--dark":"")),u=(0,e.computed)(()=>t.horizontal?"height":"width"),c=(0,e.computed)(()=>t.reverse?"after":"before"),d=(0,e.computed)(()=>void 0===t.limits?"%"===t.unit?[10,90]:[50,1/0]:t.limits);function h(e){return("%"===t.unit?e:Math.round(e))+t.unit}let p,f,m,_,g,v=(0,e.computed)(()=>({[c.value]:{[u.value]:h(t.modelValue)}}));function b(e){if(e.isFirst){let e=o.value.getBoundingClientRect()[u.value];return p=t.horizontal?"up":"left",f="%"===t.unit?100:e,m=Math.min(f,d.value[1],Math.max(d.value[0],t.modelValue)),_=(t.reverse?-1:1)*(t.horizontal?1:i.lang.rtl?-1:1)*("%"===t.unit?0===e?0:100/e:1),void o.value.classList.add("q-splitter--active")}if(e.isFinal)return g!==t.modelValue&&a("update:modelValue",g),void o.value.classList.remove("q-splitter--active");let n=m+_*(e.direction===p?-1:1)*e.distance[t.horizontal?"y":"x"];g=Math.min(f,d.value[1],Math.max(d.value[0],n)),s[c.value].value.style[u.value]=h(g),t.emitImmediately&&t.modelValue!==g&&a("update:modelValue",g)}let y=(0,e.computed)(()=>[[gi,b,void 0,{[t.horizontal?"vertical":"horizontal"]:!0,prevent:!0,stop:!0,mouse:!0,mouseAllDir:!0}]]);function w(e,t){et[1]&&a("update:modelValue",t[1])}return(0,e.watch)(()=>t.modelValue,e=>{w(e,d.value)}),(0,e.watch)(()=>t.limits,()=>{(0,e.nextTick)(()=>{w(t.modelValue,d.value)})}),()=>{let a=[(0,e.h)("div",{ref:s.before,class:["q-splitter__panel q-splitter__before"+(t.reverse?" col":""),t.beforeClass],style:v.value.before},Ae(n.before)),(0,e.h)("div",{class:["q-splitter__separator",t.separatorClass],style:t.separatorStyle,"aria-disabled":t.disable?"true":void 0},[ze("div",{class:"q-splitter__separator-area absolute-full"},Ae(n.separator),"sep",!t.disable,()=>y.value)]),(0,e.h)("div",{ref:s.after,class:["q-splitter__panel q-splitter__after"+(t.reverse?"":" col"),t.afterClass],style:v.value.after},Ae(n.after))];return(0,e.h)("div",{class:l.value,ref:o},Me(n.default,a))}}});function rc(e){32===e.keyCode&&w(e)}var oc=h({name:"StepHeader",props:{stepper:{},step:{},goToPanel:Function},setup(t,{attrs:n}){let{proxy:{$q:a}}=(0,e.getCurrentInstance)(),i=(0,e.ref)(null),r=(0,e.computed)(()=>t.stepper.modelValue===t.step.name),o=(0,e.computed)(()=>{let e=t.step.disable;return!0===e||""===e}),s=(0,e.computed)(()=>{let e=t.step.error;return!0===e||""===e}),l=(0,e.computed)(()=>{let e=t.step.done;return!o.value&&(!0===e||""===e)}),u=(0,e.computed)(()=>{let e=t.step.headerNav;return!o.value&&t.stepper.headerNav&&(!0===e||""===e||void 0===e)}),c=(0,e.computed)(()=>t.step.prefix&&(!r.value||"none"===t.stepper.activeIcon)&&(!s.value||"none"===t.stepper.errorIcon)&&(!l.value||"none"===t.stepper.doneIcon)),d=(0,e.computed)(()=>{let e=t.step.icon||t.stepper.inactiveIcon;if(r.value){let n=t.step.activeIcon||t.stepper.activeIcon;return"none"===n?e:n||a.iconSet.stepper.active}if(s.value){let n=t.step.errorIcon||t.stepper.errorIcon;return"none"===n?e:n||a.iconSet.stepper.error}if(!o.value&&l.value){let n=t.step.doneIcon||t.stepper.doneIcon;return"none"===n?e:n||a.iconSet.stepper.done}return e}),h=(0,e.computed)(()=>{let e=s.value?t.step.errorColor||t.stepper.errorColor:void 0;if(r.value){let n=t.step.activeColor||t.stepper.activeColor||t.step.color;return void 0===n?e:n}return void 0===e?!o.value&&l.value?t.step.doneColor||t.stepper.doneColor||t.step.color||t.stepper.inactiveColor:t.step.color||t.stepper.inactiveColor:e}),p=(0,e.computed)(()=>"q-stepper__tab col-grow flex items-center no-wrap relative-position"+(void 0===h.value?"":` text-${h.value}`)+(s.value?" q-stepper__tab--error q-stepper__tab--error-with-"+(c.value?"prefix":"icon"):"")+(r.value?" q-stepper__tab--active":"")+(l.value?" q-stepper__tab--done":"")+(u.value?" q-stepper__tab--navigation q-focusable q-hoverable":"")+(o.value?" q-stepper__tab--disabled":"")),f=(0,e.computed)(()=>t.stepper.headerNav&&u.value);function m(){i.value?.focus(),r.value||t.goToPanel(t.step.name)}function _(e){[13,32].includes(e.keyCode)&&(r.value||t.goToPanel(t.step.name),w(e))}return()=>{let a={class:p.value};u.value&&(a.onClick=m,a.onKeydown=rc,a.onKeyup=_,a.role="button",a["aria-current"]=r.value?"step":void 0,Object.assign(a,o.value?{tabindex:-1,"aria-disabled":"true"}:{tabindex:n.tabindex||0}));let s=[(0,e.h)("div",{class:"q-focus-helper",tabindex:-1,ref:i}),(0,e.h)("div",{class:"q-stepper__dot row flex-center q-stepper__line relative-position"},[(0,e.h)("span",{class:"row flex-center"},[c.value?t.step.prefix:(0,e.h)(Ke,{name:d.value})])])];if(void 0!==t.step.title&&null!==t.step.title){let n=[(0,e.h)("div",{class:"q-stepper__title"},t.step.title)];void 0!==t.step.caption&&null!==t.step.caption&&n.push((0,e.h)("div",{class:"q-stepper__caption"},t.step.caption)),s.push((0,e.h)("div",{class:"q-stepper__label q-stepper__line relative-position"},n))}return(0,e.withDirectives)((0,e.h)("div",a,s),[[zt,f.value]])}}});function sc(t){return(0,e.h)("div",{class:"q-stepper__step-content"},[(0,e.h)("div",{class:"q-stepper__step-inner"},Ae(t.default))])}let lc={setup:(e,{slots:t})=>()=>sc(t)};var uc=h({name:"QStep",props:{...Da,icon:String,color:String,title:{type:String,required:!0},caption:String,prefix:[String,Number],doneIcon:String,doneColor:String,activeIcon:String,activeColor:String,errorIcon:String,errorColor:String,headerNav:{type:Boolean,default:!0},done:Boolean,error:Boolean,onScroll:[Function,Array]},setup(t,{slots:n,emit:a}){let{proxy:{$q:i}}=(0,e.getCurrentInstance)(),r=(0,e.inject)(K,ee);if(r===ee)return console.error("QStep needs to be a child of QStepper"),ee;let{getCache:o}=ja(),s=(0,e.ref)(null),l=(0,e.computed)(()=>r.value.modelValue===t.name),u=(0,e.computed)(()=>!i.platform.is.ios&&i.platform.is.chrome||!l.value||!r.value.vertical?{}:{onScroll(e){let{target:n}=e;n.scrollTop>0&&(n.scrollTop=0),void 0!==t.onScroll&&a("scroll",e)}}),c=(0,e.computed)(()=>"string"==typeof t.name||"number"==typeof t.name?t.name:String(t.name));function d(){let t=r.value.vertical;return t&&r.value.keepAlive?(0,e.h)(e.KeepAlive,r.value.keepAliveProps.value,l.value?[(0,e.h)(r.value.needsUniqueKeepAliveWrapper.value?o(c.value,()=>({...lc,name:c.value})):lc,{key:c.value},n.default)]:void 0):!t||l.value?sc(n):void 0}return()=>(0,e.h)("div",{ref:s,class:"q-stepper__step",role:"tabpanel",...u.value},r.value.vertical?[(0,e.h)(oc,{stepper:r.value,step:t,goToPanel:r.value.goToPanel}),r.value.animated?(0,e.h)(es,d):d()]:[d()])}});let cc=/(-\w)/g;var dc=h({name:"QStepper",props:{...Je,...Ba,flat:Boolean,bordered:Boolean,alternativeLabels:Boolean,headerNav:Boolean,contracted:Boolean,headerClass:String,inactiveColor:String,inactiveIcon:String,doneIcon:String,doneColor:String,activeIcon:String,activeColor:String,errorIcon:String,errorColor:String},emits:Fa,setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q),{updatePanelsList:i,isValidPanelName:r,updatePanelIndex:o,getPanelContent:s,getPanels:l,panelDirectives:u,goToPanel:c,keepAliveProps:d,needsUniqueKeepAliveWrapper:h}=Ua();(0,e.provide)(K,(0,e.computed)(()=>({goToPanel:c,keepAliveProps:d,needsUniqueKeepAliveWrapper:h,...t})));let p=(0,e.computed)(()=>"q-stepper q-stepper--"+(t.vertical?"vertical":"horizontal")+(t.flat?" q-stepper--flat":"")+(t.bordered?" q-stepper--bordered":"")+(a.value?" q-stepper--dark q-dark":"")),f=(0,e.computed)(()=>`q-stepper__header row items-stretch justify-between q-stepper__header--${t.alternativeLabels?"alternative":"standard"}-labels`+(t.bordered||!t.flat?" q-stepper__header--border":"")+(t.contracted?" q-stepper__header--contracted":"")+(void 0===t.headerClass?"":` ${t.headerClass}`));function m(){let a=Ae(n.message,[]);if(t.vertical){r(t.modelValue)&&o();let i=(0,e.h)("div",{class:"q-stepper__content"},Ae(n.default));return void 0===a?[i]:a.concat(i)}return[(0,e.h)("div",{class:f.value},l().map(n=>{let a=function(e){let t={};for(let n in e){let a=n.replace(cc,e=>e[1].toUpperCase());t[a]=e[n]}return t}(n.props);return(0,e.h)(oc,{key:a.name,stepper:t,step:a,goToPanel:c})})),a,ze("div",{class:"q-stepper__content q-panel-parent"},s(),"cont",t.swipeable,()=>u.value)]}return()=>(i(n),(0,e.h)("div",{class:p.value},Me(n.navigation,m())))}}),hc=h({name:"QStepperNavigation",setup:(t,{slots:n})=>()=>(0,e.h)("div",{class:"q-stepper__nav"},Ae(n.default))}),pc=h({name:"QTh",props:{props:Object,autoWidth:Boolean},emits:["click"],setup(t,{slots:n,emit:a}){let i=(0,e.getCurrentInstance)(),{proxy:{$q:r}}=i,o=e=>{a("click",e)};return()=>{if(void 0===t.props)return(0,e.h)("th",{class:t.autoWidth?"q-table--col-auto-width":"",onClick:o},Ae(n.default));let a,s,l=i.vnode.key;if(null!==l){if(a=t.props.colsMap[l],void 0===a)return}else a=t.props.col;if(a.sortable){let t="right"===a.align?"unshift":"push";s=Le(n.default,[]),s[t]((0,e.h)(Ke,{class:a.__iconClass,name:r.iconSet.table.arrowUp}))}else s=Ae(n.default);let u={class:a.__thClass+(t.autoWidth?" q-table--col-auto-width":""),style:a.headerStyle,onClick:e=>{a.sortable&&t.props.sort(a),o(e)}};return a.sortable&&(u.tabindex=0,u["aria-sort"]=a.__ariaSort,u.onKeydown=e=>{" "===e.key&&e.preventDefault()},u.onKeyup=e=>{((e,n)=>{("Enter"===e.key||" "===e.key)&&(t.props.sort(n),o(e),e.preventDefault())})(e,a)}),(0,e.h)("th",u,s)}}});function fc(t,n){return(0,e.h)("div",t,[(0,e.h)("table",{class:"q-table"},n)])}let mc={list:vl,table:Ml},_c=["list","table","__qtable"];var gc=h({name:"QVirtualScroll",props:{...Su,type:{type:String,default:"list",validator:e=>_c.includes(e)},items:{type:Array,default:()=>[]},itemsFn:Function,itemsSize:Number,scrollTarget:Cn},setup(t,{slots:n,attrs:a}){let i,r=(0,e.ref)(null),o=(0,e.computed)(()=>t.itemsSize>=0&&void 0!==t.itemsFn?Number.parseInt(t.itemsSize,10):Array.isArray(t.items)?t.items.length:0),{virtualScrollSliceRange:s,localResetVirtualScroll:l,padVirtualScroll:u,onVirtualScrollEvt:c}=Cu({virtualScrollLength:o,getVirtualScrollTarget:function(){return i},getVirtualScrollEl:f}),d=(0,e.computed)(()=>{if(0===o.value)return[];let e=(e,t)=>({index:s.value.from+t,item:e});return void 0===t.itemsFn?t.items.slice(s.value.from,s.value.to).map(e):t.itemsFn(s.value.from,s.value.to-s.value.from).map(e)}),h=(0,e.computed)(()=>"q-virtual-scroll q-virtual-scroll"+(t.virtualScrollHorizontal?"--horizontal":"--vertical")+(void 0===t.scrollTarget?" scroll":"")),p=(0,e.computed)(()=>void 0===t.scrollTarget?{tabindex:0}:{});function f(){return r.value.$el||r.value}function _(){i=Pn(f(),t.scrollTarget),i.addEventListener("scroll",c,m.passive)}function g(){void 0!==i&&(i.removeEventListener("scroll",c,m.passive),i=void 0)}function v(){let e=u("list"===t.type?"div":"tbody",d.value.map(n.default));return void 0!==n.before&&(e=n.before().concat(e)),Me(n.after,e)}return(0,e.watch)(o,()=>{l()}),(0,e.watch)(()=>t.scrollTarget,()=>{g(),_()}),(0,e.onBeforeMount)(()=>{l()}),(0,e.onMounted)(()=>{_()}),(0,e.onActivated)(()=>{_()}),(0,e.onDeactivated)(()=>{g()}),(0,e.onBeforeUnmount)(()=>{g()}),()=>{if(void 0!==n.default)return"__qtable"===t.type?fc({ref:r,class:"q-table__middle "+h.value},v()):(0,e.h)(mc[t.type],{...a,ref:r,class:[a.class,h.value],...p.value},v);console.error("QVirtualScroll: default scoped slot is required for rendering")}}});let vc={sortMethod:Function,binaryStateSort:Boolean,columnSortOrder:{type:String,validator:e=>"ad"===e||"da"===e,default:"ad"}};function bc(t,n,a,i){let r=(0,e.computed)(()=>{let{sortBy:e}=n.value;return e&&a.value.find(t=>t.name===e)||null}),o=(0,e.computed)(()=>void 0===t.sortMethod?(e,t,n)=>{let i=a.value.find(e=>e.name===t);if(void 0===i||void 0===i.field)return e;let r=n?-1:1,o="function"==typeof i.field?e=>i.field(e):e=>e[i.field];return e.sort((e,t)=>{let n=o(e),a=o(t);return void 0===i.rawSort?null==n?-1*r:null==a?Number(r):void 0===i.sort?re(n)&&re(a)?(n-a)*r:ae(n)&&ae(a)?function(e,t){return new Date(e)-new Date(t)}(n,a)*r:"boolean"==typeof n&&"boolean"==typeof a?(n-a)*r:([n,a]=[n,a].map(e=>String(e).toLocaleString().toLowerCase()),nt.name===e);t?.sortOrder&&(r=t.sortOrder)}let{sortBy:o,descending:s}=n.value;o===e?t.binaryStateSort?s=!s:s?"ad"===r?o=null:s=!1:"ad"===r?s=!0:o=null:(o=e,s="da"===r),i({sortBy:o,descending:s,page:1})}}}let yc={filter:[String,Object],filterMethod:Function};function wc(e){return e.page<1&&(e.page=1),void 0!==e.rowsPerPage&&e.rowsPerPage<1&&(e.rowsPerPage=0),e}let kc={pagination:Object,rowsPerPageOptions:{type:Array,default:()=>[5,7,10,15,20,25,50,0]},"onUpdate:pagination":[Function,Array]};let xc={selection:{type:String,default:"none",validator:e=>["single","multiple","none"].includes(e)},selected:{type:Array,default:()=>[]}},Sc=["update:selected","selection"];function Cc(e){return Array.isArray(e)?[...e]:[]}let Tc={expanded:Array},Pc=["update:expanded"];let Ec={visibleColumns:Array};function Ac(t,n,a){let i=(0,e.computed)(()=>{if(void 0!==t.columns)return t.columns;let e=t.rows[0];return void 0===e?[]:Object.keys(e).map(t=>({name:t,label:t.toUpperCase(),field:t,align:re(e[t])?"right":"left",sortable:!0}))}),r=(0,e.computed)(()=>{let{sortBy:e,descending:a}=n.value;return(void 0===t.visibleColumns?i.value:i.value.filter(e=>e.required||t.visibleColumns.includes(e.name))).map(t=>{let n=t.align||"right",i=`text-${n}`;return{...t,align:n,__iconClass:`q-table__sort-icon q-table__sort-icon--${n}`,__ariaSort:!0===t.sortable?t.name===e?a?"descending":"ascending":"none":void 0,__thClass:i+(void 0===t.headerClasses?"":" "+t.headerClasses)+(t.sortable?" sortable":"")+(t.name===e?" sorted "+(a?"sort-desc":""):""),__tdStyle:void 0===t.style?()=>null:"function"==typeof t.style?t.style:()=>t.style,__tdClass:void 0===t.classes?()=>i:"function"==typeof t.classes?e=>i+" "+t.classes(e):()=>i+" "+t.classes}})});return{colList:i,computedCols:r,computedColsMap:(0,e.computed)(()=>{let e=Object.create(null);return r.value.forEach(t=>{e[t.name]=t}),e}),computedColspan:(0,e.computed)(()=>void 0===t.tableColspan?r.value.length+ +!!a.value:t.tableColspan)}}let Lc="q-table__bottom row items-center",Mc={};function Rc(e,t){let n="function"==typeof e.field?e.field(t):t[e.field];return void 0===e.format?n:e.format(n,t)}xu.forEach(e=>{Mc[e]={}});var zc=h({name:"QTable",props:{rows:{type:Array,required:!0},rowKey:{type:[String,Function],default:"id"},columns:Array,loading:Boolean,iconFirstPage:String,iconPrevPage:String,iconNextPage:String,iconLastPage:String,title:String,hideHeader:Boolean,grid:Boolean,gridHeader:Boolean,dense:Boolean,flat:Boolean,bordered:Boolean,square:Boolean,separator:{type:String,default:"horizontal",validator:e=>["horizontal","vertical","cell","none"].includes(e)},wrapCells:Boolean,virtualScroll:Boolean,virtualScrollTarget:{},...Mc,noDataLabel:String,noResultsLabel:String,loadingLabel:String,selectedRowsLabel:Function,rowsPerPageLabel:String,paginationLabel:Function,color:{type:String,default:"grey-8"},titleClass:[String,Array,Object],tableStyle:[String,Array,Object],tableClass:[String,Array,Object],tableHeaderStyle:[String,Array,Object],tableHeaderClass:[String,Array,Object],tableRowStyleFn:Function,tableRowClassFn:Function,cardContainerClass:[String,Array,Object],cardContainerStyle:[String,Array,Object],cardStyle:[String,Array,Object],cardClass:[String,Array,Object],cardStyleFn:Function,cardClassFn:Function,hideBottom:Boolean,hideSelectedBanner:Boolean,hideNoData:Boolean,hidePagination:Boolean,onRowClick:Function,onRowDblclick:Function,onRowContextmenu:Function,...Je,...Ha,...Ec,...yc,...kc,...Tc,...xc,...vc},emits:["request","virtualScroll",...Wa,...Pc,...Sc],setup(t,{slots:n,emit:r}){let o=(0,e.getCurrentInstance)(),{proxy:{$q:s}}=o,l=Xe(t,s),{inFullscreen:u,toggleFullscreen:c}=Ga(),d=(0,e.computed)(()=>"function"==typeof t.rowKey?t.rowKey:e=>e[t.rowKey]),h=(0,e.ref)(null),p=(0,e.ref)(null),f=(0,e.computed)(()=>!t.grid&&t.virtualScroll),m=(0,e.computed)(()=>" q-table__card"+(l.value?" q-table__card--dark q-dark":"")+(t.square?" q-table--square":"")+(t.flat?" q-table--flat":"")+(t.bordered?" q-table--bordered":"")),_=(0,e.computed)(()=>`q-table__container q-table--${t.separator}-separator column no-wrap`+(t.grid?" q-table--grid":m.value)+(l.value?" q-table--dark":"")+(t.dense?" q-table--dense":"")+(t.wrapCells?"":" q-table--no-wrap")+(u.value?" fullscreen scroll":"")),g=(0,e.computed)(()=>_.value+(t.loading?" q-table--loading":""));(0,e.watch)([()=>t.tableStyle,()=>t.tableClass,()=>t.tableHeaderStyle,()=>t.tableHeaderClass,_],()=>{f.value&&p.value?.reset()},{deep:!0});let{innerPagination:v,computedPagination:b,isServerSide:y,requestServerInteraction:w,setPagination:k}=function(t,n){let{props:a,emit:i}=t,r=(0,e.ref)({sortBy:null,descending:!1,page:1,rowsPerPage:0===a.rowsPerPageOptions.length?5:a.rowsPerPageOptions[0],...a.pagination}),o=(0,e.computed)(()=>wc(void 0===a["onUpdate:pagination"]?r.value:{...r.value,...a.pagination})),s=(0,e.computed)(()=>void 0!==o.value.rowsNumber);function l(e){u({pagination:e,filter:a.filter})}function u(t={}){(0,e.nextTick)(()=>{i("request",{pagination:void 0===t.pagination?o.value:t.pagination,filter:void 0===t.filter?a.filter:t.filter,getCellValue:n})})}return{innerPagination:r,computedPagination:o,isServerSide:s,requestServerInteraction:u,setPagination:function(e,t){let n=wc({...o.value,...e});!function(e,t){for(let n in t)if(t[n]!==e[n])return!1;return!0}(o.value,n)?s.value?l(n):void 0!==a.pagination&&void 0!==a["onUpdate:pagination"]?i("update:pagination",n):r.value=n:s.value&&t&&l(n)}}}(o,Rc),{computedFilterMethod:x}=function(t,n){let a=(0,e.computed)(()=>void 0===t.filterMethod?(e,t,n,a)=>{let i=t?t.toLowerCase():"";return e.filter(e=>n.some(t=>{let n=String(a(t,e));return("undefined"===n||"null"===n?"":n.toLowerCase()).includes(i)}))}:t.filterMethod);return(0,e.watch)(()=>t.filter,()=>{(0,e.nextTick)(()=>{n({page:1},!0)})},{deep:!0}),{computedFilterMethod:a}}(t,k),{isRowExpanded:S,setExpanded:C,updateExpanded:T}=function(t,n){let a=(0,e.ref)(Cc(t.expanded));function i(e){void 0===t.expanded?a.value=e:n("update:expanded",e)}return(0,e.watch)(()=>t.expanded,e=>{a.value=Cc(e)}),{isRowExpanded:function(e){return a.value.includes(e)},setExpanded:i,updateExpanded:function(e,t){let n=[...a.value],r=n.indexOf(e);t?-1===r&&(n.push(e),i(n)):-1!==r&&(n.splice(r,1),i(n))}}}(t,r),P=(0,e.computed)(()=>{let e=t.rows;if(y.value||0===e.length)return e;let{sortBy:n,descending:a}=b.value;return t.filter&&(e=x.value(e,t.filter,B.value,Rc)),null!==U.value&&(e=$.value(t.rows===e?[...e]:e,n,a)),e}),E=(0,e.computed)(()=>P.value.length),A=(0,e.computed)(()=>{let e=P.value;if(y.value)return e;let{rowsPerPage:n}=b.value;return 0!==n&&(0===W.value&&t.rows!==e?e.length>G.value&&(e=e.slice(0,G.value)):e=e.slice(W.value,G.value)),e}),{hasSelectionMode:L,singleSelection:M,multipleSelection:R,allRowsSelected:z,someRowsSelected:I,rowsSelectedNumber:N,isRowSelected:O,clearSelection:j,updateSelection:D}=function(t,n,a,i){let r=(0,e.computed)(()=>new Set(t.selected.map(i.value))),o=(0,e.computed)(()=>"none"!==t.selection),s=(0,e.computed)(()=>"single"===t.selection),l=(0,e.computed)(()=>"multiple"===t.selection),u=(0,e.computed)(()=>0!==a.value.length&&a.value.every(e=>r.value.has(i.value(e)))),c=(0,e.computed)(()=>!u.value&&a.value.some(e=>r.value.has(i.value(e)))),d=(0,e.computed)(()=>t.selected.length);return{hasSelectionMode:o,singleSelection:s,multipleSelection:l,allRowsSelected:u,someRowsSelected:c,rowsSelectedNumber:d,isRowSelected:function(e){return r.value.has(e)},clearSelection:function(){n("update:selected",[])},updateSelection:function(e,a,r,o){n("selection",{rows:a,added:r,keys:e,evt:o}),n("update:selected",s.value?r?a:[]:r?[...t.selected,...a]:t.selected.filter(t=>!e.includes(i.value(t))))}}}(t,r,A,d),{colList:q,computedCols:B,computedColsMap:F,computedColspan:V}=Ac(t,b,L),{columnToSort:U,computedSortMethod:$,sort:H}=bc(t,b,q,k),{firstRowIndex:W,lastRowIndex:G,isFirstPage:K,isLastPage:Y,pagesNumber:Q,computedRowsPerPageOptions:Z,computedRowsNumber:J,firstPage:X,prevPage:ee,nextPage:te,lastPage:ne}=function(t,n,a,i,r,o){let{props:s,emit:l,proxy:{$q:u}}=t,c=(0,e.computed)(()=>i.value?a.value.rowsNumber||0:o.value),d=(0,e.computed)(()=>{let{page:e,rowsPerPage:t}=a.value;return(e-1)*t}),h=(0,e.computed)(()=>{let{page:e,rowsPerPage:t}=a.value;return e*t}),p=(0,e.computed)(()=>1===a.value.page),f=(0,e.computed)(()=>0===a.value.rowsPerPage?1:Math.max(1,Math.ceil(c.value/a.value.rowsPerPage))),m=(0,e.computed)(()=>0===h.value||a.value.page>=f.value),_=(0,e.computed)(()=>(s.rowsPerPageOptions.includes(n.value.rowsPerPage)?s.rowsPerPageOptions:[n.value.rowsPerPage,...s.rowsPerPageOptions]).map(e=>({label:0===e?u.lang.table.allRows:String(e),value:e})));return(0,e.watch)(f,(e,t)=>{if(e===t)return;let n=a.value.page;e&&!n?r({page:1}):e1&&r({page:e-1})},nextPage:function(){let{page:e,rowsPerPage:t}=a.value;h.value>0&&e*t0===A.value.length),ie=(0,e.computed)(()=>{let e={};return xu.forEach(n=>{e[n]=t[n]}),void 0===e.virtualScrollItemSize&&(e.virtualScrollItemSize=t.dense?28:48),e});function re(){if(t.grid)return function(){let a=void 0===n.item?a=>{let i=a.cols.map(t=>(0,e.h)("div",{class:"q-table__grid-item-row"},[(0,e.h)("div",{class:"q-table__grid-item-title"},[t.label]),(0,e.h)("div",{class:"q-table__grid-item-value"},[t.value])]));if(L.value){let r=n["body-selection"],o=void 0===r?[(0,e.h)(oi,{modelValue:a.selected,color:t.color,dark:l.value,dense:t.dense,"onUpdate:modelValue":(e,t)=>{D([a.key],[a.row],e,t)}})]:r(a);i.unshift((0,e.h)("div",{class:"q-table__grid-item-row"},o),(0,e.h)(as,{dark:l.value}))}let o={class:["q-table__grid-item-card"+m.value,t.cardClass],style:t.cardStyle};if(void 0!==t.cardStyleFn&&(o.style=[o.style,t.cardStyleFn(a.row)]),void 0!==t.cardClassFn){let e=t.cardClassFn(a.row);e&&(o.class[0]+=` ${e}`)}return(void 0!==t.onRowClick||void 0!==t.onRowDblclick||void 0!==t.onRowContextmenu)&&(o.class[0]+=" cursor-pointer",void 0!==t.onRowClick&&(o.onClick=e=>{r("rowClick",e,a.row,a.pageIndex)}),void 0!==t.onRowDblclick&&(o.onDblclick=e=>{r("rowDblclick",e,a.row,a.pageIndex)}),void 0!==t.onRowContextmenu&&(o.onContextmenu=e=>{r("rowContextmenu",e,a.row,a.pageIndex)})),(0,e.h)("div",{class:"q-table__grid-item col-xs-12 col-sm-6 col-md-4 col-lg-3"+(a.selected?" q-table__grid-item--selected":"")},[(0,e.h)("div",o,i)])}:n.item;return(0,e.h)("div",{class:["q-table__grid-content row",t.cardContainerClass],style:t.cardContainerStyle},A.value.map((e,t)=>a(ce({key:d.value(e),row:e,pageIndex:t}))))}();let a=t.hideHeader?null:_e;if(f.value){let i=n["top-row"],r=n["bottom-row"],o={default:e=>le(e.item,n.body,e.index)};if(void 0!==i){let t=(0,e.h)("tbody",i({cols:B.value}));o.before=null===a?()=>t:()=>[a(),t]}else null!==a&&(o.before=a);return void 0!==r&&(o.after=()=>(0,e.h)("tbody",r({cols:B.value}))),(0,e.h)(gc,{ref:p,class:t.tableClass,style:t.tableStyle,...ie.value,scrollTarget:t.virtualScrollTarget,items:A.value,type:"__qtable",tableColspan:V.value,onVirtualScroll:oe},o)}let i=[ue()];return null!==a&&i.unshift(a()),fc({class:["q-table__middle scroll",t.tableClass],style:t.tableStyle},i)}function oe(e){r("virtualScroll",e)}function se(){return[(0,e.h)(Al,{class:"q-table__linear-progress",color:t.color,dark:l.value,indeterminate:!0,trackColor:"transparent"})]}function le(a,i,o){let s=d.value(a),u=O(s);if(void 0!==i){let e={key:s,row:a,pageIndex:o,__trClass:u?"selected":""};if(void 0!==t.tableRowStyleFn&&(e.__trStyle=t.tableRowStyleFn(a)),void 0!==t.tableRowClassFn){let n=t.tableRowClassFn(a);n&&(e.__trClass=`${n} ${e.__trClass}`)}return i(ce(e))}let c=n["body-cell"],h=B.value.map(t=>{let i=n[`body-cell-${t.name}`],r=void 0===i?c:i;return void 0===r?(0,e.h)("td",{class:t.__tdClass(a),style:t.__tdStyle(a)},Rc(t,a)):r(de({key:s,row:a,pageIndex:o,col:t}))});if(L.value){let i=n["body-selection"],r=void 0===i?[(0,e.h)(oi,{modelValue:u,color:t.color,dark:l.value,dense:t.dense,"onUpdate:modelValue":(e,t)=>{D([s],[a],e,t)}})]:i(function(e){return he(e),e}({key:s,row:a,pageIndex:o}));h.unshift((0,e.h)("td",{class:"q-table--col-auto-width"},r))}let p={key:s,class:{selected:u}};if(void 0!==t.onRowClick&&(p.class["cursor-pointer"]=!0,p.onClick=e=>{r("rowClick",e,a,o)}),void 0!==t.onRowDblclick&&(p.class["cursor-pointer"]=!0,p.onDblclick=e=>{r("rowDblclick",e,a,o)}),void 0!==t.onRowContextmenu&&(p.class["cursor-pointer"]=!0,p.onContextmenu=e=>{r("rowContextmenu",e,a,o)}),void 0!==t.tableRowStyleFn&&(p.style=t.tableRowStyleFn(a)),void 0!==t.tableRowClassFn){let e=t.tableRowClassFn(a);e&&(p.class[e]=!0)}return(0,e.h)("tr",p,h)}function ue(){let t=n.body,a=n["top-row"],i=n["bottom-row"],r=A.value.map((e,n)=>le(e,t,n));return(0,e.h)("tbody",[a?.({cols:B.value}),...r,i?.({cols:B.value})].flat())}function ce(e){return he(e),e.cols=e.cols.map(t=>a({...t},"value",()=>Rc(t,e.row))),e}function de(e){return he(e),a(e,"value",()=>Rc(e.col,e.row)),e}function he(e){Object.assign(e,{cols:B.value,colsMap:F.value,sort:H,rowIndex:W.value+e.pageIndex,color:t.color,dark:l.value,dense:t.dense}),L.value&&a(e,"selected",()=>O(e.key),(t,n)=>{D([e.key],[e.row],t,n)}),a(e,"expand",()=>S(e.key),t=>{T(e.key,t)})}let pe=(0,e.computed)(()=>({pagination:b.value,pagesNumber:Q.value,isFirstPage:K.value,isLastPage:Y.value,firstPage:X,prevPage:ee,nextPage:te,lastPage:ne,inFullscreen:u.value,toggleFullscreen:c}));function fe(){let a,i=n.top,r=n["top-left"],o=n["top-right"],s=n["top-selection"],l=L.value&&void 0!==s&&N.value>0,u="q-table__top relative-position row items-center";return void 0!==i?(0,e.h)("div",{class:u},[i(pe.value)]):(l?a=[s(pe.value)].flat():(a=[],void 0===r?t.title&&a.push((0,e.h)("div",{class:"q-table__control"},[(0,e.h)("div",{class:["q-table__title",t.titleClass]},t.title)])):a.push((0,e.h)("div",{class:"q-table__control"},[r(pe.value)]))),void 0!==o&&a.push((0,e.h)("div",{class:"q-table__separator col"}),(0,e.h)("div",{class:"q-table__control"},[o(pe.value)])),0!==a.length?(0,e.h)("div",{class:u},a):void 0)}let me=(0,e.computed)(()=>I.value?null:z.value);function _e(){let a=function(){let a=n.header,i=n["header-cell"];if(void 0!==a)return[a(ge({header:!0}))].flat();let r=B.value.map(t=>{let a=n[`header-cell-${t.name}`],r=void 0===a?i:a,o=ge({col:t});return void 0===r?(0,e.h)(pc,{key:t.name,props:o},()=>t.label):r(o)});if(M.value&&!t.grid)r.unshift((0,e.h)("th",{class:"q-table--col-auto-width"}," "));else if(R.value){let a=n["header-selection"],i=void 0===a?[(0,e.h)(oi,{color:t.color,modelValue:me.value,dark:l.value,dense:t.dense,"onUpdate:modelValue":ve})]:a(ge({}));r.unshift((0,e.h)("th",{class:"q-table--col-auto-width"},i))}return[(0,e.h)("tr",{class:t.tableHeaderClass,style:t.tableHeaderStyle},r)]}();return t.loading&&void 0===n.loading&&a.push((0,e.h)("tr",{class:"q-table__progress"},[(0,e.h)("th",{class:"relative-position",colspan:V.value},se())])),(0,e.h)("thead",a)}function ge(e){return Object.assign(e,{cols:B.value,sort:H,colsMap:F.value,color:t.color,dark:l.value,dense:t.dense}),R.value&&a(e,"selected",()=>me.value,ve),e}function ve(e){I.value&&(e=!1),D(A.value.map(d.value),A.value,e)}let be=(0,e.computed)(()=>{let e=[t.iconFirstPage||s.iconSet.table.firstPage,t.iconPrevPage||s.iconSet.table.prevPage,t.iconNextPage||s.iconSet.table.nextPage,t.iconLastPage||s.iconSet.table.lastPage];return s.lang.rtl?e.reverse():e});function ye(){if(t.hideBottom)return;if(ae.value){if(t.hideNoData)return;let a=t.loading?t.loadingLabel||s.lang.table.loading:t.filter?t.noResultsLabel||s.lang.table.noResults:t.noDataLabel||s.lang.table.noData,i=n["no-data"];return(0,e.h)("div",{class:"q-table__bottom row items-center q-table__bottom--nodata"},void 0===i?[(0,e.h)(Ke,{class:"q-table__bottom-nodata-icon",name:s.iconSet.table.warning}),a]:[i({message:a,icon:s.iconSet.table.warning,filter:t.filter})])}let a=n.bottom;if(void 0!==a)return(0,e.h)("div",{class:Lc},[a(pe.value)]);let i=!t.hideSelectedBanner&&L.value&&N.value>0?[(0,e.h)("div",{class:"q-table__control"},[(0,e.h)("div",[(t.selectedRowsLabel||s.lang.table.selectedRecords)(N.value)])])]:[];return t.hidePagination?0!==i.length?(0,e.h)("div",{class:Lc},i):void 0:(0,e.h)("div",{class:"q-table__bottom row items-center justify-end"},function(a){let i,{rowsPerPage:r}=b.value,o=t.paginationLabel||s.lang.table.pagination,u=n.pagination,c=t.rowsPerPageOptions.length>1;if(a.push((0,e.h)("div",{class:"q-table__separator col"})),c&&a.push((0,e.h)("div",{class:"q-table__control"},[(0,e.h)("span",{class:"q-table__bottom-item"},[t.rowsPerPageLabel||s.lang.table.recordsPerPage]),(0,e.h)(Au,{class:"q-table__select inline q-table__bottom-item",color:t.color,modelValue:r,options:Z.value,displayValue:0===r?s.lang.table.allRows:r,dark:l.value,borderless:!0,dense:!0,optionsDense:!0,optionsCover:!0,"onUpdate:modelValue":we})])),void 0!==u)i=u(pe.value);else if(i=[(0,e.h)("span",0===r?{}:{class:"q-table__bottom-item"},[r?o(W.value+1,Math.min(G.value,J.value),J.value):o(1,E.value,J.value)])],0!==r&&Q.value>1){let n={color:t.color,round:!0,dense:!0,flat:!0};t.dense&&(n.size="sm"),Q.value>2&&i.push((0,e.h)(Kt,{key:"pgFirst",...n,icon:be.value[0],disable:K.value,"aria-label":s.lang.pagination.first,onClick:X})),i.push((0,e.h)(Kt,{key:"pgPrev",...n,icon:be.value[1],disable:K.value,"aria-label":s.lang.pagination.prev,onClick:ee}),(0,e.h)(Kt,{key:"pgNext",...n,icon:be.value[2],disable:Y.value,"aria-label":s.lang.pagination.next,onClick:te})),Q.value>2&&i.push((0,e.h)(Kt,{key:"pgLast",...n,icon:be.value[3],disable:Y.value,"aria-label":s.lang.pagination.last,onClick:ne}))}return a.push((0,e.h)("div",{class:"q-table__control"},i)),a}(i))}function we(e){k({page:1,rowsPerPage:e.value})}return Object.assign(o.proxy,{requestServerInteraction:w,setPagination:k,firstPage:X,prevPage:ee,nextPage:te,lastPage:ne,isRowSelected:O,clearSelection:j,isRowExpanded:S,setExpanded:C,sort:H,resetVirtualScroll:function(){f.value&&p.value.reset()},scrollTo:function(e,n){if(null!==p.value)return void p.value.scrollTo(e,n);e=Number.parseInt(e,10);let a=h.value.querySelector(`tbody tr:nth-of-type(${e+1})`);if(null!==a){let n=h.value.querySelector(".q-table__middle.scroll"),i=a.offsetTop-t.virtualScrollStickySizeStart,o=i{let n=F.value[e];if(void 0!==n)return Rc(n,t)}}),i(o.proxy,{filteredSortedRows:()=>P.value,computedRows:()=>A.value,computedRowsNumber:()=>J.value}),()=>{let a=[fe()],i={ref:h,class:g.value};return t.grid?a.push((0,e.h)("div",{class:"q-table__middle"},t.gridHeader?[(0,e.h)("table",{class:"q-table"},[_e(e.h)])]:t.loading&&void 0===n.loading?se(e.h):void 0)):Object.assign(i,{class:[i.class,t.cardClass],style:t.cardStyle}),a.push(re(),ye()),t.loading&&void 0!==n.loading&&a.push(n.loading()),(0,e.h)("div",i,a)}}}),Ic=h({name:"QTr",props:{props:Object,noHover:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>"q-tr"+(void 0===t.props||t.props.header?"":" "+t.props.__trClass)+(t.noHover?" q-tr--no-hover":""));return()=>(0,e.h)("tr",{style:t.props?.__trStyle,class:a.value},Ae(n.default))}}),Nc=h({name:"QTd",props:{props:Object,autoWidth:Boolean,noHover:Boolean},setup(t,{slots:n}){let a=(0,e.getCurrentInstance)(),i=(0,e.computed)(()=>"q-td"+(t.autoWidth?" q-table--col-auto-width":"")+(t.noHover?" q-td--no-hover":"")+" ");return()=>{if(void 0===t.props)return(0,e.h)("td",{class:i.value},Ae(n.default));let r=a.vnode.key,o=(void 0===t.props.colsMap?null:t.props.colsMap[r])||t.props.col;if(void 0===o)return;let{row:s}=t.props;return(0,e.h)("td",{class:i.value+o.__tdClass(s),style:o.__tdStyle(s)},Ae(n.default))}}}),Oc=h({name:"QRouteTab",props:{...vt,...ji},emits:Oi,setup(t,{slots:n,emit:a}){let i=bt({useDisableForRouterLinkProps:!1}),{renderTab:r,$tabs:o}=Di(t,n,a,{exact:(0,e.computed)(()=>t.exact),...i});return(0,e.watch)(()=>`${t.name} | ${t.exact} | ${(i.resolvedLink.value||{}).href}`,o.verifyRouteModel),()=>r(i.linkTag.value,i.linkAttrs.value)}});let jc=/^-?[\d]+\/[0-1]\d\/[0-3]\d$/;function Dc(){let e=new Date;return{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}}function qc(e){32===e.keyCode&&w(e)}function Bc(e,t,n){let a=Math.abs(e-t);return Math.min(a,n-a)}function Fc(e,t,n){let a=Array.from({length:t+1},(t,n)=>n+e).filter(e=>n(e));return{min:a[0],max:a.at(-1),values:a,threshold:t+1}}var Vc=h({name:"QTime",props:{...Je,...wa,...Pr,modelValue:{required:!0,validator:e=>"string"==typeof e||null===e},mask:{...Pr.mask,default:null},format24h:{type:Boolean,default:null},defaultDate:{type:String,validator:e=>jc.test(e)},options:Function,hourOptions:Array,minuteOptions:Array,secondOptions:Array,withSeconds:Boolean,nowBtn:Boolean},emits:Er,setup(t,{slots:n,emit:a}){let i,r,o=(0,e.getCurrentInstance)(),{$q:s}=o.proxy,l=Xe(t,s),{tabindex:u,headerClass:c,getLocale:d,getCurrentDate:h}=Lr(t,s),p=xa(ka(t)),f=(0,e.ref)(null),m=(0,e.computed)(()=>"persian"!==t.calendar&&null!==t.mask?t.mask:"HH:mm"+(t.withSeconds?":ss":"")),_=(0,e.computed)(()=>d()),g=(0,e.computed)(()=>function(){if("string"!=typeof t.defaultDate){let e=h(!0);return e.dateHash=Ar(e),e}return Vr(t.defaultDate,"YYYY/MM/DD",void 0,t.calendar)}()),b=Vr(t.modelValue,m.value,_.value,t.calendar,g.value),y=(0,e.ref)(function(e,t){if(null!==e.hour){if(null===e.minute)return"minute";if(t&&null===e.second)return"second"}return"hour"}(b)),k=(0,e.ref)(b),x=(0,e.ref)(null===b.hour||b.hour<12),S=(0,e.computed)(()=>null===t.format24h?s.lang.date.format24h:t.format24h),C=(0,e.computed)(()=>"q-time q-time--"+(t.landscape?"landscape":"portrait")+(l.value?" q-time--dark q-dark":"")+(t.disable?" disabled":t.readonly?" q-time--readonly":"")+(t.bordered?" q-time--bordered":"")+(t.square?" q-time--square no-border-radius":"")+(t.flat?" q-time--flat no-shadow":"")),T=(0,e.computed)(()=>{let e=k.value;return{hour:null===e.hour?"--":S.value?ve(e.hour):String(x.value?0===e.hour?12:e.hour:e.hour>12?e.hour-12:e.hour),minute:null===e.minute?"--":ve(e.minute),second:null===e.second?"--":ve(e.second)}}),P=(0,e.computed)(()=>{let e="hour"===y.value,t=e?12:60,n=k.value[y.value],a=`rotate(${Math.round(360/t*n)-180}deg) translateX(-50%)`;return e&&S.value&&k.value.hour>=12&&(a+=" scale(.7)"),{transform:a}}),E=(0,e.computed)(()=>null!==k.value.hour),A=(0,e.computed)(()=>E.value&&null!==k.value.minute),L=(0,e.computed)(()=>void 0===t.hourOptions?void 0===t.options?null:e=>t.options(e,null,null):e=>t.hourOptions.includes(e)),M=(0,e.computed)(()=>void 0===t.minuteOptions?void 0===t.options?null:e=>t.options(k.value.hour,e,null):e=>t.minuteOptions.includes(e)),R=(0,e.computed)(()=>void 0===t.secondOptions?void 0===t.options?null:e=>t.options(k.value.hour,k.value.minute,e):e=>t.secondOptions.includes(e)),z=(0,e.computed)(()=>{if(null===L.value)return null;let e=Fc(0,11,L.value),t=Fc(12,11,L.value);return{am:e,pm:t,values:[...e.values,...t.values]}}),I=(0,e.computed)(()=>null===M.value?null:Fc(0,59,M.value)),N=(0,e.computed)(()=>null===R.value?null:Fc(0,59,R.value)),O=(0,e.computed)(()=>{switch(y.value){case"hour":return z.value;case"minute":return I.value;case"second":return N.value}}),j=(0,e.computed)(()=>{let e,t=0,n=1,a=null===O.value?void 0:O.value.values;"hour"===y.value?S.value?e=23:(e=11,x.value||(t=12)):(e=55,n=5);let i=[];for(let r=0,o=0;r<=e;r+=n,o++){let e=r+t,n=!1===a?.includes(e),s="hour"===y.value&&0===r?S.value?"00":"12":r;i.push({val:e,index:o,disable:n,label:s})}return i}),D=(0,e.computed)(()=>[[gi,U,void 0,{stop:!0,prevent:!0,mouse:!0}]]);function q(){let e={...h(),...Dc()};le(e),Object.assign(k.value,e),y.value="hour"}function B(e,{min:t,max:n,values:a,threshold:i}){if(e===t)return t;if(en)return Bc(e,t,i)<=Bc(e,n,i)?t:n;let r=a.findIndex(t=>e<=t),o=a[r-1],s=a[r];return e-o<=s-e?o:s}function F(){return ct(o)||null!==O.value&&(0===O.value.values.length||"hour"===y.value&&!S.value&&0===z.value[x.value?"am":"pm"].values.length)}function V(){let{top:e,left:t,width:n}=f.value.getBoundingClientRect(),a=n/2;return{top:e+a,left:t+a,dist:.7*a}}function U(e){if(!F()){if(e.isFirst)return i=V(),void(r=H(e.evt,i));r=H(e.evt,i,r),e.isFinal&&(i=!1,r=null,$())}}function $(){"hour"===y.value?y.value="minute":t.withSeconds&&"minute"===y.value&&(y.value="second")}function H(e,t,n){let a,i=v(e),r=Math.abs(i.top-t.top),o=Math.hypot(i.top-t.top,i.left-t.left),s=Math.asin(r/o)*(180/Math.PI);if(s=i.top=t.dist:0!==z.value.am.values.length:x.value;a=B(a+(e?0:12),z.value[e?"am":"pm"])}else a=Math.round(a),S.value?ot.modelValue,e=>{let n=Vr(e,m.value,_.value,t.calendar,g.value);(n.dateHash!==k.value.dateHash||n.timeHash!==k.value.timeHash)&&(k.value=n,null===n.hour?y.value="hour":x.value=n.hour<12)}),(0,e.watch)([m,_],()=>{(0,e.nextTick)(()=>{le()})});let W={hour(){y.value="hour"},minute(){y.value="minute"},second(){y.value="second"}};function G(e){[13,32].includes(e.keyCode)&&(ie(),w(e))}function K(e){[13,32].includes(e.keyCode)&&(re(),w(e))}function Y(e){F()||(s.platform.is.desktop||H(e,V()),$())}function Q(e){F()||H(e,V())}function Z(e){if([13,32].includes(e.keyCode))y.value="hour",w(e);else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==z.value){let e=S.value?z.value.values:z.value[x.value?"am":"pm"].values;if(0===e.length)return;null===k.value.hour?ee(e[0]):ee(e[(e.length+e.indexOf(k.value.hour)+t)%e.length])}else{let e=S.value?24:12;ee((S.value||x.value?0:12)+(24+(null===k.value.hour?-t:k.value.hour)+t)%e)}}}function J(e){if([13,32].includes(e.keyCode))y.value="minute",w(e);else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==I.value){let e=I.value.values;if(0===e.length)return;null===k.value.minute?te(e[0]):te(e[(e.length+e.indexOf(k.value.minute)+t)%e.length])}else te((60+(null===k.value.minute?-t:k.value.minute)+t)%60)}}function X(e){if([13,32].includes(e.keyCode))y.value="second",w(e);else if([37,39].includes(e.keyCode)){let t=37===e.keyCode?-1:1;if(null!==N.value){let e=N.value.values;if(0===e.length)return;null===k.value.second?ne(e[0]):ne(e[(e.length+e.indexOf(k.value.second)+t)%e.length])}else ne((60+(null===k.value.second?-t:k.value.second)+t)%60)}}function ee(e){k.value.hour!==e&&(k.value.hour=e,se())}function te(e){k.value.minute!==e&&(k.value.minute=e,se())}function ne(e){k.value.second!==e&&(k.value.second=e,se())}let ae={hour:ee,minute:te,second:ne};function ie(){x.value||(x.value=!0,null!==k.value.hour&&(k.value.hour-=12,se()))}function re(){x.value&&(x.value=!1,null!==k.value.hour&&(k.value.hour+=12,se()))}function oe(e){let n=t.modelValue;y.value!==e&&null!=n&&""!==n&&"string"!=typeof n&&(y.value=e)}function se(){return null===L.value||L.value(k.value.hour)?null===M.value||M.value(k.value.minute)?t.withSeconds&&null!==R.value&&!R.value(k.value.second)?(k.value.second=null,void oe("second")):void(null===k.value.hour||null===k.value.minute||t.withSeconds&&null===k.value.second||le()):(k.value.minute=null,k.value.second=null,void oe("minute")):(k.value=Vr(),void oe("hour"))}function le(e){let n={...k.value,...e},i="persian"===t.calendar?ve(n.hour)+":"+ve(n.minute)+(t.withSeconds?":"+ve(n.second):""):Jr(new Date(n.year,null===n.month?null:n.month-1,n.day,n.hour,n.minute,n.second,n.millisecond),m.value,_.value,n.year,n.timezoneOffset);n.changed=i!==t.modelValue,a("update:modelValue",i,n)}function ue(){let n=[(0,e.h)("div",{class:"q-time__link "+("hour"===y.value?"q-time__link--active":"cursor-pointer"),tabindex:u.value,role:"button","aria-pressed":"hour"===y.value?"true":"false",onClick:W.hour,onKeydown:qc,onKeyup:Z},T.value.hour),(0,e.h)("div",":"),(0,e.h)("div",E.value?{class:"q-time__link "+("minute"===y.value?"q-time__link--active":"cursor-pointer"),tabindex:u.value,role:"button","aria-pressed":"minute"===y.value?"true":"false",onKeydown:qc,onKeyup:J,onClick:W.minute}:{class:"q-time__link"},T.value.minute)];t.withSeconds&&n.push((0,e.h)("div",":"),(0,e.h)("div",A.value?{class:"q-time__link "+("second"===y.value?"q-time__link--active":"cursor-pointer"),tabindex:u.value,role:"button","aria-pressed":"second"===y.value?"true":"false",onKeydown:qc,onKeyup:X,onClick:W.second}:{class:"q-time__link"},T.value.second));let a=[(0,e.h)("div",{class:"q-time__header-label row items-center no-wrap",dir:"ltr"},n)];return S.value||a.push((0,e.h)("div",{class:"q-time__header-ampm column items-between no-wrap"},[(0,e.h)("div",{class:"q-time__link "+(x.value?"q-time__link--active":"cursor-pointer"),tabindex:u.value,role:"button","aria-pressed":x.value?"true":"false",onClick:ie,onKeydown:qc,onKeyup:G},"AM"),(0,e.h)("div",{class:"q-time__link "+(x.value?"cursor-pointer":"q-time__link--active"),tabindex:u.value,role:"button","aria-pressed":x.value?"false":"true",onClick:re,onKeydown:qc,onKeyup:K},"PM")])),(0,e.h)("div",{class:"q-time__header flex flex-center no-wrap "+c.value},a)}function ce(){let n=k.value[y.value];return(0,e.h)("div",{class:"q-time__content col relative-position"},[(0,e.h)(e.Transition,{name:"q-transition--scale"},()=>(0,e.h)("div",{key:"clock"+y.value,class:"q-time__container-parent absolute-full"},[(0,e.h)("div",{ref:f,class:"q-time__container-child fit overflow-hidden"},[(0,e.withDirectives)((0,e.h)("div",{class:"q-time__clock cursor-pointer non-selectable",onClick:Y,onMousedown:Q},[(0,e.h)("div",{class:"q-time__clock-circle fit"},[(0,e.h)("div",{class:"q-time__clock-pointer"+(null===k.value[y.value]?" hidden":void 0===t.color?"":` text-${t.color}`),style:P.value}),j.value.map(t=>(0,e.h)("div",{class:`q-time__clock-position row flex-center q-time__clock-pos-${t.index}`+(t.val===n?" q-time__clock-position--active "+c.value:t.disable?" q-time__clock-position--disable":"")},[(0,e.h)("span",t.label)]))])]),D.value)])])),t.nowBtn?(0,e.h)(Kt,{class:"q-time__now-button absolute",icon:s.iconSet.datetime.now,unelevated:!0,size:"sm",round:!0,color:t.color,textColor:t.textColor,tabindex:u.value,onClick:q}):null])}return o.proxy.setNow=q,()=>{let a=[ce()],i=Ae(n.default);return void 0!==i&&a.push((0,e.h)("div",{class:"q-time__actions"},i)),void 0!==t.name&&!t.disable&&p(a,"push"),(0,e.h)("div",{class:C.value,tabindex:-1},[ue(),(0,e.h)("div",{class:"q-time__main col overflow-auto"},a)])}}});let Uc=["left","right"],$c=["dense","comfortable","loose"];var Hc=h({name:"QTimeline",props:{...Je,color:{type:String,default:"primary"},side:{type:String,default:"right",validator:e=>Uc.includes(e)},layout:{type:String,default:"dense",validator:e=>$c.includes(e)}},setup(t,{slots:n}){let a=Xe(t,(0,e.getCurrentInstance)().proxy.$q);(0,e.provide)(G,t);let i=(0,e.computed)(()=>`q-timeline q-timeline--${t.layout} q-timeline--${t.layout}--${t.side}`+(a.value?" q-timeline--dark":""));return()=>(0,e.h)("ul",{class:i.value},Ae(n.default))}}),Wc=h({name:"QTimelineEntry",props:{heading:Boolean,tag:{type:String,default:"h3"},side:{type:String,default:"right",validator:e=>["left","right"].includes(e)},icon:String,avatar:String,color:String,title:String,subtitle:String,body:String},setup(t,{slots:n}){let a=(0,e.inject)(G,ee);if(a===ee)return console.error("QTimelineEntry needs to be child of QTimeline"),ee;let i=(0,e.computed)(()=>`q-timeline__entry q-timeline__entry--${t.side}`+(void 0!==t.icon||void 0!==t.avatar?" q-timeline__entry--icon":"")),r=(0,e.computed)(()=>`q-timeline__dot text-${t.color||a.color}`),o=(0,e.computed)(()=>"comfortable"===a.layout&&"left"===a.side);return()=>{let a,s=Le(n.default,[]);if(void 0!==t.body&&s.unshift(t.body),t.heading){let n=[(0,e.h)("div"),(0,e.h)("div"),(0,e.h)(t.tag,{class:"q-timeline__heading-title"},s)];return(0,e.h)("div",{class:"q-timeline__heading"},o.value?n.reverse():n)}void 0===t.icon?void 0!==t.avatar&&(a=[(0,e.h)("img",{class:"q-timeline__dot-img",src:t.avatar})]):a=[(0,e.h)(Ke,{class:"row items-center justify-center",name:t.icon})];let l=[(0,e.h)("div",{class:"q-timeline__subtitle"},[(0,e.h)("span",{},Ae(n.subtitle,[t.subtitle]))]),(0,e.h)("div",{class:r.value},a),(0,e.h)("div",{class:"q-timeline__content"},[(0,e.h)("h6",{class:"q-timeline__title"},Ae(n.title,[t.title]))].concat(s))];return(0,e.h)("li",{class:i.value},o.value?l.reverse():l)}}}),Gc=h({name:"QToolbar",props:{inset:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>"q-toolbar row no-wrap items-center"+(t.inset?" q-toolbar--inset":""));return()=>(0,e.h)("div",{class:a.value,role:"toolbar"},Ae(n.default))}}),Kc=h({name:"QToolbarTitle",props:{shrink:Boolean},setup(t,{slots:n}){let a=(0,e.computed)(()=>"q-toolbar__title ellipsis"+(t.shrink?" col-shrink":""));return()=>(0,e.h)("div",{class:a.value},Ae(n.default))}});let Yc=["none","strict","leaf","leaf-filtered"];function Qc(t){if(void 0!==t.icon)return(0,e.h)(Ke,{class:"q-tree__icon q-mr-sm",name:t.icon,color:t.iconColor});let n=t.img||t.avatar;return n?(0,e.h)("img",{class:`q-tree__${t.img?"img":"avatar"} q-mr-sm`,src:n}):void 0}var Zc=h({name:"QTree",props:{...Je,nodes:{type:Array,required:!0},nodeKey:{type:String,required:!0},labelKey:{type:String,default:"label"},childrenKey:{type:String,default:"children"},dense:Boolean,color:String,controlColor:String,textColor:String,selectedColor:String,icon:String,tickStrategy:{type:String,default:"none",validator:e=>Yc.includes(e)},ticked:Array,expanded:Array,selected:{},noSelectionUnset:Boolean,defaultExpandAll:Boolean,accordion:Boolean,filter:String,filterMethod:Function,duration:{},noConnectors:Boolean,noTransition:Boolean,noNodesLabel:String,noResultsLabel:String},emits:["update:expanded","update:ticked","update:selected","lazyLoad","afterShow","afterHide"],setup(t,{slots:n,emit:i}){let{proxy:r}=(0,e.getCurrentInstance)(),{$q:o}=r,s=Xe(t,o),l=(0,e.ref)({}),u=(0,e.ref)(t.ticked||[]),c=(0,e.ref)(t.expanded||[]),d=(0,e.ref)(null),h={},p={};(0,e.onBeforeUpdate)(()=>{h={},p={}});let f=(0,e.computed)(()=>"q-tree q-tree--"+(t.dense?"dense":"standard")+(t.noConnectors?" q-tree--no-connectors":"")+(s.value?" q-tree--dark":"")+(void 0===t.color?"":` text-${t.color}`)),m=(0,e.computed)(()=>void 0!==t.selected),_=(0,e.computed)(()=>t.icon||o.iconSet.tree.icon),g=(0,e.computed)(()=>t.controlColor||t.color),v=(0,e.computed)(()=>void 0===t.textColor?"":` text-${t.textColor}`),b=(0,e.computed)(()=>{let e=t.selectedColor||t.color;return e?` text-${e}`:""}),y=(0,e.computed)(()=>void 0===t.filterMethod?(e,n)=>{let a=n.toLowerCase();return e[t.labelKey]&&e[t.labelKey].toLowerCase().includes(a)}:t.filterMethod),k=(0,e.computed)(()=>{let e={},n=(a,i)=>{let r=a.tickStrategy||(i?i.tickStrategy:t.tickStrategy),o=a[t.nodeKey],s=a[t.childrenKey]&&Array.isArray(a[t.childrenKey])&&0!==a[t.childrenKey].length,d=!a.disabled&&m.value&&!1!==a.selectable,h=!a.disabled&&!1!==a.expandable,p="none"!==r,f="strict"===r,_="leaf-filtered"===r,g="leaf"===r||"leaf-filtered"===r,v=!a.disabled&&!1!==a.tickable;g&&!0===v&&i&&!0!==i.tickable&&(v=!1);let b=a.lazy;!0===b&&void 0!==l.value[o]&&Array.isArray(a[t.childrenKey])&&(b=l.value[o]);let w={key:o,parent:i,isParent:s,lazy:b,disabled:a.disabled,link:!a.disabled&&(d||h&&(s||!0===b)),children:[],matchesFilter:!t.filter||y.value(a,t.filter),selected:o===t.selected&&d,selectable:d,expanded:!!s&&c.value.includes(o),expandable:h,noTick:!0===a.noTick||!f&&b&&"loaded"!==b,tickable:v,tickStrategy:r,hasTicking:p,strictTicking:f,leafFilteredTicking:_,leafTicking:g,ticked:(f||!s)&&u.value.includes(o)};if(e[o]=w,s&&(w.children=a[t.childrenKey].map(e=>n(e,w)),t.filter&&(!0===w.matchesFilter?!0!==w.noTick&&!0!==w.disabled&&!0===w.tickable&&_&&w.children.every(e=>!0!==e.matchesFilter||!0===e.noTick||!0!==e.tickable)&&(w.tickable=!1):w.matchesFilter=w.children.some(e=>e.matchesFilter)),!0===w.matchesFilter&&(!0!==w.noTick&&!0!==f&&w.children.every(e=>e.noTick)&&(w.noTick=!0),g))){if(w.ticked=!1,w.indeterminate=w.children.some(e=>!0===e.indeterminate),w.tickable=!0===w.tickable&&w.children.some(e=>e.tickable),!0!==w.indeterminate){let e=w.children.reduce((e,t)=>!0===t.ticked?e+1:e,0);e===w.children.length?w.ticked=!0:e>0&&(w.indeterminate=!0)}!0===w.indeterminate&&(w.indeterminateNextState=w.children.every(e=>!0!==e.tickable||!0!==e.ticked))}return w};return t.nodes.forEach(e=>n(e,null)),e}),x=(0,e.computed)(()=>{let e=[];return function n(a){a.forEach(a=>{let i=k.value[a[t.nodeKey]];t.filter&&!0!==i.matchesFilter||(!0===i.link&&e.push(i.key),!0===i.expanded&&Array.isArray(a[t.childrenKey])&&n(a[t.childrenKey]))})}(t.nodes),e}),S=(0,e.computed)(()=>{let e=x.value;if(e.includes(d.value))return d.value;let t=e.find(e=>!0===k.value[e].selected);return void 0===t?e[0]:t});function C(e){let n=(a,i)=>a||!i?a:Array.isArray(i)?i.reduce(n,a):i[t.nodeKey]===e?i:i[t.childrenKey]?n(null,i[t.childrenKey]):void 0;return n(null,t.nodes)}function T(){let e=[],n=a=>{a[t.childrenKey]&&0!==a[t.childrenKey].length&&!1!==a.expandable&&!0!==a.disabled&&(e.push(a[t.nodeKey]),a[t.childrenKey].forEach(n))};t.nodes.forEach(n),void 0===t.expanded?c.value=e:i("update:expanded",e)}function P(n,a,r=C(n),o=k.value[n]){if(o.lazy&&"loaded"!==o.lazy){if("loading"===o.lazy)return;l.value[n]="loading",Array.isArray(r[t.childrenKey])||(r[t.childrenKey]=[]),i("lazyLoad",{node:r,key:n,done:a=>{l.value[n]="loaded",r[t.childrenKey]=Array.isArray(a)?a:[],(0,e.nextTick)(()=>{!0===k.value[n]?.isParent&&E(n,!0)})},fail:()=>{delete l.value[n],0===r[t.childrenKey].length&&delete r[t.childrenKey]}})}else!0===o.isParent&&!0===o.expandable&&E(n,a)}function E(e,n){let a=c.value,r=void 0!==t.expanded;if(r&&(a=[...a]),n){if(t.accordion&&k.value[e]){let n=[];k.value[e].parent?k.value[e].parent.children.forEach(t=>{t.key!==e&&!0===t.expandable&&n.push(t.key)}):t.nodes.forEach(a=>{let i=a[t.nodeKey];i!==e&&n.push(i)}),0!==n.length&&(a=a.filter(e=>!n.includes(e)))}a=[...a,e].filter((e,t,n)=>n.indexOf(e)===t)}else a=a.filter(t=>t!==e);r?i("update:expanded",a):c.value=a}function A(e,n){let a=u.value,r=void 0!==t.ticked;r&&(a=[...a]),a=n?[...a,...e].filter((e,t,n)=>n.indexOf(e)===t):a.filter(t=>!e.includes(t)),r&&i("update:ticked",a)}function L(e,n,i){let o={tree:r,node:e,key:i,color:t.color,dark:s.value};return a(o,"expanded",()=>n.expanded,e=>{e!==n.expanded&&P(i,e)}),a(o,"ticked",()=>n.ticked,e=>{e!==n.ticked&&A([i],e)}),o}function M(e){return(t.filter?e.filter(e=>k.value[e[t.nodeKey]].matchesFilter):e).map(e=>N(e))}function R(){i("afterShow")}function z(){i("afterHide")}function N(a){let i=a[t.nodeKey],r=k.value[i],o=a.header&&n[`header-${a.header}`]||n["default-header"],l=!0===r.isParent?M(a[t.childrenKey]):[],u=0!==l.length||r.lazy&&"loaded"!==r.lazy,c=a.body&&n[`body-${a.body}`]||n["default-body"],f=void 0!==o||void 0!==c?L(a,r,i):null;return void 0!==c&&(c=(0,e.h)("div",{class:"q-tree__node-body relative-position"},[(0,e.h)("div",{class:v.value},[c(f)])])),(0,e.h)("div",{key:i,class:"q-tree__node relative-position q-tree__node--"+(u?"parent":"child")},[(0,e.h)("div",{class:"q-tree__node-header relative-position row no-wrap items-center"+(!0===r.link?" q-tree__node--link q-hoverable q-focusable":"")+(!0===r.selected?" q-tree__node--selected":"")+(!0===r.disabled?" q-tree__node--disabled":""),ref:e=>{p[r.key]=e},tabindex:!0===r.link&&r.key===S.value?0:-1,"aria-expanded":u?r.expanded?"true":"false":null,"aria-selected":r.selectable?r.selected?"true":"false":null,"aria-disabled":!0===r.disabled?"true":null,role:"treeitem",onFocus(){!0===r.link&&(d.value=r.key)},onClick:e=>{q(a,r,e)},onKeydown(e){!0!==I(e)&&(13===e.keyCode?q(a,r,e,!0):32===e.keyCode?B(a,r,e,!0):function(e,t){let n=x.value,a=n.indexOf(e.key);if(36===t)return j(n[0]),!0;if(35===t)return j(n.at(-1)),!0;if(38===t)return j(n[a-1]),!0;if(40===t)return j(n[a+1]),!0;if(39===t)return!0!==e.isParent&&!e.lazy||(!0===e.expanded?j(D(e.children)):P(e.key,!0)),!0;if(37===t){if(!0===e.expanded)P(e.key,!1);else{let t=e.parent;for(;null!==t&&!0!==t.link;)t=t.parent;j(t?.key)}return!0}return!1}(r,e.keyCode)&&w(e))}},[(0,e.h)("div",{class:"q-focus-helper",tabindex:-1,ref:e=>{h[r.key]=e}}),"loading"===r.lazy?(0,e.h)(xt,{class:"q-tree__spinner",color:g.value}):u?(0,e.h)(Ke,{class:"q-tree__arrow"+(!0===r.expanded?" q-tree__arrow--rotate":""),name:_.value,onClick(e){B(a,r,e)}}):null,!0===r.hasTicking&&!0!==r.noTick?(0,e.h)(oi,{class:"q-tree__tickbox",modelValue:!0===r.indeterminate?null:r.ticked,color:g.value,dark:s.value,dense:!0,keepColor:!0,disable:!0!==r.tickable,onKeydown:w,"onUpdate:modelValue":e=>{!function(e,t){if(!0===e.indeterminate&&(t=e.indeterminateNextState),e.strictTicking)A([e.key],t);else if(e.leafTicking){let n=[],a=e=>{e.isParent?(!0!==t&&!0!==e.noTick&&!0===e.tickable&&n.push(e.key),!0===e.leafTicking&&e.children.forEach(a)):!0!==e.noTick&&!0===e.tickable&&(!0!==e.leafFilteredTicking||!0===e.matchesFilter)&&n.push(e.key)};a(e),A(n,t)}}(r,e)}}):null,(0,e.h)("div",{class:"q-tree__node-header-content col row no-wrap items-center"+(!0===r.selected?b.value:v.value)},[o?o(f):[Qc(a),(0,e.h)("div",a[t.labelKey])]])]),u?t.noTransition?!0===r.expanded?(0,e.h)("div",{class:"q-tree__node-collapsible"+v.value,key:`${i}__q`},[c,(0,e.h)("div",{class:"q-tree__children"+(!0===r.disabled?" q-tree__node--disabled":""),role:"group"},l)]):null:(0,e.h)(es,{duration:t.duration,onShow:R,onHide:z},()=>(0,e.withDirectives)((0,e.h)("div",{class:"q-tree__node-collapsible"+v.value,key:`${i}__q`},[c,(0,e.h)("div",{class:"q-tree__children"+(!0===r.disabled?" q-tree__node--disabled":""),role:"group"},l)]),[[e.vShow,r.expanded]])):c])}function O(e){h[e]?.focus()}function j(e){void 0!==e&&(d.value=e,p[e]?.focus())}function D(e){for(let n of e)if(!t.filter||!0===n.matchesFilter){if(!0===n.link)return n.key;if(!0===n.expanded){let e=D(n.children);if(void 0!==e)return e}}}function q(e,n,a,r){!0===n.link&&(d.value=n.key),!0!==r&&!1!==n.selectable&&O(n.key),m.value&&n.selectable?t.noSelectionUnset?n.key!==t.selected&&i("update:selected",void 0===n.key?null:n.key):i("update:selected",n.key===t.selected?null:n.key):B(e,n,a,r),"function"==typeof e.handler&&e.handler(e)}function B(e,t,n,a){!0===t.link&&(d.value=t.key),void 0!==n&&w(n),!0!==a&&!1!==t.selectable&&O(t.key),P(t.key,!t.expanded,e,t)}return(0,e.watch)(()=>t.ticked,e=>{u.value=e}),(0,e.watch)(()=>t.expanded,e=>{c.value=e}),t.defaultExpandAll&&T(),Object.assign(r,{getNodeByKey:C,getTickedNodes:function(){return u.value.map(e=>C(e))},getExpandedNodes:function(){return c.value.map(e=>C(e))},isExpanded:function(e){return!(!e||!k.value[e])&&k.value[e].expanded},collapseAll:function(){void 0===t.expanded?c.value=[]:i("update:expanded",[])},expandAll:T,setExpanded:P,isTicked:function(e){return!(!e||!k.value[e])&&k.value[e].ticked},setTicked:A}),()=>{let n=M(t.nodes);return(0,e.h)("div",{class:f.value,role:"tree"},0===n.length?t.filter?t.noResultsLabel||o.lang.tree.noResults:t.noNodesLabel||o.lang.tree.noNodes:n)}}});function Jc(e){return(100*e).toFixed(2)+"%"}let Xc={...Je,...Ms,label:String,color:String,textColor:String,square:Boolean,flat:Boolean,bordered:Boolean,noThumbnails:Boolean,thumbnailFit:{type:String,default:"cover"},autoUpload:Boolean,hideUploadBtn:Boolean,disable:Boolean,readonly:Boolean},ed=[...Rs,"start","finish","added","removed"];function td(t,n){let r=(0,e.getCurrentInstance)(),{props:o,slots:s,emit:l,proxy:u}=r,{$q:c}=u,d=Xe(o,c);let h=(0,e.computed)(()=>!o.disable&&!o.readonly),p=(0,e.ref)(!1),f=(0,e.ref)(null),m=(0,e.ref)(null),_={files:(0,e.ref)([]),queuedFiles:(0,e.ref)([]),uploadedFiles:(0,e.ref)([]),uploadedSize:(0,e.ref)(0),updateFileStatus:function(e,t,n){if(e.__status=t,"idle"===t)return e.__uploaded=0,e.__progress=0,e.__sizeLabel=fe(e.size),void(e.__progressLabel="0.00%");"failed"!==t?(e.__uploaded="uploaded"===t?e.size:n,e.__progress="uploaded"===t?1:0===e.size?0:Math.min(.9999,e.__uploaded/e.size),e.__progressLabel=Jc(e.__progress),u.$forceUpdate()):u.$forceUpdate()},isAlive:()=>!ct(r)},{pickFiles:g,addFiles:v,onDragover:y,onDragleave:w,processFiles:k,getDndNode:x,maxFilesNumber:S,maxTotalSizeNumber:C}=zs({editable:h,dnd:p,getFileInput:B,addFilesToQueue:F});Object.assign(_,t({props:o,slots:s,emit:l,helpers:_,exposeApi:e=>{Object.assign(_,e)}})),void 0===_.isBusy&&(_.isBusy=(0,e.ref)(!1));let T=(0,e.ref)(0),P=(0,e.computed)(()=>0===T.value?0:_.uploadedSize.value/T.value),E=(0,e.computed)(()=>Jc(P.value)),A=(0,e.computed)(()=>fe(T.value)),L=(0,e.computed)(()=>h.value&&!_.isUploading.value&&(o.multiple||0===_.queuedFiles.value.length)&&(void 0===o.maxFiles||_.files.value.lengthh.value&&!_.isBusy.value&&!_.isUploading.value&&0!==_.queuedFiles.value.length);(0,e.provide)(X,$);let R=(0,e.computed)(()=>"q-uploader column no-wrap"+(d.value?" q-uploader--dark q-dark":"")+(o.bordered?" q-uploader--bordered":"")+(o.square?" q-uploader--square no-border-radius":"")+(o.flat?" q-uploader--flat no-shadow":"")+(o.disable?" disabled q-uploader--disable":"")+(p.value?" q-uploader--dnd":"")),z=(0,e.computed)(()=>"q-uploader__header"+(void 0===o.color?"":` bg-${o.color}`)+(void 0===o.textColor?"":` text-${o.textColor}`));function I(){o.disable||(_.abort(),_.uploadedSize.value=0,T.value=0,q(),_.files.value=[],_.queuedFiles.value=[],_.uploadedFiles.value=[])}function N(){o.disable||j(["uploaded"],({size:e})=>{_.uploadedSize.value-=e,T.value-=e,_.uploadedFiles.value=[]})}function O(){j(["idle","failed"],({size:e})=>{T.value-=e,_.queuedFiles.value=[]})}function j(e,t){if(o.disable)return;let n={files:[],size:0},a=_.files.value.filter(t=>!e.includes(t.__status)||(n.size+=t.size,n.files.push(t),void 0!==t.__img&&window.URL.revokeObjectURL(t.__img.src),!1));0!==n.files.length&&(_.files.value=a,t(n),l("removed",n.files))}function D(e){if(o.disable)return;let t="uploading"===e.__status;"uploaded"===e.__status?(_.uploadedSize.value-=e.size,T.value-=e.size,_.uploadedFiles.value=_.uploadedFiles.value.filter(t=>t.__key!==e.__key)):T.value-=e.size,_.files.value=_.files.value.filter(t=>t.__key!==e.__key||(void 0!==t.__img&&window.URL.revokeObjectURL(t.__img.src),!1)),_.queuedFiles.value=_.queuedFiles.value.filter(t=>t.__key!==e.__key),t&&e.__abort(),l("removed",[e])}function q(){_.files.value.forEach(e=>{void 0!==e.__img&&window.URL.revokeObjectURL(e.__img.src)})}function B(){return m.value||f.value.getElementsByClassName("q-uploader__input")[0]}function F(e,t){let n=k(e,t,_.files.value,!0),a=B();null!=a&&(a.value=""),void 0!==n&&(n.forEach(e=>{if(_.updateFileStatus(e,"idle"),T.value+=e.size,!o.noThumbnails&&e.type.toUpperCase().startsWith("IMAGE")){let t=new Image;t.src=window.URL.createObjectURL(e),e.__img=t}}),_.files.value.push(...n),_.queuedFiles.value.push(...n),l("added",n),o.autoUpload&&_.upload())}function V(){M.value&&_.upload()}function U(t,n,a){if(t){let t,i={type:"a",key:n,icon:c.iconSet.uploader[n],flat:!0,dense:!0};return"add"===n?(i.onClick=g,t=$):i.onClick=a,(0,e.h)(Kt,i,t)}}function $(){return(0,e.h)("input",{ref:m,class:"q-uploader__input overflow-hidden absolute-full",tabindex:-1,type:"file",title:"",accept:o.accept,multiple:o.multiple?"multiple":void 0,capture:o.capture,onMousedown:b,onClick:g,onChange:F})}(0,e.watch)(_.isUploading,(e,t)=>{!t&&e?l("start"):t&&!e&&l("finish")}),(0,e.onBeforeUnmount)(()=>{_.isUploading.value&&_.abort(),0!==_.files.value.length&&q()});let H={};for(let t in _)(0,e.isRef)(_[t])?a(H,t,()=>_[t].value):H[t]=_[t];return Object.assign(H,{upload:V,reset:I,removeUploadedFiles:N,removeQueuedFiles:O,removeFile:D,pickFiles:g,addFiles:v}),i(H,{canAddFiles:()=>L.value,canUpload:()=>M.value,uploadSizeLabel:()=>A.value,uploadProgressLabel:()=>E.value}),n({..._,upload:V,reset:I,removeUploadedFiles:N,removeQueuedFiles:O,removeFile:D,pickFiles:g,addFiles:v,canAddFiles:L,canUpload:M,uploadSizeLabel:A,uploadProgressLabel:E}),()=>{let t=[(0,e.h)("div",{class:z.value},void 0===s.header?[(0,e.h)("div",{class:"q-uploader__header-content column"},[(0,e.h)("div",{class:"flex flex-center no-wrap q-gutter-xs"},[U(0!==_.queuedFiles.value.length,"removeQueue",O),U(0!==_.uploadedFiles.value.length,"removeUploaded",N),_.isUploading.value?(0,e.h)(xt,{class:"q-uploader__spinner"}):null,(0,e.h)("div",{class:"col column justify-center"},[void 0===o.label?null:(0,e.h)("div",{class:"q-uploader__title"},[o.label]),(0,e.h)("div",{class:"q-uploader__subtitle"},[A.value+" / "+E.value])]),U(L.value,"add"),U(!o.hideUploadBtn&&M.value,"upload",_.upload),U(_.isUploading.value,"clear",_.abort)])])]:s.header(H)),(0,e.h)("div",{class:"q-uploader__list scroll"},void 0===s.list?_.files.value.map(t=>(0,e.h)("div",{key:t.__key,class:"q-uploader__file relative-position"+(o.noThumbnails||void 0===t.__img?"":" q-uploader__file--img")+("failed"===t.__status?" q-uploader__file--failed":"uploaded"===t.__status?" q-uploader__file--uploaded":""),style:o.noThumbnails||void 0===t.__img?null:{backgroundImage:'url("'+t.__img.src+'")',backgroundSize:o.thumbnailFit}},[(0,e.h)("div",{class:"q-uploader__file-header row flex-center no-wrap"},["failed"===t.__status?(0,e.h)(Ke,{class:"q-uploader__file-status",name:c.iconSet.type.negative,color:"negative"}):null,(0,e.h)("div",{class:"q-uploader__file-header-content col"},[(0,e.h)("div",{class:"q-uploader__title"},[t.name]),(0,e.h)("div",{class:"q-uploader__subtitle row items-center no-wrap"},[t.__sizeLabel+" / "+t.__progressLabel])]),"uploading"===t.__status?(0,e.h)(pi,{value:t.__progress,min:0,max:1,indeterminate:0===t.__progress}):(0,e.h)(Kt,{round:!0,dense:!0,flat:!0,icon:c.iconSet.uploader["uploaded"===t.__status?"done":"clear"],onClick:()=>{D(t)}})])])):s.list(H)),x("uploader")];_.isBusy.value&&t.push((0,e.h)("div",{class:"q-uploader__overlay absolute-full flex flex-center"},[(0,e.h)(xt)]));let n={ref:f,class:R.value};return L.value&&Object.assign(n,{onDragover:y,onDragleave:w}),(0,e.h)("div",n,t)}}let nd=()=>!0;function ad(e){let t={};return e.forEach(e=>{t[e]=nd}),t}let id=ad(ed);function rd({name:e,props:t,emits:n,injectPlugin:a}){return h({name:e,props:{...Xc,...t},emits:ne(n)?{...id,...n}:[...ed,...n],setup:(e,{expose:t})=>td(a,t)})}function od(e){return"function"==typeof e?e:()=>e}let sd={url:[Function,String],method:{type:[Function,String],default:"POST"},fieldName:{type:[Function,String],default:()=>e=>e.name},headers:[Function,Array],formFields:[Function,Array],withCredentials:[Function,Boolean],sendRaw:[Function,Boolean],batch:[Function,Boolean],factory:Function};var ld=rd({name:"QUploader",props:sd,emits:["factoryFailed","uploaded","failed","uploading"],injectPlugin:function({props:t,emit:n,helpers:a}){let i=(0,e.ref)([]),r=(0,e.ref)([]),o=(0,e.ref)(0),s=new WeakSet,l=(0,e.computed)(()=>({url:od(t.url),method:od(t.method),headers:od(t.headers),formFields:od(t.formFields),fieldName:od(t.fieldName),withCredentials:od(t.withCredentials),sendRaw:od(t.sendRaw),batch:od(t.batch)})),u=(0,e.computed)(()=>o.value>0),c=(0,e.computed)(()=>0!==r.value.length),d=e=>e.filter(e=>a.files.value.includes(e));function h(e){o.value++;let i,l=(t,i)=>{if(a.isAlive()){void 0!==i&&(r.value=r.value.filter(e=>e!==i));let s=d(e);0!==s.length&&(a.queuedFiles.value.push(...s),s.forEach(e=>{a.updateFileStatus(e,"failed")}),n("factoryFailed",t,s)),o.value--}};if("function"==typeof t.factory){try{i=t.factory(e)}catch(e){return void l(e)}Object(i)===i?"function"==typeof i.catch&&"function"==typeof i.then?(r.value.push(i),i.then(e=>{s.has(i)?l(Error("Aborted"),i):Object(e)===e?a.isAlive()&&(r.value=r.value.filter(e=>e!==i),u(e)):l(Error("QUploader: factory() does not return properly"),i)}).catch(e=>{l(e,i)})):u(i):l(Error("QUploader: factory() does not return properly"))}else u({});function u(t){let n=d(e);if(0!==n.length)try{p(n,t)}catch(e){l(e)}else o.value--}}function p(e,t){let r=new FormData,s=new XMLHttpRequest,u=(e,n)=>void 0===t[e]?l.value[e](n):od(t[e])(n),c=u("url",e);if(!c)return console.error("q-uploader: invalid or no URL specified"),a.queuedFiles.value.push(...e),e.forEach(e=>{a.updateFileStatus(e,"failed")}),void o.value--;let h=u("formFields",e);void 0!==h&&h.forEach(e=>{r.append(e.name,e.value)});let p,f=0,m=0,_=0,g=0;s.upload.addEventListener("progress",t=>{if(p)return;let n=Math.min(g,t.loaded);a.uploadedSize.value+=n-_,_=n;let i=_-m;for(let t=f;i>0&&t=n.size))return void a.updateFileStatus(n,"uploading",i);i-=n.size,f++,m+=n.size,a.updateFileStatus(n,"uploading",n.size)}},!1),s.addEventListener("readystatechange",()=>{if(!(s.readyState<4)){if(s.status&&s.status<400){let t=d(e),i=t.reduce((e,t)=>e+t.size,0);a.uploadedSize.value+=i-_,0!==t.length&&(a.uploadedFiles.value.push(...t),t.forEach(e=>{a.updateFileStatus(e,"uploaded")}),n("uploaded",{files:t,xhr:s}))}else{p=!0,a.uploadedSize.value-=_;let t=d(e);0!==t.length&&(a.queuedFiles.value.push(...t),t.forEach(e=>{a.updateFileStatus(e,"failed")}),n("failed",{files:t,xhr:s}))}o.value--,i.value=i.value.filter(e=>e!==s)}}),s.open(u("method",e),c),!0===u("withCredentials",e)&&(s.withCredentials=!0);let v=u("headers",e);void 0!==v&&v.forEach(e=>{s.setRequestHeader(e.name,e.value)});let b=u("sendRaw",e);e.forEach(e=>{a.updateFileStatus(e,"uploading",0),!0!==b&&r.append(u("fieldName",e),e,e.name),e.xhr=s,e.__abort=()=>{s.abort()},g+=e.size}),n("uploading",{files:e,xhr:s}),i.value.push(s),!0===b?s.send(new Blob(e)):s.send(r)}return{isUploading:u,isBusy:c,abort:function(){i.value.forEach(e=>{e.abort()}),r.value.forEach(e=>{s.add(e)})},upload:function(){let e=[...a.queuedFiles.value];a.queuedFiles.value=[],l.value.batch(e)?h(e):e.forEach(e=>{h([e])})}}}}),ud=h({name:"QUploaderAddTrigger",setup(){let t=(0,e.inject)(X,ee);return t===ee&&console.error("QUploaderAddTrigger needs to be child of QUploader"),t}}),cd=h({name:"QVideo",props:{...$s,src:{type:String,required:!0},title:String,fetchpriority:{type:String,default:"auto"},loading:{type:String,default:"eager"},referrerpolicy:{type:String,default:"strict-origin-when-cross-origin"}},setup(t){let n=Hs(t),a=(0,e.computed)(()=>"q-video"+(void 0===t.ratio?"":" q-video--responsive"));return()=>(0,e.h)("div",{class:a.value,style:n.value},[(0,e.h)("iframe",{src:t.src,title:t.title,fetchpriority:t.fetchpriority,loading:t.loading,referrerpolicy:t.referrerpolicy,frameborder:"0",allowfullscreen:!0})])}}),dd=n({QAjaxBar:()=>Ce,QAvatar:()=>Ye,QBadge:()=>Ze,QBanner:()=>et,QBar:()=>tt,QBreadcrumbs:()=>ht,QBreadcrumbsEl:()=>yt,QBtn:()=>Kt,QBtnDropdown:()=>ya,QBtnGroup:()=>Yt,QBtnToggle:()=>Ca,QCard:()=>Ta,QCardActions:()=>Ea,QCardSection:()=>Pa,QCarousel:()=>Qa,QCarouselControl:()=>Ja,QCarouselSlide:()=>Za,QChatMessage:()=>Xa,QCheckbox:()=>oi,QChip:()=>ui,QCircularProgress:()=>pi,QColor:()=>mr,QDate:()=>so,QDialog:()=>Po,QDrawer:()=>Eo,QEditor:()=>Jo,QExpansionItem:()=>ss,QFab:()=>ps,QFabAction:()=>_s,QField:()=>Es,QFile:()=>Os,QFooter:()=>Ds,QForm:()=>Bs,QFormChildMixin:()=>Fs,QHeader:()=>Us,QIcon:()=>Ke,QImg:()=>Ws,QInfiniteScroll:()=>Ks,QInnerLoading:()=>Ys,QInput:()=>dl,QIntersection:()=>_l,QItem:()=>jo,QItemLabel:()=>Xo,QItemSection:()=>Do,QKnob:()=>wl,QLayout:()=>Tl,QLinearProgress:()=>Al,QList:()=>vl,QMarkupTable:()=>Ml,QMenu:()=>ma,QNoSsr:()=>Rl,QOptionGroup:()=>ql,QPage:()=>Bl,QPageContainer:()=>Fl,QPageScroller:()=>$l,QPageSticky:()=>Hl,QPagination:()=>Gl,QParallax:()=>Zl,QPopupEdit:()=>Xl,QPopupProxy:()=>eu,QPullToRefresh:()=>tu,QRadio:()=>Il,QRange:()=>ru,QRating:()=>ou,QResizeObserver:()=>Ai,QResponsive:()=>su,QRouteTab:()=>Oc,QScrollArea:()=>pu,QScrollObserver:()=>Sl,QSelect:()=>Au,QSeparator:()=>as,QSkeleton:()=>Ru,QSlideItem:()=>Iu,QSlideTransition:()=>es,QSlider:()=>Ci,QSpace:()=>Nu,QSpinner:()=>xt,QSpinnerAudio:()=>Ou,QSpinnerBall:()=>ju,QSpinnerBars:()=>Du,QSpinnerBox:()=>qu,QSpinnerClock:()=>Bu,QSpinnerComment:()=>Fu,QSpinnerCube:()=>Vu,QSpinnerDots:()=>Uu,QSpinnerFacebook:()=>$u,QSpinnerGears:()=>Hu,QSpinnerGrid:()=>Wu,QSpinnerHearts:()=>Gu,QSpinnerHourglass:()=>Ku,QSpinnerInfinity:()=>Yu,QSpinnerIos:()=>Qu,QSpinnerOrbit:()=>Zu,QSpinnerOval:()=>Ju,QSpinnerPie:()=>Xu,QSpinnerPuff:()=>ec,QSpinnerRadio:()=>tc,QSpinnerRings:()=>nc,QSpinnerTail:()=>ac,QSplitter:()=>ic,QStep:()=>uc,QStepper:()=>dc,QStepperNavigation:()=>hc,QTab:()=>qi,QTabPanel:()=>Fi,QTabPanels:()=>Bi,QTable:()=>zc,QTabs:()=>Ii,QTd:()=>Nc,QTh:()=>pc,QTime:()=>Vc,QTimeline:()=>Hc,QTimelineEntry:()=>Wc,QToggle:()=>Nl,QToolbar:()=>Gc,QToolbarTitle:()=>Kc,QTooltip:()=>Oo,QTr:()=>Ic,QTree:()=>Zc,QUploader:()=>ld,QUploaderAddTrigger:()=>ud,QVideo:()=>cd,QVirtualScroll:()=>gc});function hd(e){return!1===e?0:!0===e||void 0===e?1:Number.parseInt(e,10)||0}var pd=p({name:"close-popup",beforeMount(e,{value:t}){let n={depth:hd(t),handler(t){0!==n.depth&&setTimeout(()=>{let a=function(e){return rn.find(t=>null!==t.contentEl&&t.contentEl.contains(e))}(e);void 0!==a&&function(e,t,n){for(;0!==n&&null!=e;){if(e.__qPortal){if(n--,"QMenu"===e.$options.name){e=on(e,t);continue}e.hide(t)}e=ot(e)}}(a,t,n.depth)},0)},handlerKey(e){N(e,13)&&n.handler(e)}};e.__qclosepopup=n,e.addEventListener("click",n.handler),e.addEventListener("keyup",n.handlerKey)},updated(e,{value:t,oldValue:n}){t!==n&&(e.__qclosepopup.depth=hd(t))},beforeUnmount(e){let t=e.__qclosepopup;e.removeEventListener("click",t.handler),e.removeEventListener("keyup",t.handlerKey),delete e.__qclosepopup}});let fd,md=0;function _d(){return!1}function gd(e,t){void 0===fd&&(fd=document.createElement("div"),fd.style.cssText="position: absolute; left: 0; top: 0",document.body.append(fd));let n=e.getBoundingClientRect(),a=fd.getBoundingClientRect(),{marginLeft:i,marginRight:r,marginTop:o,marginBottom:s}=window.getComputedStyle(e),l=Number.parseInt(i,10)+Number.parseInt(r,10),u=Number.parseInt(o,10)+Number.parseInt(s,10);return{left:n.left-a.left,top:n.top-a.top,width:n.right-n.left,height:n.bottom-n.top,widthM:n.right-n.left+(t?0:l),heightM:n.bottom-n.top+(t?0:u),marginH:t?l:0,marginV:t?u:0}}function vd(e){return{width:e.scrollWidth,height:e.scrollHeight}}let bd=["Top","Right","Bottom","Left"],yd=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],wd=/-block|-inline|block-|inline-/,kd=/(-block|-inline|block-|inline-).*:/;function xd(e,t){let n=window.getComputedStyle(e),a={};for(let e=0;e!kd.test(e)).join(";"):n[i]}return a}let Sd=["absolute","fixed","relative","sticky"];function Cd(e){let t=e,n=0;for(;null!==t&&t!==document;){let{position:a,zIndex:i}=window.getComputedStyle(t),r=Number(i);r>n&&(t===e||Sd.includes(a))&&(n=r),t=t.parentNode}return n}function Td(e,t){let n=Number.parseFloat(e);return Number.isFinite(n)?Math.max(0,Math.min(1,n)):t}function Pd(e){let t=typeof e;return"function"===t?e():"string"===t?document.querySelector(e):e}function Ed(e){return e&&e.ownerDocument===document&&null!==e.parentNode}function Ad(e){let t=_d,n=!1,a=!0,i=function(e){return{from:e.from,to:void 0===e.to?e.from:e.to}}(e),r=function(e){"number"==typeof e?e={duration:e}:"function"==typeof e&&(e={onEnd:e});let t=Number.parseInt(e.duration,10),n=Number.parseInt(e.delay,10);return{...e,waitFor:void 0===e.waitFor?0:e.waitFor,duration:Number.isNaN(t)?300:t,delay:Number.isNaN(n)?0:n,easing:"string"==typeof e.easing&&0!==e.easing.length?e.easing:"ease-in-out",fill:"string"==typeof e.fill&&0!==e.fill.length?e.fill:"none",resize:!0===e.resize,useCSS:!0===e.useCSS||!0===e.usecss,hideFromClone:!0===e.hideFromClone||!0===e.hidefromclone,keepToClone:!0===e.keepToClone||!0===e.keeptoclone,tween:!0===e.tween,tweenFromOpacity:Td(e.tweenFromOpacity,.6),tweenToOpacity:Td(e.tweenToOpacity,.5)}}(e),o=Pd(i.from);if(!Ed(o))return t;"function"==typeof o.qMorphCancel&&o.qMorphCancel();let s,l,u,c,d=o.parentNode,h=o.nextElementSibling,p=gd(o,r.resize),{width:f,height:m}=vd(d),{borderWidth:_,borderStyle:g,borderColor:v,borderRadius:b,backgroundColor:y,transform:w,position:k,cssText:x}=xd(o,["borderWidth","borderStyle","borderColor","borderRadius","backgroundColor","transform","position","cssText"]),S=o.classList.toString(),C=o.style.cssText,T=o.cloneNode(!0),P=!0===r.tween?o.cloneNode(!0):void 0;return void 0!==P&&(P.className=P.classList.toString().split(" ").filter(e=>!e.startsWith("bg-")).join(" ")),!0===r.hideFromClone&&T.classList.add("q-morph--internal"),T.setAttribute("aria-hidden","true"),T.style.transition="none",T.style.animation="none",T.style.pointerEvents="none",d.insertBefore(T,h),o.qMorphCancel=()=>{n=!0,T.remove(),P?.remove(),!0===r.hideFromClone&&T.classList.remove("q-morph--internal"),o.qMorphCancel=void 0},"function"==typeof e.onToggle&&e.onToggle(),requestAnimationFrame(()=>{let e=Pd(i.to);if(!0===n||!Ed(e))return void("function"==typeof o.qMorphCancel&&o.qMorphCancel());o!==e&&"function"==typeof e.qMorphCancel&&e.qMorphCancel(),!0!==r.keepToClone&&e.classList.add("q-morph--internal"),T.classList.add("q-morph--internal");let{width:h,height:E}=vd(d),{width:A,height:L}=vd(e.parentNode);!0!==r.hideFromClone&&T.classList.remove("q-morph--internal"),e.qMorphCancel=()=>{n=!0,T.remove(),P?.remove(),!0===r.hideFromClone&&T.classList.remove("q-morph--internal"),!0!==r.keepToClone&&e.classList.remove("q-morph--internal"),o.qMorphCancel=void 0,e.qMorphCancel=void 0};let M=()=>{if(!0===n)return void("function"==typeof e.qMorphCancel&&e.qMorphCancel());!0!==r.hideFromClone&&(T.classList.add("q-morph--internal"),T.innerHTML="",T.style.left=0,T.style.right="unset",T.style.top=0,T.style.bottom="unset",T.style.transform="none"),!0!==r.keepToClone&&e.classList.remove("q-morph--internal");let i=e.parentNode,{width:M,height:R}=vd(i),z=e.cloneNode(r.keepToClone);z.setAttribute("aria-hidden","true"),!0!==r.keepToClone&&(z.style.left=0,z.style.right="unset",z.style.top=0,z.style.bottom="unset",z.style.transform="none",z.style.pointerEvents="none"),z.classList.add("q-morph--internal");let I=e===o&&d===i?T:e.nextElementSibling;i.insertBefore(z,I);let{borderWidth:N,borderStyle:O,borderColor:j,borderRadius:D,backgroundColor:q,transform:B,position:F,cssText:V}=xd(e,["borderWidth","borderStyle","borderColor","borderRadius","backgroundColor","transform","position","cssText"]),U=e.classList.toString(),$=e.style.cssText;e.style.cssText=V,e.style.transform="none",e.style.animation="none",e.style.transition="none",e.className=U.split(" ").filter(e=>!e.startsWith("bg-")).join(" ");let H=gd(e,r.resize),W=p.left-H.left,G=p.top-H.top,K=p.width/(H.width>0?H.width:10),Y=p.height/(H.height>0?H.height:100),Q=f-h,Z=m-E,J=M-A,X=R-L,ee=Math.max(p.widthM,Q),te=Math.max(p.heightM,Z),ae=Math.max(H.widthM,J),ie=Math.max(H.heightM,X),re=o===e&&!["absolute","fixed"].includes(F)&&!["absolute","fixed"].includes(k),oe="fixed"===F,se=i;for(;!oe&&se!==document;)oe="fixed"===window.getComputedStyle(se).position,se=se.parentNode;if(!0!==r.hideFromClone&&(T.style.display="block",T.style.flex="0 0 auto",T.style.opacity=0,T.style.minWidth="unset",T.style.maxWidth="unset",T.style.minHeight="unset",T.style.maxHeight="unset",T.classList.remove("q-morph--internal")),!0!==r.keepToClone&&(z.style.display="block",z.style.flex="0 0 auto",z.style.opacity=0,z.style.minWidth="unset",z.style.maxWidth="unset",z.style.minHeight="unset",z.style.maxHeight="unset"),z.classList.remove("q-morph--internal"),"string"==typeof r.classes&&(e.className+=" "+r.classes),"string"==typeof r.style)e.style.cssText+=" "+r.style;else if(ne(r.style))for(let t in r.style)e.style[t]=r.style[t];let le=Cd(T),ue=Cd(e),ce=oe?document.documentElement:{scrollLeft:0,scrollTop:0};e.style.position=oe?"fixed":"absolute",e.style.left=H.left-ce.scrollLeft+"px",e.style.right="unset",e.style.top=H.top-ce.scrollTop+"px",e.style.margin=0,!0===r.resize&&(e.style.minWidth="unset",e.style.maxWidth="unset",e.style.minHeight="unset",e.style.maxHeight="unset",e.style.overflow="hidden",e.style.overflowX="hidden",e.style.overflowY="hidden"),document.body.append(e),void 0!==P&&(P.style.cssText=x,P.style.transform="none",P.style.animation="none",P.style.transition="none",P.style.position=e.style.position,P.style.left=p.left-ce.scrollLeft+"px",P.style.right="unset",P.style.top=p.top-ce.scrollTop+"px",P.style.margin=0,P.style.pointerEvents="none",!0===r.resize&&(P.style.minWidth="unset",P.style.maxWidth="unset",P.style.minHeight="unset",P.style.maxHeight="unset",P.style.overflow="hidden",P.style.overflowX="hidden",P.style.overflowY="hidden"),document.body.append(P));let de=n=>{o===e&&!0!==a?(e.style.cssText=C,e.className=S):(e.style.cssText=$,e.className=U),z.parentNode===i&&z.before(e),T.remove(),z.remove(),P?.remove(),t=_d,o.qMorphCancel=void 0,e.qMorphCancel=void 0,"function"==typeof r.onEnd&&r.onEnd(!0===a?"to":"from",!0===n)};if(!0!==r.useCSS&&"function"==typeof e.animate){let i=!0===r.resize?{transform:`translate(${W}px, ${G}px)`,width:`${ee}px`,height:`${te}px`}:{transform:`translate(${W}px, ${G}px) scale(${K}, ${Y})`},d=!0===r.resize?{width:`${ae}px`,height:`${ie}px`}:{},h=!0===r.resize?{width:`${ee}px`,height:`${te}px`}:{},f=!0===r.resize?{transform:`translate(${-1*W}px, ${-1*G}px)`,width:`${ae}px`,height:`${ie}px`}:{transform:`translate(${-1*W}px, ${-1*G}px) scale(${1/K}, ${1/Y})`},m=void 0===P?{backgroundColor:y}:{opacity:r.tweenToOpacity},k=void 0===P?{backgroundColor:q}:{opacity:1};c=e.animate([{margin:0,borderWidth:_,borderStyle:g,borderColor:v,borderRadius:b,zIndex:le,transformOrigin:"0 0",...i,...m},{margin:0,borderWidth:N,borderStyle:O,borderColor:j,borderRadius:D,zIndex:ue,transformOrigin:"0 0",transform:B,...d,...k}],{duration:r.duration,easing:r.easing,fill:r.fill,delay:r.delay}),l=void 0===P?void 0:P.animate([{opacity:r.tweenFromOpacity,margin:0,borderWidth:_,borderStyle:g,borderColor:v,borderRadius:b,zIndex:le,transformOrigin:"0 0",transform:w,...h},{opacity:0,margin:0,borderWidth:N,borderStyle:O,borderColor:j,borderRadius:D,zIndex:ue,transformOrigin:"0 0",...f}],{duration:r.duration,easing:r.easing,fill:r.fill,delay:r.delay}),s=!0===r.hideFromClone||!0===re?void 0:T.animate([{margin:`${Z<0?Z/2:0}px ${Q<0?Q/2:0}px`,width:`${ee+p.marginH}px`,height:`${te+p.marginV}px`},{margin:0,width:0,height:0}],{duration:r.duration,easing:r.easing,fill:r.fill,delay:r.delay}),u=!0===r.keepToClone?void 0:z.animate([!0===re?{margin:`${Z<0?Z/2:0}px ${Q<0?Q/2:0}px`,width:`${ee+p.marginH}px`,height:`${te+p.marginV}px`}:{margin:0,width:0,height:0},{margin:`${X<0?X/2:0}px ${J<0?J/2:0}px`,width:`${ae+H.marginH}px`,height:`${ie+H.marginV}px`}],{duration:r.duration,easing:r.easing,fill:r.fill,delay:r.delay});let x=e=>{s?.cancel(),l?.cancel(),u?.cancel(),c.cancel(),c.removeEventListener("finish",x),c.removeEventListener("cancel",x),de(e),s=void 0,l=void 0,u=void 0,c=void 0};o.qMorphCancel=()=>{o.qMorphCancel=void 0,n=!0,x()},e.qMorphCancel=()=>{e.qMorphCancel=void 0,n=!0,x()},c.addEventListener("finish",x),c.addEventListener("cancel",x),t=e=>!0!==n&&void 0!==c&&(!0===e?(x(!0),!0):(a=!0!==a,s?.reverse(),l?.reverse(),u?.reverse(),c.reverse(),!0))}else{let i="q-morph-anim-"+ ++md,s=document.createElement("style"),l=!0===r.resize?`\n transform: translate(${W}px, ${G}px);\n width: ${ee}px;\n height: ${te}px;\n `:`transform: translate(${W}px, ${G}px) scale(${K}, ${Y});`,u=!0===r.resize?`\n width: ${ae}px;\n height: ${ie}px;\n `:"",c=!0===r.resize?`\n width: ${ee}px;\n height: ${te}px;\n `:"",d=!0===r.resize?`\n transform: translate(${-1*W}px, ${-1*G}px);\n width: ${ae}px;\n height: ${ie}px;\n `:`transform: translate(${-1*W}px, ${-1*G}px) scale(${1/K}, ${1/Y});`,h=void 0===P?`background-color: ${y};`:`opacity: ${r.tweenToOpacity};`,f=void 0===P?`background-color: ${q};`:"opacity: 1;",m=void 0===P?"":`\n @keyframes ${i}-from-tween {\n 0% {\n opacity: ${r.tweenFromOpacity};\n margin: 0;\n border-width: ${_};\n border-style: ${g};\n border-color: ${v};\n border-radius: ${b};\n z-index: ${le};\n transform-origin: 0 0;\n transform: ${w};\n ${c}\n }\n\n 100% {\n opacity: 0;\n margin: 0;\n border-width: ${N};\n border-style: ${O};\n border-color: ${j};\n border-radius: ${D};\n z-index: ${ue};\n transform-origin: 0 0;\n ${d}\n }\n }\n `,k=!0===r.hideFromClone||!0===re?"":`\n @keyframes ${i}-from {\n 0% {\n margin: ${Z<0?Z/2:0}px ${Q<0?Q/2:0}px;\n width: ${ee+p.marginH}px;\n height: ${te+p.marginV}px;\n }\n\n 100% {\n margin: 0;\n width: 0;\n height: 0;\n }\n }\n `,x=!0===re?`\n margin: ${Z<0?Z/2:0}px ${Q<0?Q/2:0}px;\n width: ${ee+p.marginH}px;\n height: ${te+p.marginV}px;\n `:"\n margin: 0;\n width: 0;\n height: 0;\n ",S=!0===r.keepToClone?"":`\n @keyframes ${i}-to {\n 0% {\n ${x}\n }\n\n 100% {\n margin: ${X<0?X/2:0}px ${J<0?J/2:0}px;\n width: ${ae+H.marginH}px;\n height: ${ie+H.marginV}px;\n }\n }\n `;s.innerHTML=`\n @keyframes ${i} {\n 0% {\n margin: 0;\n border-width: ${_};\n border-style: ${g};\n border-color: ${v};\n border-radius: ${b};\n background-color: ${y};\n z-index: ${le};\n transform-origin: 0 0;\n ${l}\n ${h}\n }\n\n 100% {\n margin: 0;\n border-width: ${N};\n border-style: ${O};\n border-color: ${j};\n border-radius: ${D};\n background-color: ${q};\n z-index: ${ue};\n transform-origin: 0 0;\n transform: ${B};\n ${u}\n ${f}\n }\n }\n\n ${k}\n\n ${m}\n\n ${S}\n `,document.head.append(s);let C="normal";T.style.animation=`${r.duration}ms ${r.easing} ${r.delay}ms ${C} ${r.fill} ${i}-from`,void 0!==P&&(P.style.animation=`${r.duration}ms ${r.easing} ${r.delay}ms ${C} ${r.fill} ${i}-from-tween`),z.style.animation=`${r.duration}ms ${r.easing} ${r.delay}ms ${C} ${r.fill} ${i}-to`,e.style.animation=`${r.duration}ms ${r.easing} ${r.delay}ms ${C} ${r.fill} ${i}`;let E=t=>{(t!==Object(t)||t.animationName===i)&&(e.removeEventListener("animationend",E),e.removeEventListener("animationcancel",E),de(),s.remove())};o.qMorphCancel=()=>{o.qMorphCancel=void 0,n=!0,E()},e.qMorphCancel=()=>{e.qMorphCancel=void 0,n=!0,E()},e.addEventListener("animationend",E),e.addEventListener("animationcancel",E),t=t=>!!(!0!==n&&e&&T&&z)&&(!0===t?(E(),!0):(a=!0!==a,C="normal"===C?"reverse":"normal",T.style.animationDirection=C,P.style.animationDirection=C,z.style.animationDirection=C,e.style.animationDirection=C,!0))}};r.waitFor>0||"transitionend"===r.waitFor||r.waitFor===Object(r.waitFor)&&"function"==typeof r.waitFor.then?(r.waitFor>0?new Promise(e=>{setTimeout(e,r.waitFor)}):"transitionend"===r.waitFor?new Promise(t=>{let n=()=>{null!==a&&(clearTimeout(a),a=null),e&&(e.removeEventListener("transitionend",n),e.removeEventListener("transitioncancel",n)),t?.(),t=null},a=setTimeout(n,400);e.addEventListener("transitionend",n),e.addEventListener("transitioncancel",n)}):r.waitFor).then(M).catch(()=>{"function"==typeof e.qMorphCancel&&e.qMorphCancel()}):M()}),e=>t(e)}let Ld={},Md=["duration","delay","easing","fill","classes","style","duration","resize","useCSS","hideFromClone","keepToClone","tween","tweenFromOpacity","tweenToOpacity","waitFor","onEnd"],Rd=["resize","useCSS","hideFromClone","keepToClone","tween"];function zd(e,t){e.clsAction!==t&&(e.clsAction=t,e.el.classList[t]("q-morph--invisible"))}function Id(e){if(e.animating||e.queue.length<2)return;let[t,n]=e.queue;e.animating=!0,t.animating=!0,n.animating=!0,zd(t,"remove"),zd(n,"remove");let a=Ad({from:t.el,to:n.el,onToggle(){zd(t,"add"),zd(n,"remove")},...n.opts,onEnd(a,i){n.opts.onEnd?.(a,i),!i&&(t.animating=!1,n.animating=!1,e.animating=!1,e.cancel=void 0,e.queue.shift(),Id(e))}});e.cancel=()=>{a(!0),e.cancel=void 0}}function Nd(e,t){let n=t.opts;Rd.forEach(t=>{n[t]=!0===e[t]})}function Od(e,t){if(t.name===e){let n=Ld[t.group];return void(void 0===n?(Ld[t.group]={name:t.group,model:e,queue:[t],animating:!1},zd(t,"remove")):n.model!==e&&(n.model=e,n.queue.push(t),!n.animating&&2===n.queue.length&&Id(n)))}t.animating||zd(t,"add")}function jd(e,t){let n;Object(t)===t?(n=String(t.model),function(e,t){void 0!==e.group&&(t.group=e.group),void 0!==e.name&&(t.name=e.name);let n=t.opts;Md.forEach(t=>{void 0!==e[t]&&(n[t]=e[t])})}(t,e),Nd(t,e)):n=String(t),n===e.model?!e.animating&&void 0!==e.clsAction&&e.el.classList[e.clsAction]("q-morph--invisible"):(e.model=n,Od(n,e))}var Dd=p({name:"morph",mounted(e,t){let n={el:e,animating:!1,opts:{}};Nd(t.modifiers,n),function(e,t){let n="string"==typeof e&&0!==e.length?e.split(":"):[];t.name=n[0],t.group=n[1];let a=Number.parseFloat(n[2]);Object.assign(t.opts,{duration:Number.isFinite(a)?a:300,waitFor:n[3]})}(t.arg,n),jd(n,t.value),e.__qmorph=n},updated(e,t){jd(e.__qmorph,t.value)},beforeUnmount(e){let t=e.__qmorph,n=Ld[t.group];n?.queue.includes(t)&&(n.queue=n.queue.filter(e=>e!==t),0===n.queue.length&&(n.cancel?.(),delete Ld[t.group])),"add"===t.clsAction&&e.classList.remove("q-morph--invisible"),delete e.__qmorph}});let qd={childList:!0,subtree:!0,attributes:!0,characterData:!0,attributeOldValue:!0,characterDataOldValue:!0};function Bd(e,t,n){t.handler=n,t.observer?.disconnect(),t.observer=new MutationObserver(n=>{"function"==typeof t.handler&&(!1===t.handler(n)||!0===t.once)&&Fd(e)}),t.observer.observe(e,t.opts)}function Fd(e){let t=e.__qmutation;void 0!==t&&(t.observer?.disconnect(),delete e.__qmutation)}var Vd=p({name:"mutation",mounted(e,{modifiers:{once:t,...n},value:a}){let i={once:t,opts:0===Object.keys(n).length?qd:n};Bd(e,i,a),e.__qmutation=i},updated(e,{oldValue:t,value:n}){let a=e.__qmutation;void 0!==a&&t!==n&&Bd(e,a,n)},beforeUnmount:Fd});let{passive:Ud}=m;function $d(e,{value:t,oldValue:n}){"function"==typeof t?(e.handler=t,"function"!=typeof n&&(e.scrollTarget.addEventListener("scroll",e.scroll,Ud),e.scroll())):e.scrollTarget.removeEventListener("scroll",e.scroll,Ud)}var Hd=p({name:"scroll-fire",mounted(e,t){let n={scrollTarget:Pn(e),scroll:T(()=>{let t,a;n.scrollTarget===window?(a=e.getBoundingClientRect().bottom,t=window.innerHeight):(a=St(e).top+Ct(e),t=St(n.scrollTarget).top+Ct(n.scrollTarget)),a>0&&a{a.styleCleanup=void 0,!0===e?(Qt(),setTimeout(Kd,10)):Kd()}),a.triggered=!1,a.sensitivity=t?a.mouseSensitivity:a.touchSensitivity,a.timer=setTimeout(()=>{a.timer=void 0,Qt(),a.triggered=!0,a.handler({evt:e,touch:!t,mouse:!0===t,position:a.origin,duration:Date.now()-n})},a.duration)},move(e){let{top:t,left:n}=v(e);void 0!==a.timer&&(Math.abs(n-a.origin.left)>=a.sensitivity||Math.abs(t-a.origin.top)>=a.sensitivity)&&(clearTimeout(a.timer),a.timer=void 0)},end(e){S(a,"temp"),a.styleCleanup?.(a.triggered),a.triggered?void 0!==e&&w(e):void 0!==a.timer&&(clearTimeout(a.timer),a.timer=void 0)}},i=[600,5,7];"string"==typeof t.arg&&0!==t.arg.length&&t.arg.split(":").forEach((e,t)=>{let n=Number.parseInt(e,10);n&&(i[t]=n)}),[a.duration,a.touchSensitivity,a.mouseSensitivity]=i,e.__qtouchhold=a,n.mouse&&x(a,"main",[[e,"mousedown","mouseStart","passive"+(n.mouseCapture||n.mousecapture?"Capture":"")]]),c.has.touch&&x(a,"main",[[e,"touchstart","touchStart","passive"+(n.capture?"Capture":"")],[e,"touchend","noop","notPassiveCapture"]])},updated(e,t){let n=e.__qtouchhold;void 0!==n&&t.oldValue!==t.value&&("function"!=typeof t.value&&n.end(),n.handler=t.value)},beforeUnmount(e){let t=e.__qtouchhold;void 0!==t&&(S(t,"main"),S(t,"temp"),void 0!==t.timer&&clearTimeout(t.timer),t.styleCleanup?.(),delete e.__qtouchhold)}});let Qd={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Zd=RegExp(`^([\\d+]+|${Object.keys(Qd).join("|")})$`,"i");function Jd(){document.body.classList.remove("non-selectable")}var Xd=p({name:"touch-repeat",beforeMount(e,{modifiers:t,value:n,arg:a}){let i=Object.keys(t).reduce((e,t)=>{if(Zd.test(t)){let n=Number.parseInt(t,10),a=Number.isNaN(n)?Qd[t.toLowerCase()]:n;void 0!==a&&e.push(...[a].flat())}return e},[]);if(!t.mouse&&!c.has.touch&&0===i.length)return;let r="string"==typeof a&&0!==a.length?a.split(":").map(e=>Number.parseInt(e,10)):[0,600,300],o=r.length-1,s={keyboard:i,handler:n,noop:_,mouseStart(e){void 0===s.event&&"function"==typeof s.handler&&g(e)&&(x(s,"temp",[[document,"mousemove","move","passiveCapture"],[document,"click","end","notPassiveCapture"]]),s.start(e,!0))},keyboardStart(t){if("function"==typeof s.handler&&N(t,i)){if((0===r[0]||void 0!==s.event)&&(w(t),e.focus(),void 0!==s.event))return;x(s,"temp",[[document,"keyup","end","notPassiveCapture"],[document,"click","end","notPassiveCapture"]]),s.start(t,!1,!0)}},touchStart(e){if(void 0!==e.target&&"function"==typeof s.handler){let t=e.target;x(s,"temp",[[t,"touchmove","move","passiveCapture"],[t,"touchcancel","end","notPassiveCapture"],[t,"touchend","end","notPassiveCapture"]]),s.start(e)}},start(e,t,n){function a(e){s.styleCleanup=void 0,document.documentElement.style.cursor="",!0===e?(Qt(),setTimeout(Jd,10)):Jd()}n||(s.origin=v(e)),c.is.mobile&&(document.body.classList.add("non-selectable"),Qt(),s.styleCleanup=a),s.event={touch:!t&&!n,mouse:!0===t,keyboard:!0===n,startTime:Date.now(),repeatCount:0};let i=()=>{if(s.timer=void 0,void 0===s.event)return;0===s.event.repeatCount&&(s.event.evt=e,n?s.event.keyCode=e.keyCode:s.event.position=v(e),c.is.mobile||(document.documentElement.style.cursor="pointer",document.body.classList.add("non-selectable"),Qt(),s.styleCleanup=a)),s.event.duration=Date.now()-s.event.startTime,s.event.repeatCount+=1,s.handler(s.event);let t=o=7||Math.abs(n-t.top)>=7}(e,s.origin)&&(clearTimeout(s.timer),s.timer=void 0)},end(e){void 0!==s.event&&(s.styleCleanup?.(!0),void 0!==e&&s.event.repeatCount>0&&w(e),S(s,"temp"),void 0!==s.timer&&(clearTimeout(s.timer),s.timer=void 0),s.event=void 0)}};e.__qtouchrepeat=s,t.mouse&&x(s,"main",[[e,"mousedown","mouseStart","passive"+(t.mouseCapture||t.mousecapture?"Capture":"")]]),c.has.touch&&x(s,"main",[[e,"touchstart","touchStart","passive"+(t.capture?"Capture":"")],[e,"touchend","noop","passiveCapture"]]),0!==i.length&&x(s,"main",[[e,"keydown","keyboardStart","notPassive"+(t.keyCapture||t.keycapture?"Capture":"")]])},updated(e,{oldValue:t,value:n}){let a=e.__qtouchrepeat;void 0!==a&&t!==n&&("function"!=typeof n&&a.end(),a.handler=n)},beforeUnmount(e){let t=e.__qtouchrepeat;void 0!==t&&(void 0!==t.timer&&clearTimeout(t.timer),S(t,"main"),S(t,"temp"),t.styleCleanup?.(),delete e.__qtouchrepeat)}}),eh=n({ClosePopup:()=>pd,Intersection:()=>ml,Morph:()=>Dd,Mutation:()=>Vd,Ripple:()=>zt,Scroll:()=>Gd,ScrollFire:()=>Hd,TouchHold:()=>Yd,TouchPan:()=>gi,TouchRepeat:()=>Xd,TouchSwipe:()=>Oa});function th(e,t=document.body){if("string"!=typeof e)throw TypeError("Expected a string as propName");if(!(t instanceof Element))throw TypeError("Expected a DOM element");return getComputedStyle(t).getPropertyValue(`--q-${e}`).trim()||null}let nh;function ah(e){void 0===nh&&(nh=c.is.winphone?"msapplication-navbutton-color":"theme-color");let t=function(e){let t=document.getElementsByTagName("META");for(let n in t)if(t[n].name===e)return t[n]}(nh),n=void 0===t;n&&(t=document.createElement("meta"),t.setAttribute("name",nh)),t.setAttribute("content",e),n&&document.head.append(t)}var ih={set:c.is.mobile&&(c.is.nativeMobile||c.is.winphone||c.is.safari||c.is.webkit||c.is.vivaldi)?e=>{let t=e||th("primary");c.is.nativeMobile&&window.StatusBar?window.StatusBar.backgroundColorByHexString(t):ah(t)}:_,install({$q:e}){e.addressbarColor=this,e.config.addressbarColor&&this.set(e.config.addressbarColor)}};let rh={};function oh(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement||null}function sh(){let e=ch.activeEl=ch.isActive?oh():null;!function(e){if(e===mn)return;if(mn=e,mn===document.body||pn.reduce((e,t)=>"dialog"===t?e+1:e,0)<2)return void hn.forEach(e=>{e.contains(mn)||mn.append(e)});let t=pn.lastIndexOf("dialog");for(let e=0;evoid 0!==document.documentElement[e]),ch.isCapable=void 0!==rh.request,ch.isCapable?(Object.assign(ch,{request(e){let t=e||document.documentElement,{activeEl:n}=ch;return t===n?Promise.resolve():(null!==n&&t.contains(n)?ch.exit():Promise.resolve()).finally(()=>uh(t,rh.request))},exit:()=>ch.isActive?uh(document,rh.exit):Promise.resolve(),toggle:e=>ch.isActive?ch.exit():ch.request(e)}),rh.exit=["exitFullscreen","msExitFullscreen","mozCancelFullScreen","webkitExitFullscreen"].find(e=>document[e]),ch.isActive=!!oh(),ch.isActive&&sh(),["onfullscreenchange","onmsfullscreenchange","onwebkitfullscreenchange"].forEach(e=>{document[e]=lh})):function(e){Object.assign(ch,{request:e,exit:e,toggle:e})}(()=>Promise.reject(Error("Not capable")));let dh=f({appVisible:!0},{install({$q:e}){a(e,"appVisible",()=>this.appVisible)}});{let e,t;void 0===document.hidden?void 0===document.msHidden?void 0!==document.webkitHidden&&(e="webkitHidden",t="webkitvisibilitychange"):(e="msHidden",t="msvisibilitychange"):(e="hidden",t="visibilitychange"),t&&void 0!==document[e]&&document.addEventListener(t,()=>{dh.appVisible=!document[e]},!1)}var hh=h({name:"BottomSheetComponent",props:{...Je,title:String,message:String,actions:Array,grid:Boolean,cardClass:[String,Array,Object],cardStyle:[String,Array,Object]},emits:["ok","hide"],setup(t,{emit:n}){let{proxy:a}=(0,e.getCurrentInstance)(),i=Xe(t,a.$q),r=(0,e.ref)(null);function o(){r.value.hide()}function s(e){n("ok",e),o()}function l(){n("hide")}function u(){let n=[];return t.title&&n.push((0,e.h)(Pa,{class:"q-dialog__title"},()=>t.title)),t.message&&n.push((0,e.h)(Pa,{class:"q-dialog__message"},()=>t.message)),n.push(t.grid?(0,e.h)("div",{class:"row items-stretch justify-start",role:"list"},t.actions.map(t=>{let n=t.avatar||t.img;return void 0===t.label?(0,e.h)(as,{class:"col-all",dark:i.value}):(0,e.h)("div",{class:["q-bottom-sheet__item q-hoverable q-focusable cursor-pointer relative-position",t.class],style:t.style,tabindex:0,role:"listitem",onClick(){s(t)},onKeyup(e){13===e.keyCode&&s(t)}},[(0,e.h)("div",{class:"q-focus-helper"}),t.icon?(0,e.h)(Ke,{name:t.icon,color:t.color}):n?(0,e.h)("img",{class:t.avatar?"q-bottom-sheet__avatar":"",src:n}):(0,e.h)("div",{class:"q-bottom-sheet__empty-icon"}),(0,e.h)("div",t.label)])})):(0,e.h)("div",{role:"list"},t.actions.map(t=>{let n=t.avatar||t.img;return void 0===t.label?(0,e.h)(as,{spaced:!0,dark:i.value}):(0,e.h)(jo,{class:["q-bottom-sheet__item",t.classes],style:t.style,tabindex:0,clickable:!0,dark:i.value,onClick(){s(t)}},()=>[(0,e.h)(Do,{avatar:!0},()=>t.icon?(0,e.h)(Ke,{name:t.icon,color:t.color}):n?(0,e.h)("img",{class:t.avatar?"q-bottom-sheet__avatar":"",src:n}):null),(0,e.h)(Do,()=>t.label)])}))),n}function c(){return[(0,e.h)(Ta,{class:["q-bottom-sheet q-bottom-sheet--"+(t.grid?"grid":"list")+(i.value?" q-bottom-sheet--dark q-dark":""),t.cardClass],style:t.cardStyle},u)]}return Object.assign(a,{show:function(){r.value.show()},hide:o}),()=>(0,e.h)(Po,{ref:r,position:"bottom",onHide:l},c)}});function ph(e,t){for(let n in t)"spinner"!==n&&Object(t[n])===t[n]?(e[n]=Object(e[n])===e[n]?{...e[n]}:{},ph(e[n],t[n])):e[n]=t[n]}function fh(t,n,a){return i=>{let r,o,s=n&&void 0!==i.component;if(s){let{component:e,componentProps:t}=i;r="string"==typeof e?a.component(e):e,o=t||{}}else{let{class:e,style:n,...a}=i;r=t,o=a,void 0!==e&&(a.cardClass=e),void 0!==n&&(a.cardStyle=n)}let l,u=!1,c=(0,e.ref)(null),d=_n(!1,"dialog"),h=e=>{if(void 0!==c.value?.[e])return void c.value[e]();let t=l.$.subTree;if(t?.component){if(t.component.proxy&&t.component.proxy[e])return void t.component.proxy[e]();if(t.component.subTree&&t.component.subTree.component&&t.component.subTree.component.proxy&&t.component.subTree.component.proxy[e])return void t.component.subTree.component.proxy[e]()}console.error("[Quasar] Incorrectly defined Dialog component")},p=[],f=[],m={onOk:e=>(p.push(e),m),onCancel:e=>(f.push(e),m),onDismiss:e=>(p.push(e),f.push(e),m),hide:()=>(h("hide"),m),update(e){if(null!==l){if(s)Object.assign(o,e);else{let{class:t,style:n,...a}=e;void 0!==t&&(a.cardClass=t),void 0!==n&&(a.cardStyle=n),ph(o,a)}l.$forceUpdate()}return m}},_=e=>{u=!0,p.forEach(t=>{t(e)})},g=()=>{v.unmount(d),gn(d),v=null,l=null,u||f.forEach(e=>{e()})},v=ce({name:"QGlobalDialog",setup:()=>()=>(0,e.h)(r,{...o,ref:c,onOk:_,onHide:g,onVnodeMounted(...t){"function"==typeof o.onVnodeMounted&&o.onVnodeMounted(...t),(0,e.nextTick)(()=>h("show"))}})},a);return l=v.mount(d),m}}var mh={install({$q:e,parentApp:t}){e.bottomSheet=this.create=fh(hh,!1,t)}};function _h(e){if(""===e)return e;0===e.indexOf('"')&&(e=e.slice(1,-1).replaceAll(String.raw`\"`,'"').replaceAll(String.raw`\\`,"\\"));try{e=decodeURIComponent(e.replaceAll("+"," "))}catch{return}try{let t=JSON.parse(e);(t===Object(t)||Array.isArray(t))&&(e=t)}catch{}return e}let gh=/(\d+)([dhms])/g,vh={d:86400,h:3600,m:60,s:1};function bh(e,t,n={},a){let i,r=!1;if(void 0!==n.expires){if(Number.isFinite(n.expires))i=Math.round(86400*n.expires);else if(n.expires instanceof Date){let e=n.expires.getTime();Number.isFinite(e)&&(i=Math.round((e-Date.now())/1e3))}else"string"==typeof n.expires&&(i=function(e){let t=0,n=!1,a=e.matchAll(gh);for(let e of a){n=!0;let a=Number.parseInt(e[1],10),i=e[2];t+=a*vh[i]}if(n)return t;let i=Date.parse(e);return Number.isNaN(i)?void 0:Math.round((i-Date.now())/1e3)}(n.expires));void 0!==i&&(r=i<=0)}let o=`${encodeURIComponent(e)}=${function(e){return encodeURIComponent(e===Object(e)?JSON.stringify(e):String(e))}(t)}`,s=[o,void 0===i?"":`; Max-Age=${i}`,n.path?`; Path=${n.path}`:"",n.domain?`; Domain=${n.domain}`:"",n.sameSite?`; SameSite=${n.sameSite}`:"",n.httpOnly?"; HttpOnly":"",n.secure?"; Secure":"",n.other?`; ${n.other}`:""].join("");if(a){a.req.qCookies?a.req.qCookies.push(s):a.req.qCookies=[s],a.res.setHeader("Set-Cookie",a.req.qCookies);let t=a.req.headers.cookie||"";if(void 0!==i&&r){let n=encodeURIComponent(e);t=t.split("; ").filter(e=>e.split("=",1)[0]!==n).join("; ")}else t=t?`${o}; ${t}`:o;a.req.headers.cookie=t}else document.cookie=s}function yh(e,t){let n,a,i,r=t?t.req.headers:document,o=r.cookie?r.cookie.split("; "):[],s=o.length,l=e?null:{},u=0;for(;uyh(t,e),set:(t,n,a)=>bh(t,n,a,e),has:t=>function(e,t){return null!==yh(e,t)}(t,e),remove:(t,n)=>function(e,t,n){bh(e,"",{expires:-1,...t},n)}(t,n,e),getAll:()=>yh(null,e)}}());var kh=h({name:"DialogPluginComponent",props:{...Je,title:String,message:String,prompt:Object,options:Object,progress:[Boolean,Object],html:Boolean,ok:{type:[String,Object,Boolean],default:!0},cancel:[String,Object,Boolean],focus:{type:String,default:"ok",validator:e=>["ok","cancel","none"].includes(e)},stackButtons:Boolean,color:String,cardClass:[String,Array,Object],cardStyle:[String,Array,Object]},emits:["ok","hide"],setup(t,{emit:n}){let{proxy:a}=(0,e.getCurrentInstance)(),{$q:i}=a,r=Xe(t,i),o=(0,e.ref)(null),s=(0,e.ref)(void 0===t.prompt?void 0===t.options?void 0:t.options.model:t.prompt.model),l=(0,e.computed)(()=>"q-dialog-plugin"+(r.value?" q-dialog-plugin--dark q-dark":"")+(!1===t.progress?"":" q-dialog-plugin--progress")),u=(0,e.computed)(()=>t.color||(r.value?"amber":"primary")),c=(0,e.computed)(()=>!1===t.progress?null:ne(t.progress)?{component:t.progress.spinner||xt,props:{color:t.progress.color||u.value}}:{component:xt,props:{color:u.value}}),d=(0,e.computed)(()=>void 0!==t.prompt||void 0!==t.options),h=(0,e.computed)(()=>{if(!d.value)return{};let{model:e,isValid:n,items:a,...i}=void 0===t.prompt?t.options:t.prompt;return i}),p=(0,e.computed)(()=>ne(t.ok)||!0===t.ok?i.lang.label.ok:t.ok),f=(0,e.computed)(()=>ne(t.cancel)||!0===t.cancel?i.lang.label.cancel:t.cancel),m=(0,e.computed)(()=>void 0===t.prompt?void 0!==t.options&&void 0!==t.options.isValid&&!t.options.isValid(s.value):void 0!==t.prompt.isValid&&!t.prompt.isValid(s.value)),_=(0,e.computed)(()=>({color:u.value,label:p.value,ripple:!1,disable:m.value,...ne(t.ok)?t.ok:{flat:!0},"data-autofocus":"ok"===t.focus&&!d.value||void 0,onClick:b})),g=(0,e.computed)(()=>({color:u.value,label:f.value,ripple:!1,...ne(t.cancel)?t.cancel:{flat:!0},"data-autofocus":"cancel"===t.focus&&!d.value||void 0,onClick:y}));function v(){o.value.hide()}function b(){n("ok",(0,e.toRaw)(s.value)),v()}function y(){v()}function w(){n("hide")}function k(e){s.value=e}function x(e){!m.value&&"textarea"!==t.prompt.type&&N(e,13)&&b()}function S(n,a){return t.html?(0,e.h)(Pa,{class:n,innerHTML:a}):(0,e.h)(Pa,{class:n},()=>a)}function C(){return[(0,e.h)(dl,{color:u.value,dense:!0,autofocus:!0,dark:r.value,...h.value,modelValue:s.value,"onUpdate:modelValue":k,onKeyup:x})]}function T(){return[(0,e.h)(ql,{color:u.value,options:t.options.items,dark:r.value,...h.value,modelValue:s.value,"onUpdate:modelValue":k})]}function P(){let n=[];return t.title&&n.push(S("q-dialog__title",t.title)),!1!==t.progress&&n.push((0,e.h)(Pa,{class:"q-dialog__progress"},()=>(0,e.h)(c.value.component,c.value.props))),t.message&&n.push(S("q-dialog__message",t.message)),void 0===t.prompt?void 0!==t.options&&n.push((0,e.h)(as,{dark:r.value}),(0,e.h)(Pa,{class:"scroll q-dialog-plugin__form"},T),(0,e.h)(as,{dark:r.value})):n.push((0,e.h)(Pa,{class:"scroll q-dialog-plugin__form"},C)),(t.ok||t.cancel)&&n.push(function(){let n=[];return t.cancel&&n.push((0,e.h)(Kt,g.value)),t.ok&&n.push((0,e.h)(Kt,_.value)),(0,e.h)(Ea,{class:t.stackButtons?"items-end":"",vertical:t.stackButtons,align:"right"},()=>n)}()),n}function E(){return[(0,e.h)(Ta,{class:[l.value,t.cardClass],style:t.cardStyle,dark:r.value},P)]}return(0,e.watch)(()=>t.prompt&&t.prompt.model,k),(0,e.watch)(()=>t.options&&t.options.model,k),Object.assign(a,{show:function(){o.value.show()},hide:v}),()=>(0,e.h)(Po,{ref:o,onHide:w},E)}}),xh={install({$q:e,parentApp:t}){e.dialog=this.create=fh(kh,!0,t)}};let Sh,Ch,Th=0,Ph=null,Eh={},Ah={},Lh={group:"__default_quasar_group__",delay:0,message:!1,html:!1,spinnerSize:80,spinnerColor:"",messageColor:"",backgroundColor:"",boxClass:"",spinner:xt,customClass:""},Mh={...Lh};let Rh,zh=f({isActive:!1},{show(t){Eh=function(e){if(void 0!==e?.group&&void 0!==Ah[e.group])return Object.assign(Ah[e.group],e);let t=ne(e)&&e.ignoreDefaults?{...Lh,...e}:{...Mh,...e};return Ah[t.group]=t,t}(t);let{group:n}=Eh;return zh.isActive=!0,void 0===Sh?(Eh.uid=++Th,null!==Ph&&clearTimeout(Ph),Ph=setTimeout(()=>{Ph=null;let t=_n("q-loading");Sh=ce({name:"QLoading",setup(){function n(){!zh.isActive&&void 0!==Sh&&(ko(!1),Sh.unmount(t),gn(t),Sh=void 0,Ch=void 0)}function a(){if(!zh.isActive)return null;let t=[(0,e.h)(Eh.spinner,{class:"q-loading__spinner",color:Eh.spinnerColor,size:Eh.spinnerSize})];return Eh.message&&t.push((0,e.h)("div",{class:"q-loading__message"+(Eh.messageColor?` text-${Eh.messageColor}`:""),[Eh.html?"innerHTML":"textContent"]:Eh.message})),(0,e.h)("div",{class:"q-loading fullscreen flex flex-center z-max "+Eh.customClass.trim(),key:Eh.uid},[(0,e.h)("div",{class:"q-loading__backdrop"+(Eh.backgroundColor?` bg-${Eh.backgroundColor}`:"")}),(0,e.h)("div",{class:"q-loading__box column items-center "+Eh.boxClass},t)])}return(0,e.onMounted)(()=>{ko(!0)}),()=>(0,e.h)(e.Transition,{name:"q-transition--fade",appear:!0,onAfterLeave:n},a)}},zh.__parentApp),Ch=Sh.mount(t)},Eh.delay)):(Eh.uid=Th,Ch.$forceUpdate()),e=>{void 0!==e&&Object(e)===e?zh.show({...e,group:n}):zh.hide(n)}},hide(e){if(zh.isActive){if(void 0===e)Ah={};else{if(void 0===Ah[e])return;{delete Ah[e];let t=Object.keys(Ah);if(0!==t.length){let e=t.at(-1);return void zh.show({group:e})}}}null!==Ph&&(clearTimeout(Ph),Ph=null),zh.isActive=!1}},setDefaults(e){ne(e)&&Object.assign(Mh,e)},install({$q:e,parentApp:t}){e.loading=this,zh.__parentApp=t,void 0!==e.config.loading&&this.setDefaults(e.config.loading)}}),Ih=(0,e.ref)(null),Nh=f({isActive:!1},{start:_,stop:_,increment:_,setDefaults:_,install({$q:t,parentApp:n}){if(t.loadingBar=this,this.__installed)return void(void 0!==t.config.loadingBar&&this.setDefaults(t.config.loadingBar));let a=(0,e.ref)(void 0===t.config.loadingBar?{}:{...t.config.loadingBar});function i(){Nh.isActive=!0}function r(){Nh.isActive=!1}let o=_n("q-loading-bar");ce({name:"LoadingBar",devtools:{hide:!0},setup:()=>()=>(0,e.h)(Ce,{...a.value,onStart:i,onStop:r,ref:Ih})},n).mount(o),Object.assign(this,{start(e){Ih.value.start(e)},stop(){Ih.value.stop()},increment(...e){Ih.value.increment(...e)},setDefaults(e){ne(e)&&Object.assign(a.value,e)}})}}),Oh=null;String.raw`\u003C`,String.raw`\u003E`,String.raw`\u0026`,String.raw`\u2028`,String.raw`\u2029`;let jh=[];function Dh(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!0;for(let n in e)if(e[n]!==t[n])return!0}function qh(e){return!["class","style"].includes(e)}function Bh(e){return!["lang","dir"].includes(e)}function Fh(){Oh=null;let e={title:"",titleTemplate:null,meta:{},link:{},script:{},htmlAttr:{},bodyAttr:{}};for(let t=0;t{let n=e[t[0]],a=t[1];for(let e in n){let t=n[e];t.template&&(1===Object.keys(t).length?delete n[e]:(t[a]=t.template(t[a]||""),delete t.template))}})})(e),function({add:e,remove:t}){e.title&&(document.title=e.title),0!==Object.keys(t).length&&(["meta","link","script"].forEach(e=>{t[e].forEach(t=>{document.head.querySelector(`${e}[data-qmeta="${t}"]`).remove()})}),t.htmlAttr.filter(Bh).forEach(e=>{document.documentElement.removeAttribute(e)}),t.bodyAttr.filter(qh).forEach(e=>{document.body.removeAttribute(e)})),["meta","link","script"].forEach(t=>{let n=e[t];for(let e in n){let a=document.createElement(t);for(let t in n[e])"innerHTML"!==t&&a.setAttribute(t,n[e][t]);a.dataset.qmeta=e,"script"===t&&(a.innerHTML=n[e].innerHTML||""),document.head.append(a)}}),Object.keys(e.htmlAttr).filter(Bh).forEach(t=>{document.documentElement.setAttribute(t,e.htmlAttr[t]||"")}),Object.keys(e.bodyAttr).filter(qh).forEach(t=>{document.body.setAttribute(t,e.bodyAttr[t]||"")})}(function(e,t){let n={},a={};return void 0===e?{add:t,remove:a}:(e.title!==t.title&&(n.title=t.title),["meta","link","script","htmlAttr","bodyAttr"].forEach(i=>{let r=e[i],o=t[i];if(a[i]=[],null!=r){n[i]={};for(let e in r)Object.hasOwn(o,e)||a[i].push(e);for(let e in o)Object.hasOwn(r,e)?Dh(r[e],o[e])&&(a[i].push(e),n[i][e]=o[e]):n[i][e]=o[e]}else n[i]=o}),{add:n,remove:a})}(Rh,e)),Rh=e}function Vh(){null!==Oh&&clearTimeout(Oh),Oh=setTimeout(Fh,50)}var Uh={install(e){!this.__installed&&o.value&&(Rh=window.__Q_META__,document.getElementById("qmeta-init").remove())}};let $h=0,Hh={},Wh={},Gh={},Kh={},Yh=/^\s*$/,Qh=[],Zh=[void 0,null,!0,!1,""],Jh=["top-left","top-right","bottom-left","bottom-right","top","bottom","left","right","center"],Xh=["top-left","top-right","bottom-left","bottom-right"],ep={positive:{icon:e=>e.iconSet.type.positive,color:"positive"},negative:{icon:e=>e.iconSet.type.negative,color:"negative"},warning:{icon:e=>e.iconSet.type.warning,color:"warning",textColor:"dark"},info:{icon:e=>e.iconSet.type.info,color:"info"},ongoing:{group:!1,timeout:0,spinner:!0,color:"grey-8"}};function tp(t,n,a){if(!t)return ap("parameter required");let i,r={textColor:"white"};if(t.ignoreDefaults||Object.assign(r,Hh),ne(t)||(r.type&&Object.assign(r,ep[r.type]),t={message:t}),Object.assign(r,ep[t.type||r.type],t),"function"==typeof r.icon&&(r.icon=r.icon(n)),r.spinner?r.spinner=!0===r.spinner?xt:(0,e.markRaw)(r.spinner):r.spinner=!1,r.meta={hasMedia:!!(r.spinner||r.icon||r.avatar),hasText:np(r.message)||np(r.caption)},r.position){if(!Jh.includes(r.position))return ap("wrong position",t)}else r.position="bottom";if(Zh.includes(r.timeout))r.timeout=5e3;else{let e=Number.parseFloat(r.timeout);if(!Number.isFinite(e)||e<0)return ap("wrong timeout",t);r.timeout=e}0===r.timeout?r.progress=!1:r.progress&&(r.meta.progressClass="q-notification__progress"+(r.progressClass?` ${r.progressClass}`:""),r.meta.progressStyle={animationDuration:`${r.timeout+1e3}ms`});let o=[...Array.isArray(t.actions)?t.actions:[],...!t.ignoreDefaults&&Array.isArray(Hh.actions)?Hh.actions:[],...Array.isArray(ep[t.type]?.actions)?ep[t.type].actions:[]],{closeBtn:s}=r;if(s&&o.push({label:"string"==typeof s?s:n.lang.label.close}),r.actions=o.map(({handler:e,noDismiss:t,...n})=>({flat:!0,...n,onClick:"function"==typeof e?()=>{e(),t||l()}:()=>{l()}})),void 0===r.multiLine&&(r.multiLine=r.actions.length>1),Object.assign(r.meta,{class:"q-notification row items-stretch q-notification--"+(r.multiLine?"multi-line":"standard")+(void 0===r.color?"":` bg-${r.color}`)+(void 0===r.textColor?"":` text-${r.textColor}`)+(void 0===r.classes?"":` ${r.classes}`),wrapperClass:"q-notification__wrapper col relative-position border-radius-inherit "+(r.multiLine?"column no-wrap justify-center":"row items-center"),contentClass:"q-notification__content row items-center"+(r.multiLine?"":" col"),leftClass:r.meta.hasText?"additional":"single",attrs:{role:"alert",...r.attrs}}),!1===r.group?(r.group=void 0,r.meta.group=void 0):((void 0===r.group||!0===r.group)&&(r.group=[r.message,r.caption,r.multiline,...r.actions.map(e=>`${e.label}*${e.icon}`)].join("|")),r.meta.group=r.group+"|"+r.position),0===r.actions.length?r.actions=void 0:r.meta.actionsClass="q-notification__actions row items-center "+(r.multiLine?"justify-end":"col-auto")+(r.meta.hasMedia?" q-notification__actions--with-media":""),void 0!==a){a.notif.meta.timer&&(clearTimeout(a.notif.meta.timer),a.notif.meta.timer=void 0),r.meta.uid=a.notif.meta.uid;let e=Gh[r.position].value.indexOf(a.notif);Gh[r.position].value[e]=r}else{let e=Wh[r.meta.group];if(void 0===e){if(r.meta.uid=$h++,r.meta.badge=1,["left","right","center"].includes(r.position))Gh[r.position].value.splice(Math.floor(Gh[r.position].value.length/2),0,r);else{let e=r.position.includes("top")?"unshift":"push";Gh[r.position].value[e](r)}void 0!==r.group&&(Wh[r.meta.group]=r)}else{if(e.meta.timer&&(clearTimeout(e.meta.timer),e.meta.timer=void 0),void 0!==r.badgePosition){if(!Xh.includes(r.badgePosition))return ap("wrong badgePosition",t)}else r.badgePosition="top-"+(r.position.includes("left")?"right":"left");r.meta.uid=e.meta.uid,r.meta.badge=e.meta.badge+1,r.meta.badgeClass=`q-notification__badge q-notification__badge--${r.badgePosition}`+(void 0===r.badgeColor?"":` bg-${r.badgeColor}`)+(void 0===r.badgeTextColor?"":` text-${r.badgeTextColor}`)+(r.badgeClass?` ${r.badgeClass}`:"");let n=Gh[r.position].value.indexOf(e);Gh[r.position].value[n]=Wh[r.meta.group]=r}}let l=()=>{(function(e){e.meta.timer&&(clearTimeout(e.meta.timer),e.meta.timer=void 0);let t=Gh[e.position].value.indexOf(e);if(-1!==t){void 0!==e.group&&delete Wh[e.meta.group];let n=Qh[String(e.meta.uid)];if(n){let{width:e,height:t}=getComputedStyle(n);n.style.left=`${n.offsetLeft}px`,n.style.width=e,n.style.height=t}Gh[e.position].value.splice(t,1),"function"==typeof e.onDismiss&&e.onDismiss()}})(r),i=void 0};return r.timeout>0&&(r.meta.timer=setTimeout(()=>{r.meta.timer=void 0,l()},r.timeout+1e3)),void 0!==r.group?e=>{void 0===e?l():ap("trying to update a grouped one which is forbidden",t)}:(i={dismiss:l,config:t,notif:r},void 0===a?e=>{void 0!==i&&(void 0===e?i.dismiss():tp({...i.config,...e,group:!1,position:r.position},n,i))}:void Object.assign(a,i))}function np(e){return null!=e&&!Yh.test(e)}function ap(e,t){return console.error(`Notify: ${e}`,t),!1}var ip={setDefaults(e){ne(e)&&Object.assign(Hh,e)},registerType(e,t){ne(t)&&(ep[e]=t)},install({$q:t,parentApp:n}){if(t.notify=this.create=e=>tp(e,t),t.notify.setDefaults=this.setDefaults,t.notify.registerType=this.registerType,void 0!==t.config.notify&&this.setDefaults(t.config.notify),!this.__installed){Jh.forEach(t=>{Gh[t]=(0,e.ref)([]);let n="left"===t||"center"===t||"right"===t?"center":t.includes("top")?"top":"bottom",a=t.includes("left")?"start":t.includes("right")?"end":"center",i="left"===t||"right"===t?`items-${"left"===t?"start":"end"} justify-center`:"center"===t?"flex-center":`items-${a}`;Kh[t]=`q-notifications__list q-notifications__list--${n} fixed column no-wrap ${i}`});let t=_n("q-notify");ce(h({name:"QNotifications",devtools:{hide:!0},setup:()=>()=>(0,e.h)("div",{class:"q-notifications"},Jh.map(t=>(0,e.h)(e.TransitionGroup,{key:t,class:Kh[t],tag:"div",name:`q-notification--${t}`},()=>Gh[t].value.map(t=>{let n=t.meta,a=[];if(n.hasMedia&&(t.spinner?a.push((0,e.h)(t.spinner,{class:"q-notification__spinner q-notification__spinner--"+n.leftClass,color:t.spinnerColor,size:t.spinnerSize})):t.icon?a.push((0,e.h)(Ke,{class:"q-notification__icon q-notification__icon--"+n.leftClass,name:t.icon,color:t.iconColor,size:t.iconSize,role:"img"})):t.avatar&&a.push((0,e.h)(Ye,{class:"q-notification__avatar q-notification__avatar--"+n.leftClass},()=>(0,e.h)("img",{src:t.avatar,"aria-hidden":"true"})))),n.hasText){let n,i={class:"q-notification__message col"};if(t.html)i.innerHTML=t.caption?`
${t.message}
${t.caption}
`:t.message;else{let a=[t.message];n=t.caption?[(0,e.h)("div",a),(0,e.h)("div",{class:"q-notification__caption"},[t.caption])]:a}a.push((0,e.h)("div",i,n))}let i=[(0,e.h)("div",{class:n.contentClass},a)];return t.progress&&i.push((0,e.h)("div",{key:`${n.uid}|p|${n.badge}`,class:n.progressClass,style:n.progressStyle})),t.actions&&i.push((0,e.h)("div",{class:n.actionsClass},t.actions.map(t=>(0,e.h)(Kt,t)))),n.badge>1&&i.push((0,e.h)("div",{key:`${n.uid}|${n.badge}`,class:t.meta.badgeClass,style:t.badgeStyle},[n.badge])),(0,e.h)("div",{ref:e=>{Qh[String(n.uid)]=e},key:n.uid,class:n.class,...n.attrs},[(0,e.h)("div",{class:n.wrapperClass},i)])}))))}),n).mount(t)}}};let rp=/^-?\d+$/;function op(){return{has:()=>!1,hasItem:()=>!1,getLength:()=>0,getItem:()=>null,getIndex:()=>null,getKey:()=>null,getAll:()=>({}),getAllKeys:()=>[],set:_,setItem:_,remove:_,removeItem:_,clear:_,isEmpty:()=>!0}}function sp(e){let t=window[e+"Storage"],n=e=>{let n=t.getItem(e);return n?function(e){if(e.length<9)return e;let t=e.slice(0,8),n=e.slice(9);switch(t){case"__q_date":return new Date(rp.test(n)?Number.parseInt(n,10):n);case"__q_expr":return new RegExp(n);case"__q_numb":return Number(n);case"__q_bool":return"1"===n;case"__q_strn":return String(n);case"__q_objt":return JSON.parse(n);default:return e}}(n):null},a=e=>null!==t.getItem(e),i=(e,n)=>{t.setItem(e,function(e){return ae(e)?"__q_date|"+e.getTime():ie(e)?"__q_expr|"+e.source:"number"==typeof e?"__q_numb|"+e:"boolean"==typeof e?"__q_bool|"+(e?"1":"0"):"string"==typeof e?"__q_strn|"+e:"function"==typeof e?"__q_strn|"+e.toString():e===Object(e)?"__q_objt|"+JSON.stringify(e):e}(n))},r=e=>{t.removeItem(e)};return{has:a,hasItem:a,getLength:()=>t.length,getItem:n,getIndex:e=>ee{let e,a={},i=t.length;for(let r=0;r{let e=[],n=t.length;for(let a=0;a{t.clear()},isEmpty:()=>0===t.length}}let lp=c.has.webStorage?sp("local"):op(),up={install({$q:e}){e.localStorage=lp},...lp},cp=c.has.webStorage?sp("session"):op(),dp={install({$q:e}){e.sessionStorage=cp},...cp};var hp=n({AddressbarColor:()=>ih,AppFullscreen:()=>ch,AppVisibility:()=>dh,BottomSheet:()=>mh,Cookies:()=>wh,Dark:()=>L,Dialog:()=>xh,IconSet:()=>W,Lang:()=>$,Loading:()=>zh,LoadingBar:()=>Nh,LocalStorage:()=>up,Meta:()=>Uh,Notify:()=>ip,Platform:()=>d,Screen:()=>A,SessionStorage:()=>dp});function pp(e){if(navigator.clipboard)return navigator.clipboard.writeText(e);let t=function(e){let t=document.createElement("textarea");t.value=e,t.contentEditable="true",t.style.position="fixed";let n=()=>{};Qn(n),document.body.append(t),t.focus(),t.select();let a=document.execCommand("copy");return t.remove(),Zn(n),a}(e);return t?Promise.resolve(!0):Promise.reject(t)}function fp(e){let t={activated(){this.__qMeta.active=!0,Vh()},deactivated(){this.__qMeta.active=!1,Vh()},unmounted(){jh.splice(jh.indexOf(this.__qMeta),1),Vh(),this.__qMeta=void 0}};return"function"==typeof e?Object.assign(t,{computed:{__qMetaOptions(){return e.call(this)||{}}},watch:{__qMetaOptions(e){this.__qMeta.val=e,this.__qMeta.active&&Vh()}},created(){this.__qMeta={active:!0,val:this.__qMetaOptions},jh.push(this.__qMeta),Vh()}}):t.created=function(){this.__qMeta={active:!0,val:e},jh.push(this.__qMeta),Vh()},t}var mp=class{constructor(){this.__stack={}}on(e,t,n){return(this.__stack[e]||=[]).push({fn:t,ctx:n}),this}once(e,t,n){let a=(...i)=>{this.off(e,a),t.apply(n,i)};return a.__callback=t,this.on(e,a,n)}emit(e,...t){let n=this.__stack[e];return void 0!==n&&n.forEach(e=>{e.fn.apply(e.ctx,t)}),this}off(e,t){let n=this.__stack[e];if(void 0===n)return this;if(void 0===t)return delete this.__stack[e],this;let a=n.filter(e=>e.fn!==t&&e.fn.__callback!==t);return 0===a.length?delete this.__stack[e]:this.__stack[e]=a,this}};function _p(e){setTimeout(()=>{window.URL.revokeObjectURL(e.href)},1e4),e.remove()}function gp(e,t,n={}){let{mimeType:a,byteOrderMark:i,encoding:r}="string"==typeof n?{mimeType:n}:n,o=void 0===r?t:new TextEncoder(r).encode([t]),s=new Blob(void 0===i?[o]:[i,o],{type:a||"application/octet-stream"}),l=document.createElement("a");l.href=window.URL.createObjectURL(s),l.setAttribute("download",e),void 0===l.download&&l.setAttribute("target","_blank"),l.classList.add("hidden"),l.style.position="fixed",document.body.append(l);try{return l.click(),_p(l),!0}catch(e){return _p(l),e}}function vp(e,t,n){let a=window.open;if(d.is.cordova)if(void 0!==cordova?.InAppBrowser?.open)a=cordova.InAppBrowser.open;else if(void 0!==navigator?.app)return navigator.app.loadUrl(e,{openExternal:!0});let i={noopener:!0,...n},r=i.noopener||i.noreferrer,o=a(e,"_blank",function(e){let t={noopener:!0,...e},n=[];for(let e in t){let a=t[e];!0===a?n.push(e):(re(a)||"string"==typeof a&&""!==a)&&n.push(e+"="+a)}return n.join(",")}(n));if(o)return d.is.desktop&&o.focus(),o;r||t?.()}function bp(e,t,n){if(!d.is.ios||void 0===window.SafariViewController)return vp(e,t,n);window.SafariViewController.isAvailable(a=>{a?window.SafariViewController.show({url:e},_,t):vp(e,t,n)})}function yp(e,{threadsNumber:t=1,abortOnFail:n=!0}={}){let a=-1,i=!1,{isList:r,totalJobs:o,resultAggregator:s,resultKeys:l}=function(e){if(Array.isArray(e)){let t=e.length;return{isList:!0,totalJobs:t,resultAggregator:Array(t).fill(null)}}let t=Object.keys(e),n=t.reduce((e,t)=>(e[t]=null,e),{});return{isList:!1,totalJobs:t.length,resultAggregator:n,resultKeys:t}}(e);if(0===o)return Promise.resolve(s);let u=o-1,c=t=>{if(i||a>=u)return t.resolve();let o=++a,d=r?o:l[o];Promise.resolve().then(()=>e[d](s)).then(e=>{i||(s[d]={key:d,status:"fulfilled",value:e})}).catch(e=>{if(i)return;let a={key:d,status:"rejected",reason:e};s[d]=a,n&&(i=!0,t.reject({...a,resultAggregator:s}))}).finally(()=>{i||c(t)})},d=Math.min(o,Math.max(1,t)),h=Array.from({length:d},()=>{let e=Promise.withResolvers();return c(e),e.promise});return Promise.all(h).then(()=>s)}var wp=n({EventBus:()=>mp,clone:()=>Jl,colors:()=>lr,copyToClipboard:()=>pp,createMetaMixin:()=>fp,createUploaderComponent:()=>rd,date:()=>Xr,debounce:()=>T,dom:()=>At,event:()=>C,exportFile:()=>gp,extend:()=>Zo,format:()=>be,frameDebounce:()=>Kl,getCssVar:()=>th,is:()=>oe,morph:()=>Ad,noop:()=>_,openURL:()=>bp,patterns:()=>Xi,runSequentialPromises:()=>yp,scroll:()=>qn,setCssVar:()=>M,throttle:()=>Lt,uid:()=>_a});function kp(){let{emit:t,proxy:n}=(0,e.getCurrentInstance)(),a=(0,e.ref)(null);function i(){a.value.hide()}return Object.assign(n,{show:function(){a.value.show()},hide:i}),{dialogRef:a,onDialogHide:function(){t("hide")},onDialogOK:function(e){t("ok",e),i()},onDialogCancel:i}}let xp=["ok","hide"];function Sp(t){{let n={active:!0};if("function"==typeof t){let a=(0,e.computed)(t);n.val=a.value,(0,e.watch)(a,e=>{n.val=e,n.active&&Vh()})}else n.val=t;jh.push(n),Vh(),(0,e.onActivated)(()=>{n.active=!0,Vh()}),(0,e.onDeactivated)(()=>{n.active=!1,Vh()}),(0,e.onUnmounted)(()=>{jh.splice(jh.indexOf(n),1),Vh()})}}function Cp(){return(0,e.inject)("_q_")}function Tp(){let t=null,n=(0,e.getCurrentInstance)();function a(){null!==t&&(clearInterval(t),t=null)}return(0,e.onDeactivated)(a),(0,e.onBeforeUnmount)(a),{removeInterval:a,registerInterval(e,i){a(),ct(n)||(t=setInterval(e,i))}}}kp.emits=xp,kp.emitsObject=ad(xp);var Pp=n({useDialogPluginComponent:()=>kp,useFormChild:()=>gs,useHydration:()=>Ti,useId:()=>va,useInterval:()=>Tp,useMeta:()=>Sp,useQuasar:()=>Cp,useRenderCache:()=>ja,useSplitAttrs:()=>Wo,useTick:()=>kn,useTimeout:()=>xn});void 0===window.Vue&&console.error("[ Quasar ] Vue is required to run. Please add a script tag for it before loading Quasar."),window.Quasar={version:"2.22.0",install(e,t){he(e,{components:dd,directives:eh,plugins:hp,...t})},lang:$,iconSet:W,...dd,...eh,...hp,...Pp,...wp}}(window.Vue); /*! * vuex v4.1.0 * (c) 2022 Evan You * @license MIT */ -var Vuex=function(e){"use strict";var t="store";function n(){return"undefined"!=typeof navigator?window:"undefined"!=typeof global?global:{}}function a(e,t){var a=n().__VUE_DEVTOOLS_GLOBAL_HOOK__;if(a)a.emit("devtools-plugin:setup",e,t);else{var i=n();(i.__VUE_DEVTOOLS_PLUGINS__=i.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:e,setupFn:t})}}function i(e,t){if(void 0===t&&(t=[]),null===e||"object"!=typeof e)return e;var n,a=(n=function(t){return t.original===e},t.filter(n)[0]);if(a)return a.copy;var o=Array.isArray(e)?[]:{};return t.push({original:e,copy:o}),Object.keys(e).forEach(function(n){o[n]=i(e[n],t)}),o}function o(e,t){Object.keys(e).forEach(function(n){return t(e[n],n)})}function r(e){return null!==e&&"object"==typeof e}function s(e,t){if(!e)throw new Error("[vuex] "+t)}function l(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function u(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;d(e,n,[],e._modules.root,!0),c(e,n,t)}function c(t,n,a){var i=t._state,r=t._scope;t.getters={},t._makeLocalGettersCache=Object.create(null);var l=t._wrappedGetters,u={},c={},d=e.effectScope(!0);d.run(function(){o(l,function(n,a){u[a]=function(e,t){return function(){return e(t)}}(n,t),c[a]=e.computed(function(){return u[a]()}),Object.defineProperty(t.getters,a,{get:function(){return c[a].value},enumerable:!0})})}),t._state=e.reactive({data:n}),t._scope=d,t.strict&&function(t){e.watch(function(){return t._state.data},function(){s(t._committing,"do not mutate vuex store state outside mutation handlers.")},{deep:!0,flush:"sync"})}(t),i&&a&&t._withCommit(function(){i.data=null}),r&&r.stop()}function d(e,t,n,a,i){var o=!n.length,r=e._modules.getNamespace(n);if(a.namespaced&&(e._modulesNamespaceMap[r]&&console.error("[vuex] duplicate namespace "+r+" for the namespaced module "+n.join("/")),e._modulesNamespaceMap[r]=a),!o&&!i){var s=p(t,n.slice(0,-1)),l=n[n.length-1];e._withCommit(function(){l in s&&console.warn('[vuex] state field "'+l+'" was overridden by a module with the same name at "'+n.join(".")+'"'),s[l]=a.state})}var u=a.context=function(e,t,n){var a=""===t,i={dispatch:a?e.dispatch:function(n,a,i){var o=f(n,a,i),r=o.payload,s=o.options,l=o.type;if(s&&s.root||(l=t+l,e._actions[l]))return e.dispatch(l,r);console.error("[vuex] unknown local action type: "+o.type+", global type: "+l)},commit:a?e.commit:function(n,a,i){var o=f(n,a,i),r=o.payload,s=o.options,l=o.type;s&&s.root||(l=t+l,e._mutations[l])?e.commit(l,r,s):console.error("[vuex] unknown local mutation type: "+o.type+", global type: "+l)}};return Object.defineProperties(i,{getters:{get:a?function(){return e.getters}:function(){return h(e,t)}},state:{get:function(){return p(e.state,n)}}}),i}(e,r,n);a.forEachMutation(function(t,n){!function(e,t,n,a){var i=e._mutations[t]||(e._mutations[t]=[]);i.push(function(t){n.call(e,a.state,t)})}(e,r+n,t,u)}),a.forEachAction(function(t,n){var a=t.root?n:r+n,i=t.handler||t;!function(e,t,n,a){var i=e._actions[t]||(e._actions[t]=[]);i.push(function(t){var i,o=n.call(e,{dispatch:a.dispatch,commit:a.commit,getters:a.getters,state:a.state,rootGetters:e.getters,rootState:e.state},t);return(i=o)&&"function"==typeof i.then||(o=Promise.resolve(o)),e._devtoolHook?o.catch(function(t){throw e._devtoolHook.emit("vuex:error",t),t}):o})}(e,a,i,u)}),a.forEachGetter(function(t,n){!function(e,t,n,a){if(e._wrappedGetters[t])return void console.error("[vuex] duplicate getter key: "+t);e._wrappedGetters[t]=function(e){return n(a.state,a.getters,e.state,e.getters)}}(e,r+n,t,u)}),a.forEachChild(function(a,o){d(e,t,n.concat(o),a,i)})}function h(e,t){if(!e._makeLocalGettersCache[t]){var n={},a=t.length;Object.keys(e.getters).forEach(function(i){if(i.slice(0,a)===t){var o=i.slice(a);Object.defineProperty(n,o,{get:function(){return e.getters[i]},enumerable:!0})}}),e._makeLocalGettersCache[t]=n}return e._makeLocalGettersCache[t]}function p(e,t){return t.reduce(function(e,t){return e[t]},e)}function f(e,t,n){return r(e)&&e.type&&(n=t,t=e,e=e.type),s("string"==typeof e,"expects string as the type, but found "+typeof e+"."),{type:e,payload:t,options:n}}var m="vuex:mutations",g="vuex:actions",_="vuex",v=0;function b(e,t){a({id:"org.vuejs.vuex",app:e,label:"Vuex",homepage:"https://next.vuex.vuejs.org/",logo:"https://vuejs.org/images/icons/favicon-96x96.png",packageName:"vuex",componentStateTypes:["vuex bindings"]},function(n){n.addTimelineLayer({id:m,label:"Vuex Mutations",color:y}),n.addTimelineLayer({id:g,label:"Vuex Actions",color:y}),n.addInspector({id:_,label:"Vuex",icon:"storage",treeFilterPlaceholder:"Filter stores..."}),n.on.getInspectorTree(function(n){if(n.app===e&&n.inspectorId===_)if(n.filter){var a=[];S(a,t._modules.root,n.filter,""),n.rootNodes=a}else n.rootNodes=[x(t._modules.root,"")]}),n.on.getInspectorState(function(n){if(n.app===e&&n.inspectorId===_){var a=n.nodeId;h(t,a),n.state=function(e,t,n){t="root"===n?t:t[n];var a=Object.keys(t),i={state:Object.keys(e.state).map(function(t){return{key:t,editable:!0,value:e.state[t]}})};if(a.length){var o=function(e){var t={};return Object.keys(e).forEach(function(n){var a=n.split("/");if(a.length>1){var i=t,o=a.pop();a.forEach(function(e){i[e]||(i[e]={_custom:{value:{},display:e,tooltip:"Module",abstract:!0}}),i=i[e]._custom.value}),i[o]=C(function(){return e[n]})}else t[n]=C(function(){return e[n]})}),t}(t);i.getters=Object.keys(o).map(function(e){return{key:e.endsWith("/")?k(e):e,editable:!1,value:C(function(){return o[e]})}})}return i}((i=t._modules,(r=(o=a).split("/").filter(function(e){return e})).reduce(function(e,t,n){var a=e[t];if(!a)throw new Error('Missing module "'+t+'" for path "'+o+'".');return n===r.length-1?a:a._children},"root"===o?i:i.root._children)),"root"===a?t.getters:t._makeLocalGettersCache,a)}var i,o,r}),n.on.editInspectorState(function(n){if(n.app===e&&n.inspectorId===_){var a=n.nodeId,i=n.path;"root"!==a&&(i=a.split("/").filter(Boolean).concat(i)),t._withCommit(function(){n.set(t._state.data,i,n.state.value)})}}),t.subscribe(function(e,t){var a={};e.payload&&(a.payload=e.payload),a.state=t,n.notifyComponentUpdate(),n.sendInspectorTree(_),n.sendInspectorState(_),n.addTimelineEvent({layerId:m,event:{time:Date.now(),title:e.type,data:a}})}),t.subscribeAction({before:function(e,t){var a={};e.payload&&(a.payload=e.payload),e._id=v++,e._time=Date.now(),a.state=t,n.addTimelineEvent({layerId:g,event:{time:e._time,title:e.type,groupId:e._id,subtitle:"start",data:a}})},after:function(e,t){var a={},i=Date.now()-e._time;a.duration={_custom:{type:"duration",display:i+"ms",tooltip:"Action duration",value:i}},e.payload&&(a.payload=e.payload),a.state=t,n.addTimelineEvent({layerId:g,event:{time:Date.now(),title:e.type,groupId:e._id,subtitle:"end",data:a}})}})})}var y=8702998,w={label:"namespaced",textColor:16777215,backgroundColor:6710886};function k(e){return e&&"root"!==e?e.split("/").slice(-2,-1)[0]:"Root"}function x(e,t){return{id:t||"root",label:k(t),tags:e.namespaced?[w]:[],children:Object.keys(e._children).map(function(n){return x(e._children[n],t+n+"/")})}}function S(e,t,n,a){a.includes(n)&&e.push({id:a||"root",label:a.endsWith("/")?a.slice(0,a.length-1):a||"Root",tags:t.namespaced?[w]:[]}),Object.keys(t._children).forEach(function(i){S(e,t._children[i],n,a+i+"/")})}function C(e){try{return e()}catch(e){return e}}var T=function(e,t){this.runtime=t,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=("function"==typeof n?n():n)||{}},P={namespaced:{configurable:!0}};P.namespaced.get=function(){return!!this._rawModule.namespaced},T.prototype.addChild=function(e,t){this._children[e]=t},T.prototype.removeChild=function(e){delete this._children[e]},T.prototype.getChild=function(e){return this._children[e]},T.prototype.hasChild=function(e){return e in this._children},T.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)},T.prototype.forEachChild=function(e){o(this._children,e)},T.prototype.forEachGetter=function(e){this._rawModule.getters&&o(this._rawModule.getters,e)},T.prototype.forEachAction=function(e){this._rawModule.actions&&o(this._rawModule.actions,e)},T.prototype.forEachMutation=function(e){this._rawModule.mutations&&o(this._rawModule.mutations,e)},Object.defineProperties(T.prototype,P);var E=function(e){this.register([],e,!1)};function A(e,t,n){if(R(e,n),t.update(n),n.modules)for(var a in n.modules){if(!t.getChild(a))return void console.warn("[vuex] trying to add a new module '"+a+"' on hot reloading, manual reload is needed");A(e.concat(a),t.getChild(a),n.modules[a])}}E.prototype.get=function(e){return e.reduce(function(e,t){return e.getChild(t)},this.root)},E.prototype.getNamespace=function(e){var t=this.root;return e.reduce(function(e,n){return e+((t=t.getChild(n)).namespaced?n+"/":"")},"")},E.prototype.update=function(e){A([],this.root,e)},E.prototype.register=function(e,t,n){var a=this;void 0===n&&(n=!0),R(e,t);var i=new T(t,n);0===e.length?this.root=i:this.get(e.slice(0,-1)).addChild(e[e.length-1],i);t.modules&&o(t.modules,function(t,i){a.register(e.concat(i),t,n)})},E.prototype.unregister=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1],a=t.getChild(n);a?a.runtime&&t.removeChild(n):console.warn("[vuex] trying to unregister module '"+n+"', which is not registered")},E.prototype.isRegistered=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1];return!!t&&t.hasChild(n)};var M={assert:function(e){return"function"==typeof e},expected:"function"},L={getters:M,mutations:M,actions:{assert:function(e){return"function"==typeof e||"object"==typeof e&&"function"==typeof e.handler},expected:'function or object with "handler" function'}};function R(e,t){Object.keys(L).forEach(function(n){if(t[n]){var a=L[n];o(t[n],function(t,i){s(a.assert(t),function(e,t,n,a,i){var o=t+" should be "+i+' but "'+t+"."+n+'"';e.length>0&&(o+=' in module "'+e.join(".")+'"');return o+=" is "+JSON.stringify(a)+".",o}(e,n,i,t,a.expected))})}})}var z=function e(t){var n=this;void 0===t&&(t={}),s("undefined"!=typeof Promise,"vuex requires a Promise polyfill in this browser."),s(this instanceof e,"store must be called with the new operator.");var a=t.plugins;void 0===a&&(a=[]);var i=t.strict;void 0===i&&(i=!1);var o=t.devtools;this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new E(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._makeLocalGettersCache=Object.create(null),this._scope=null,this._devtools=o;var r=this,l=this.dispatch,u=this.commit;this.dispatch=function(e,t){return l.call(r,e,t)},this.commit=function(e,t,n){return u.call(r,e,t,n)},this.strict=i;var h=this._modules.root.state;d(this,h,[],this._modules.root),c(this,h),a.forEach(function(e){return e(n)})},N={state:{configurable:!0}};z.prototype.install=function(e,n){e.provide(n||t,this),e.config.globalProperties.$store=this,(void 0===this._devtools||this._devtools)&&b(e,this)},N.state.get=function(){return this._state.data},N.state.set=function(e){s(!1,"use store.replaceState() to explicit replace store state.")},z.prototype.commit=function(e,t,n){var a=this,i=f(e,t,n),o=i.type,r=i.payload,s=i.options,l={type:o,payload:r},u=this._mutations[o];u?(this._withCommit(function(){u.forEach(function(e){e(r)})}),this._subscribers.slice().forEach(function(e){return e(l,a.state)}),s&&s.silent&&console.warn("[vuex] mutation type: "+o+". Silent option has been removed. Use the filter functionality in the vue-devtools")):console.error("[vuex] unknown mutation type: "+o)},z.prototype.dispatch=function(e,t){var n=this,a=f(e,t),i=a.type,o=a.payload,r={type:i,payload:o},s=this._actions[i];if(s){try{this._actionSubscribers.slice().filter(function(e){return e.before}).forEach(function(e){return e.before(r,n.state)})}catch(e){console.warn("[vuex] error in before action subscribers: "),console.error(e)}var l=s.length>1?Promise.all(s.map(function(e){return e(o)})):s[0](o);return new Promise(function(e,t){l.then(function(t){try{n._actionSubscribers.filter(function(e){return e.after}).forEach(function(e){return e.after(r,n.state)})}catch(e){console.warn("[vuex] error in after action subscribers: "),console.error(e)}e(t)},function(e){try{n._actionSubscribers.filter(function(e){return e.error}).forEach(function(t){return t.error(r,n.state,e)})}catch(e){console.warn("[vuex] error in error action subscribers: "),console.error(e)}t(e)})})}console.error("[vuex] unknown action type: "+i)},z.prototype.subscribe=function(e,t){return l(e,this._subscribers,t)},z.prototype.subscribeAction=function(e,t){return l("function"==typeof e?{before:e}:e,this._actionSubscribers,t)},z.prototype.watch=function(t,n,a){var i=this;return s("function"==typeof t,"store.watch only accepts a function."),e.watch(function(){return t(i.state,i.getters)},n,Object.assign({},a))},z.prototype.replaceState=function(e){var t=this;this._withCommit(function(){t._state.data=e})},z.prototype.registerModule=function(e,t,n){void 0===n&&(n={}),"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),s(e.length>0,"cannot register the root module by using registerModule."),this._modules.register(e,t),d(this,this.state,e,this._modules.get(e),n.preserveState),c(this,this.state)},z.prototype.unregisterModule=function(e){var t=this;"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),this._modules.unregister(e),this._withCommit(function(){delete p(t.state,e.slice(0,-1))[e[e.length-1]]}),u(this)},z.prototype.hasModule=function(e){return"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),this._modules.isRegistered(e)},z.prototype.hotUpdate=function(e){this._modules.update(e),u(this,!0)},z.prototype._withCommit=function(e){var t=this._committing;this._committing=!0,e(),this._committing=t},Object.defineProperties(z.prototype,N);var O=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapState: mapper parameter must be either an Array or an Object"),j(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){var t=this.$store.state,n=this.$store.getters;if(e){var a=$(this.$store,"mapState",e);if(!a)return;t=a.context.state,n=a.context.getters}return"function"==typeof i?i.call(this,t,n):t[i]},n[a].vuex=!0}),n}),I=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapMutations: mapper parameter must be either an Array or an Object"),j(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var a=this.$store.commit;if(e){var o=$(this.$store,"mapMutations",e);if(!o)return;a=o.context.commit}return"function"==typeof i?i.apply(this,[a].concat(t)):a.apply(this.$store,[i].concat(t))}}),n}),q=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapGetters: mapper parameter must be either an Array or an Object"),j(t).forEach(function(t){var a=t.key,i=t.val;i=e+i,n[a]=function(){if(!e||$(this.$store,"mapGetters",e)){if(i in this.$store.getters)return this.$store.getters[i];console.error("[vuex] unknown getter: "+i)}},n[a].vuex=!0}),n}),D=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapActions: mapper parameter must be either an Array or an Object"),j(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var a=this.$store.dispatch;if(e){var o=$(this.$store,"mapActions",e);if(!o)return;a=o.context.dispatch}return"function"==typeof i?i.apply(this,[a].concat(t)):a.apply(this.$store,[i].concat(t))}}),n});function j(e){return B(e)?Array.isArray(e)?e.map(function(e){return{key:e,val:e}}):Object.keys(e).map(function(t){return{key:t,val:e[t]}}):[]}function B(e){return Array.isArray(e)||r(e)}function F(e){return function(t,n){return"string"!=typeof t?(n=t,t=""):"/"!==t.charAt(t.length-1)&&(t+="/"),e(t,n)}}function $(e,t,n){var a=e._modulesNamespaceMap[n];return a||console.error("[vuex] module namespace not found in "+t+"(): "+n),a}function V(e,t,n){var a=n?e.groupCollapsed:e.group;try{a.call(e,t)}catch(n){e.log(t)}}function U(e){try{e.groupEnd()}catch(t){e.log("—— log end ——")}}function H(){var e=new Date;return" @ "+W(e.getHours(),2)+":"+W(e.getMinutes(),2)+":"+W(e.getSeconds(),2)+"."+W(e.getMilliseconds(),3)}function W(e,t){return n="0",a=t-e.toString().length,new Array(a+1).join(n)+e;var n,a}return{version:"4.1.0",Store:z,storeKey:t,createStore:function(e){return new z(e)},useStore:function(n){return void 0===n&&(n=null),e.inject(null!==n?n:t)},mapState:O,mapMutations:I,mapGetters:q,mapActions:D,createNamespacedHelpers:function(e){return{mapState:O.bind(null,e),mapGetters:q.bind(null,e),mapMutations:I.bind(null,e),mapActions:D.bind(null,e)}},createLogger:function(e){void 0===e&&(e={});var t=e.collapsed;void 0===t&&(t=!0);var n=e.filter;void 0===n&&(n=function(e,t,n){return!0});var a=e.transformer;void 0===a&&(a=function(e){return e});var o=e.mutationTransformer;void 0===o&&(o=function(e){return e});var r=e.actionFilter;void 0===r&&(r=function(e,t){return!0});var s=e.actionTransformer;void 0===s&&(s=function(e){return e});var l=e.logMutations;void 0===l&&(l=!0);var u=e.logActions;void 0===u&&(u=!0);var c=e.logger;return void 0===c&&(c=console),function(e){var d=i(e.state);void 0!==c&&(l&&e.subscribe(function(e,r){var s=i(r);if(n(e,d,s)){var l=H(),u=o(e),h="mutation "+e.type+l;V(c,h,t),c.log("%c prev state","color: #9E9E9E; font-weight: bold",a(d)),c.log("%c mutation","color: #03A9F4; font-weight: bold",u),c.log("%c next state","color: #4CAF50; font-weight: bold",a(s)),U(c)}d=s}),u&&e.subscribeAction(function(e,n){if(r(e,n)){var a=H(),i=s(e),o="action "+e.type+a;V(c,o,t),c.log("%c action","color: #03A9F4; font-weight: bold",i),U(c)}}))}}}}(Vue),VueI18n=function(e,t){"use strict";var n=function(e){var t=Object.create(null);if(e)for(var n in e)t[n]=e[n];return t.default=e,Object.freeze(t)}(t);function a(e,t){"undefined"!=typeof console&&(console.warn("[intlify] "+e),t&&console.warn(t.stack))}const i="undefined"!=typeof window,o=(e,t=!1)=>t?Symbol.for(e):Symbol(e),r=(e,t,n)=>s({l:e,k:t,s:n}),s=e=>JSON.stringify(e).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/\u0027/g,"\\u0027"),l=e=>"number"==typeof e&&isFinite(e),u=e=>"[object RegExp]"===S(e),c=e=>C(e)&&0===Object.keys(e).length,d=Object.assign,h=Object.create,p=(e=null)=>h(e);function f(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/").replace(/=/g,"=")}function m(e){return e.replace(/&(?![a-zA-Z0-9#]{2,6};)/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}const g=Object.prototype.hasOwnProperty;function _(e,t){return g.call(e,t)}const v=Array.isArray,b=e=>"function"==typeof e,y=e=>"string"==typeof e,w=e=>"boolean"==typeof e,k=e=>null!==e&&"object"==typeof e,x=Object.prototype.toString,S=e=>x.call(e),C=e=>"[object Object]"===S(e);function T(e,t=""){return e.reduce((e,n,a)=>0===a?e+n:e+t+n,"")}const P=e=>!k(e)||v(e);function E(e,t){if(P(e)||P(t))throw new Error("Invalid value");const n=[{src:e,des:t}];for(;n.length;){const{src:e,des:t}=n.pop();Object.keys(e).forEach(a=>{"__proto__"!==a&&(k(e[a])&&!k(t[a])&&(t[a]=Array.isArray(e[a])?[]:p()),P(t[a])||P(e[a])?t[a]=e[a]:n.push({src:e[a],des:t[a]}))})}}function A(e){throw e}const M=" ",L="\n",R=String.fromCharCode(8232),z=String.fromCharCode(8233);function N(e){const t=e;let n=0,a=1,i=1,o=0;const r=e=>"\r"===t[e]&&t[e+1]===L,s=e=>t[e]===z,l=e=>t[e]===R,u=e=>r(e)||s(e)||l(e)?L:t[e];function c(){return o=0,(e=>r(e)||(e=>t[e]===L)(e)||s(e)||l(e))(n)&&(a++,i=0),r(n)&&n++,n++,i++,t[n]}return{index:()=>n,line:()=>a,column:()=>i,peekOffset:()=>o,charAt:u,currentChar:()=>u(n),currentPeek:()=>u(n+o),next:c,peek:function(){return r(n+o)&&o++,o++,t[n+o]},reset:function(){n=0,a=1,i=1,o=0},resetPeek:function(e=0){o=e},skipToPeek:function(){const e=n+o;for(;e!==n;)c();o=0}}}const O=void 0;function I(e,t={}){const n=!1!==t.location,a=N(e),i=()=>a.index(),o=()=>({line:a.line(),column:a.column(),offset:a.index()}),r=o(),s=i(),l={currentType:13,offset:s,startLoc:r,endLoc:r,lastType:13,lastOffset:s,lastStartLoc:r,lastEndLoc:r,braceNest:0,inLinked:!1,text:""},{onError:u}=t;function c(e,t,a){e.endLoc=o(),e.currentType=t;const i={type:t};return n&&(i.loc=function(e,t){return{start:e,end:t}}(e.startLoc,e.endLoc)),null!=a&&(i.value=a),i}const d=e=>c(e,13);function h(e,t){return e.currentChar()===t?(e.next(),t):(o(),"")}function p(e){let t="";for(;e.currentPeek()===M||e.currentPeek()===L;)t+=e.currentPeek(),e.peek();return t}function f(e){const t=p(e);return e.skipToPeek(),t}function m(e){if(e===O)return!1;const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||95===t}function g(e){p(e);const t="|"===e.currentPeek();return e.resetPeek(),t}function _(e,t=!0){const n=(t=!1,a="")=>{const i=e.currentPeek();return"{"===i?t:"@"!==i&&i?"|"===i?!(a===M||a===L):i===M?(e.peek(),n(!0,M)):i!==L||(e.peek(),n(!0,L)):t},a=n();return t&&e.resetPeek(),a}function v(e,t){const n=e.currentChar();return n===O?O:t(n)?(e.next(),n):null}function b(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t}function y(e){return v(e,b)}function w(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t||45===t}function k(e){return v(e,w)}function x(e){const t=e.charCodeAt(0);return t>=48&&t<=57}function S(e){return v(e,x)}function C(e){const t=e.charCodeAt(0);return t>=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102}function T(e){return v(e,C)}function P(e){let t="",n="";for(;t=S(e);)n+=t;return n}function E(e){return"'"!==e&&e!==L}function A(e){const t=e.currentChar();switch(t){case"\\":case"'":return e.next(),`\\${t}`;case"u":return R(e,t,4);case"U":return R(e,t,6);default:return o(),""}}function R(e,t,n){h(e,t);let a="";for(let t=0;t=1&&o(),e.next(),n=c(t,2,"{"),f(e),t.braceNest++,n;case"}":return t.braceNest>0&&2===t.currentType&&o(),e.next(),n=c(t,3,"}"),t.braceNest--,t.braceNest>0&&f(e),t.inLinked&&0===t.braceNest&&(t.inLinked=!1),n;case"@":return t.braceNest>0&&o(),n=j(e,t)||d(t),t.braceNest=0,n;default:{let a=!0,i=!0,r=!0;if(g(e))return t.braceNest>0&&o(),n=c(t,1,q(e)),t.braceNest=0,t.inLinked=!1,n;if(t.braceNest>0&&(4===t.currentType||5===t.currentType||6===t.currentType))return o(),t.braceNest=0,B(e,t);if(a=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a=m(e.currentPeek());return e.resetPeek(),a}(e,t))return n=c(t,4,function(e){f(e);let t="",n="";for(;t=k(e);)n+=t;const a=e.currentChar();if(a&&"}"!==a&&a!==O&&a!==M&&a!==L&&" "!==a){const t=I(e);return o(),n+t}return e.currentChar()===O&&o(),n}(e)),f(e),n;if(i=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a=function(e){if(e===O)return!1;const t=e.charCodeAt(0);return t>=48&&t<=57}("-"===e.currentPeek()?e.peek():e.currentPeek());return e.resetPeek(),a}(e,t))return n=c(t,5,function(e){f(e);let t="";return"-"===e.currentChar()?(e.next(),t+=`-${P(e)}`):t+=P(e),e.currentChar()===O&&o(),t}(e)),f(e),n;if(r=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a="'"===e.currentPeek();return e.resetPeek(),a}(e,t))return n=c(t,6,function(e){f(e),h(e,"'");let t="",n="";for(;t=v(e,E);)n+="\\"===t?A(e):t;const a=e.currentChar();return a===L||a===O?(o(),a===L&&(e.next(),h(e,"'")),n):(h(e,"'"),n)}(e)),f(e),n;if(!a&&!i&&!r)return n=c(t,12,I(e)),o(),n.value,f(e),n;break}}return n}function j(e,t){const{currentType:n}=t;let a=null;const i=e.currentChar();switch(7!==n&&8!==n&&11!==n&&9!==n||i!==L&&i!==M||o(),i){case"@":return e.next(),a=c(t,7,"@"),t.inLinked=!0,a;case".":return f(e),e.next(),c(t,8,".");case":":return f(e),e.next(),c(t,9,":");default:return g(e)?(a=c(t,1,q(e)),t.braceNest=0,t.inLinked=!1,a):function(e,t){const{currentType:n}=t;if(7!==n)return!1;p(e);const a="."===e.currentPeek();return e.resetPeek(),a}(e,t)||function(e,t){const{currentType:n}=t;if(7!==n&&11!==n)return!1;p(e);const a=":"===e.currentPeek();return e.resetPeek(),a}(e,t)?(f(e),j(e,t)):function(e,t){const{currentType:n}=t;if(8!==n)return!1;p(e);const a=m(e.currentPeek());return e.resetPeek(),a}(e,t)?(f(e),c(t,11,function(e){let t="",n="";for(;t=y(e);)n+=t;return n}(e))):function(e,t){const{currentType:n}=t;if(9!==n)return!1;const a=()=>{const t=e.currentPeek();return"{"===t?m(e.peek()):!("@"===t||"|"===t||":"===t||"."===t||t===M||!t)&&(t===L?(e.peek(),a()):_(e,!1))},i=a();return e.resetPeek(),i}(e,t)?(f(e),"{"===i?D(e,t)||a:c(t,10,function(e){const t=n=>{const a=e.currentChar();return"{"!==a&&"@"!==a&&"|"!==a&&"("!==a&&")"!==a&&a?a===M?n:(n+=a,e.next(),t(n)):n};return t("")}(e))):(7===n&&o(),t.braceNest=0,t.inLinked=!1,B(e,t))}}function B(e,t){let n={type:13};if(t.braceNest>0)return D(e,t)||d(t);if(t.inLinked)return j(e,t)||d(t);switch(e.currentChar()){case"{":return D(e,t)||d(t);case"}":return o(),e.next(),c(t,3,"}");case"@":return j(e,t)||d(t);default:if(g(e))return n=c(t,1,q(e)),t.braceNest=0,t.inLinked=!1,n;if(_(e))return c(t,0,function(e){let t="";for(;;){const n=e.currentChar();if("{"===n||"}"===n||"@"===n||"|"===n||!n)break;if(n===M||n===L)if(_(e))t+=n,e.next();else{if(g(e))break;t+=n,e.next()}else t+=n,e.next()}return t}(e))}return n}return{nextToken:function(){const{currentType:e,offset:t,startLoc:n,endLoc:r}=l;return l.lastType=e,l.lastOffset=t,l.lastStartLoc=n,l.lastEndLoc=r,l.offset=i(),l.startLoc=o(),a.currentChar()===O?c(l,13):B(a,l)},currentOffset:i,currentPosition:o,context:()=>l}}const q=/(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;function D(e,t,n){switch(e){case"\\\\":return"\\";case"\\'":return"'";default:{const e=parseInt(t||n,16);return e<=55295||e>=57344?String.fromCodePoint(e):"�"}}}function j(e={}){const t=!1!==e.location,{onError:n}=e;function a(e,n,a){const i={type:e};return t&&(i.start=n,i.end=n,i.loc={start:a,end:a}),i}function i(e,n,a,i){t&&(e.end=n,e.loc&&(e.loc.end=a))}function o(e,t){const n=e.context(),o=a(3,n.offset,n.startLoc);return o.value=t,i(o,e.currentOffset(),e.currentPosition()),o}function r(e,t){const n=e.context(),{lastOffset:o,lastStartLoc:r}=n,s=a(5,o,r);return s.index=parseInt(t,10),e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function s(e,t){const n=e.context(),{lastOffset:o,lastStartLoc:r}=n,s=a(4,o,r);return s.key=t,e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function l(e,t){const n=e.context(),{lastOffset:o,lastStartLoc:r}=n,s=a(9,o,r);return s.value=t.replace(q,D),e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function u(e){const t=e.context(),n=a(6,t.offset,t.startLoc);let o=e.nextToken();if(8===o.type){const t=function(e){const t=e.nextToken(),n=e.context(),{lastOffset:o,lastStartLoc:r}=n,s=a(8,o,r);return 11!==t.type?(n.lastStartLoc,s.value="",i(s,o,r),{nextConsumeToken:t,node:s}):(null==t.value&&(n.lastStartLoc,B(t)),s.value=t.value||"",i(s,e.currentOffset(),e.currentPosition()),{node:s})}(e);n.modifier=t.node,o=t.nextConsumeToken||e.nextToken()}switch(9!==o.type&&(t.lastStartLoc,B(o)),o=e.nextToken(),2===o.type&&(o=e.nextToken()),o.type){case 10:null==o.value&&(t.lastStartLoc,B(o)),n.key=function(e,t){const n=e.context(),o=a(7,n.offset,n.startLoc);return o.value=t,i(o,e.currentOffset(),e.currentPosition()),o}(e,o.value||"");break;case 4:null==o.value&&(t.lastStartLoc,B(o)),n.key=s(e,o.value||"");break;case 5:null==o.value&&(t.lastStartLoc,B(o)),n.key=r(e,o.value||"");break;case 6:null==o.value&&(t.lastStartLoc,B(o)),n.key=l(e,o.value||"");break;default:{t.lastStartLoc;const r=e.context(),s=a(7,r.offset,r.startLoc);return s.value="",i(s,r.offset,r.startLoc),n.key=s,i(n,r.offset,r.startLoc),{nextConsumeToken:o,node:n}}}return i(n,e.currentOffset(),e.currentPosition()),{node:n}}function c(e){const t=e.context(),n=a(2,1===t.currentType?e.currentOffset():t.offset,1===t.currentType?t.endLoc:t.startLoc);n.items=[];let c=null;do{const a=c||e.nextToken();switch(c=null,a.type){case 0:null==a.value&&(t.lastStartLoc,B(a)),n.items.push(o(e,a.value||""));break;case 5:null==a.value&&(t.lastStartLoc,B(a)),n.items.push(r(e,a.value||""));break;case 4:null==a.value&&(t.lastStartLoc,B(a)),n.items.push(s(e,a.value||""));break;case 6:null==a.value&&(t.lastStartLoc,B(a)),n.items.push(l(e,a.value||""));break;case 7:{const t=u(e);n.items.push(t.node),c=t.nextConsumeToken||null;break}}}while(13!==t.currentType&&1!==t.currentType);return i(n,1===t.currentType?t.lastOffset:e.currentOffset(),1===t.currentType?t.lastEndLoc:e.currentPosition()),n}return{parse:function(n){const o=I(n,d({},e)),r=o.context(),s=a(0,r.offset,r.startLoc);return t&&s.loc&&(s.loc.source=n),s.body=function(e){const t=e.context(),{offset:n,startLoc:o}=t,r=c(e);return 13===t.currentType?r:function(e,t,n,o){const r=e.context();let s=0===o.items.length;const l=a(1,t,n);l.cases=[],l.cases.push(o);do{const t=c(e);s||(s=0===t.items.length),l.cases.push(t)}while(13!==r.currentType);return i(l,e.currentOffset(),e.currentPosition()),l}(e,n,o,r)}(o),e.onCacheKey&&(s.cacheKey=e.onCacheKey(n)),13!==r.currentType&&(r.lastStartLoc,n[r.offset]),i(s,o.currentOffset(),o.currentPosition()),s}}}function B(e){if(13===e.type)return"EOF";const t=(e.value||"").replace(/\r?\n/gu,"\\n");return t.length>10?t.slice(0,9)+"…":t}function F(e,t){for(let n=0;n1){e.push(`${n("plural")}([`),e.indent(a());const i=t.cases.length;for(let n=0;n{const n=y(t.mode)?t.mode:"normal",a=y(t.filename)?t.filename:"message.intl",i=!!t.sourceMap,o=null!=t.breakLineCode?t.breakLineCode:"arrow"===n?";":"\n",r=t.needIndent?t.needIndent:"arrow"!==n,s=e.helpers||[],l=function(e,t){const{sourceMap:n,filename:a,breakLineCode:i,needIndent:o}=t,r={filename:a,code:"",column:1,line:1,offset:0,map:void 0,breakLineCode:i,needIndent:o,indentLevel:0};function s(e,t){r.code+=e}function l(e,t=!0){const n=t?i:"";s(o?n+" ".repeat(e):n)}return!1!==t.location&&e.loc&&(r.source=e.loc.source),{context:()=>r,push:s,indent:function(e=!0){const t=++r.indentLevel;e&&l(t)},deindent:function(e=!0){const t=--r.indentLevel;e&&l(t)},newline:function(){l(r.indentLevel)},helper:e=>`_${e}`,needIndent:()=>r.needIndent}}(e,{mode:n,filename:a,sourceMap:i,breakLineCode:o,needIndent:r});l.push("normal"===n?"function __msg__ (ctx) {":"(ctx) => {"),l.indent(r),s.length>0&&(l.push(`const { ${T(s.map(e=>`${e}: _${e}`),", ")} } = ctx`),l.newline()),l.push("return "),H(l,e),l.deindent(r),l.push("}"),delete e.helpers;const{code:u,map:c}=l.context();return{ast:e,code:u,map:c?c.toJSON():void 0}};function G(e,t={}){const n=d({},t),a=!!n.jit,i=!!n.minify,o=null==n.optimize||n.optimize,r=j(n).parse(e);return a?(o&&function(e){const t=e.body;2===t.type?V(t):t.cases.forEach(e=>V(e))}(r),i&&U(r),{ast:r,code:""}):(function(e){const t=function(e){const t={ast:e,helpers:new Set};return{context:()=>t,helper:e=>(t.helpers.add(e),e)}}(e);t.helper("normalize"),e.body&&$(e.body,t);const n=t.context();e.helpers=Array.from(n.helpers)}(r,n),W(r,n))}function K(e){return k(e)&&0===ee(e)&&(_(e,"b")||_(e,"body"))}const Y=["b","body"],Q=["c","cases"],Z=["s","static"],J=["i","items"],X=["t","type"];function ee(e){return ie(e,X)}const te=["v","value"];const ne=["m","modifier"],ae=["k","key"];function ie(e,t,n){for(let n=0;nfunction(e,t){const n=ie(t,Y);if(null==n)throw re(0);if(1===ee(n)){const t=function(e){return ie(e,Q,[])}(n);return e.plural(t.reduce((t,n)=>[...t,le(e,n)],[]))}return le(e,n)}(t,e)}function le(e,t){const n=function(e){return ie(e,Z)}(t);if(null!=n)return"text"===e.type?n:e.normalize([n]);{const n=function(e){return ie(e,J,[])}(t).reduce((t,n)=>[...t,ue(e,n)],[]);return e.normalize(n)}}function ue(e,t){const n=ee(t);switch(n){case 3:case 9:case 7:case 8:return function(e,t){const n=ie(e,te);if(null!=n)return n;throw re(t)}(t,n);case 4:{const a=t;if(_(a,"k")&&a.k)return e.interpolate(e.named(a.k));if(_(a,"key")&&a.key)return e.interpolate(e.named(a.key));throw re(n)}case 5:{const a=t;if(_(a,"i")&&l(a.i))return e.interpolate(e.list(a.i));if(_(a,"index")&&l(a.index))return e.interpolate(e.list(a.index));throw re(n)}case 6:{const n=t,a=function(e){return ie(e,ne)}(n),i=function(e){const t=ie(e,ae);if(t)return t;throw re(6)}(n);return e.linked(ue(e,i),a?ue(e,a):void 0,e.type)}default:throw new Error(`unhandled node on format message part: ${n}`)}}const ce=e=>e;let de=p();const he=17,pe=18,fe=19,me=21,ge=22,_e=23;function ve(e,t){return null!=t.locale?ye(t.locale):ye(e.locale)}let be;function ye(e){if(y(e))return e;if(b(e)){if(e.resolvedOnce&&null!=be)return be;if("Function"===e.constructor.name){const t=e();if((e=>k(e)&&b(e.then)&&b(e.catch))(t))throw Error(me);return be=t}throw Error(ge)}throw Error(_e)}function we(e,t,n){return[...new Set([n,...v(t)?t:k(t)?Object.keys(t):y(t)?[t]:[n]])]}function ke(e,t,n){const a=y(n)?n:Le,i=e;i.__localeChainCache||(i.__localeChainCache=new Map);let o=i.__localeChainCache.get(a);if(!o){o=[];let e=[n];for(;v(e);)e=xe(o,e,t);const r=v(t)||!C(t)?t:t.default?t.default:null;e=y(r)?[r]:r,v(e)&&xe(o,e,!1),i.__localeChainCache.set(a,o)}return o}function xe(e,t,n){let a=!0;for(let i=0;i`${e.charAt(0).toLocaleUpperCase()}${e.substr(1)}`;let ze,Ne,Oe,Ie=null;const qe=e=>{Ie=e};let De=0;function je(e={}){const t=b(e.onWarn)?e.onWarn:a,n=y(e.version)?e.version:"11.2.2",i=y(e.locale)||b(e.locale)?e.locale:Le,o=b(i)?Le:i,r=v(e.fallbackLocale)||C(e.fallbackLocale)||y(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:o,s=C(e.messages)?e.messages:Be(o),l=C(e.datetimeFormats)?e.datetimeFormats:Be(o),c=C(e.numberFormats)?e.numberFormats:Be(o),h=d(p(),e.modifiers,{upper:(e,t)=>"text"===t&&y(e)?e.toUpperCase():"vnode"===t&&k(e)&&"__v_isVNode"in e?e.children.toUpperCase():e,lower:(e,t)=>"text"===t&&y(e)?e.toLowerCase():"vnode"===t&&k(e)&&"__v_isVNode"in e?e.children.toLowerCase():e,capitalize:(e,t)=>"text"===t&&y(e)?Re(e):"vnode"===t&&k(e)&&"__v_isVNode"in e?Re(e.children):e}),f=e.pluralRules||p(),m=b(e.missing)?e.missing:null,g=!w(e.missingWarn)&&!u(e.missingWarn)||e.missingWarn,_=!w(e.fallbackWarn)&&!u(e.fallbackWarn)||e.fallbackWarn,x=!!e.fallbackFormat,S=!!e.unresolving,T=b(e.postTranslation)?e.postTranslation:null,P=C(e.processor)?e.processor:null,E=!w(e.warnHtmlMessage)||e.warnHtmlMessage,A=!!e.escapeParameter,M=b(e.messageCompiler)?e.messageCompiler:ze,L=b(e.messageResolver)?e.messageResolver:Ne||Me,R=b(e.localeFallbacker)?e.localeFallbacker:Oe||we,z=k(e.fallbackContext)?e.fallbackContext:void 0,N=e,O=k(N.__datetimeFormatters)?N.__datetimeFormatters:new Map,I=k(N.__numberFormatters)?N.__numberFormatters:new Map,q=k(N.__meta)?N.__meta:{};De++;const D={version:n,cid:De,locale:i,fallbackLocale:r,messages:s,modifiers:h,pluralRules:f,missing:m,missingWarn:g,fallbackWarn:_,fallbackFormat:x,unresolving:S,postTranslation:T,processor:P,warnHtmlMessage:E,escapeParameter:A,messageCompiler:M,messageResolver:L,localeFallbacker:R,fallbackContext:z,onWarn:t,__meta:q};return D.datetimeFormats=l,D.numberFormats=c,D.__datetimeFormatters=O,D.__numberFormatters=I,D}const Be=e=>({[e]:p()});function Fe(e,t,n,a,i){const{missing:o,onWarn:r}=e;if(null!==o){const a=o(e,n,t,i);return y(a)?a:t}return t}function $e(e,t,n){e.__localeChainCache=new Map,e.localeFallbacker(e,n,t)}function Ve(e,t){const n=t.indexOf(e);if(-1===n)return!1;for(let o=n+1;o"[object Date]"===S(e))(t)){if(isNaN(t.getTime()))throw Error(pe);r=t}else{if(!l(t))throw Error(he);r=t}return y(n)?o.key=n:C(n)&&Object.keys(n).forEach(e=>{He.includes(e)?s[e]=n[e]:o[e]=n[e]}),y(a)?o.locale=a:C(a)&&(s=a),C(i)&&(s=i),[o.key||"",r,o,s]}function Ge(e,t,n){const a=e;for(const e in n){const n=`${t}__${e}`;a.__datetimeFormatters.has(n)&&a.__datetimeFormatters.delete(n)}}function Ke(e,...t){const{numberFormats:n,unresolving:a,fallbackLocale:i,onWarn:o,localeFallbacker:r}=e,{__numberFormatters:s}=e,[l,u,h,p]=Qe(...t);w(h.missingWarn)?h.missingWarn:e.missingWarn,w(h.fallbackWarn)?h.fallbackWarn:e.fallbackWarn;const f=!!h.part,m=ve(e,h),g=r(e,i,m);if(!y(l)||""===l)return new Intl.NumberFormat(m,p).format(u);let _,v={},b=null;for(let t=0;t{Ye.includes(e)?r[e]=n[e]:o[e]=n[e]}),y(a)?o.locale=a:C(a)&&(r=a),C(i)&&(r=i),[o.key||"",s,o,r]}function Ze(e,t,n){const a=e;for(const e in n){const n=`${t}__${e}`;a.__numberFormatters.has(n)&&a.__numberFormatters.delete(n)}}const Je=e=>e,Xe=e=>"",et=e=>0===e.length?"":T(e),tt=e=>null==e?"":v(e)||C(e)&&e.toString===x?JSON.stringify(e,null,2):String(e);function nt(e,t){return e=Math.abs(e),2===t?e?e>1?1:0:1:e?Math.min(e,2):0}function at(e={}){const t=e.locale,n=function(e){const t=l(e.pluralIndex)?e.pluralIndex:-1;return e.named&&(l(e.named.count)||l(e.named.n))?l(e.named.count)?e.named.count:l(e.named.n)?e.named.n:t:t}(e),a=k(e.pluralRules)&&y(t)&&b(e.pluralRules[t])?e.pluralRules[t]:nt,i=k(e.pluralRules)&&y(t)&&b(e.pluralRules[t])?nt:void 0,o=e.list||[],r=e.named||p();function s(t,n){return(b(e.messages)?e.messages(t,!!n):!!k(e.messages)&&e.messages[t])||(e.parent?e.parent.message(t):Xe)}l(e.pluralIndex)&&function(e,t){t.count||(t.count=e),t.n||(t.n=e)}(n,r);const u=C(e.processor)&&b(e.processor.normalize)?e.processor.normalize:et,c=C(e.processor)&&b(e.processor.interpolate)?e.processor.interpolate:tt,h={list:e=>o[e],named:e=>r[e],plural:e=>e[a(n,e.length,i)],linked:(t,...n)=>{const[a,i]=n;let o="text",r="";1===n.length?k(a)?(r=a.modifier||r,o=a.type||o):y(a)&&(r=a||r):2===n.length&&(y(a)&&(r=a||r),y(i)&&(o=i||o));const l=s(t,!0)(h),u="vnode"===o&&v(l)&&r?l[0]:l;return r?(c=r,e.modifiers?e.modifiers[c]:Je)(u,o):u;var c},message:s,type:C(e.processor)&&y(e.processor.type)?e.processor.type:"text",interpolate:c,normalize:u,values:d(p(),o,r)};return h}const it=()=>"",ot=e=>b(e);function rt(e,...t){const{fallbackFormat:n,postTranslation:a,unresolving:i,messageCompiler:o,fallbackLocale:r,messages:s}=e,[u,c]=ut(...t),d=w(c.missingWarn)?c.missingWarn:e.missingWarn,h=w(c.fallbackWarn)?c.fallbackWarn:e.fallbackWarn,g=w(c.escapeParameter)?c.escapeParameter:e.escapeParameter,_=!!c.resolvedMessage,x=y(c.default)||w(c.default)?w(c.default)?o?u:()=>u:c.default:n?o?u:()=>u:null,S=n||null!=x&&(y(x)||b(x)),C=ve(e,c);g&&function(e){v(e.list)?e.list=e.list.map(e=>y(e)?f(e):e):k(e.named)&&Object.keys(e.named).forEach(t=>{y(e.named[t])&&(e.named[t]=f(e.named[t]))})}(c);let[T,P,E]=_?[u,C,s[C]||p()]:st(e,u,C,r,h,d),A=T,M=u;if(_||y(A)||K(A)||ot(A)||S&&(A=x,M=A),!(_||(y(A)||K(A)||ot(A))&&y(P)))return i?-1:u;let L=!1;const R=ot(A)?A:lt(e,u,P,A,M,()=>{L=!0});if(L)return A;const z=function(e,t,n,a){const{modifiers:i,pluralRules:o,messageResolver:r,fallbackLocale:s,fallbackWarn:u,missingWarn:c,fallbackContext:d}=e,h={locale:t,modifiers:i,pluralRules:o,messages:(a,i)=>{let o=r(n,a);if(null==o&&(d||i)){const[,,n]=st(d||e,a,t,s,u,c);o=r(n,a)}if(y(o)||K(o)){let n=!1;const i=lt(e,a,t,o,a,()=>{n=!0});return n?it:i}return ot(o)?o:it}};return e.processor&&(h.processor=e.processor),a.list&&(h.list=a.list),a.named&&(h.named=a.named),l(a.plural)&&(h.pluralIndex=a.plural),h}(e,P,E,c),N=function(e,t,n){return t(n)}(0,R,at(z));let O=a?a(N,u):N;var I;return g&&y(O)&&(I=(I=(I=O).replace(/(\w+)\s*=\s*"([^"]*)"/g,(e,t,n)=>`${t}="${m(n)}"`)).replace(/(\w+)\s*=\s*'([^']*)'/g,(e,t,n)=>`${t}='${m(n)}'`),/\s*on\w+\s*=\s*["']?[^"'>]+["']?/gi.test(I)&&(I=I.replace(/(\s+)(on)(\w+\s*=)/gi,"$1on$3")),[/(\s+(?:href|src|action|formaction)\s*=\s*["']?)\s*javascript:/gi,/(style\s*=\s*["'][^"']*url\s*\(\s*)javascript:/gi].forEach(e=>{I=I.replace(e,"$1javascript:")}),O=I),O}function st(e,t,n,a,i,o){const{messages:r,onWarn:s,messageResolver:l,localeFallbacker:u}=e,c=u(e,a,n);let d,h=p(),f=null;for(let n=0;na;return e.locale=n,e.key=t,e}const u=s(a,function(e,t,n,a,i,o){return{locale:t,key:n,warnHtmlMessage:i,onError:e=>{throw o&&o(e),e},onCacheKey:e=>r(t,n,e)}}(0,n,i,0,l,o));return u.locale=n,u.key=t,u.source=a,u}function ut(...e){const[t,n,a]=e,i=p();if(!(y(t)||l(t)||ot(t)||K(t)))throw Error(he);const o=l(t)?String(t):(ot(t),t);return l(n)?i.plural=n:y(n)?i.default=n:C(n)&&!c(n)?i.named=n:v(n)&&(i.list=n),l(a)?i.plural=a:y(a)?i.default=a:C(a)&&d(i,a),[o,i]}const ct="11.2.2",dt=24,ht=25,pt=26,ft=27,mt=28,gt=29,_t=31,vt=32,bt=o("__translateVNode"),yt=o("__datetimeParts"),wt=o("__numberParts"),kt=o("__setPluralRules"),xt=o("__injectWithOption"),St=o("__dispose");function Ct(e){if(!k(e))return e;if(K(e))return e;for(const t in e)if(_(e,t))if(t.includes(".")){const n=t.split("."),a=n.length-1;let i=e,o=!1;for(let e=0;e{if("locale"in e&&"resource"in e){const{locale:t,resource:n}=e;t?(r[t]=r[t]||p(),E(n,r[t])):E(n,r)}else y(e)&&E(JSON.parse(e),r)}),null==i&&o)for(const e in r)_(r,e)&&Ct(r[e]);return r}function Pt(e,t,n){let a=k(t.messages)?t.messages:p();"__i18nGlobal"in n&&(a=Tt(e.locale.value,{messages:a,__i18n:n.__i18nGlobal}));const i=Object.keys(a);if(i.length&&i.forEach(t=>{e.mergeLocaleMessage(t,a[t])}),k(t.datetimeFormats)){const n=Object.keys(t.datetimeFormats);n.length&&n.forEach(n=>{e.mergeDateTimeFormat(n,t.datetimeFormats[n])})}if(k(t.numberFormats)){const n=Object.keys(t.numberFormats);n.length&&n.forEach(n=>{e.mergeNumberFormat(n,t.numberFormats[n])})}}function Et(e){return t.createVNode(t.Text,null,e,0)}function At(){return"currentInstance"in n?n.currentInstance:n.getCurrentInstance()}const Mt=()=>[],Lt=()=>!1;let Rt=0;function zt(e){return(t,n,a,i)=>e(n,a,At()||void 0,i)}function Nt(e={}){const{__root:n,__injectWithOption:a}=e,o=void 0===n,r=e.flatJson,s=i?t.ref:t.shallowRef;let c=!w(e.inheritLocale)||e.inheritLocale;const h=s(n&&c?n.locale.value:y(e.locale)?e.locale:Le),p=s(n&&c?n.fallbackLocale.value:y(e.fallbackLocale)||v(e.fallbackLocale)||C(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:h.value),f=s(Tt(h.value,e)),m=s(C(e.datetimeFormats)?e.datetimeFormats:{[h.value]:{}}),g=s(C(e.numberFormats)?e.numberFormats:{[h.value]:{}});let x=n?n.missingWarn:!w(e.missingWarn)&&!u(e.missingWarn)||e.missingWarn,S=n?n.fallbackWarn:!w(e.fallbackWarn)&&!u(e.fallbackWarn)||e.fallbackWarn,T=n?n.fallbackRoot:!w(e.fallbackRoot)||e.fallbackRoot,P=!!e.fallbackFormat,A=b(e.missing)?e.missing:null,M=b(e.missing)?zt(e.missing):null,L=b(e.postTranslation)?e.postTranslation:null,R=n?n.warnHtmlMessage:!w(e.warnHtmlMessage)||e.warnHtmlMessage,z=!!e.escapeParameter;const N=n?n.modifiers:C(e.modifiers)?e.modifiers:{};let O,I=e.pluralRules||n&&n.pluralRules;O=(()=>{o&&qe(null);const t={version:ct,locale:h.value,fallbackLocale:p.value,messages:f.value,modifiers:N,pluralRules:I,missing:null===M?void 0:M,missingWarn:x,fallbackWarn:S,fallbackFormat:P,unresolving:!0,postTranslation:null===L?void 0:L,warnHtmlMessage:R,escapeParameter:z,messageResolver:e.messageResolver,messageCompiler:e.messageCompiler,__meta:{framework:"vue"}};t.datetimeFormats=m.value,t.numberFormats=g.value,t.__datetimeFormatters=C(O)?O.__datetimeFormatters:void 0,t.__numberFormatters=C(O)?O.__numberFormatters:void 0;const n=je(t);return o&&qe(n),n})(),$e(O,h.value,p.value);const q=t.computed({get:()=>h.value,set:e=>{O.locale=e,h.value=e}}),D=t.computed({get:()=>p.value,set:e=>{O.fallbackLocale=e,p.value=e,$e(O,h.value,e)}}),j=t.computed(()=>f.value),B=t.computed(()=>m.value),F=t.computed(()=>g.value),$=(e,t,a,i,r,s)=>{let u;h.value,p.value,f.value,m.value,g.value;try{o||(O.fallbackContext=n?Ie:void 0),u=e(O)}finally{o||(O.fallbackContext=void 0)}if("translate exists"!==a&&l(u)&&-1===u||"translate exists"===a&&!u){const[e,a]=t();return n&&T?i(n):r(e)}if(s(u))return u;throw Error(dt)};function V(...e){return $(t=>Reflect.apply(rt,null,[t,...e]),()=>ut(...e),"translate",t=>Reflect.apply(t.t,t,[...e]),e=>e,e=>y(e))}const U={normalize:function(e){return e.map(e=>y(e)||l(e)||w(e)?Et(String(e)):e)},interpolate:e=>e,type:"vnode"};function H(e){return f.value[e]||{}}Rt++,n&&i&&(t.watch(n.locale,e=>{c&&(h.value=e,O.locale=e,$e(O,h.value,p.value))}),t.watch(n.fallbackLocale,e=>{c&&(p.value=e,O.fallbackLocale=e,$e(O,h.value,p.value))}));const W={id:Rt,locale:q,fallbackLocale:D,get inheritLocale(){return c},set inheritLocale(e){c=e,e&&n&&(h.value=n.locale.value,p.value=n.fallbackLocale.value,$e(O,h.value,p.value))},get availableLocales(){return Object.keys(f.value).sort()},messages:j,get modifiers(){return N},get pluralRules(){return I||{}},get isGlobal(){return o},get missingWarn(){return x},set missingWarn(e){x=e,O.missingWarn=x},get fallbackWarn(){return S},set fallbackWarn(e){S=e,O.fallbackWarn=S},get fallbackRoot(){return T},set fallbackRoot(e){T=e},get fallbackFormat(){return P},set fallbackFormat(e){P=e,O.fallbackFormat=P},get warnHtmlMessage(){return R},set warnHtmlMessage(e){R=e,O.warnHtmlMessage=e},get escapeParameter(){return z},set escapeParameter(e){z=e,O.escapeParameter=e},t:V,getLocaleMessage:H,setLocaleMessage:function(e,t){if(r){const n={[e]:t};for(const e in n)_(n,e)&&Ct(n[e]);t=n[e]}f.value[e]=t,O.messages=f.value},mergeLocaleMessage:function(e,t){f.value[e]=f.value[e]||{};const n={[e]:t};if(r)for(const e in n)_(n,e)&&Ct(n[e]);E(t=n[e],f.value[e]),O.messages=f.value},getPostTranslationHandler:function(){return b(L)?L:null},setPostTranslationHandler:function(e){L=e,O.postTranslation=e},getMissingHandler:function(){return A},setMissingHandler:function(e){null!==e&&(M=zt(e)),A=e,O.missing=M},[kt]:function(e){I=e,O.pluralRules=I}};return W.datetimeFormats=B,W.numberFormats=F,W.rt=function(...e){const[t,n,a]=e;if(a&&!k(a))throw Error(ht);return V(t,n,d({resolvedMessage:!0},a||{}))},W.te=function(e,t){return $(()=>{if(!e)return!1;const n=H(y(t)?t:h.value),a=O.messageResolver(n,e);return K(a)||ot(a)||y(a)},()=>[e],"translate exists",n=>Reflect.apply(n.te,n,[e,t]),Lt,e=>w(e))},W.tm=function(e){const t=function(e){let t=null;const n=ke(O,p.value,h.value);for(let a=0;aReflect.apply(Ue,null,[t,...e]),()=>We(...e),"datetime format",t=>Reflect.apply(t.d,t,[...e]),()=>"",e=>y(e)||v(e))},W.n=function(...e){return $(t=>Reflect.apply(Ke,null,[t,...e]),()=>Qe(...e),"number format",t=>Reflect.apply(t.n,t,[...e]),()=>"",e=>y(e)||v(e))},W.getDateTimeFormat=function(e){return m.value[e]||{}},W.setDateTimeFormat=function(e,t){m.value[e]=t,O.datetimeFormats=m.value,Ge(O,e,t)},W.mergeDateTimeFormat=function(e,t){m.value[e]=d(m.value[e]||{},t),O.datetimeFormats=m.value,Ge(O,e,t)},W.getNumberFormat=function(e){return g.value[e]||{}},W.setNumberFormat=function(e,t){g.value[e]=t,O.numberFormats=g.value,Ze(O,e,t)},W.mergeNumberFormat=function(e,t){g.value[e]=d(g.value[e]||{},t),O.numberFormats=g.value,Ze(O,e,t)},W[xt]=a,W[bt]=function(...e){return $(t=>{let n;const a=t;try{a.processor=U,n=Reflect.apply(rt,null,[a,...e])}finally{a.processor=null}return n},()=>ut(...e),"translate",t=>t[bt](...e),e=>[Et(e)],e=>v(e))},W[yt]=function(...e){return $(t=>Reflect.apply(Ue,null,[t,...e]),()=>We(...e),"datetime format",t=>t[yt](...e),Mt,e=>y(e)||v(e))},W[wt]=function(...e){return $(t=>Reflect.apply(Ke,null,[t,...e]),()=>Qe(...e),"number format",t=>t[wt](...e),Mt,e=>y(e)||v(e))},W}function Ot(e={}){const t=Nt(function(e){const t=y(e.locale)?e.locale:Le,n=y(e.fallbackLocale)||v(e.fallbackLocale)||C(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:t,a=b(e.missing)?e.missing:void 0,i=!w(e.silentTranslationWarn)&&!u(e.silentTranslationWarn)||!e.silentTranslationWarn,o=!w(e.silentFallbackWarn)&&!u(e.silentFallbackWarn)||!e.silentFallbackWarn,r=!w(e.fallbackRoot)||e.fallbackRoot,s=!!e.formatFallbackMessages,l=C(e.modifiers)?e.modifiers:{},c=e.pluralizationRules,h=b(e.postTranslation)?e.postTranslation:void 0,p=!y(e.warnHtmlInMessage)||"off"!==e.warnHtmlInMessage,f=!!e.escapeParameterHtml,m=!w(e.sync)||e.sync;let g=e.messages;if(C(e.sharedMessages)){const t=e.sharedMessages;g=Object.keys(t).reduce((e,n)=>{const a=e[n]||(e[n]={});return d(a,t[n]),e},g||{})}const{__i18n:_,__root:k,__injectWithOption:x}=e,S=e.datetimeFormats,T=e.numberFormats;return{locale:t,fallbackLocale:n,messages:g,flatJson:e.flatJson,datetimeFormats:S,numberFormats:T,missing:a,missingWarn:i,fallbackWarn:o,fallbackRoot:r,fallbackFormat:s,modifiers:l,pluralRules:c,postTranslation:h,warnHtmlMessage:p,escapeParameter:f,messageResolver:e.messageResolver,inheritLocale:m,__i18n:_,__root:k,__injectWithOption:x}}(e)),{__extender:n}=e,a={id:t.id,get locale(){return t.locale.value},set locale(e){t.locale.value=e},get fallbackLocale(){return t.fallbackLocale.value},set fallbackLocale(e){t.fallbackLocale.value=e},get messages(){return t.messages.value},get datetimeFormats(){return t.datetimeFormats.value},get numberFormats(){return t.numberFormats.value},get availableLocales(){return t.availableLocales},get missing(){return t.getMissingHandler()},set missing(e){t.setMissingHandler(e)},get silentTranslationWarn(){return w(t.missingWarn)?!t.missingWarn:t.missingWarn},set silentTranslationWarn(e){t.missingWarn=w(e)?!e:e},get silentFallbackWarn(){return w(t.fallbackWarn)?!t.fallbackWarn:t.fallbackWarn},set silentFallbackWarn(e){t.fallbackWarn=w(e)?!e:e},get modifiers(){return t.modifiers},get formatFallbackMessages(){return t.fallbackFormat},set formatFallbackMessages(e){t.fallbackFormat=e},get postTranslation(){return t.getPostTranslationHandler()},set postTranslation(e){t.setPostTranslationHandler(e)},get sync(){return t.inheritLocale},set sync(e){t.inheritLocale=e},get warnHtmlInMessage(){return t.warnHtmlMessage?"warn":"off"},set warnHtmlInMessage(e){t.warnHtmlMessage="off"!==e},get escapeParameterHtml(){return t.escapeParameter},set escapeParameterHtml(e){t.escapeParameter=e},get pluralizationRules(){return t.pluralRules||{}},__composer:t,t:(...e)=>Reflect.apply(t.t,t,[...e]),rt:(...e)=>Reflect.apply(t.rt,t,[...e]),te:(e,n)=>t.te(e,n),tm:e=>t.tm(e),getLocaleMessage:e=>t.getLocaleMessage(e),setLocaleMessage(e,n){t.setLocaleMessage(e,n)},mergeLocaleMessage(e,n){t.mergeLocaleMessage(e,n)},d:(...e)=>Reflect.apply(t.d,t,[...e]),getDateTimeFormat:e=>t.getDateTimeFormat(e),setDateTimeFormat(e,n){t.setDateTimeFormat(e,n)},mergeDateTimeFormat(e,n){t.mergeDateTimeFormat(e,n)},n:(...e)=>Reflect.apply(t.n,t,[...e]),getNumberFormat:e=>t.getNumberFormat(e),setNumberFormat(e,n){t.setNumberFormat(e,n)},mergeNumberFormat(e,n){t.mergeNumberFormat(e,n)}};return a.__extender=n,a}function It(e,t){e.locale=t.locale||e.locale,e.fallbackLocale=t.fallbackLocale||e.fallbackLocale,e.missing=t.missing||e.missing,e.silentTranslationWarn=t.silentTranslationWarn||e.silentFallbackWarn,e.silentFallbackWarn=t.silentFallbackWarn||e.silentFallbackWarn,e.formatFallbackMessages=t.formatFallbackMessages||e.formatFallbackMessages,e.postTranslation=t.postTranslation||e.postTranslation,e.warnHtmlInMessage=t.warnHtmlInMessage||e.warnHtmlInMessage,e.escapeParameterHtml=t.escapeParameterHtml||e.escapeParameterHtml,e.sync=t.sync||e.sync,e.__composer[kt](t.pluralizationRules||e.pluralizationRules);const n=Tt(e.locale,{messages:t.messages,__i18n:t.__i18n});return Object.keys(n).forEach(t=>e.mergeLocaleMessage(t,n[t])),t.datetimeFormats&&Object.keys(t.datetimeFormats).forEach(n=>e.mergeDateTimeFormat(n,t.datetimeFormats[n])),t.numberFormats&&Object.keys(t.numberFormats).forEach(n=>e.mergeNumberFormat(n,t.numberFormats[n])),e}const qt={tag:{type:[String,Object]},locale:{type:String},scope:{type:String,validator:e=>"parent"===e||"global"===e,default:"parent"},i18n:{type:Object}};function Dt(){return t.Fragment}const jt=t.defineComponent({name:"i18n-t",props:d({keypath:{type:String,required:!0},plural:{type:[Number,String],validator:e=>l(e)||!isNaN(e)}},qt),setup(e,n){const{slots:a,attrs:i}=n,o=e.i18n||Kt({useScope:e.scope,__useComponent:!0});return()=>{const r=Object.keys(a).filter(e=>"_"!==e[0]),s=p();e.locale&&(s.locale=e.locale),void 0!==e.plural&&(s.plural=y(e.plural)?+e.plural:e.plural);const l=function({slots:e},n){return 1===n.length&&"default"===n[0]?(e.default?e.default():[]).reduce((e,n)=>[...e,...n.type===t.Fragment?n.children:[n]],[]):n.reduce((t,n)=>{const a=e[n];return a&&(t[n]=a()),t},p())}(n,r),u=o[bt](e.keypath,l,s),c=d(p(),i),h=y(e.tag)||k(e.tag)?e.tag:Dt();return t.h(h,c,u)}}}),Bt=jt;function Ft(e,n,a,i){const{slots:o,attrs:r}=n;return()=>{const n={part:!0};let s=p();e.locale&&(n.locale=e.locale),y(e.format)?n.key=e.format:k(e.format)&&(y(e.format.key)&&(n.key=e.format.key),s=Object.keys(e.format).reduce((t,n)=>a.includes(n)?d(p(),t,{[n]:e.format[n]}):t,p()));const l=i(e.value,n,s);let u=[n.key];v(l)?u=l.map((e,t)=>{const n=o[e.type],a=n?n({[e.type]:e.value,index:t,parts:l}):[e.value];var i;return v(i=a)&&!y(i[0])&&(a[0].key=`${e.type}-${t}`),a}):y(l)&&(u=[l]);const c=d(p(),r),h=y(e.tag)||k(e.tag)?e.tag:Dt();return t.h(h,c,u)}}const $t=t.defineComponent({name:"i18n-n",props:d({value:{type:Number,required:!0},format:{type:[String,Object]}},qt),setup(e,t){const n=e.i18n||Kt({useScope:e.scope,__useComponent:!0});return Ft(e,t,Ye,(...e)=>n[wt](...e))}}),Vt=$t;function Ut(e){const n=t=>{const{instance:n,value:a}=t;if(!n||!n.$)throw Error(vt);const i=function(e,t){const n=e;if("composition"===e.mode)return n.__getInstance(t)||e.global;{const a=n.__getInstance(t);return null!=a?a.__composer:e.global.__composer}}(e,n.$),o=Ht(a);return[Reflect.apply(i.t,i,[...Wt(o)]),i]};return{created:(a,o)=>{const[r,s]=n(o);i&&e.global===s&&(a.__i18nWatcher=t.watch(s.locale,()=>{o.instance&&o.instance.$forceUpdate()})),a.__composer=s,a.textContent=r},unmounted:e=>{i&&e.__i18nWatcher&&(e.__i18nWatcher(),e.__i18nWatcher=void 0,delete e.__i18nWatcher),e.__composer&&(e.__composer=void 0,delete e.__composer)},beforeUpdate:(e,{value:t})=>{if(e.__composer){const n=e.__composer,a=Ht(t);e.textContent=Reflect.apply(n.t,n,[...Wt(a)])}},getSSRProps:e=>{const[t]=n(e);return{textContent:t}}}}function Ht(e){if(y(e))return{path:e};if(C(e)){if(!("path"in e))throw Error(mt,"path");return e}throw Error(gt)}function Wt(e){const{path:t,locale:n,args:a,choice:i,plural:o}=e,r={},s=a||{};return y(n)&&(r.locale=n),l(i)&&(r.plural=i),l(o)&&(r.plural=o),[t,s,r]}const Gt=o("global-vue-i18n");function Kt(e={}){const n=At();if(null==n)throw Error(pt);if(!n.isCE&&null!=n.appContext.app&&!n.appContext.app.__VUE_I18N_SYMBOL__)throw Error(ft);const a=function(e){const n=t.inject(e.isCE?Gt:e.appContext.app.__VUE_I18N_SYMBOL__);if(!n)throw Error(e.isCE?_t:vt);return n}(n),i=function(e){return"composition"===e.mode?e.global:e.global.__composer}(a),o=function(e){return e.type}(n),r=function(e,t){return c(e)?"__i18n"in t?"local":"global":e.useScope?e.useScope:"local"}(e,o);if("global"===r)return Pt(i,e,o),i;if("parent"===r){let t=function(e,t,n=!1){let a=null;const i=t.root;let o=function(e,t=!1){return null==e?null:t&&e.vnode.ctx||e.parent}(t,n);for(;null!=o;){const t=e;if("composition"===e.mode)a=t.__getInstance(o);else{const e=t.__getInstance(o);null!=e&&(a=e.__composer,n&&a&&!a[xt]&&(a=null))}if(null!=a)break;if(i===o)break;o=o.parent}return a}(a,n,e.__useComponent);return null==t&&(t=i),t}const s=a;let l=s.__getInstance(n);if(null==l){const a=d({},e);"__i18n"in o&&(a.__i18n=o.__i18n),i&&(a.__root=i),l=Nt(a),s.__composerExtend&&(l[St]=s.__composerExtend(l)),function(e,n,a){t.onMounted(()=>{},n),t.onUnmounted(()=>{const t=a;e.__deleteInstance(n);const i=t[St];i&&(i(),delete t[St])},n)}(s,n,l),s.__setInstance(n,l)}return l}const Yt=["locale","fallbackLocale","availableLocales"],Qt=["t","rt","d","n","tm","te"],Zt=t.defineComponent({name:"i18n-d",props:d({value:{type:[Number,Date],required:!0},format:{type:[String,Object]}},qt),setup(e,t){const n=e.i18n||Kt({useScope:e.scope,__useComponent:!0});return Ft(e,t,He,(...e)=>n[yt](...e))}}),Jt=Zt;return ze=function(e,t){if(y(e)){!w(t.warnHtmlMessage)||t.warnHtmlMessage;const n=(t.onCacheKey||ce)(e),a=de[n];if(a)return a;const{ast:i,detectError:o}=function(e,t={}){let n=!1;const a=t.onError||A;return t.onError=e=>{n=!0,a(e)},{...G(e,t),detectError:n}}(e,{...t,location:!1,jit:!0}),r=se(i);return o?r:de[n]=r}{const t=e.cacheKey;if(t){return de[t]||(de[t]=se(e))}return se(e)}},Ne=function(e,t){if(!k(e))return null;let n=Ae.get(t);if(n||(n=function(e){const t=[];let n,a,i,o,r,s,l,u=-1,c=0,d=0;const h=[];function p(){const t=e[u+1];if(5===c&&"'"===t||6===c&&'"'===t)return u++,i="\\"+t,h[0](),!0}for(h[0]=()=>{void 0===a?a=i:a+=i},h[1]=()=>{void 0!==a&&(t.push(a),a=void 0)},h[2]=()=>{h[0](),d++},h[3]=()=>{if(d>0)d--,c=4,h[0]();else{if(d=0,void 0===a)return!1;if(a=function(e){const t=e.trim();return("0"!==e.charAt(0)||!isNaN(parseInt(e)))&&(n=t,Pe.test(n)?function(e){const t=e.charCodeAt(0);return t!==e.charCodeAt(e.length-1)||34!==t&&39!==t?e:e.slice(1,-1)}(t):"*"+t);var n}(a),!1===a)return!1;h[1]()}};null!==c;)if(u++,n=e[u],"\\"!==n||!p()){if(o=Ee(n),l=Te[c],r=l[o]||l.l||8,8===r)return;if(c=r[0],void 0!==r[1]&&(s=h[r[1]],s&&(i=n,!1===s())))return;if(7===c)return t}}(t),n&&Ae.set(t,n)),!n)return null;const a=n.length;let i=e,o=0;for(;oOt(e)):a.run(()=>Nt(e));if(null==i)throw Error(vt);return[a,i]}(e,n),l=o(""),u={get mode(){return n?"legacy":"composition"},async install(e,...i){if(e.__VUE_I18N_SYMBOL__=l,e.provide(e.__VUE_I18N_SYMBOL__,u),C(i[0])){const e=i[0];u.__composerExtend=e.__composerExtend,u.__vueI18nExtend=e.__vueI18nExtend}let o=null;!n&&a&&(o=function(e,n){const a=Object.create(null);Yt.forEach(e=>{const i=Object.getOwnPropertyDescriptor(n,e);if(!i)throw Error(vt);const o=t.isRef(i.value)?{get:()=>i.value.value,set(e){i.value.value=e}}:{get:()=>i.get&&i.get()};Object.defineProperty(a,e,o)}),e.config.globalProperties.$i18n=a,Qt.forEach(t=>{const a=Object.getOwnPropertyDescriptor(n,t);if(!a||!a.value)throw Error(vt);Object.defineProperty(e.config.globalProperties,`$${t}`,a)});return()=>{delete e.config.globalProperties.$i18n,Qt.forEach(t=>{delete e.config.globalProperties[`$${t}`]})}}(e,u.global)),function(e,t,...n){const a=C(n[0])?n[0]:{};(!w(a.globalInstall)||a.globalInstall)&&([jt.name,"I18nT"].forEach(t=>e.component(t,jt)),[$t.name,"I18nN"].forEach(t=>e.component(t,$t)),[Zt.name,"I18nD"].forEach(t=>e.component(t,Zt))),e.directive("t",Ut(t))}(e,u,...i),n&&e.mixin(function(e,t,n){return{beforeCreate(){const a=At();if(!a)throw Error(vt);const i=this.$options;if(i.i18n){const a=i.i18n;if(i.__i18n&&(a.__i18n=i.__i18n),a.__root=t,this===this.$root)this.$i18n=It(e,a);else{a.__injectWithOption=!0,a.__extender=n.__vueI18nExtend,this.$i18n=Ot(a);const e=this.$i18n;e.__extender&&(e.__disposer=e.__extender(this.$i18n))}}else if(i.__i18n)if(this===this.$root)this.$i18n=It(e,i);else{this.$i18n=Ot({__i18n:i.__i18n,__injectWithOption:!0,__extender:n.__vueI18nExtend,__root:t});const e=this.$i18n;e.__extender&&(e.__disposer=e.__extender(this.$i18n))}else this.$i18n=e;i.__i18nGlobal&&Pt(t,i,i),this.$t=(...e)=>this.$i18n.t(...e),this.$rt=(...e)=>this.$i18n.rt(...e),this.$te=(e,t)=>this.$i18n.te(e,t),this.$d=(...e)=>this.$i18n.d(...e),this.$n=(...e)=>this.$i18n.n(...e),this.$tm=e=>this.$i18n.tm(e),n.__setInstance(a,this.$i18n)},mounted(){},unmounted(){const e=At();if(!e)throw Error(vt);const t=this.$i18n;delete this.$t,delete this.$rt,delete this.$te,delete this.$d,delete this.$n,delete this.$tm,t.__disposer&&(t.__disposer(),delete t.__disposer,delete t.__extender),n.__deleteInstance(e),delete this.$i18n}}}(s,s.__composer,u));const r=e.unmount;e.unmount=()=>{o&&o(),u.dispose(),r()}},get global(){return s},dispose(){r.stop()},__instances:i,__getInstance:function(e){return i.get(e)||null},__setInstance:function(e,t){i.set(e,t)},__deleteInstance:function(e){i.delete(e)}};return u},e.useI18n=Kt,e.vTDirective=Ut,e}({},Vue),VueRouter=function(e,t){var n=Object.create,a=Object.defineProperty,i=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,r=Object.getPrototypeOf,s=Object.prototype.hasOwnProperty,l=(e,t)=>function(){return t||(0,e[o(e)[0]])((t={exports:{}}).exports,t),t.exports},u=(e,t,l)=>(l=null!=e?n(r(e)):{},((e,t,n,r)=>{if(t&&"object"==typeof t||"function"==typeof t)for(var l,u=o(t),c=0,d=u.length;ct[e]).bind(null,l),enumerable:!(r=i(t,l))||r.enumerable});return e})(!t&&e&&e.__esModule?l:a(l,"default",{value:e,enumerable:!0}),e));t=u(t);const c="undefined"!=typeof document;function d(e){return"object"==typeof e||"displayName"in e||"props"in e||"__vccOpts"in e}function h(e){return e.__esModule||"Module"===e[Symbol.toStringTag]||e.default&&d(e.default)}const p=Object.assign;function f(e,t){const n={};for(const a in t){const i=t[a];n[a]=g(i)?i.map(e):e(i)}return n}const m=()=>{},g=Array.isArray;function _(e,t){const n={};for(const a in e)n[a]=a in t?t[a]:e[a];return n}function v(e){const t=Array.from(arguments).slice(1);console.warn.apply(console,["[Vue Router warn]: "+e].concat(t))}const b=/#/g,y=/&/g,w=/\//g,k=/=/g,x=/\?/g,S=/\+/g,C=/%5B/g,T=/%5D/g,P=/%5E/g,E=/%60/g,A=/%7B/g,M=/%7C/g,L=/%7D/g,R=/%20/g;function z(e){return null==e?"":encodeURI(""+e).replace(M,"|").replace(C,"[").replace(T,"]")}function N(e){return z(e).replace(S,"%2B").replace(R,"+").replace(b,"%23").replace(y,"%26").replace(E,"`").replace(A,"{").replace(L,"}").replace(P,"^")}function O(e){return N(e).replace(k,"%3D")}function I(e){return function(e){return z(e).replace(b,"%23").replace(x,"%3F")}(e).replace(w,"%2F")}function q(e){if(null==e)return null;try{return decodeURIComponent(""+e)}catch(t){v(`Error decoding "${e}". Using original value`)}return""+e}const D=/\/$/;function j(e,t,n="/"){let a,i={},o="",r="";const s=t.indexOf("#");let l=t.indexOf("?");return l=s>=0&&l>s?-1:l,l>=0&&(a=t.slice(0,l),o=t.slice(l,s>0?s:t.length),i=e(o.slice(1))),s>=0&&(a=a||t.slice(0,s),r=t.slice(s,t.length)),a=function(e,t){if(e.startsWith("/"))return e;if(!t.startsWith("/"))return v(`Cannot resolve a relative location without an absolute path. Trying to resolve "${e}" from "${t}". It should look like "/${t}".`),e;if(!e)return t;const n=t.split("/"),a=e.split("/"),i=a[a.length-1];".."!==i&&"."!==i||a.push("");let o,r,s=n.length-1;for(o=0;o1&&s--}return n.slice(0,s).join("/")+"/"+a.slice(o).join("/")}(null!=a?a:t,n),{fullPath:a+o+r,path:a,query:i,hash:q(r)}}function B(e,t){return t&&e.toLowerCase().startsWith(t.toLowerCase())?e.slice(t.length)||"/":e}function F(e,t,n){const a=t.matched.length-1,i=n.matched.length-1;return a>-1&&a===i&&$(t.matched[a],n.matched[i])&&V(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function $(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function V(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!U(e[n],t[n]))return!1;return!0}function U(e,t){return g(e)?H(e,t):g(t)?H(t,e):e===t}function H(e,t){return g(t)?e.length===t.length&&e.every((e,n)=>e===t[n]):1===e.length&&e[0]===t}const W={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0};let G=function(e){return e.pop="pop",e.push="push",e}({}),K=function(e){return e.back="back",e.forward="forward",e.unknown="",e}({});function Y(e){if(!e)if(c){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(D,"")}const Q=/^[^#]+#/;function Z(e,t){return e.replace(Q,"#")+t}const J=()=>({left:window.scrollX,top:window.scrollY});function X(e){let t;if("el"in e){const n=e.el,a="string"==typeof n&&n.startsWith("#");if(!("string"!=typeof e.el||a&&document.getElementById(e.el.slice(1))))try{const t=document.querySelector(e.el);if(a&&t)return void v(`The selector "${e.el}" should be passed as "el: document.querySelector('${e.el}')" because it starts with "#".`)}catch(t){return void v(`The selector "${e.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`)}const i="string"==typeof n?a?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!i)return void v(`Couldn't find element using selector "${e.el}" returned by scrollBehavior.`);t=function(e,t){const n=document.documentElement.getBoundingClientRect(),a=e.getBoundingClientRect();return{behavior:t.behavior,left:a.left-n.left-(t.left||0),top:a.top-n.top-(t.top||0)}}(i,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.scrollX,null!=t.top?t.top:window.scrollY)}function ee(e,t){return(history.state?history.state.position-t:-1)+e}const te=new Map;function ne(e,t){const{pathname:n,search:a,hash:i}=t,o=e.indexOf("#");if(o>-1){let t=i.includes(e.slice(o))?e.slice(o).length:1,n=i.slice(t);return"/"!==n[0]&&(n="/"+n),B(n,"")}return B(n,e)+a+i}function ae(e,t,n,a=!1,i=!1){return{back:e,current:t,forward:n,replaced:a,position:window.history.length,scroll:i?J():null}}function ie(e){const{history:t,location:n}=window,a={value:ne(e,n)},i={value:t.state};function o(a,o,r){const s=e.indexOf("#"),l=s>-1?(n.host&&document.querySelector("base")?e:e.slice(s))+a:location.protocol+"//"+location.host+e+a;try{t[r?"replaceState":"pushState"](o,"",l),i.value=o}catch(e){v("Error with push/replace State",e),n[r?"replace":"assign"](l)}}return i.value||o(a.value,{back:null,current:a.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:a,state:i,push:function(e,n){const r=p({},i.value,t.state,{forward:e,scroll:J()});t.state||v("history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\n\nhistory.replaceState(history.state, '', url)\n\nYou can find more information at https://router.vuejs.org/guide/migration/#Usage-of-history-state"),o(r.current,r,!0),o(e,p({},ae(a.value,e,null),{position:r.position+1},n),!1),a.value=e},replace:function(e,n){o(e,p({},t.state,ae(i.value.back,e,i.value.forward,!0),n,{position:i.value.position}),!0),a.value=e}}}function oe(e){const t=ie(e=Y(e)),n=function(e,t,n,a){let i=[],o=[],r=null;const s=({state:o})=>{const s=ne(e,location),l=n.value,u=t.value;let c=0;if(o){if(n.value=s,t.value=o,r&&r===l)return void(r=null);c=u?o.position-u.position:0}else a(s);i.forEach(e=>{e(n.value,l,{delta:c,type:G.pop,direction:c?c>0?K.forward:K.back:K.unknown})})};function l(){if("hidden"===document.visibilityState){const{history:e}=window;if(!e.state)return;e.replaceState(p({},e.state,{scroll:J()}),"")}}return window.addEventListener("popstate",s),window.addEventListener("pagehide",l),document.addEventListener("visibilitychange",l),{pauseListeners:function(){r=n.value},listen:function(e){i.push(e);const t=()=>{const t=i.indexOf(e);t>-1&&i.splice(t,1)};return o.push(t),t},destroy:function(){for(const e of o)e();o=[],window.removeEventListener("popstate",s),window.removeEventListener("pagehide",l),document.removeEventListener("visibilitychange",l)}}}(e,t.state,t.location,t.replace);const a=p({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:Z.bind(null,e)},t,n);return Object.defineProperty(a,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(a,"state",{enumerable:!0,get:()=>t.state.value}),a}function re(e){return"string"==typeof e||e&&"object"==typeof e}function se(e){return"string"==typeof e||"symbol"==typeof e}let le=function(e){return e[e.MATCHER_NOT_FOUND=1]="MATCHER_NOT_FOUND",e[e.NAVIGATION_GUARD_REDIRECT=2]="NAVIGATION_GUARD_REDIRECT",e[e.NAVIGATION_ABORTED=4]="NAVIGATION_ABORTED",e[e.NAVIGATION_CANCELLED=8]="NAVIGATION_CANCELLED",e[e.NAVIGATION_DUPLICATED=16]="NAVIGATION_DUPLICATED",e}({});const ue=Symbol("navigation failure");let ce=function(e){return e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated",e}({});const de={[le.MATCHER_NOT_FOUND]:({location:e,currentLocation:t})=>`No match for\n ${JSON.stringify(e)}${t?"\nwhile being at\n"+JSON.stringify(t):""}`,[le.NAVIGATION_GUARD_REDIRECT]:({from:e,to:t})=>`Redirected from "${e.fullPath}" to "${function(e){if("string"==typeof e)return e;if(null!=e.path)return e.path;const t={};for(const n of fe)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}(t)}" via a navigation guard.`,[le.NAVIGATION_ABORTED]:({from:e,to:t})=>`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`,[le.NAVIGATION_CANCELLED]:({from:e,to:t})=>`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`,[le.NAVIGATION_DUPLICATED]:({from:e,to:t})=>`Avoided redundant navigation to current location: "${e.fullPath}".`};function he(e,t){return p(new Error(de[e](t)),{type:e,[ue]:!0},t)}function pe(e,t){return e instanceof Error&&ue in e&&(null==t||!!(e.type&t))}const fe=["params","query","hash"];let me=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e}({});var ge=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e}(ge||{});const _e={type:me.Static,value:""},ve=/[a-zA-Z0-9_]/;const be="[^/]+?",ye={sensitive:!1,strict:!1,start:!0,end:!0};var we=function(e){return e[e._multiplier=10]="_multiplier",e[e.Root=90]="Root",e[e.Segment=40]="Segment",e[e.SubSegment=30]="SubSegment",e[e.Static=40]="Static",e[e.Dynamic=20]="Dynamic",e[e.BonusCustomRegExp=10]="BonusCustomRegExp",e[e.BonusWildcard=-50]="BonusWildcard",e[e.BonusRepeatable=-20]="BonusRepeatable",e[e.BonusOptional=-8]="BonusOptional",e[e.BonusStrict=.7000000000000001]="BonusStrict",e[e.BonusCaseSensitive=.25]="BonusCaseSensitive",e}(we||{});const ke=/[.+*?^${}()[\]/\\]/g;function xe(e,t){let n=0;for(;nt.length?1===t.length&&t[0]===we.Static+we.Segment?1:-1:0}function Se(e,t){let n=0;const a=e.score,i=t.score;for(;n0&&t[t.length-1]<0}const Te={strict:!1,end:!0,sensitive:!1};function Pe(e,t,n){const a=function(e,t){const n=p({},ye,t),a=[];let i=n.start?"^":"";const o=[];for(const t of e){const e=t.length?[]:[we.Root];n.strict&&!t.length&&(i+="/");for(let a=0;a1&&("*"===s||"+"===s)&&t(`A repeatable param (${u}) must be alone in its segment. eg: '/:ids+.`),o.push({type:me.Param,value:u,regexp:c,repeatable:"*"===s||"+"===s,optional:"*"===s||"?"===s})):t("Invalid state to consume buffer"),u="")}function h(){u+=s}for(;l{o(h)}:m}function o(e){if(se(e)){const t=a.get(e);t&&(a.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(o),t.alias.forEach(o))}else{const t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&a.delete(e.record.name),e.children.forEach(o),e.alias.forEach(o))}}function r(e){const t=function(e,t){let n=0,a=t.length;for(;n!==a;){const i=n+a>>1;Se(e,t[i])<0?a=i:n=i+1}const i=function(e){let t=e;for(;t=t.parent;)if(De(t)&&0===Se(e,t))return t}(e);i&&(a=t.lastIndexOf(i,a-1),a<0&&v(`Finding ancestor route "${i.record.path}" failed for "${e.record.path}"`));return a}(e,n);n.splice(t,0,e),e.record.name&&!Re(e)&&a.set(e.record.name,e)}return t=_(Te,t),e.forEach(e=>i(e)),{addRoute:i,resolve:function(e,t){let i,o,r,s={};if("name"in e&&e.name){if(i=a.get(e.name),!i)throw he(le.MATCHER_NOT_FOUND,{location:e});{const t=Object.keys(e.params||{}).filter(e=>!i.keys.find(t=>t.name===e));t.length&&v(`Discarded invalid param(s) "${t.join('", "')}" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`)}r=i.record.name,s=p(Ae(t.params,i.keys.filter(e=>!e.optional).concat(i.parent?i.parent.keys.filter(e=>e.optional):[]).map(e=>e.name)),e.params&&Ae(e.params,i.keys.map(e=>e.name))),o=i.stringify(s)}else if(null!=e.path)o=e.path,o.startsWith("/")||v(`The Matcher cannot resolve relative paths but received "${o}". Unless you directly called \`matcher.resolve("${o}")\`, this is probably a bug in vue-router. Please open an issue at https://github.com/vuejs/router/issues/new/choose.`),i=n.find(e=>e.re.test(o)),i&&(s=i.parse(o),r=i.record.name);else{if(i=t.name?a.get(t.name):n.find(e=>e.re.test(t.path)),!i)throw he(le.MATCHER_NOT_FOUND,{location:e,currentLocation:t});r=i.record.name,s=p({},t.params,e.params),o=i.stringify(s)}const l=[];let u=i;for(;u;)l.unshift(u.record),u=u.parent;return{name:r,path:o,params:s,matched:l,meta:ze(l)}},removeRoute:o,clearRoutes:function(){n.length=0,a.clear()},getRoutes:function(){return n},getRecordMatcher:function(e){return a.get(e)}}}function Ae(e,t){const n={};for(const a of t)a in e&&(n[a]=e[a]);return n}function Me(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Le(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function Le(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const a in e.components)t[a]="object"==typeof n?n[a]:n;return t}function Re(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function ze(e){return e.reduce((e,t)=>p(e,t.meta),{})}function Ne(e,t){return e.name===t.name&&e.optional===t.optional&&e.repeatable===t.repeatable}function Oe(e,t){for(const n of e.keys)if(!n.optional&&!t.keys.find(Ne.bind(null,n)))return v(`Alias "${t.record.path}" and the original record: "${e.record.path}" must have the exact same param named "${n.name}"`);for(const n of t.keys)if(!n.optional&&!e.keys.find(Ne.bind(null,n)))return v(`Alias "${t.record.path}" and the original record: "${e.record.path}" must have the exact same param named "${n.name}"`)}function Ie(e,t){for(let n=t;n;n=n.parent)if(n.record.name===e.name)throw new Error(`A route named "${String(e.name)}" has been added as a ${t===n?"child":"descendant"} of a route with the same name. Route names must be unique and a nested route cannot use the same name as an ancestor.`)}function qe(e,t){for(const n of t.keys)if(!e.keys.find(Ne.bind(null,n)))return v(`Absolute path "${e.record.path}" must have the exact same param named "${n.name}" as its parent "${t.record.path}".`)}function De({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function je(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let e=0;ee&&N(e)):[a&&N(a)]).forEach(e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}):void 0!==a&&(t+=(t.length?"&":"")+n)}return t}function Fe(e){const t={};for(const n in e){const a=e[n];void 0!==a&&(t[n]=g(a)?a.map(e=>null==e?null:""+e):null==a?a:""+a)}return t}const $e=Symbol("router view location matched"),Ve=Symbol("router view depth"),Ue=Symbol("router"),He=Symbol("route location"),We=Symbol("router view location");function Ge(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e.slice(),reset:function(){e=[]}}}function Ke(e,n,a){const i=()=>{e[n].delete(a)};(0,t.onUnmounted)(i),(0,t.onDeactivated)(i),(0,t.onActivated)(()=>{e[n].add(a)}),e[n].add(a)}function Ye(e,t,n,a,i,o=e=>e()){const r=a&&(a.enterCallbacks[i]=a.enterCallbacks[i]||[]);return()=>new Promise((s,l)=>{const u=e=>{!1===e?l(he(le.NAVIGATION_ABORTED,{from:n,to:t})):e instanceof Error?l(e):re(e)?l(he(le.NAVIGATION_GUARD_REDIRECT,{from:t,to:e})):(r&&a.enterCallbacks[i]===r&&"function"==typeof e&&r.push(e),s())},c=o(()=>e.call(a&&a.instances[i],t,n,function(e,t,n){let a=0;return function(){1===a++&&v(`The "next" callback was called more than once in one navigation guard when going from "${n.fullPath}" to "${t.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`),e._called=!0,1===a&&e.apply(null,arguments)}}(u,t,n)));let d=Promise.resolve(c);if(e.length<3&&(d=d.then(u)),e.length>2){const t=`The "next" callback was never called inside of ${e.name?'"'+e.name+'"':""}:\n${e.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;if("object"==typeof c&&"then"in c)d=d.then(e=>u._called?e:(v(t),Promise.reject(new Error("Invalid navigation guard"))));else if(void 0!==c&&!u._called)return v(t),void l(new Error("Invalid navigation guard"))}d.catch(e=>l(e))})}function Qe(e,t,n,a,i=e=>e()){const o=[];for(const r of e){r.components||!r.children||r.children.length||v(`Record with path "${r.path}" is either missing a "component(s)" or "children" property.`);for(const e in r.components){let s=r.components[e];if(!s||"object"!=typeof s&&"function"!=typeof s)throw v(`Component "${e}" in record with path "${r.path}" is not a valid component. Received "${String(s)}".`),new Error("Invalid route component");if("then"in s){v(`Component "${e}" in record with path "${r.path}" is a Promise instead of a function that returns a Promise. Did you write "import('./MyPage.vue')" instead of "() => import('./MyPage.vue')" ? This will break in production if not fixed.`);const t=s;s=()=>t}else s.__asyncLoader&&!s.__warnedDefineAsync&&(s.__warnedDefineAsync=!0,v(`Component "${e}" in record with path "${r.path}" is defined using "defineAsyncComponent()". Write "() => import('./MyPage.vue')" instead of "defineAsyncComponent(() => import('./MyPage.vue'))".`));if("beforeRouteEnter"===t||r.instances[e])if(d(s)){const l=(s.__vccOpts||s)[t];l&&o.push(Ye(l,n,a,r,e,i))}else{let l=s();"catch"in l||(v(`Component "${e}" in record with path "${r.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`),l=Promise.resolve(l)),o.push(()=>l.then(o=>{if(!o)throw new Error(`Couldn't resolve component "${e}" at "${r.path}"`);const s=h(o)?o.default:o;r.mods[e]=o,r.components[e]=s;const l=(s.__vccOpts||s)[t];return l&&Ye(l,n,a,r,e,i)()}))}}}return o}function Ze(e){const n=(0,t.inject)(Ue),a=(0,t.inject)(He);let i=!1,o=null;const r=(0,t.computed)(()=>{const a=(0,t.unref)(e.to);return i&&a===o||(re(a)||(i?v('Invalid value for prop "to" in useLink()\n- to:',a,"\n- previous to:",o,"\n- props:",e):v('Invalid value for prop "to" in useLink()\n- to:',a,"\n- props:",e)),o=a,i=!0),n.resolve(a)}),s=(0,t.computed)(()=>{const{matched:e}=r.value,{length:t}=e,n=e[t-1],i=a.matched;if(!n||!i.length)return-1;const o=i.findIndex($.bind(null,n));if(o>-1)return o;const s=Xe(e[t-2]);return t>1&&Xe(n)===s&&i[i.length-1].path!==s?i.findIndex($.bind(null,e[t-2])):o}),l=(0,t.computed)(()=>s.value>-1&&function(e,t){for(const n in t){const a=t[n],i=e[n];if("string"==typeof a){if(a!==i)return!1}else if(!g(i)||i.length!==a.length||a.some((e,t)=>e!==i[t]))return!1}return!0}(a.params,r.value.params)),u=(0,t.computed)(()=>s.value>-1&&s.value===a.matched.length-1&&V(a.params,r.value.params));if(c){const n=(0,t.getCurrentInstance)();if(n){const a={route:r.value,isActive:l.value,isExactActive:u.value,error:null};n.__vrl_devtools=n.__vrl_devtools||[],n.__vrl_devtools.push(a),(0,t.watchEffect)(()=>{a.route=r.value,a.isActive=l.value,a.isExactActive=u.value,a.error=re((0,t.unref)(e.to))?null:'Invalid "to" value'},{flush:"post"})}}return{route:r,href:(0,t.computed)(()=>r.value.href),isActive:l,isExactActive:u,navigate:function(a={}){if(function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(a)){const a=n[(0,t.unref)(e.replace)?"replace":"push"]((0,t.unref)(e.to)).catch(m);return e.viewTransition&&"undefined"!=typeof document&&"startViewTransition"in document&&document.startViewTransition(()=>a),a}return Promise.resolve()}}}const Je=(0,t.defineComponent)({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:Ze,setup(e,{slots:n}){const a=(0,t.reactive)(Ze(e)),{options:i}=(0,t.inject)(Ue),o=(0,t.computed)(()=>({[et(e.activeClass,i.linkActiveClass,"router-link-active")]:a.isActive,[et(e.exactActiveClass,i.linkExactActiveClass,"router-link-exact-active")]:a.isExactActive}));return()=>{const i=n.default&&(1===(r=n.default(a)).length?r[0]:r);var r;return e.custom?i:(0,t.h)("a",{"aria-current":a.isExactActive?e.ariaCurrentValue:null,href:a.href,onClick:a.navigate,class:o.value},i)}}});function Xe(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const et=(e,t,n)=>null!=e?e:null!=t?t:n;function tt(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const nt=(0,t.defineComponent)({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:n,slots:a}){!function(){const e=(0,t.getCurrentInstance)(),n=e.parent&&e.parent.type.name,a=e.parent&&e.parent.subTree&&e.parent.subTree.type;if(n&&("KeepAlive"===n||n.includes("Transition"))&&"object"==typeof a&&"RouterView"===a.name){const e="KeepAlive"===n?"keep-alive":"transition";v(` can no longer be used directly inside or .\nUse slot props instead:\n\n\n <${e}>\n \n \n`)}}();const i=(0,t.inject)(We),o=(0,t.computed)(()=>e.route||i.value),r=(0,t.inject)(Ve,0),s=(0,t.computed)(()=>{let e=(0,t.unref)(r);const{matched:n}=o.value;let a;for(;(a=n[e])&&!a.components;)e++;return e}),l=(0,t.computed)(()=>o.value.matched[s.value]);(0,t.provide)(Ve,(0,t.computed)(()=>s.value+1)),(0,t.provide)($e,l),(0,t.provide)(We,o);const u=(0,t.ref)();return(0,t.watch)(()=>[u.value,l.value,e.name],([e,t,n],[a,i,o])=>{t&&(t.instances[n]=e,i&&i!==t&&e&&e===a&&(t.leaveGuards.size||(t.leaveGuards=i.leaveGuards),t.updateGuards.size||(t.updateGuards=i.updateGuards))),!e||!t||i&&$(t,i)&&a||(t.enterCallbacks[n]||[]).forEach(t=>t(e))},{flush:"post"}),()=>{const i=o.value,r=e.name,d=l.value,h=d&&d.components[r];if(!h)return tt(a.default,{Component:h,route:i});const f=d.props[r],m=f?!0===f?i.params:"function"==typeof f?f(i):f:null,_=(0,t.h)(h,p({},m,n,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(d.instances[r]=null)},ref:u}));if(c&&_.ref){const e={depth:s.value,name:d.name,path:d.path,meta:d.meta};(g(_.ref)?_.ref.map(e=>e.i):[_.ref.i]).forEach(t=>{t.__vrv_devtools=e})}return tt(a.default,{Component:_,route:i})||_}}});var at=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/env.js":e=>{function t(){return"undefined"!=typeof navigator&&"undefined"!=typeof window?window:"undefined"!=typeof globalThis?globalThis:{}}Object.defineProperty(e,"__esModule",{value:!0}),e.getDevtoolsGlobalHook=function(){return t().__VUE_DEVTOOLS_GLOBAL_HOOK__},e.getTarget=t,e.isProxyAvailable="function"==typeof Proxy}}),it=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/const.js":e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.HOOK_SETUP="devtools-plugin:setup",e.HOOK_PLUGIN_SETTINGS_SET="plugin:settings:set"}}),ot=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/time.js":e=>{let t,n;function a(){var e;return void 0!==t||("undefined"!=typeof window&&window.performance?(t=!0,n=window.performance):"undefined"!=typeof globalThis&&(null===(e=globalThis.perf_hooks)||void 0===e?void 0:e.performance)?(t=!0,n=globalThis.perf_hooks.performance):t=!1),t}Object.defineProperty(e,"__esModule",{value:!0}),e.isPerformanceSupported=a,e.now=function(){return a()?n.now():Date.now()}}}),rt=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/proxy.js":e=>{Object.defineProperty(e,"__esModule",{value:!0});const t=it(),n=ot();e.ApiProxy=class{constructor(e,a){this.target=null,this.targetQueue=[],this.onQueue=[],this.plugin=e,this.hook=a;const i={};if(e.settings)for(const t in e.settings)i[t]=e.settings[t].defaultValue;const o=`__vue-devtools-plugin-settings__${e.id}`;let r=Object.assign({},i);try{const e=localStorage.getItem(o),t=JSON.parse(e);Object.assign(r,t)}catch(e){}this.fallbacks={getSettings:()=>r,setSettings(e){try{localStorage.setItem(o,JSON.stringify(e))}catch(e){}r=e},now:()=>(0,n.now)()},a&&a.on(t.HOOK_PLUGIN_SETTINGS_SET,(e,t)=>{e===this.plugin.id&&this.fallbacks.setSettings(t)}),this.proxiedOn=new Proxy({},{get:(e,t)=>this.target?this.target.on[t]:(...e)=>{this.onQueue.push({method:t,args:e})}}),this.proxiedTarget=new Proxy({},{get:(e,t)=>this.target?this.target[t]:"on"===t?this.proxiedOn:Object.keys(this.fallbacks).includes(t)?(...e)=>(this.targetQueue.push({method:t,args:e,resolve:()=>{}}),this.fallbacks[t](...e)):(...e)=>new Promise(n=>{this.targetQueue.push({method:t,args:e,resolve:n})})})}async setRealTarget(e){this.target=e;for(const e of this.onQueue)this.target.on[e.method](...e.args);for(const e of this.targetQueue)e.resolve(await this.target[e.method](...e.args))}}}}),st=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/api.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),lt=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/app.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),ut=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/component.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),ct=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/context.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),dt=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/hooks.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),ht=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/util.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),pt=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/api/index.js":e=>{var t=e&&e.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var i=Object.getOwnPropertyDescriptor(t,n);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,i)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),n=e&&e.__exportStar||function(e,n){for(var a in e)"default"===a||Object.prototype.hasOwnProperty.call(n,a)||t(n,e,a)};Object.defineProperty(e,"__esModule",{value:!0}),n(st(),e),n(lt(),e),n(ut(),e),n(ct(),e),n(dt(),e),n(ht(),e)}}),ft=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/plugin.js":e=>{Object.defineProperty(e,"__esModule",{value:!0})}}),mt=l({"../../node_modules/.pnpm/@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api/lib/cjs/index.js":e=>{var t=e&&e.__createBinding||(Object.create?function(e,t,n,a){void 0===a&&(a=n);var i=Object.getOwnPropertyDescriptor(t,n);i&&!("get"in i?!t.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,a,i)}:function(e,t,n,a){void 0===a&&(a=n),e[a]=t[n]}),n=e&&e.__exportStar||function(e,n){for(var a in e)"default"===a||Object.prototype.hasOwnProperty.call(n,a)||t(n,e,a)};Object.defineProperty(e,"__esModule",{value:!0}),e.setupDevtoolsPlugin=void 0;const a=at(),i=it(),o=rt();n(pt(),e),n(ft(),e),n(ot(),e),e.setupDevtoolsPlugin=function(e,t){const n=e,r=(0,a.getTarget)(),s=(0,a.getDevtoolsGlobalHook)(),l=a.isProxyAvailable&&n.enableEarlyProxy;if(!s||!r.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__&&l){const e=l?new o.ApiProxy(n,s):null;(r.__VUE_DEVTOOLS_PLUGINS__=r.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:n,setupFn:t,proxy:e}),e&&t(e.proxiedTarget)}else s.emit(i.HOOK_SETUP,e,t)}}}),gt=u(mt());function _t(e,t){const n=p({},e,{matched:e.matched.map(e=>function(e,t){const n={};for(const a in e)t.includes(a)||(n[a]=e[a]);return n}(e,["instances","children","aliasOf"]))});return{_custom:{type:null,readOnly:!0,display:e.fullPath,tooltip:t,value:n}}}function vt(e){return{_custom:{display:e}}}let bt=0;function yt(e,n,a){if(n.__hasDevtools)return;n.__hasDevtools=!0;const i=bt++;(0,gt.setupDevtoolsPlugin)({id:"org.vuejs.router"+(i?"."+i:""),label:"Vue Router",packageName:"vue-router",homepage:"https://router.vuejs.org",logo:"https://router.vuejs.org/logo.png",componentStateTypes:["Routing"],app:e},o=>{"function"!=typeof o.now&&v("[Vue Router]: You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html."),o.on.inspectComponent((e,t)=>{e.instanceData&&e.instanceData.state.push({type:"Routing",key:"$route",editable:!1,value:_t(n.currentRoute.value,"Current Route")})}),o.on.visitComponentTree(({treeNode:e,componentInstance:t})=>{if(t.__vrv_devtools){const n=t.__vrv_devtools;e.tags.push({label:(n.name?`${n.name.toString()}: `:"")+n.path,textColor:0,tooltip:"This component is rendered by <router-view>",backgroundColor:kt})}g(t.__vrl_devtools)&&(t.__devtoolsApi=o,t.__vrl_devtools.forEach(t=>{let n=t.route.path,a=Tt,i="",o=0;t.error?(n=t.error,a=Et,o=At):t.isExactActive?(a=St,i="This is exactly active"):t.isActive&&(a=xt,i="This link is active"),e.tags.push({label:n,textColor:o,tooltip:i,backgroundColor:a})}))}),(0,t.watch)(n.currentRoute,()=>{u(),o.notifyComponentUpdate(),o.sendInspectorTree(l),o.sendInspectorState(l)});const r="router:navigations:"+i;o.addTimelineLayer({id:r,label:`Router${i?" "+i:""} Navigations`,color:4237508}),n.onError((e,t)=>{o.addTimelineEvent({layerId:r,event:{title:"Error during Navigation",subtitle:t.fullPath,logType:"error",time:o.now(),data:{error:e},groupId:t.meta.__navigationId}})});let s=0;n.beforeEach((e,t)=>{const n={guard:vt("beforeEach"),from:_t(t,"Current Location during this navigation"),to:_t(e,"Target location")};Object.defineProperty(e.meta,"__navigationId",{value:s++}),o.addTimelineEvent({layerId:r,event:{time:o.now(),title:"Start of navigation",subtitle:e.fullPath,data:n,groupId:e.meta.__navigationId}})}),n.afterEach((e,t,n)=>{const a={guard:vt("afterEach")};n?(a.failure={_custom:{type:Error,readOnly:!0,display:n?n.message:"",tooltip:"Navigation Failure",value:n}},a.status=vt("❌")):a.status=vt("✅"),a.from=_t(t,"Current Location during this navigation"),a.to=_t(e,"Target location"),o.addTimelineEvent({layerId:r,event:{title:"End of navigation",subtitle:e.fullPath,time:o.now(),data:a,logType:n?"warning":"default",groupId:e.meta.__navigationId}})});const l="router-inspector:"+i;function u(){if(!c)return;const e=c;let t=a.getRoutes().filter(e=>!e.parent||!e.parent.record.components);t.forEach(Nt),e.filter&&(t=t.filter(t=>Ot(t,e.filter.toLowerCase()))),t.forEach(e=>zt(e,n.currentRoute.value)),e.rootNodes=t.map(Mt)}let c;o.addInspector({id:l,label:"Routes"+(i?" "+i:""),icon:"book",treeFilterPlaceholder:"Search routes"}),o.on.getInspectorTree(t=>{c=t,t.app===e&&t.inspectorId===l&&u()}),o.on.getInspectorState(t=>{if(t.app===e&&t.inspectorId===l){const e=a.getRoutes().find(e=>e.record.__vd_id===t.nodeId);e&&(t.state={options:wt(e)})}}),o.sendInspectorTree(l),o.sendInspectorState(l)})}function wt(e){const{record:t}=e,n=[{editable:!1,key:"path",value:t.path}];return null!=t.name&&n.push({editable:!1,key:"name",value:t.name}),n.push({editable:!1,key:"regexp",value:e.re}),e.keys.length&&n.push({editable:!1,key:"keys",value:{_custom:{type:null,readOnly:!0,display:e.keys.map(e=>`${e.name}${function(e){return e.optional?e.repeatable?"*":"?":e.repeatable?"+":""}(e)}`).join(" "),tooltip:"Param keys",value:e.keys}}}),null!=t.redirect&&n.push({editable:!1,key:"redirect",value:t.redirect}),e.alias.length&&n.push({editable:!1,key:"aliases",value:e.alias.map(e=>e.record.path)}),Object.keys(e.record.meta).length&&n.push({editable:!1,key:"meta",value:e.record.meta}),n.push({key:"score",editable:!1,value:{_custom:{type:null,readOnly:!0,display:e.score.map(e=>e.join(", ")).join(" | "),tooltip:"Score used to sort routes",value:e.score}}}),n}const kt=15485081,xt=2450411,St=8702998,Ct=2282478,Tt=16486972,Pt=6710886,Et=16704226,At=12131356;function Mt(e){const t=[],{record:n}=e;null!=n.name&&t.push({label:String(n.name),textColor:0,backgroundColor:Ct}),n.aliasOf&&t.push({label:"alias",textColor:0,backgroundColor:Tt}),e.__vd_match&&t.push({label:"matches",textColor:0,backgroundColor:kt}),e.__vd_exactActive&&t.push({label:"exact",textColor:0,backgroundColor:St}),e.__vd_active&&t.push({label:"active",textColor:0,backgroundColor:xt}),n.redirect&&t.push({label:"string"==typeof n.redirect?`redirect: ${n.redirect}`:"redirects",textColor:16777215,backgroundColor:Pt});let a=n.__vd_id;return null==a&&(a=String(Lt++),n.__vd_id=a),{id:a,label:n.path,tags:t,children:e.children.map(Mt)}}let Lt=0;const Rt=/^\/(.*)\/([a-z]*)$/;function zt(e,t){const n=t.matched.length&&$(t.matched[t.matched.length-1],e.record);e.__vd_exactActive=e.__vd_active=n,n||(e.__vd_active=t.matched.some(t=>$(t,e.record))),e.children.forEach(e=>zt(e,t))}function Nt(e){e.__vd_match=!1,e.children.forEach(Nt)}function Ot(e,t){const n=String(e.re).match(Rt);if(e.__vd_match=!1,!n||n.length<3)return!1;if(new RegExp(n[1].replace(/\$$/,""),n[2]).test(t))return e.children.forEach(e=>Ot(e,t)),("/"!==e.record.path||"/"===t)&&(e.__vd_match=e.re.test(t),!0);const a=e.record.path.toLowerCase(),i=q(a);return!(t.startsWith("/")||!i.includes(t)&&!a.includes(t))||(!(!i.startsWith(t)&&!a.startsWith(t))||(!(!e.record.name||!String(e.record.name).includes(t))||e.children.some(e=>Ot(e,t))))}return e.NavigationFailureType=ce,e.RouterLink=Je,e.RouterView=nt,e.START_LOCATION=W,e.createMemoryHistory=function(e=""){let t=[],n=[["",{}]],a=0;function i(e,t={}){a++,a!==n.length&&n.splice(a),n.push([e,t])}const o={location:"",state:{},base:e=Y(e),createHref:Z.bind(null,e),replace(e,t){n.splice(a--,1),i(e,t)},push(e,t){i(e,t)},listen:e=>(t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)}),destroy(){t=[],n=[["",{}]],a=0},go(e,i=!0){const o=this.location,r=e<0?K.back:K.forward;a=Math.max(0,Math.min(a+e,n.length-1)),i&&function(e,n,{direction:a,delta:i}){const o={direction:a,delta:i,type:G.pop};for(const a of t)a(e,n,o)}(this.location,o,{direction:r,delta:e})}};return Object.defineProperty(o,"location",{enumerable:!0,get:()=>n[a][0]}),Object.defineProperty(o,"state",{enumerable:!0,get:()=>n[a][1]}),o},e.createRouter=function(e){const n=Ee(e.routes,e),a=e.parseQuery||je,i=e.stringifyQuery||Be,o=e.history;if(!o)throw new Error('Provide the "history" option when calling "createRouter()": https://router.vuejs.org/api/interfaces/RouterOptions.html#history');const r=Ge(),s=Ge(),l=Ge(),u=(0,t.shallowRef)(W);let d=W;c&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const h=f.bind(null,e=>""+e),_=f.bind(null,I),b=f.bind(null,q);function y(e,t){if(t=p({},t||u.value),"string"==typeof e){const i=j(a,e,t.path),r=n.resolve({path:i.path},t),s=o.createHref(i.fullPath);return s.startsWith("//")?v(`Location "${e}" resolved to "${s}". A resolved location cannot start with multiple slashes.`):r.matched.length||v(`No match found for location with path "${e}"`),p(i,r,{params:b(r.params),hash:q(i.hash),redirectedFrom:void 0,href:s})}if(!re(e))return v("router.resolve() was passed an invalid location. This will fail in production.\n- Location:",e),y({});let r;if(null!=e.path)"params"in e&&!("name"in e)&&Object.keys(e.params).length&&v(`Path "${e.path}" was passed with params but they will be ignored. Use a named route alongside params instead.`),r=p({},e,{path:j(a,e.path,t.path).path});else{const n=p({},e.params);for(const e in n)null==n[e]&&delete n[e];r=p({},e,{params:_(n)}),t.params=_(t.params)}const s=n.resolve(r,t),l=e.hash||"";l&&!l.startsWith("#")&&v(`A \`hash\` should always start with the character "#". Replace "${l}" with "#${l}".`),s.params=h(b(s.params));const c=function(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(i,p({},e,{hash:(d=l,z(d).replace(A,"{").replace(L,"}").replace(P,"^")),path:s.path}));var d;const f=o.createHref(c);return f.startsWith("//")?v(`Location "${e}" resolved to "${f}". A resolved location cannot start with multiple slashes.`):s.matched.length||v(`No match found for location with path "${null!=e.path?e.path:e}"`),p({fullPath:c,hash:l,query:i===Be?Fe(e.query):e.query||{}},s,{redirectedFrom:void 0,href:f})}function w(e){return"string"==typeof e?j(a,e,u.value.path):p({},e)}function k(e,t){if(d!==e)return he(le.NAVIGATION_CANCELLED,{from:t,to:e})}function x(e){return C(e)}function S(e,t){const n=e.matched[e.matched.length-1];if(n&&n.redirect){const{redirect:a}=n;let i="function"==typeof a?a(e,t):a;if("string"==typeof i&&(i=i.includes("?")||i.includes("#")?i=w(i):{path:i},i.params={}),null==i.path&&!("name"in i))throw v(`Invalid redirect found:\n${JSON.stringify(i,null,2)}\n when navigating to "${e.fullPath}". A redirect must contain a name or path. This will break in production.`),new Error("Invalid redirect");return p({query:e.query,hash:e.hash,params:null!=i.path?{}:e.params},i)}}function C(e,t){const n=d=y(e),a=u.value,o=e.state,r=e.force,s=!0===e.replace,l=S(n,a);if(l)return C(p(w(l),{state:"object"==typeof l?p({},o,l.state):o,force:r,replace:s}),t||n);const c=n;let h;return c.redirectedFrom=t,!r&&F(i,a,n)&&(h=he(le.NAVIGATION_DUPLICATED,{to:c,from:a}),Y(a,a,!0,!1)),(h?Promise.resolve(h):M(c,a)).catch(e=>pe(e)?pe(e,le.NAVIGATION_GUARD_REDIRECT)?e:K(e):H(e,c,a)).then(e=>{if(e){if(pe(e,le.NAVIGATION_GUARD_REDIRECT))return F(i,y(e.to),c)&&t&&(t._count=t._count?t._count+1:1)>30?(v(`Detected a possibly infinite redirection in a navigation guard when going from "${a.fullPath}" to "${c.fullPath}". Aborting to avoid a Stack Overflow.\n Are you always returning a new location within a navigation guard? That would lead to this error. Only return when redirecting or aborting, that should fix this. This might break in production if not fixed.`),Promise.reject(new Error("Infinite redirect in navigation guard"))):C(p({replace:s},w(e.to),{state:"object"==typeof e.to?p({},o,e.to.state):o,force:r}),t||c)}else e=N(c,a,!0,s,o);return R(c,a,e),e})}function T(e,t){const n=k(e,t);return n?Promise.reject(n):Promise.resolve()}function E(e){const t=ne.values().next().value;return t&&"function"==typeof t.runWithContext?t.runWithContext(e):e()}function M(e,t){let n;const[a,i,o]=function(e,t){const n=[],a=[],i=[],o=Math.max(t.matched.length,e.matched.length);for(let r=0;r$(e,o))?a.push(o):n.push(o));const s=e.matched[r];s&&(t.matched.find(e=>$(e,s))||i.push(s))}return[n,a,i]}(e,t);n=Qe(a.reverse(),"beforeRouteLeave",e,t);for(const i of a)i.leaveGuards.forEach(a=>{n.push(Ye(a,e,t))});const l=T.bind(null,e,t);return n.push(l),ie(n).then(()=>{n=[];for(const a of r.list())n.push(Ye(a,e,t));return n.push(l),ie(n)}).then(()=>{n=Qe(i,"beforeRouteUpdate",e,t);for(const a of i)a.updateGuards.forEach(a=>{n.push(Ye(a,e,t))});return n.push(l),ie(n)}).then(()=>{n=[];for(const a of o)if(a.beforeEnter)if(g(a.beforeEnter))for(const i of a.beforeEnter)n.push(Ye(i,e,t));else n.push(Ye(a.beforeEnter,e,t));return n.push(l),ie(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Qe(o,"beforeRouteEnter",e,t,E),n.push(l),ie(n))).then(()=>{n=[];for(const a of s.list())n.push(Ye(a,e,t));return n.push(l),ie(n)}).catch(e=>pe(e,le.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function R(e,t,n){l.list().forEach(a=>E(()=>a(e,t,n)))}function N(e,t,n,a,i){const r=k(e,t);if(r)return r;const s=t===W,l=c?history.state:{};n&&(a||s?o.replace(e.fullPath,p({scroll:s&&l&&l.scroll},i)):o.push(e.fullPath,i)),u.value=e,Y(e,t,n,s),K()}let O;function D(){O||(O=o.listen((e,t,n)=>{if(!ae.listening)return;const a=y(e),i=S(a,ae.currentRoute.value);if(i)return void C(p(i,{replace:!0,force:!0}),a).catch(m);d=a;const r=u.value;var s,l;c&&(s=ee(r.fullPath,n.delta),l=J(),te.set(s,l)),M(a,r).catch(e=>pe(e,le.NAVIGATION_ABORTED|le.NAVIGATION_CANCELLED)?e:pe(e,le.NAVIGATION_GUARD_REDIRECT)?(C(p(w(e.to),{force:!0}),a).then(e=>{pe(e,le.NAVIGATION_ABORTED|le.NAVIGATION_DUPLICATED)&&!n.delta&&n.type===G.pop&&o.go(-1,!1)}).catch(m),Promise.reject()):(n.delta&&o.go(-n.delta,!1),H(e,a,r))).then(e=>{(e=e||N(a,r,!1))&&(n.delta&&!pe(e,le.NAVIGATION_CANCELLED)?o.go(-n.delta,!1):n.type===G.pop&&pe(e,le.NAVIGATION_ABORTED|le.NAVIGATION_DUPLICATED)&&o.go(-1,!1)),R(a,r,e)}).catch(m)}))}let B,V=Ge(),U=Ge();function H(e,t,n){K(e);const a=U.list();return a.length?a.forEach(a=>a(e,t,n)):(v("uncaught error during route navigation:"),console.error(e)),Promise.reject(e)}function K(e){return B||(B=!e,D(),V.list().forEach(([t,n])=>e?n(e):t()),V.reset()),e}function Y(n,a,i,o){const{scrollBehavior:r}=e;if(!c||!r)return Promise.resolve();const s=!i&&function(e){const t=te.get(e);return te.delete(e),t}(ee(n.fullPath,0))||(o||!i)&&history.state&&history.state.scroll||null;return(0,t.nextTick)().then(()=>r(n,a,s)).then(e=>e&&X(e)).catch(e=>H(e,n,a))}const Q=e=>o.go(e);let Z;const ne=new Set,ae={currentRoute:u,listening:!0,addRoute:function(e,t){let a,i;return se(e)?(a=n.getRecordMatcher(e),a||v(`Parent route "${String(e)}" not found when adding child route`,t),i=t):i=e,n.addRoute(i,a)},removeRoute:function(e){const t=n.getRecordMatcher(e);t?n.removeRoute(t):v(`Cannot remove non-existent route "${String(e)}"`)},clearRoutes:n.clearRoutes,hasRoute:function(e){return!!n.getRecordMatcher(e)},getRoutes:function(){return n.getRoutes().map(e=>e.record)},resolve:y,options:e,push:x,replace:function(e){return x(p(w(e),{replace:!0}))},go:Q,back:()=>Q(-1),forward:()=>Q(1),beforeEach:r.add,beforeResolve:s.add,afterEach:l.add,onError:U.add,isReady:function(){return B&&u.value!==W?Promise.resolve():new Promise((e,t)=>{V.add([e,t])})},install(e){e.component("RouterLink",Je),e.component("RouterView",nt),e.config.globalProperties.$router=ae,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>(0,t.unref)(u)}),c&&!Z&&u.value===W&&(Z=!0,x(o.location).catch(e=>{v("Unexpected error when starting the router:",e)}));const a={};for(const e in W)Object.defineProperty(a,e,{get:()=>u.value[e],enumerable:!0});e.provide(Ue,ae),e.provide(He,(0,t.shallowReactive)(a)),e.provide(We,u);const i=e.unmount;ne.add(e),e.unmount=function(){ne.delete(e),ne.size<1&&(d=W,O&&O(),O=null,u.value=W,Z=!1,B=!1),i()},c&&yt(e,ae,n)}};function ie(e){return e.reduce((e,t)=>e.then(()=>E(t)),Promise.resolve())}return ae},e.createRouterMatcher=Ee,e.createWebHashHistory=function(e){return(e=location.host?e||location.pathname+location.search:"").includes("#")||(e+="#"),e.endsWith("#/")||e.endsWith("#")||v(`A hash base must end with a "#":\n"${e}" should be "${e.replace(/#.*$/,"#")}".`),oe(e)},e.createWebHistory=oe,e.isNavigationFailure=pe,e.loadRouteLocation=function(e){return e.matched.every(e=>e.redirect)?Promise.reject(new Error("Cannot load a route that redirects.")):Promise.all(e.matched.map(e=>e.components&&Promise.all(Object.keys(e.components).reduce((t,n)=>{const a=e.components[n];return"function"!=typeof a||"displayName"in a||t.push(a().then(t=>{if(!t)return Promise.reject(new Error(`Couldn't resolve component "${n}" at "${e.path}". Ensure you passed a function that returns a promise.`));const a=h(t)?t.default:t;e.mods[n]=t,e.components[n]=a})),t},[])))).then(()=>e)},e.matchedRouteKey=$e,e.onBeforeRouteLeave=function(e){if(!(0,t.getCurrentInstance)())return void v("getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function");const n=(0,t.inject)($e,{}).value;n?Ke(n,"leaveGuards",e):v("No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?")},e.onBeforeRouteUpdate=function(e){if(!(0,t.getCurrentInstance)())return void v("getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function");const n=(0,t.inject)($e,{}).value;n?Ke(n,"updateGuards",e):v("No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?")},e.parseQuery=je,e.routeLocationKey=He,e.routerKey=Ue,e.routerViewLocationKey=We,e.stringifyQuery=Be,e.useLink=Ze,e.useRoute=function(e){return(0,t.inject)(He)},e.useRouter=function(){return(0,t.inject)(Ue)},e.viewDepthKey=Ve,e}({},Vue); +var Vuex=function(e){"use strict";var t="store";function n(){return"undefined"!=typeof navigator?window:"undefined"!=typeof global?global:{}}function a(e,t){var a=n().__VUE_DEVTOOLS_GLOBAL_HOOK__;if(a)a.emit("devtools-plugin:setup",e,t);else{var i=n();(i.__VUE_DEVTOOLS_PLUGINS__=i.__VUE_DEVTOOLS_PLUGINS__||[]).push({pluginDescriptor:e,setupFn:t})}}function i(e,t){if(void 0===t&&(t=[]),null===e||"object"!=typeof e)return e;var n,a=(n=function(t){return t.original===e},t.filter(n)[0]);if(a)return a.copy;var r=Array.isArray(e)?[]:{};return t.push({original:e,copy:r}),Object.keys(e).forEach(function(n){r[n]=i(e[n],t)}),r}function r(e,t){Object.keys(e).forEach(function(n){return t(e[n],n)})}function o(e){return null!==e&&"object"==typeof e}function s(e,t){if(!e)throw new Error("[vuex] "+t)}function l(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function u(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;d(e,n,[],e._modules.root,!0),c(e,n,t)}function c(t,n,a){var i=t._state,o=t._scope;t.getters={},t._makeLocalGettersCache=Object.create(null);var l=t._wrappedGetters,u={},c={},d=e.effectScope(!0);d.run(function(){r(l,function(n,a){u[a]=function(e,t){return function(){return e(t)}}(n,t),c[a]=e.computed(function(){return u[a]()}),Object.defineProperty(t.getters,a,{get:function(){return c[a].value},enumerable:!0})})}),t._state=e.reactive({data:n}),t._scope=d,t.strict&&function(t){e.watch(function(){return t._state.data},function(){s(t._committing,"do not mutate vuex store state outside mutation handlers.")},{deep:!0,flush:"sync"})}(t),i&&a&&t._withCommit(function(){i.data=null}),o&&o.stop()}function d(e,t,n,a,i){var r=!n.length,o=e._modules.getNamespace(n);if(a.namespaced&&(e._modulesNamespaceMap[o]&&console.error("[vuex] duplicate namespace "+o+" for the namespaced module "+n.join("/")),e._modulesNamespaceMap[o]=a),!r&&!i){var s=p(t,n.slice(0,-1)),l=n[n.length-1];e._withCommit(function(){l in s&&console.warn('[vuex] state field "'+l+'" was overridden by a module with the same name at "'+n.join(".")+'"'),s[l]=a.state})}var u=a.context=function(e,t,n){var a=""===t,i={dispatch:a?e.dispatch:function(n,a,i){var r=f(n,a,i),o=r.payload,s=r.options,l=r.type;if(s&&s.root||(l=t+l,e._actions[l]))return e.dispatch(l,o);console.error("[vuex] unknown local action type: "+r.type+", global type: "+l)},commit:a?e.commit:function(n,a,i){var r=f(n,a,i),o=r.payload,s=r.options,l=r.type;s&&s.root||(l=t+l,e._mutations[l])?e.commit(l,o,s):console.error("[vuex] unknown local mutation type: "+r.type+", global type: "+l)}};return Object.defineProperties(i,{getters:{get:a?function(){return e.getters}:function(){return h(e,t)}},state:{get:function(){return p(e.state,n)}}}),i}(e,o,n);a.forEachMutation(function(t,n){!function(e,t,n,a){var i=e._mutations[t]||(e._mutations[t]=[]);i.push(function(t){n.call(e,a.state,t)})}(e,o+n,t,u)}),a.forEachAction(function(t,n){var a=t.root?n:o+n,i=t.handler||t;!function(e,t,n,a){var i=e._actions[t]||(e._actions[t]=[]);i.push(function(t){var i,r=n.call(e,{dispatch:a.dispatch,commit:a.commit,getters:a.getters,state:a.state,rootGetters:e.getters,rootState:e.state},t);return(i=r)&&"function"==typeof i.then||(r=Promise.resolve(r)),e._devtoolHook?r.catch(function(t){throw e._devtoolHook.emit("vuex:error",t),t}):r})}(e,a,i,u)}),a.forEachGetter(function(t,n){!function(e,t,n,a){if(e._wrappedGetters[t])return void console.error("[vuex] duplicate getter key: "+t);e._wrappedGetters[t]=function(e){return n(a.state,a.getters,e.state,e.getters)}}(e,o+n,t,u)}),a.forEachChild(function(a,r){d(e,t,n.concat(r),a,i)})}function h(e,t){if(!e._makeLocalGettersCache[t]){var n={},a=t.length;Object.keys(e.getters).forEach(function(i){if(i.slice(0,a)===t){var r=i.slice(a);Object.defineProperty(n,r,{get:function(){return e.getters[i]},enumerable:!0})}}),e._makeLocalGettersCache[t]=n}return e._makeLocalGettersCache[t]}function p(e,t){return t.reduce(function(e,t){return e[t]},e)}function f(e,t,n){return o(e)&&e.type&&(n=t,t=e,e=e.type),s("string"==typeof e,"expects string as the type, but found "+typeof e+"."),{type:e,payload:t,options:n}}var m="vuex:mutations",_="vuex:actions",g="vuex",v=0;function b(e,t){a({id:"org.vuejs.vuex",app:e,label:"Vuex",homepage:"https://next.vuex.vuejs.org/",logo:"https://vuejs.org/images/icons/favicon-96x96.png",packageName:"vuex",componentStateTypes:["vuex bindings"]},function(n){n.addTimelineLayer({id:m,label:"Vuex Mutations",color:y}),n.addTimelineLayer({id:_,label:"Vuex Actions",color:y}),n.addInspector({id:g,label:"Vuex",icon:"storage",treeFilterPlaceholder:"Filter stores..."}),n.on.getInspectorTree(function(n){if(n.app===e&&n.inspectorId===g)if(n.filter){var a=[];S(a,t._modules.root,n.filter,""),n.rootNodes=a}else n.rootNodes=[x(t._modules.root,"")]}),n.on.getInspectorState(function(n){if(n.app===e&&n.inspectorId===g){var a=n.nodeId;h(t,a),n.state=function(e,t,n){t="root"===n?t:t[n];var a=Object.keys(t),i={state:Object.keys(e.state).map(function(t){return{key:t,editable:!0,value:e.state[t]}})};if(a.length){var r=function(e){var t={};return Object.keys(e).forEach(function(n){var a=n.split("/");if(a.length>1){var i=t,r=a.pop();a.forEach(function(e){i[e]||(i[e]={_custom:{value:{},display:e,tooltip:"Module",abstract:!0}}),i=i[e]._custom.value}),i[r]=C(function(){return e[n]})}else t[n]=C(function(){return e[n]})}),t}(t);i.getters=Object.keys(r).map(function(e){return{key:e.endsWith("/")?k(e):e,editable:!1,value:C(function(){return r[e]})}})}return i}((i=t._modules,(o=(r=a).split("/").filter(function(e){return e})).reduce(function(e,t,n){var a=e[t];if(!a)throw new Error('Missing module "'+t+'" for path "'+r+'".');return n===o.length-1?a:a._children},"root"===r?i:i.root._children)),"root"===a?t.getters:t._makeLocalGettersCache,a)}var i,r,o}),n.on.editInspectorState(function(n){if(n.app===e&&n.inspectorId===g){var a=n.nodeId,i=n.path;"root"!==a&&(i=a.split("/").filter(Boolean).concat(i)),t._withCommit(function(){n.set(t._state.data,i,n.state.value)})}}),t.subscribe(function(e,t){var a={};e.payload&&(a.payload=e.payload),a.state=t,n.notifyComponentUpdate(),n.sendInspectorTree(g),n.sendInspectorState(g),n.addTimelineEvent({layerId:m,event:{time:Date.now(),title:e.type,data:a}})}),t.subscribeAction({before:function(e,t){var a={};e.payload&&(a.payload=e.payload),e._id=v++,e._time=Date.now(),a.state=t,n.addTimelineEvent({layerId:_,event:{time:e._time,title:e.type,groupId:e._id,subtitle:"start",data:a}})},after:function(e,t){var a={},i=Date.now()-e._time;a.duration={_custom:{type:"duration",display:i+"ms",tooltip:"Action duration",value:i}},e.payload&&(a.payload=e.payload),a.state=t,n.addTimelineEvent({layerId:_,event:{time:Date.now(),title:e.type,groupId:e._id,subtitle:"end",data:a}})}})})}var y=8702998,w={label:"namespaced",textColor:16777215,backgroundColor:6710886};function k(e){return e&&"root"!==e?e.split("/").slice(-2,-1)[0]:"Root"}function x(e,t){return{id:t||"root",label:k(t),tags:e.namespaced?[w]:[],children:Object.keys(e._children).map(function(n){return x(e._children[n],t+n+"/")})}}function S(e,t,n,a){a.includes(n)&&e.push({id:a||"root",label:a.endsWith("/")?a.slice(0,a.length-1):a||"Root",tags:t.namespaced?[w]:[]}),Object.keys(t._children).forEach(function(i){S(e,t._children[i],n,a+i+"/")})}function C(e){try{return e()}catch(e){return e}}var T=function(e,t){this.runtime=t,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=("function"==typeof n?n():n)||{}},P={namespaced:{configurable:!0}};P.namespaced.get=function(){return!!this._rawModule.namespaced},T.prototype.addChild=function(e,t){this._children[e]=t},T.prototype.removeChild=function(e){delete this._children[e]},T.prototype.getChild=function(e){return this._children[e]},T.prototype.hasChild=function(e){return e in this._children},T.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)},T.prototype.forEachChild=function(e){r(this._children,e)},T.prototype.forEachGetter=function(e){this._rawModule.getters&&r(this._rawModule.getters,e)},T.prototype.forEachAction=function(e){this._rawModule.actions&&r(this._rawModule.actions,e)},T.prototype.forEachMutation=function(e){this._rawModule.mutations&&r(this._rawModule.mutations,e)},Object.defineProperties(T.prototype,P);var E=function(e){this.register([],e,!1)};function A(e,t,n){if(R(e,n),t.update(n),n.modules)for(var a in n.modules){if(!t.getChild(a))return void console.warn("[vuex] trying to add a new module '"+a+"' on hot reloading, manual reload is needed");A(e.concat(a),t.getChild(a),n.modules[a])}}E.prototype.get=function(e){return e.reduce(function(e,t){return e.getChild(t)},this.root)},E.prototype.getNamespace=function(e){var t=this.root;return e.reduce(function(e,n){return e+((t=t.getChild(n)).namespaced?n+"/":"")},"")},E.prototype.update=function(e){A([],this.root,e)},E.prototype.register=function(e,t,n){var a=this;void 0===n&&(n=!0),R(e,t);var i=new T(t,n);0===e.length?this.root=i:this.get(e.slice(0,-1)).addChild(e[e.length-1],i);t.modules&&r(t.modules,function(t,i){a.register(e.concat(i),t,n)})},E.prototype.unregister=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1],a=t.getChild(n);a?a.runtime&&t.removeChild(n):console.warn("[vuex] trying to unregister module '"+n+"', which is not registered")},E.prototype.isRegistered=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1];return!!t&&t.hasChild(n)};var L={assert:function(e){return"function"==typeof e},expected:"function"},M={getters:L,mutations:L,actions:{assert:function(e){return"function"==typeof e||"object"==typeof e&&"function"==typeof e.handler},expected:'function or object with "handler" function'}};function R(e,t){Object.keys(M).forEach(function(n){if(t[n]){var a=M[n];r(t[n],function(t,i){s(a.assert(t),function(e,t,n,a,i){var r=t+" should be "+i+' but "'+t+"."+n+'"';e.length>0&&(r+=' in module "'+e.join(".")+'"');return r+=" is "+JSON.stringify(a)+".",r}(e,n,i,t,a.expected))})}})}var z=function e(t){var n=this;void 0===t&&(t={}),s("undefined"!=typeof Promise,"vuex requires a Promise polyfill in this browser."),s(this instanceof e,"store must be called with the new operator.");var a=t.plugins;void 0===a&&(a=[]);var i=t.strict;void 0===i&&(i=!1);var r=t.devtools;this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new E(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._makeLocalGettersCache=Object.create(null),this._scope=null,this._devtools=r;var o=this,l=this.dispatch,u=this.commit;this.dispatch=function(e,t){return l.call(o,e,t)},this.commit=function(e,t,n){return u.call(o,e,t,n)},this.strict=i;var h=this._modules.root.state;d(this,h,[],this._modules.root),c(this,h),a.forEach(function(e){return e(n)})},I={state:{configurable:!0}};z.prototype.install=function(e,n){e.provide(n||t,this),e.config.globalProperties.$store=this,(void 0===this._devtools||this._devtools)&&b(e,this)},I.state.get=function(){return this._state.data},I.state.set=function(e){s(!1,"use store.replaceState() to explicit replace store state.")},z.prototype.commit=function(e,t,n){var a=this,i=f(e,t,n),r=i.type,o=i.payload,s=i.options,l={type:r,payload:o},u=this._mutations[r];u?(this._withCommit(function(){u.forEach(function(e){e(o)})}),this._subscribers.slice().forEach(function(e){return e(l,a.state)}),s&&s.silent&&console.warn("[vuex] mutation type: "+r+". Silent option has been removed. Use the filter functionality in the vue-devtools")):console.error("[vuex] unknown mutation type: "+r)},z.prototype.dispatch=function(e,t){var n=this,a=f(e,t),i=a.type,r=a.payload,o={type:i,payload:r},s=this._actions[i];if(s){try{this._actionSubscribers.slice().filter(function(e){return e.before}).forEach(function(e){return e.before(o,n.state)})}catch(e){console.warn("[vuex] error in before action subscribers: "),console.error(e)}var l=s.length>1?Promise.all(s.map(function(e){return e(r)})):s[0](r);return new Promise(function(e,t){l.then(function(t){try{n._actionSubscribers.filter(function(e){return e.after}).forEach(function(e){return e.after(o,n.state)})}catch(e){console.warn("[vuex] error in after action subscribers: "),console.error(e)}e(t)},function(e){try{n._actionSubscribers.filter(function(e){return e.error}).forEach(function(t){return t.error(o,n.state,e)})}catch(e){console.warn("[vuex] error in error action subscribers: "),console.error(e)}t(e)})})}console.error("[vuex] unknown action type: "+i)},z.prototype.subscribe=function(e,t){return l(e,this._subscribers,t)},z.prototype.subscribeAction=function(e,t){return l("function"==typeof e?{before:e}:e,this._actionSubscribers,t)},z.prototype.watch=function(t,n,a){var i=this;return s("function"==typeof t,"store.watch only accepts a function."),e.watch(function(){return t(i.state,i.getters)},n,Object.assign({},a))},z.prototype.replaceState=function(e){var t=this;this._withCommit(function(){t._state.data=e})},z.prototype.registerModule=function(e,t,n){void 0===n&&(n={}),"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),s(e.length>0,"cannot register the root module by using registerModule."),this._modules.register(e,t),d(this,this.state,e,this._modules.get(e),n.preserveState),c(this,this.state)},z.prototype.unregisterModule=function(e){var t=this;"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),this._modules.unregister(e),this._withCommit(function(){delete p(t.state,e.slice(0,-1))[e[e.length-1]]}),u(this)},z.prototype.hasModule=function(e){return"string"==typeof e&&(e=[e]),s(Array.isArray(e),"module path must be a string or an Array."),this._modules.isRegistered(e)},z.prototype.hotUpdate=function(e){this._modules.update(e),u(this,!0)},z.prototype._withCommit=function(e){var t=this._committing;this._committing=!0,e(),this._committing=t},Object.defineProperties(z.prototype,I);var N=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapState: mapper parameter must be either an Array or an Object"),q(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){var t=this.$store.state,n=this.$store.getters;if(e){var a=V(this.$store,"mapState",e);if(!a)return;t=a.context.state,n=a.context.getters}return"function"==typeof i?i.call(this,t,n):t[i]},n[a].vuex=!0}),n}),O=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapMutations: mapper parameter must be either an Array or an Object"),q(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var a=this.$store.commit;if(e){var r=V(this.$store,"mapMutations",e);if(!r)return;a=r.context.commit}return"function"==typeof i?i.apply(this,[a].concat(t)):a.apply(this.$store,[i].concat(t))}}),n}),j=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapGetters: mapper parameter must be either an Array or an Object"),q(t).forEach(function(t){var a=t.key,i=t.val;i=e+i,n[a]=function(){if(!e||V(this.$store,"mapGetters",e)){if(i in this.$store.getters)return this.$store.getters[i];console.error("[vuex] unknown getter: "+i)}},n[a].vuex=!0}),n}),D=F(function(e,t){var n={};return B(t)||console.error("[vuex] mapActions: mapper parameter must be either an Array or an Object"),q(t).forEach(function(t){var a=t.key,i=t.val;n[a]=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];var a=this.$store.dispatch;if(e){var r=V(this.$store,"mapActions",e);if(!r)return;a=r.context.dispatch}return"function"==typeof i?i.apply(this,[a].concat(t)):a.apply(this.$store,[i].concat(t))}}),n});function q(e){return B(e)?Array.isArray(e)?e.map(function(e){return{key:e,val:e}}):Object.keys(e).map(function(t){return{key:t,val:e[t]}}):[]}function B(e){return Array.isArray(e)||o(e)}function F(e){return function(t,n){return"string"!=typeof t?(n=t,t=""):"/"!==t.charAt(t.length-1)&&(t+="/"),e(t,n)}}function V(e,t,n){var a=e._modulesNamespaceMap[n];return a||console.error("[vuex] module namespace not found in "+t+"(): "+n),a}function U(e,t,n){var a=n?e.groupCollapsed:e.group;try{a.call(e,t)}catch(n){e.log(t)}}function $(e){try{e.groupEnd()}catch(t){e.log("—— log end ——")}}function H(){var e=new Date;return" @ "+W(e.getHours(),2)+":"+W(e.getMinutes(),2)+":"+W(e.getSeconds(),2)+"."+W(e.getMilliseconds(),3)}function W(e,t){return n="0",a=t-e.toString().length,new Array(a+1).join(n)+e;var n,a}return{version:"4.1.0",Store:z,storeKey:t,createStore:function(e){return new z(e)},useStore:function(n){return void 0===n&&(n=null),e.inject(null!==n?n:t)},mapState:N,mapMutations:O,mapGetters:j,mapActions:D,createNamespacedHelpers:function(e){return{mapState:N.bind(null,e),mapGetters:j.bind(null,e),mapMutations:O.bind(null,e),mapActions:D.bind(null,e)}},createLogger:function(e){void 0===e&&(e={});var t=e.collapsed;void 0===t&&(t=!0);var n=e.filter;void 0===n&&(n=function(e,t,n){return!0});var a=e.transformer;void 0===a&&(a=function(e){return e});var r=e.mutationTransformer;void 0===r&&(r=function(e){return e});var o=e.actionFilter;void 0===o&&(o=function(e,t){return!0});var s=e.actionTransformer;void 0===s&&(s=function(e){return e});var l=e.logMutations;void 0===l&&(l=!0);var u=e.logActions;void 0===u&&(u=!0);var c=e.logger;return void 0===c&&(c=console),function(e){var d=i(e.state);void 0!==c&&(l&&e.subscribe(function(e,o){var s=i(o);if(n(e,d,s)){var l=H(),u=r(e),h="mutation "+e.type+l;U(c,h,t),c.log("%c prev state","color: #9E9E9E; font-weight: bold",a(d)),c.log("%c mutation","color: #03A9F4; font-weight: bold",u),c.log("%c next state","color: #4CAF50; font-weight: bold",a(s)),$(c)}d=s}),u&&e.subscribeAction(function(e,n){if(o(e,n)){var a=H(),i=s(e),r="action "+e.type+a;U(c,r,t),c.log("%c action","color: #03A9F4; font-weight: bold",i),$(c)}}))}}}}(Vue),VueI18n=function(e,t){"use strict";var n=function(e){var t=Object.create(null);if(e)for(var n in e)t[n]=e[n];return t.default=e,Object.freeze(t)}(t);function a(e,t){"undefined"!=typeof console&&(console.warn("[intlify] "+e),t&&console.warn(t.stack))}const i="undefined"!=typeof window,r=(e,t=!1)=>t?Symbol.for(e):Symbol(e),o=(e,t,n)=>s({l:e,k:t,s:n}),s=e=>JSON.stringify(e).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/\u0027/g,"\\u0027"),l=e=>"number"==typeof e&&isFinite(e),u=e=>"[object Date]"===C(e),c=e=>"[object RegExp]"===C(e),d=e=>T(e)&&0===Object.keys(e).length,h=Object.assign,p=Object.create,f=(e=null)=>p(e);function m(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/").replace(/=/g,"=")}function _(e){return e.replace(/&(?![a-zA-Z0-9#]{2,6};)/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}const g=Object.prototype.hasOwnProperty;function v(e,t){return g.call(e,t)}const b=Array.isArray,y=e=>"function"==typeof e,w=e=>"string"==typeof e,k=e=>"boolean"==typeof e,x=e=>null!==e&&"object"==typeof e,S=Object.prototype.toString,C=e=>S.call(e),T=e=>"[object Object]"===C(e);function P(e,t=""){return e.reduce((e,n,a)=>0===a?e+n:e+t+n,"")}const E=e=>!x(e)||b(e);function A(e,t){if(E(e)||E(t))throw new Error("Invalid value");const n=[{src:e,des:t}];for(;n.length;){const{src:e,des:t}=n.pop();Object.keys(e).forEach(a=>{"__proto__"!==a&&(x(e[a])&&!x(t[a])&&(t[a]=Array.isArray(e[a])?[]:f()),E(t[a])||E(e[a])?t[a]=e[a]:n.push({src:e[a],des:t[a]}))})}}function L(e){throw e}const M=" ",R="\n",z=String.fromCharCode(8232),I=String.fromCharCode(8233);function N(e){const t=e;let n=0,a=1,i=1,r=0;const o=e=>"\r"===t[e]&&t[e+1]===R,s=e=>t[e]===I,l=e=>t[e]===z,u=e=>o(e)||s(e)||l(e)?R:t[e];function c(){return r=0,(e=>o(e)||(e=>t[e]===R)(e)||s(e)||l(e))(n)&&(a++,i=0),o(n)&&n++,n++,i++,t[n]}return{index:()=>n,line:()=>a,column:()=>i,peekOffset:()=>r,charAt:u,currentChar:()=>u(n),currentPeek:()=>u(n+r),next:c,peek:function(){return o(n+r)&&r++,r++,t[n+r]},reset:function(){n=0,a=1,i=1,r=0},resetPeek:function(e=0){r=e},skipToPeek:function(){const e=n+r;for(;e!==n;)c();r=0}}}const O=void 0;function j(e,t={}){const n=!1!==t.location,a=N(e),i=()=>a.index(),r=()=>({line:a.line(),column:a.column(),offset:a.index()}),o=r(),s=i(),l={currentType:13,offset:s,startLoc:o,endLoc:o,lastType:13,lastOffset:s,lastStartLoc:o,lastEndLoc:o,braceNest:0,inLinked:!1,text:""},{onError:u}=t;function c(e,t,a){e.endLoc=r(),e.currentType=t;const i={type:t};return n&&(i.loc=function(e,t){return{start:e,end:t}}(e.startLoc,e.endLoc)),null!=a&&(i.value=a),i}const d=e=>c(e,13);function h(e,t){return e.currentChar()===t?(e.next(),t):(r(),"")}function p(e){let t="";for(;e.currentPeek()===M||e.currentPeek()===R;)t+=e.currentPeek(),e.peek();return t}function f(e){const t=p(e);return e.skipToPeek(),t}function m(e){if(e===O)return!1;const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||95===t}function _(e){p(e);const t="|"===e.currentPeek();return e.resetPeek(),t}function g(e,t=!0){const n=(t=!1,a="")=>{const i=e.currentPeek();return"{"===i?t:"@"!==i&&i?"|"===i?!(a===M||a===R):i===M?(e.peek(),n(!0,M)):i!==R||(e.peek(),n(!0,R)):t},a=n();return t&&e.resetPeek(),a}function v(e,t){const n=e.currentChar();return n===O?O:t(n)?(e.next(),n):null}function b(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t}function y(e){return v(e,b)}function w(e){const t=e.charCodeAt(0);return t>=97&&t<=122||t>=65&&t<=90||t>=48&&t<=57||95===t||36===t||45===t}function k(e){return v(e,w)}function x(e){const t=e.charCodeAt(0);return t>=48&&t<=57}function S(e){return v(e,x)}function C(e){const t=e.charCodeAt(0);return t>=48&&t<=57||t>=65&&t<=70||t>=97&&t<=102}function T(e){return v(e,C)}function P(e){let t="",n="";for(;t=S(e);)n+=t;return n}function E(e){return"'"!==e&&e!==R}function A(e){const t=e.currentChar();switch(t){case"\\":case"'":return e.next(),`\\${t}`;case"u":return L(e,t,4);case"U":return L(e,t,6);default:return r(),""}}function L(e,t,n){h(e,t);let a="";for(let t=0;t=1&&r(),e.next(),n=c(t,2,"{"),f(e),t.braceNest++,n;case"}":return t.braceNest>0&&2===t.currentType&&r(),e.next(),n=c(t,3,"}"),t.braceNest--,t.braceNest>0&&f(e),t.inLinked&&0===t.braceNest&&(t.inLinked=!1),n;case"@":return t.braceNest>0&&r(),n=q(e,t)||d(t),t.braceNest=0,n;default:{let a=!0,i=!0,o=!0;if(_(e))return t.braceNest>0&&r(),n=c(t,1,j(e)),t.braceNest=0,t.inLinked=!1,n;if(t.braceNest>0&&(4===t.currentType||5===t.currentType||6===t.currentType))return r(),t.braceNest=0,B(e,t);if(a=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a=m(e.currentPeek());return e.resetPeek(),a}(e,t))return n=c(t,4,function(e){f(e);let t="",n="";for(;t=k(e);)n+=t;const a=e.currentChar();if(a&&"}"!==a&&a!==O&&a!==M&&a!==R&&" "!==a){const t=I(e);return r(),n+t}return e.currentChar()===O&&r(),n}(e)),f(e),n;if(i=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a=function(e){if(e===O)return!1;const t=e.charCodeAt(0);return t>=48&&t<=57}("-"===e.currentPeek()?e.peek():e.currentPeek());return e.resetPeek(),a}(e,t))return n=c(t,5,function(e){f(e);let t="";return"-"===e.currentChar()?(e.next(),t+=`-${P(e)}`):t+=P(e),e.currentChar()===O&&r(),t}(e)),f(e),n;if(o=function(e,t){const{currentType:n}=t;if(2!==n)return!1;p(e);const a="'"===e.currentPeek();return e.resetPeek(),a}(e,t))return n=c(t,6,function(e){f(e),h(e,"'");let t="",n="";for(;t=v(e,E);)n+="\\"===t?A(e):t;const a=e.currentChar();return a===R||a===O?(r(),a===R&&(e.next(),h(e,"'")),n):(h(e,"'"),n)}(e)),f(e),n;if(!a&&!i&&!o)return n=c(t,12,I(e)),r(),n.value,f(e),n;break}}return n}function q(e,t){const{currentType:n}=t;let a=null;const i=e.currentChar();switch(7!==n&&8!==n&&11!==n&&9!==n||i!==R&&i!==M||r(),i){case"@":return e.next(),a=c(t,7,"@"),t.inLinked=!0,a;case".":return f(e),e.next(),c(t,8,".");case":":return f(e),e.next(),c(t,9,":");default:return _(e)?(a=c(t,1,j(e)),t.braceNest=0,t.inLinked=!1,a):function(e,t){const{currentType:n}=t;if(7!==n)return!1;p(e);const a="."===e.currentPeek();return e.resetPeek(),a}(e,t)||function(e,t){const{currentType:n}=t;if(7!==n&&11!==n)return!1;p(e);const a=":"===e.currentPeek();return e.resetPeek(),a}(e,t)?(f(e),q(e,t)):function(e,t){const{currentType:n}=t;if(8!==n)return!1;p(e);const a=m(e.currentPeek());return e.resetPeek(),a}(e,t)?(f(e),c(t,11,function(e){let t="",n="";for(;t=y(e);)n+=t;return n}(e))):function(e,t){const{currentType:n}=t;if(9!==n)return!1;const a=()=>{const t=e.currentPeek();return"{"===t?m(e.peek()):!("@"===t||"|"===t||":"===t||"."===t||t===M||!t)&&(t===R?(e.peek(),a()):g(e,!1))},i=a();return e.resetPeek(),i}(e,t)?(f(e),"{"===i?D(e,t)||a:c(t,10,function(e){const t=n=>{const a=e.currentChar();return"{"!==a&&"@"!==a&&"|"!==a&&"("!==a&&")"!==a&&a?a===M?n:(n+=a,e.next(),t(n)):n};return t("")}(e))):(7===n&&r(),t.braceNest=0,t.inLinked=!1,B(e,t))}}function B(e,t){let n={type:13};if(t.braceNest>0)return D(e,t)||d(t);if(t.inLinked)return q(e,t)||d(t);switch(e.currentChar()){case"{":return D(e,t)||d(t);case"}":return r(),e.next(),c(t,3,"}");case"@":return q(e,t)||d(t);default:if(_(e))return n=c(t,1,j(e)),t.braceNest=0,t.inLinked=!1,n;if(g(e))return c(t,0,function(e){let t="";for(;;){const n=e.currentChar();if("\\"===n){const a=e.peek();"{"===a||"}"===a||"@"===a||"|"===a||"\\"===a?(t+=n+a,e.next(),e.next()):(e.resetPeek(),t+=n,e.next())}else{if("{"===n||"}"===n||"@"===n||"|"===n||!n)break;if(n===M||n===R)if(g(e))t+=n,e.next();else{if(_(e))break;t+=n,e.next()}else t+=n,e.next()}}return t}(e))}return n}return{nextToken:function(){const{currentType:e,offset:t,startLoc:n,endLoc:o}=l;return l.lastType=e,l.lastOffset=t,l.lastStartLoc=n,l.lastEndLoc=o,l.offset=i(),l.startLoc=r(),a.currentChar()===O?c(l,13):B(a,l)},currentOffset:i,currentPosition:r,context:()=>l}}const D=/(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g,q=/\\([\\@{}|])/g;function B(e,t){return t}function F(e,t,n){switch(e){case"\\\\":return"\\";case"\\'":return"'";default:{const e=parseInt(t||n,16);return e<=55295||e>=57344?String.fromCodePoint(e):"�"}}}function V(e={}){const t=!1!==e.location,{onError:n}=e;function a(e,n,a){const i={type:e};return t&&(i.start=n,i.end=n,i.loc={start:a,end:a}),i}function i(e,n,a,i){t&&(e.end=n,e.loc&&(e.loc.end=a))}function r(e,t){const n=e.context(),r=a(3,n.offset,n.startLoc);return r.value=t.replace(q,B),i(r,e.currentOffset(),e.currentPosition()),r}function o(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:o}=n,s=a(5,r,o);return s.index=parseInt(t,10),e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function s(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:o}=n,s=a(4,r,o);return s.key=t,e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function l(e,t){const n=e.context(),{lastOffset:r,lastStartLoc:o}=n,s=a(9,r,o);return s.value=t.replace(D,F),e.nextToken(),i(s,e.currentOffset(),e.currentPosition()),s}function u(e){const t=e.context(),n=a(6,t.offset,t.startLoc);let r=e.nextToken();if(8===r.type){const t=function(e){const t=e.nextToken(),n=e.context(),{lastOffset:r,lastStartLoc:o}=n,s=a(8,r,o);return 11!==t.type?(n.lastStartLoc,s.value="",i(s,r,o),{nextConsumeToken:t,node:s}):(null==t.value&&(n.lastStartLoc,U(t)),s.value=t.value||"",i(s,e.currentOffset(),e.currentPosition()),{node:s})}(e);n.modifier=t.node,r=t.nextConsumeToken||e.nextToken()}switch(9!==r.type&&(t.lastStartLoc,U(r)),r=e.nextToken(),2===r.type&&(r=e.nextToken()),r.type){case 10:null==r.value&&(t.lastStartLoc,U(r)),n.key=function(e,t){const n=e.context(),r=a(7,n.offset,n.startLoc);return r.value=t,i(r,e.currentOffset(),e.currentPosition()),r}(e,r.value||"");break;case 4:null==r.value&&(t.lastStartLoc,U(r)),n.key=s(e,r.value||"");break;case 5:null==r.value&&(t.lastStartLoc,U(r)),n.key=o(e,r.value||"");break;case 6:null==r.value&&(t.lastStartLoc,U(r)),n.key=l(e,r.value||"");break;default:{t.lastStartLoc;const o=e.context(),s=a(7,o.offset,o.startLoc);return s.value="",i(s,o.offset,o.startLoc),n.key=s,i(n,o.offset,o.startLoc),{nextConsumeToken:r,node:n}}}return i(n,e.currentOffset(),e.currentPosition()),{node:n}}function c(e){const t=e.context(),n=a(2,1===t.currentType?e.currentOffset():t.offset,1===t.currentType?t.endLoc:t.startLoc);n.items=[];let c=null;do{const a=c||e.nextToken();switch(c=null,a.type){case 0:null==a.value&&(t.lastStartLoc,U(a)),n.items.push(r(e,a.value||""));break;case 5:null==a.value&&(t.lastStartLoc,U(a)),n.items.push(o(e,a.value||""));break;case 4:null==a.value&&(t.lastStartLoc,U(a)),n.items.push(s(e,a.value||""));break;case 6:null==a.value&&(t.lastStartLoc,U(a)),n.items.push(l(e,a.value||""));break;case 7:{const t=u(e);n.items.push(t.node),c=t.nextConsumeToken||null;break}}}while(13!==t.currentType&&1!==t.currentType);return i(n,1===t.currentType?t.lastOffset:e.currentOffset(),1===t.currentType?t.lastEndLoc:e.currentPosition()),n}return{parse:function(n){const r=j(n,h({},e)),o=r.context(),s=a(0,o.offset,o.startLoc);return t&&s.loc&&(s.loc.source=n),s.body=function(e){const t=e.context(),{offset:n,startLoc:r}=t,o=c(e);return 13===t.currentType?o:function(e,t,n,r){const o=e.context();let s=0===r.items.length;const l=a(1,t,n);l.cases=[],l.cases.push(r);do{const t=c(e);s||(s=0===t.items.length),l.cases.push(t)}while(13!==o.currentType);return i(l,e.currentOffset(),e.currentPosition()),l}(e,n,r,o)}(r),e.onCacheKey&&(s.cacheKey=e.onCacheKey(n)),13!==o.currentType&&(o.lastStartLoc,n[o.offset]),i(s,r.currentOffset(),r.currentPosition()),s}}}function U(e){if(13===e.type)return"EOF";const t=(e.value||"").replace(/\r?\n/gu,"\\n");return t.length>10?t.slice(0,9)+"…":t}function $(e,t){for(let n=0;n1){e.push(`${n("plural")}([`),e.indent(a());const i=t.cases.length;for(let n=0;n{const n=w(t.mode)?t.mode:"normal",a=w(t.filename)?t.filename:"message.intl",i=!!t.sourceMap,r=null!=t.breakLineCode?t.breakLineCode:"arrow"===n?";":"\n",o=t.needIndent?t.needIndent:"arrow"!==n,s=e.helpers||[],l=function(e,t){const{sourceMap:n,filename:a,breakLineCode:i,needIndent:r}=t,o={filename:a,code:"",column:1,line:1,offset:0,map:void 0,breakLineCode:i,needIndent:r,indentLevel:0};function s(e,t){o.code+=e}function l(e,t=!0){const n=t?i:"";s(r?n+" ".repeat(e):n)}return!1!==t.location&&e.loc&&(o.source=e.loc.source),{context:()=>o,push:s,indent:function(e=!0){const t=++o.indentLevel;e&&l(t)},deindent:function(e=!0){const t=--o.indentLevel;e&&l(t)},newline:function(){l(o.indentLevel)},helper:e=>`_${e}`,needIndent:()=>o.needIndent}}(e,{mode:n,filename:a,sourceMap:i,breakLineCode:r,needIndent:o});l.push("normal"===n?"function __msg__ (ctx) {":"(ctx) => {"),l.indent(o),s.length>0&&(l.push(`const { ${P(s.map(e=>`${e}: _${e}`),", ")} } = ctx`),l.newline()),l.push("return "),K(l,e),l.deindent(o),l.push("}"),delete e.helpers;const{code:u,map:c}=l.context();return{ast:e,code:u,map:c?c.toJSON():void 0}};function Q(e,t={}){const n=h({},t),a=!!n.jit,i=!!n.minify,r=null==n.optimize||n.optimize,o=V(n).parse(e);return a?(r&&function(e){const t=e.body;2===t.type?W(t):t.cases.forEach(e=>W(e))}(o),i&&G(o),{ast:o,code:""}):(function(e){const t=function(e){const t={ast:e,helpers:new Set};return{context:()=>t,helper:e=>(t.helpers.add(e),e)}}(e);t.helper("normalize"),e.body&&H(e.body,t);const n=t.context();e.helpers=Array.from(n.helpers)}(o,n),Y(o,n))}function Z(e){return x(e)&&0===ae(e)&&(v(e,"b")||v(e,"body"))}const J=["b","body"],X=["c","cases"],ee=["s","static"],te=["i","items"],ne=["t","type"];function ae(e){return se(e,ne)}const ie=["v","value"];const re=["m","modifier"],oe=["k","key"];function se(e,t,n){for(let n=0;nfunction(e,t){const n=se(t,J);if(null==n)throw ue(0);if(1===ae(n)){const t=function(e){return se(e,X,[])}(n);return e.plural(t.reduce((t,n)=>[...t,de(e,n)],[]))}return de(e,n)}(t,e)}function de(e,t){const n=function(e){return se(e,ee)}(t);if(null!=n)return"text"===e.type?n:e.normalize([n]);{const n=function(e){return se(e,te,[])}(t).reduce((t,n)=>[...t,he(e,n)],[]);return e.normalize(n)}}function he(e,t){const n=ae(t);switch(n){case 3:case 9:case 7:case 8:return function(e,t){const n=se(e,ie);if(null!=n)return n;throw ue(t)}(t,n);case 4:{const a=t;if(v(a,"k")&&a.k)return e.interpolate(e.named(a.k));if(v(a,"key")&&a.key)return e.interpolate(e.named(a.key));throw ue(n)}case 5:{const a=t;if(v(a,"i")&&l(a.i))return e.interpolate(e.list(a.i));if(v(a,"index")&&l(a.index))return e.interpolate(e.list(a.index));throw ue(n)}case 6:{const n=t,a=function(e){return se(e,re)}(n),i=function(e){const t=se(e,oe);if(t)return t;throw ue(6)}(n);return e.linked(he(e,i),a?he(e,a):void 0,e.type)}default:throw new Error(`unhandled node on format message part: ${n}`)}}const pe=e=>e;let fe=f();const me=17,_e=18,ge=19,ve=21,be=22,ye=23;function we(e,t){return null!=t.locale?xe(t.locale):xe(e.locale)}let ke;function xe(e){if(w(e))return e;if(y(e)){if(e.resolvedOnce&&null!=ke)return ke;if("Function"===e.constructor.name){const t=e();if((e=>x(e)&&y(e.then)&&y(e.catch))(t))throw Error(ve);return ke=t}throw Error(be)}throw Error(ye)}function Se(e,t,n){return[...new Set([n,...b(t)?t:x(t)?Object.keys(t):w(t)?[t]:[n]])]}function Ce(e,t,n){const a=w(n)?n:Ie,i=e;i.__localeChainCache||(i.__localeChainCache=new Map);let r=i.__localeChainCache.get(a);if(!r){r=[];let e=[n];for(;b(e);)e=Te(r,e,t);const o=b(t)||!T(t)?t:t.default?t.default:null;e=w(o)?[o]:o,b(e)&&Te(r,e,!1),i.__localeChainCache.set(a,r)}return r}function Te(e,t,n){let a=!0;for(let i=0;i`${e.charAt(0).toLocaleUpperCase()}${e.substr(1)}`;let Oe,je,De,qe=null;const Be=e=>{qe=e};let Fe=0;function Ve(e={}){const t=y(e.onWarn)?e.onWarn:a,n=w(e.version)?e.version:"11.4.2",i=w(e.locale)||y(e.locale)?e.locale:Ie,r=y(i)?Ie:i,o=b(e.fallbackLocale)||T(e.fallbackLocale)||w(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:r,s=T(e.messages)?e.messages:Ue(r),l=T(e.datetimeFormats)?e.datetimeFormats:Ue(r),u=T(e.numberFormats)?e.numberFormats:Ue(r),d=h(f(),e.modifiers,{upper:(e,t)=>"text"===t&&w(e)?e.toUpperCase():"vnode"===t&&x(e)&&"__v_isVNode"in e?e.children.toUpperCase():e,lower:(e,t)=>"text"===t&&w(e)?e.toLowerCase():"vnode"===t&&x(e)&&"__v_isVNode"in e?e.children.toLowerCase():e,capitalize:(e,t)=>"text"===t&&w(e)?Ne(e):"vnode"===t&&x(e)&&"__v_isVNode"in e?Ne(e.children):e}),p=e.pluralRules||f(),m=y(e.missing)?e.missing:null,_=!k(e.missingWarn)&&!c(e.missingWarn)||e.missingWarn,g=!k(e.fallbackWarn)&&!c(e.fallbackWarn)||e.fallbackWarn,v=!!e.fallbackFormat,S=!!e.unresolving,C=y(e.postTranslation)?e.postTranslation:null,P=T(e.processor)?e.processor:null,E=!k(e.warnHtmlMessage)||e.warnHtmlMessage,A=!!e.escapeParameter,L=y(e.messageCompiler)?e.messageCompiler:Oe,M=y(e.messageResolver)?e.messageResolver:je||ze,R=y(e.localeFallbacker)?e.localeFallbacker:De||Se,z=x(e.fallbackContext)?e.fallbackContext:void 0,I=e,N=x(I.__datetimeFormatters)?I.__datetimeFormatters:new Map,O=x(I.__numberFormatters)?I.__numberFormatters:new Map,j=x(I.__meta)?I.__meta:{};Fe++;const D={version:n,cid:Fe,locale:i,fallbackLocale:o,messages:s,modifiers:d,pluralRules:p,missing:m,missingWarn:_,fallbackWarn:g,fallbackFormat:v,unresolving:S,postTranslation:C,processor:P,warnHtmlMessage:E,escapeParameter:A,messageCompiler:L,messageResolver:M,localeFallbacker:R,fallbackContext:z,onWarn:t,__meta:j};return D.datetimeFormats=l,D.numberFormats=u,D.__datetimeFormatters=N,D.__numberFormatters=O,D}const Ue=e=>({[e]:f()});function $e(e,t,n,a,i){const{missing:r,onWarn:o}=e;if(null!==r){const a=r(e,n,t,i);return w(a)?a:t}return t}function He(e,t,n){e.__localeChainCache=new Map,e.localeFallbacker(e,n,t)}function We(e,t){const n=t.indexOf(e);if(-1===n)return!1;for(let r=n+1;r{Ke.includes(e)?s[e]=n[e]:r[e]=n[e]}),w(a)?r.locale=a:T(a)&&(s=a),T(i)&&(s=i),[r.key||"",o,r,s]}function Qe(e,t,n){const a=e;for(const e in n){const n=`${t}__${e}`;a.__datetimeFormatters.has(n)&&a.__datetimeFormatters.delete(n)}}function Ze(e,...t){const{numberFormats:n,unresolving:a,fallbackLocale:i,onWarn:r,localeFallbacker:o}=e,{__numberFormatters:s}=e;if(!l(t[0]))return"";const[u,c,p,f]=Xe(...t);k(p.missingWarn)?p.missingWarn:e.missingWarn,k(p.fallbackWarn)?p.fallbackWarn:e.fallbackWarn;const m=!!p.part,_=we(e,p),g=o(e,i,_);if(!w(u)||""===u)return new Intl.NumberFormat(_.replace(/!/g,""),f).format(c);let v,b={},y=null;for(let t=0;t{Je.includes(e)?o[e]=n[e]:r[e]=n[e]}),w(a)?r.locale=a:T(a)&&(o=a),T(i)&&(o=i),[r.key||"",s,r,o]}function et(e,t,n){const a=e;for(const e in n){const n=`${t}__${e}`;a.__numberFormatters.has(n)&&a.__numberFormatters.delete(n)}}const tt=e=>e,nt=e=>"",at=e=>0===e.length?"":P(e),it=e=>null==e?"":b(e)||T(e)&&e.toString===S?JSON.stringify(e,null,2):String(e);function rt(e,t){return e=Math.abs(e),2===t?1===e?0:1:Math.min(e,2)}function ot(e={}){const t=e.locale,n=function(e){const t=l(e.pluralIndex)?e.pluralIndex:-1;return l(e.named?.count)?e.named.count:l(e.named?.n)?e.named.n:t}(e),a=w(t)&&y(e.pluralRules?.[t])?e.pluralRules[t]:rt,i=a===rt?void 0:rt,r=e.list||[],o=e.named||f();function s(t,n){return(y(e.messages)?e.messages(t,!!n):!!x(e.messages)&&e.messages[t])||(e.parent?e.parent.message(t):nt)}l(e.pluralIndex)&&(o.count||=e.pluralIndex,o.n||=e.pluralIndex);const u=y(e.processor?.normalize)?e.processor.normalize:at,c=y(e.processor?.interpolate)?e.processor.interpolate:it,d={list:e=>r[e],named:e=>o[e],plural:e=>e[a(n,e.length,i)],linked:(t,...n)=>{const[a,i]=n;let r="text",o="";1===n.length?x(a)?(o=a.modifier||o,r=a.type||r):w(a)&&(o=a||o):2===n.length&&(w(a)&&(o=a||o),w(i)&&(r=i||r));const l=s(t,!0)(d),u=""===l||void 0===l?t:l,c="vnode"===r&&b(u)&&o?u[0]:u;return o?(h=o,e.modifiers?e.modifiers[h]:tt)(c,r):c;var h},message:s,type:w(e.processor?.type)?e.processor.type:"text",interpolate:c,normalize:u,values:h(f(),r,o)};return d}const st=()=>"",lt=e=>y(e);function ut(e,...t){const{fallbackFormat:n,postTranslation:a,unresolving:i,messageCompiler:r,fallbackLocale:o,messages:s}=e,[u,c]=ht(...t),d=k(c.missingWarn)?c.missingWarn:e.missingWarn,h=k(c.fallbackWarn)?c.fallbackWarn:e.fallbackWarn,p=k(c.escapeParameter)?c.escapeParameter:e.escapeParameter,g=!!c.resolvedMessage,v=w(c.default)||k(c.default)?k(c.default)?r?u:()=>u:c.default:n?r?u:()=>u:null,S=n||null!=v&&(w(v)||y(v)),C=we(e,c);p&&function(e){b(e.list)?e.list=e.list.map(e=>w(e)?m(e):e):x(e.named)&&Object.keys(e.named).forEach(t=>{w(e.named[t])&&(e.named[t]=m(e.named[t]))})}(c);let[T,P,E]=g?[u,C,s[C]||f()]:ct(e,u,C,o,h,d),A=T,L=u;if(g||w(A)||Z(A)||lt(A)||S&&(A=v,L=A),!(g||(w(A)||Z(A)||lt(A))&&w(P)))return i?-1:u;let M=!1;const R=lt(A)?A:dt(e,u,P,A,L,()=>{M=!0});if(M)return A;const z=function(e,t,n,a){const{modifiers:i,pluralRules:r,messageResolver:o,fallbackLocale:s,fallbackWarn:u,missingWarn:c,fallbackContext:d}=e,h={locale:t,modifiers:i,pluralRules:r,messages:(a,i)=>{let r=o(n,a);if(null==r&&(d||i)){const[n,,i]=ct(d||e,a,t,s,u,c);r=n??o(i,a)}if(w(r)||Z(r)){let n=!1;const i=dt(e,a,t,r,a,()=>{n=!0});return n?st:i}return lt(r)?r:st}};return e.processor&&(h.processor=e.processor),a.list&&(h.list=a.list),a.named&&(h.named=a.named),l(a.plural)&&(h.pluralIndex=a.plural),h}(e,P,E,c),I=function(e,t,n){return t(n)}(0,R,ot(z));let N=a?a(I,u):I;var O;return p&&w(N)&&(O=(O=(O=N).replace(/(\w+)\s*=\s*"([^"]*)"/g,(e,t,n)=>`${t}="${_(n)}"`)).replace(/(\w+)\s*=\s*'([^']*)'/g,(e,t,n)=>`${t}='${_(n)}'`),/\s*on\w+\s*=\s*["']?[^"'>]+["']?/gi.test(O)&&(O=O.replace(/(\s+)(on)(\w+\s*=)/gi,"$1on$3")),[/(\s+(?:href|src|action|formaction)\s*=\s*["']?)\s*javascript:/gi,/(style\s*=\s*["'][^"']*url\s*\(\s*)javascript:/gi].forEach(e=>{O=O.replace(e,"$1javascript:")}),N=O),N}function ct(e,t,n,a,i,r){const{messages:o,onWarn:s,messageResolver:l,localeFallbacker:u}=e,c=u(e,a,n);let d,h=f(),p=null;for(let n=0;na;return e.locale=n,e.key=t,e}const u=s(a,function(e,t,n,a,i,r){return{locale:t,key:n,warnHtmlMessage:i,onError:e=>{throw r&&r(e),e},onCacheKey:e=>o(t,n,e)}}(0,n,i,0,l,r));return u.locale=n,u.key=t,u.source=a,u}function ht(...e){const[t,n,a]=e,i=f();if(!(w(t)||l(t)||lt(t)||Z(t)))throw Error(me);const r=l(t)?String(t):(lt(t),t);return l(n)?i.plural=n:w(n)?i.default=n:T(n)&&!d(n)?i.named=n:b(n)&&(i.list=n),l(a)?i.plural=a:w(a)?i.default=a:T(a)&&h(i,a),[r,i]}const pt="11.4.2",ft=24,mt=25,_t=26,gt=27,vt=28,bt=29,yt=31,wt=32,kt=34,xt=r("__translateVNode"),St=r("__datetimeParts"),Ct=r("__numberParts"),Tt=r("__setPluralRules"),Pt=r("__injectWithOption"),Et=r("__dispose");function At(e){if(!x(e))return e;if(Z(e))return e;for(const t in e)if(v(e,t))if(t.includes(".")){const n=t.split("."),a=n.length-1;let i=e,r=!1;for(let e=0;e{if("locale"in e&&"resource"in e){const{locale:t,resource:n}=e;t?(o[t]=o[t]||f(),A(n,o[t])):A(n,o)}else w(e)&&A(JSON.parse(e),o)}),null==i&&r)for(const e in o)v(o,e)&&At(o[e]);return o}function Mt(e,t,n){let a=x(t.messages)?t.messages:f();"__i18nGlobal"in n&&(a=Lt(e.locale.value,{messages:a,__i18n:n.__i18nGlobal}));const i=Object.keys(a);if(i.length&&i.forEach(t=>{e.mergeLocaleMessage(t,a[t])}),x(t.datetimeFormats)){const n=Object.keys(t.datetimeFormats);n.length&&n.forEach(n=>{e.mergeDateTimeFormat(n,t.datetimeFormats[n])})}if(x(t.numberFormats)){const n=Object.keys(t.numberFormats);n.length&&n.forEach(n=>{e.mergeNumberFormat(n,t.numberFormats[n])})}}function Rt(e){return t.createVNode(t.Text,null,e,0)}function zt(){const e="currentInstance";return e in n?n[e]:n.getCurrentInstance()}const It=()=>[],Nt=()=>!1;let Ot=0;function jt(e){return(t,n,a,i)=>e(n,a,zt()||void 0,i)}function Dt(e={}){const{__root:n,__injectWithOption:a}=e,r=void 0===n,o=e.flatJson,s=i?t.ref:t.shallowRef;let u=!k(e.inheritLocale)||e.inheritLocale;const d=s(n&&u?n.locale.value:w(e.locale)?e.locale:Ie),p=s(n&&u?n.fallbackLocale.value:w(e.fallbackLocale)||b(e.fallbackLocale)||T(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:d.value),f=s(Lt(d.value,e)),m=s(T(e.datetimeFormats)?e.datetimeFormats:{[d.value]:{}}),_=s(T(e.numberFormats)?e.numberFormats:{[d.value]:{}});let g=n?n.missingWarn:!k(e.missingWarn)&&!c(e.missingWarn)||e.missingWarn,S=n?n.fallbackWarn:!k(e.fallbackWarn)&&!c(e.fallbackWarn)||e.fallbackWarn,C=n?n.fallbackRoot:!k(e.fallbackRoot)||e.fallbackRoot,P=!!e.fallbackFormat,E=y(e.missing)?e.missing:null,L=y(e.missing)?jt(e.missing):null,M=y(e.postTranslation)?e.postTranslation:null,R=n?n.warnHtmlMessage:!k(e.warnHtmlMessage)||e.warnHtmlMessage,z=!!e.escapeParameter;const I=n?n.modifiers:T(e.modifiers)?e.modifiers:{};let N,O=e.pluralRules||n&&n.pluralRules;N=(()=>{r&&Be(null);const t={version:pt,locale:d.value,fallbackLocale:p.value,messages:f.value,modifiers:I,pluralRules:O,missing:null===L?void 0:L,missingWarn:g,fallbackWarn:S,fallbackFormat:P,unresolving:!0,postTranslation:null===M?void 0:M,warnHtmlMessage:R,escapeParameter:z,messageResolver:e.messageResolver,messageCompiler:e.messageCompiler,__meta:{framework:"vue"}};t.datetimeFormats=m.value,t.numberFormats=_.value,t.__datetimeFormatters=T(N)?N.__datetimeFormatters:void 0,t.__numberFormatters=T(N)?N.__numberFormatters:void 0;const n=Ve(t);return r&&Be(n),n})(),He(N,d.value,p.value);const j=t.computed({get:()=>d.value,set:e=>{N.locale=e,d.value=e}}),D=t.computed({get:()=>p.value,set:e=>{N.fallbackLocale=e,p.value=e,He(N,d.value,e)}}),q=t.computed(()=>f.value),B=t.computed(()=>m.value),F=t.computed(()=>_.value),V=(e,t,a,i,o,s)=>{let u;d.value,p.value,f.value,m.value,_.value;try{r||(N.fallbackContext=n?qe:void 0),u=e(N)}finally{r||(N.fallbackContext=void 0)}if("translate exists"!==a&&l(u)&&-1===u||"translate exists"===a&&!u){const[e,a]=t();return n&&C?i(n):o(e)}if(s(u))return u;throw Error(ft)};function U(...e){return V(t=>Reflect.apply(ut,null,[t,...e]),()=>ht(...e),"translate",t=>Reflect.apply(t.t,t,[...e]),e=>e,e=>w(e))}const $={normalize:function(e){return e.map(e=>w(e)||l(e)||k(e)?Rt(String(e)):e)},interpolate:e=>e,type:"vnode"};function H(e){return f.value[e]||{}}Ot++,n&&i&&(t.watch(n.locale,e=>{u&&(d.value=e,N.locale=e,He(N,d.value,p.value))}),t.watch(n.fallbackLocale,e=>{u&&(p.value=e,N.fallbackLocale=e,He(N,d.value,p.value))}));const W={id:Ot,locale:j,fallbackLocale:D,get inheritLocale(){return u},set inheritLocale(e){u=e,e&&n&&(d.value=n.locale.value,p.value=n.fallbackLocale.value,He(N,d.value,p.value))},get availableLocales(){return Object.keys(f.value).sort()},messages:q,get modifiers(){return I},get pluralRules(){return O||{}},get isGlobal(){return r},get missingWarn(){return g},set missingWarn(e){g=e,N.missingWarn=g},get fallbackWarn(){return S},set fallbackWarn(e){S=e,N.fallbackWarn=S},get fallbackRoot(){return C},set fallbackRoot(e){C=e},get fallbackFormat(){return P},set fallbackFormat(e){P=e,N.fallbackFormat=P},get warnHtmlMessage(){return R},set warnHtmlMessage(e){R=e,N.warnHtmlMessage=e},get escapeParameter(){return z},set escapeParameter(e){z=e,N.escapeParameter=e},t:U,getLocaleMessage:H,setLocaleMessage:function(e,t){if(o){const n={[e]:t};for(const e in n)v(n,e)&&At(n[e]);t=n[e]}f.value[e]=t,N.messages=f.value},mergeLocaleMessage:function(e,t){f.value[e]=f.value[e]||{};const n={[e]:t};if(o)for(const e in n)v(n,e)&&At(n[e]);A(t=n[e],f.value[e]),N.messages=f.value},getPostTranslationHandler:function(){return y(M)?M:null},setPostTranslationHandler:function(e){M=e,N.postTranslation=e},getMissingHandler:function(){return E},setMissingHandler:function(e){null!==e&&(L=jt(e)),E=e,N.missing=L},[Tt]:function(e){O=e,N.pluralRules=O}};return W.datetimeFormats=B,W.numberFormats=F,W.rt=function(...e){const[t,n,a]=e;if(a&&!x(a))throw Error(mt);return U(t,n,h({resolvedMessage:!0},a||{}))},W.te=function(e,t){return V(()=>{if(!e)return!1;const n=w(t)?t:d.value,a=w(t)?[n]:Ce(N,p.value,n);for(let t=0;t[e],"translate exists",n=>Reflect.apply(n.te,n,[e,t]),Nt,e=>k(e))},W.tm=function(e){const t=function(e){let t=null;const n=Ce(N,p.value,d.value);for(let a=0;aReflect.apply(Ge,null,[t,...e]),()=>Ye(...e),"datetime format",t=>Reflect.apply(t.d,t,[...e]),()=>"",e=>w(e)||b(e))},W.n=function(...e){return V(t=>Reflect.apply(Ze,null,[t,...e]),()=>Xe(...e),"number format",t=>Reflect.apply(t.n,t,[...e]),()=>"",e=>w(e)||b(e))},W.getDateTimeFormat=function(e){return m.value[e]||{}},W.setDateTimeFormat=function(e,t){m.value[e]=t,N.datetimeFormats=m.value,Qe(N,e,t)},W.mergeDateTimeFormat=function(e,t){m.value[e]=h(m.value[e]||{},t),N.datetimeFormats=m.value,Qe(N,e,t)},W.getNumberFormat=function(e){return _.value[e]||{}},W.setNumberFormat=function(e,t){_.value[e]=t,N.numberFormats=_.value,et(N,e,t)},W.mergeNumberFormat=function(e,t){_.value[e]=h(_.value[e]||{},t),N.numberFormats=_.value,et(N,e,t)},W[Pt]=a,W[xt]=function(...e){return V(t=>{let n;const a=t;try{a.processor=$,n=Reflect.apply(ut,null,[a,...e])}finally{a.processor=null}return n},()=>ht(...e),"translate",t=>t[xt](...e),e=>[Rt(e)],e=>b(e))},W[St]=function(...e){return V(t=>Reflect.apply(Ge,null,[t,...e]),()=>Ye(...e),"datetime format",t=>t[St](...e),It,e=>w(e)||b(e))},W[Ct]=function(...e){return V(t=>Reflect.apply(Ze,null,[t,...e]),()=>Xe(...e),"number format",t=>t[Ct](...e),It,e=>w(e)||b(e))},W}function qt(e={}){const t=Dt(function(e){const t=w(e.locale)?e.locale:Ie,n=w(e.fallbackLocale)||b(e.fallbackLocale)||T(e.fallbackLocale)||!1===e.fallbackLocale?e.fallbackLocale:t,a=y(e.missing)?e.missing:void 0,i=!k(e.silentTranslationWarn)&&!c(e.silentTranslationWarn)||!e.silentTranslationWarn,r=!k(e.silentFallbackWarn)&&!c(e.silentFallbackWarn)||!e.silentFallbackWarn,o=!k(e.fallbackRoot)||e.fallbackRoot,s=!!e.formatFallbackMessages,l=T(e.modifiers)?e.modifiers:{},u=e.pluralizationRules,d=y(e.postTranslation)?e.postTranslation:void 0,p=!w(e.warnHtmlInMessage)||"off"!==e.warnHtmlInMessage,f=!!e.escapeParameterHtml,m=!k(e.sync)||e.sync;let _=e.messages;if(T(e.sharedMessages)){const t=e.sharedMessages;_=Object.keys(t).reduce((e,n)=>{const a=e[n]||(e[n]={});return h(a,t[n]),e},_||{})}const{__i18n:g,__root:v,__injectWithOption:x}=e,S=e.datetimeFormats,C=e.numberFormats;return{locale:t,fallbackLocale:n,messages:_,flatJson:e.flatJson,datetimeFormats:S,numberFormats:C,missing:a,missingWarn:i,fallbackWarn:r,fallbackRoot:o,fallbackFormat:s,modifiers:l,pluralRules:u,postTranslation:d,warnHtmlMessage:p,escapeParameter:f,messageResolver:e.messageResolver,inheritLocale:m,__i18n:g,__root:v,__injectWithOption:x}}(e)),{__extender:n}=e,a={id:t.id,get locale(){return t.locale.value},set locale(e){t.locale.value=e},get fallbackLocale(){return t.fallbackLocale.value},set fallbackLocale(e){t.fallbackLocale.value=e},get messages(){return t.messages.value},get datetimeFormats(){return t.datetimeFormats.value},get numberFormats(){return t.numberFormats.value},get availableLocales(){return t.availableLocales},get missing(){return t.getMissingHandler()},set missing(e){t.setMissingHandler(e)},get silentTranslationWarn(){return k(t.missingWarn)?!t.missingWarn:t.missingWarn},set silentTranslationWarn(e){t.missingWarn=k(e)?!e:e},get silentFallbackWarn(){return k(t.fallbackWarn)?!t.fallbackWarn:t.fallbackWarn},set silentFallbackWarn(e){t.fallbackWarn=k(e)?!e:e},get modifiers(){return t.modifiers},get formatFallbackMessages(){return t.fallbackFormat},set formatFallbackMessages(e){t.fallbackFormat=e},get postTranslation(){return t.getPostTranslationHandler()},set postTranslation(e){t.setPostTranslationHandler(e)},get sync(){return t.inheritLocale},set sync(e){t.inheritLocale=e},get warnHtmlInMessage(){return t.warnHtmlMessage?"warn":"off"},set warnHtmlInMessage(e){t.warnHtmlMessage="off"!==e},get escapeParameterHtml(){return t.escapeParameter},set escapeParameterHtml(e){t.escapeParameter=e},get pluralizationRules(){return t.pluralRules||{}},__composer:t,t:(...e)=>Reflect.apply(t.t,t,[...e]),rt:(...e)=>Reflect.apply(t.rt,t,[...e]),te:(e,n)=>t.te(e,n),tm:e=>t.tm(e),getLocaleMessage:e=>t.getLocaleMessage(e),setLocaleMessage(e,n){t.setLocaleMessage(e,n)},mergeLocaleMessage(e,n){t.mergeLocaleMessage(e,n)},d:(...e)=>Reflect.apply(t.d,t,[...e]),getDateTimeFormat:e=>t.getDateTimeFormat(e),setDateTimeFormat(e,n){t.setDateTimeFormat(e,n)},mergeDateTimeFormat(e,n){t.mergeDateTimeFormat(e,n)},n:(...e)=>Reflect.apply(t.n,t,[...e]),getNumberFormat:e=>t.getNumberFormat(e),setNumberFormat(e,n){t.setNumberFormat(e,n)},mergeNumberFormat(e,n){t.mergeNumberFormat(e,n)}};return a.__extender=n,a}function Bt(e,t){e.locale=t.locale||e.locale,e.fallbackLocale=t.fallbackLocale||e.fallbackLocale,e.missing=t.missing||e.missing,e.silentTranslationWarn=t.silentTranslationWarn||e.silentFallbackWarn,e.silentFallbackWarn=t.silentFallbackWarn||e.silentFallbackWarn,e.formatFallbackMessages=t.formatFallbackMessages||e.formatFallbackMessages,e.postTranslation=t.postTranslation||e.postTranslation,e.warnHtmlInMessage=t.warnHtmlInMessage||e.warnHtmlInMessage,e.escapeParameterHtml=t.escapeParameterHtml||e.escapeParameterHtml,e.sync=t.sync||e.sync,e.__composer[Tt](t.pluralizationRules||e.pluralizationRules);const n=Lt(e.locale,{messages:t.messages,__i18n:t.__i18n});return Object.keys(n).forEach(t=>e.mergeLocaleMessage(t,n[t])),t.datetimeFormats&&Object.keys(t.datetimeFormats).forEach(n=>e.mergeDateTimeFormat(n,t.datetimeFormats[n])),t.numberFormats&&Object.keys(t.numberFormats).forEach(n=>e.mergeNumberFormat(n,t.numberFormats[n])),e}const Ft={tag:{type:[String,Object]},locale:{type:String},scope:{type:String,validator:e=>"parent"===e||"global"===e,default:"parent"},i18n:{type:Object}};function Vt(){return t.Fragment}const Ut=t.defineComponent({name:"i18n-t",props:h({keypath:{type:String,required:!0},plural:{type:[Number,String],validator:e=>l(e)||!isNaN(e)}},Ft),setup(e,n){const{slots:a,attrs:i}=n,r=e.i18n||Jt({useScope:e.scope,__useComponent:!0});return()=>{const o=()=>{const i=Object.keys(a).filter(e=>"_"!==e[0]),o=f();e.locale&&(o.locale=e.locale),void 0!==e.plural&&(o.plural=w(e.plural)?+e.plural:e.plural);const s=function({slots:e},n){return 1===n.length&&"default"===n[0]?(e.default?e.default():[]).reduce((e,n)=>[...e,...n.type===t.Fragment?n.children:[n]],[]):n.reduce((t,n)=>{const a=e[n];return a&&(t[n]=a()),t},f())}(n,i);return r[xt](e.keypath,s,o)},s=h(f(),i),l=w(e.tag)||x(e.tag)?e.tag:Vt();return x(l)?t.h(l,s,{default:o}):t.h(l,s,o())}}}),$t=Ut;function Ht(e,n,a,i){const{slots:r,attrs:o}=n;return()=>{const n=()=>{const t={part:!0};let n=f();e.locale&&(t.locale=e.locale),w(e.format)?t.key=e.format:x(e.format)&&(w(e.format.key)&&(t.key=e.format.key),n=Object.keys(e.format).reduce((t,n)=>a.includes(n)?h(f(),t,{[n]:e.format[n]}):t,f()));const o=i(e.value,t,n);let s=[t.key];return b(o)?s=o.map((e,t)=>{const n=r[e.type],a=n?n({[e.type]:e.value,index:t,parts:o}):[e.value];var i;return b(i=a)&&!w(i[0])&&(a[0].key=`${e.type}-${t}`),a}):w(o)&&(s=[o]),s},s=h(f(),o),l=w(e.tag)||x(e.tag)?e.tag:Vt();return x(l)?t.h(l,s,{default:n}):t.h(l,s,n())}}const Wt=t.defineComponent({name:"i18n-n",props:h({value:{type:Number,required:!0},format:{type:[String,Object]}},Ft),setup(e,t){const n=e.i18n||Jt({useScope:e.scope,__useComponent:!0});return Ht(e,t,Je,(...e)=>n[Ct](...e))}}),Gt=Wt;function Kt(e){const n=t=>{const{instance:n,value:a}=t;if(!n||!n.$)throw Error(wt);const i=function(e,t){const n=e;if("composition"===e.mode)return n.__getInstance(t)||e.global;{const a=n.__getInstance(t);return null!=a?a.__composer:e.global.__composer}}(e,n.$),r=Yt(a);return[Reflect.apply(i.t,i,[...Qt(r)]),i]};return{created:(e,a)=>{const[r,o]=n(a);i&&(e.__i18nWatcher=t.watch(o.locale,()=>{a.instance&&a.instance.$forceUpdate()})),e.__composer=o,e.textContent=r},unmounted:e=>{i&&e.__i18nWatcher&&(e.__i18nWatcher(),e.__i18nWatcher=void 0,delete e.__i18nWatcher),e.__composer&&(e.__composer=void 0,delete e.__composer)},beforeUpdate:(e,{value:t})=>{if(e.__composer){const n=e.__composer,a=Yt(t);e.textContent=Reflect.apply(n.t,n,[...Qt(a)])}},getSSRProps:e=>{const[t]=n(e);return{textContent:t}}}}function Yt(e){if(w(e))return{path:e};if(T(e)){if(!("path"in e))throw Error(vt,"path");return e}throw Error(bt)}function Qt(e){const{path:t,locale:n,args:a,choice:i,plural:r}=e,o={},s=a||{};return w(n)&&(o.locale=n),l(i)&&(o.plural=i),l(r)&&(o.plural=r),[t,s,o]}const Zt=r("global-vue-i18n");function Jt(e={}){const n=zt();if(null==n)throw Error(_t);if(!n.isCE&&null!=n.appContext.app&&!n.appContext.app.__VUE_I18N_SYMBOL__)throw Error(gt);const a=function(e){const n=t.inject(e.isCE?Zt:e.appContext.app.__VUE_I18N_SYMBOL__);if(!n)throw Error(e.isCE?yt:wt);return n}(n),i=function(e){return"composition"===e.mode?e.global:e.global.__composer}(a),r=function(e){return e.type}(n),o=function(e,t){return d(e)?"__i18n"in t?"local":"global":e.useScope?e.useScope:"local"}(e,r);if("global"===o)return Mt(i,e,r),i;if("parent"===o){let t=Xt(a,n,e.__useComponent);return null==t&&(t=i),t}if("isolated"===o){if("composition"!==a.mode)throw Error(kt);const r=a,o=h({},e),s=Xt(a,n);o.__root=s||i;const l=Dt(o);return r.__composerExtend&&(l[Et]=r.__composerExtend(l)),t.getCurrentScope()&&t.onScopeDispose(()=>{const e=l[Et];e&&(e(),delete l[Et])}),l}const s=a;let l=s.__getInstance(n);if(null==l){const a=h({},e);"__i18n"in r&&(a.__i18n=r.__i18n),i&&(a.__root=i),l=Dt(a),s.__composerExtend&&(l[Et]=s.__composerExtend(l)),function(e,n,a){t.onMounted(()=>{},n),t.onUnmounted(()=>{const t=a;e.__deleteInstance(n);const i=t[Et];i&&(i(),delete t[Et])},n)}(s,n,l),s.__setInstance(n,l)}return l}function Xt(e,t,n=!1){let a=null;const i=t.root;let r=function(e,t=!1){return null==e?null:t&&e.vnode.ctx||e.parent}(t,n);for(;null!=r;){const t=e;if("composition"===e.mode)a=t.__getInstance(r);else{const e=t.__getInstance(r);null!=e&&(a=e.__composer,n&&a&&!a[Pt]&&(a=null))}if(null!=a)break;if(i===r)break;r=r.parent}return a}const en=["locale","fallbackLocale","availableLocales"],tn=["t","rt","d","n","tm","te"],nn=t.defineComponent({name:"i18n-d",props:h({value:{type:[Number,Date],required:!0},format:{type:[String,Object]}},Ft),setup(e,t){const n=e.i18n||Jt({useScope:e.scope,__useComponent:!0});return Ht(e,t,Ke,(...e)=>n[St](...e))}}),an=nn;return Oe=function(e,t){if(w(e)){!k(t.warnHtmlMessage)||t.warnHtmlMessage;const n=(t.onCacheKey||pe)(e),a=fe[n];if(a)return a;const{ast:i,detectError:r}=function(e,t={}){let n=!1;const a=t.onError||L;return t.onError=e=>{n=!0,a(e)},{...Q(e,t),detectError:n}}(e,{...t,location:!1,jit:!0}),o=ce(i);return r?o:fe[n]=o}{const t=e.cacheKey;if(t){return fe[t]||(fe[t]=ce(e))}return ce(e)}},je=function(e,t){if(!x(e))return null;let n=Re.get(t);if(n||(n=function(e){const t=[];let n,a,i,r,o,s,l,u=-1,c=0,d=0;const h=[];function p(){const t=e[u+1];if(5===c&&"'"===t||6===c&&'"'===t)return u++,i="\\"+t,h[0](),!0}for(h[0]=()=>{void 0===a?a=i:a+=i},h[1]=()=>{void 0!==a&&(t.push(a),a=void 0)},h[2]=()=>{h[0](),d++},h[3]=()=>{if(d>0)d--,c=4,h[0]();else{if(d=0,void 0===a)return!1;if(a=function(e){const t=e.trim();return("0"!==e.charAt(0)||!isNaN(parseInt(e)))&&(n=t,Le.test(n)?function(e){const t=e.charCodeAt(0);return t!==e.charCodeAt(e.length-1)||34!==t&&39!==t?e:e.slice(1,-1)}(t):"*"+t);var n}(a),!1===a)return!1;h[1]()}};null!==c;)if(u++,n=e[u],"\\"!==n||!p()){if(r=Me(n),l=Ae[c],o=l[r]||l.l||8,8===o)return;if(c=o[0],void 0!==o[1]&&(s=h[o[1]],s&&(i=n,!1===s())))return;if(7===c)return t}}(t),n&&Re.set(t,n)),!n)return null;const a=n.length;let i=e,r=0;for(;rqt(e)):a.run(()=>Dt(e));if(null==i)throw Error(wt);return[a,i]}(e,n),l=r(""),u={get mode(){return n?"legacy":"composition"},async install(e,...i){if(e.__VUE_I18N_SYMBOL__=l,e.provide(e.__VUE_I18N_SYMBOL__,u),T(i[0])){const e=i[0];u.__composerExtend=e.__composerExtend,u.__vueI18nExtend=e.__vueI18nExtend}let r=null;!n&&a&&(r=function(e,n){const a=Object.create(null);en.forEach(e=>{const i=Object.getOwnPropertyDescriptor(n,e);if(!i)throw Error(wt);const r=t.isRef(i.value)?{get:()=>i.value.value,set(e){i.value.value=e}}:{get:()=>i.get&&i.get()};Object.defineProperty(a,e,r)}),e.config.globalProperties.$i18n=a,tn.forEach(t=>{const a=Object.getOwnPropertyDescriptor(n,t);if(!a||!a.value)throw Error(wt);Object.defineProperty(e.config.globalProperties,`$${t}`,a)});return()=>{delete e.config.globalProperties.$i18n,tn.forEach(t=>{delete e.config.globalProperties[`$${t}`]})}}(e,u.global)),function(e,t,...n){const a=T(n[0])?n[0]:{};(!k(a.globalInstall)||a.globalInstall)&&([Ut.name,"I18nT"].forEach(t=>e.component(t,Ut)),[Wt.name,"I18nN"].forEach(t=>e.component(t,Wt)),[nn.name,"I18nD"].forEach(t=>e.component(t,nn))),e.directive("t",Kt(t))}(e,u,...i),n&&e.mixin(function(e,t,n){return{beforeCreate(){const a=zt();if(!a)throw Error(wt);const i=this.$options;if(i.i18n){const a=i.i18n;if(i.__i18n&&(a.__i18n=i.__i18n),a.__root=t,this===this.$root)this.$i18n=Bt(e,a);else{a.__injectWithOption=!0,a.__extender=n.__vueI18nExtend,this.$i18n=qt(a);const e=this.$i18n;e.__extender&&(e.__disposer=e.__extender(this.$i18n))}}else if(i.__i18n)if(this===this.$root)this.$i18n=Bt(e,i);else{this.$i18n=qt({__i18n:i.__i18n,__injectWithOption:!0,__extender:n.__vueI18nExtend,__root:t});const e=this.$i18n;e.__extender&&(e.__disposer=e.__extender(this.$i18n))}else this.$i18n=e;i.__i18nGlobal&&Mt(t,i,i),this.$t=(...e)=>this.$i18n.t(...e),this.$rt=(...e)=>this.$i18n.rt(...e),this.$te=(e,t)=>this.$i18n.te(e,t),this.$d=(...e)=>this.$i18n.d(...e),this.$n=(...e)=>this.$i18n.n(...e),this.$tm=e=>this.$i18n.tm(e),n.__setInstance(a,this.$i18n)},mounted(){},unmounted(){const e=zt();if(!e)throw Error(wt);const t=this.$i18n;delete this.$t,delete this.$rt,delete this.$te,delete this.$d,delete this.$n,delete this.$tm,t.__disposer&&(t.__disposer(),delete t.__disposer,delete t.__extender),n.__deleteInstance(e),delete this.$i18n}}}(s,s.__composer,u));const o=e.unmount;e.unmount=()=>{r&&r(),u.dispose(),o()}},get global(){return s},dispose(){o.stop()},__instances:i,__getInstance:function(e){return i.get(e)||null},__setInstance:function(e,t){i.set(e,t)},__deleteInstance:function(e){i.delete(e)}};return u},e.useI18n=Jt,e.vTDirective=Kt,e}({},Vue),VueRouter=function(e,t){const n="undefined"!=typeof document;function a(e){return"object"==typeof e||"displayName"in e||"props"in e||"__vccOpts"in e}function i(e){return e.__esModule||"Module"===e[Symbol.toStringTag]||e.default&&a(e.default)}const r=Object.assign;function o(e,t){const n={};for(const a in t){const i=t[a];n[a]=l(i)?i.map(e):e(i)}return n}const s=()=>{},l=Array.isArray;function u(e,t){const n={};for(const a in e)n[a]=a in t?t[a]:e[a];return n}function c(e){const t=Array.from(arguments).slice(1);console.warn.apply(console,["[Vue Router warn]: "+e].concat(t))}const d=/#/g,h=/&/g,p=/\//g,f=/=/g,m=/\?/g,_=/\+/g,g=/%5B/g,v=/%5D/g,b=/%5E/g,y=/%60/g,w=/%7B/g,k=/%7C/g,x=/%7D/g,S=/%20/g;function C(e){return null==e?"":encodeURI(""+e).replace(k,"|").replace(g,"[").replace(v,"]")}function T(e){return C(e).replace(_,"%2B").replace(S,"+").replace(d,"%23").replace(h,"%26").replace(y,"`").replace(w,"{").replace(x,"}").replace(b,"^")}function P(e){return T(e).replace(f,"%3D")}function E(e){return function(e){return C(e).replace(d,"%23").replace(m,"%3F")}(e).replace(p,"%2F")}function A(e){if(null==e)return null;try{return decodeURIComponent(""+e)}catch{c(`Error decoding "${e}". Using original value`)}return""+e}const L=/\/$/;function M(e,t,n="/"){let a,i={},r="",o="";const s=t.indexOf("#");let l=t.indexOf("?");return l=s>=0&&l>s?-1:l,l>=0&&(a=t.slice(0,l),r=t.slice(l,s>0?s:t.length),i=e(r.slice(1))),s>=0&&(a=a||t.slice(0,s),o=t.slice(s,t.length)),a=function(e,t){if(e.startsWith("/"))return e;if(!t.startsWith("/"))return c(`Cannot resolve a relative location without an absolute path. Trying to resolve "${e}" from "${t}". It should look like "/${t}".`),e;if(!e)return t;const n=t.split("/"),a=e.split("/"),i=a[a.length-1];".."!==i&&"."!==i||a.push("");let r,o,s=n.length-1;for(r=0;r1&&s--}return n.slice(0,s).join("/")+"/"+a.slice(r).join("/")}(null!=a?a:t,n),{fullPath:a+r+o,path:a,query:i,hash:A(o)}}function R(e,t){return t&&e.toLowerCase().startsWith(t.toLowerCase())?e.slice(t.length)||"/":e}function z(e,t,n){const a=t.matched.length-1,i=n.matched.length-1;return a>-1&&a===i&&I(t.matched[a],n.matched[i])&&N(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function I(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function N(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(var n in e)if(!O(e[n],t[n]))return!1;return!0}function O(e,t){return l(e)?j(e,t):l(t)?j(t,e):(e&&e.valueOf())===(t&&t.valueOf())}function j(e,t){return l(t)?e.length===t.length&&e.every((e,n)=>e===t[n]):1===e.length&&e[0]===t}const D={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0};let q=function(e){return e.pop="pop",e.push="push",e}({}),B=function(e){return e.back="back",e.forward="forward",e.unknown="",e}({});function F(e){if(!e)if(n){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(L,"")}const V=/^[^#]+#/;function U(e,t){return e.replace(V,"#")+t}const $=()=>({left:window.scrollX,top:window.scrollY});function H(e){let t;if("el"in e){const n=e.el,a="string"==typeof n&&n.startsWith("#");if(!("string"!=typeof e.el||a&&document.getElementById(e.el.slice(1))))try{const t=document.querySelector(e.el);if(a&&t)return void c(`The selector "${e.el}" should be passed as "el: document.querySelector('${e.el}')" because it starts with "#".`)}catch{return void c(`The selector "${e.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`)}const i="string"==typeof n?a?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!i)return void c(`Couldn't find element using selector "${e.el}" returned by scrollBehavior.`);t=function(e,t){const n=document.documentElement.getBoundingClientRect(),a=e.getBoundingClientRect();return{behavior:t.behavior,left:a.left-n.left-(t.left||0),top:a.top-n.top-(t.top||0)}}(i,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.scrollX,null!=t.top?t.top:window.scrollY)}function W(e,t){return(history.state?history.state.position-t:-1)+e}const G=new Map;let K=()=>location.protocol+"//"+location.host;function Y(e,t){const{pathname:n,search:a,hash:i}=t,r=e.indexOf("#");if(r>-1){let t=i.includes(e.slice(r))?e.slice(r).length:1,n=i.slice(t);return"/"!==n[0]&&(n="/"+n),R(n,"")}return R(n,e)+a+i}function Q(e,t,n,a=!1,i=!1){return{back:e,current:t,forward:n,replaced:a,position:window.history.length,scroll:i?$():null}}function Z(e){const t=function(e){const{history:t,location:n}=window,a={value:Y(e,n)},i={value:t.state};function o(a,r,o){const s=e.indexOf("#"),l=s>-1?(n.host&&document.querySelector("base")?e:e.slice(s))+a:K()+e+a;try{t[o?"replaceState":"pushState"](r,"",l),i.value=r}catch(e){c("Error with push/replace State",e),n[o?"replace":"assign"](l)}}return i.value||o(a.value,{back:null,current:a.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:a,state:i,push:function(e,n){const s=r({},i.value,t.state,{forward:e,scroll:$()});t.state||c("history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\n\nhistory.replaceState(history.state, '', url)\n\nYou can find more information at https://router.vuejs.org/guide/migration/#Usage-of-history-state"),o(s.current,s,!0),o(e,r({},Q(a.value,e,null),{position:s.position+1},n),!1),a.value=e},replace:function(e,n){o(e,r({},t.state,Q(i.value.back,e,i.value.forward,!0),n,{position:i.value.position}),!0),a.value=e}}}(e=F(e)),n=function(e,t,n,a){let i=[],o=[],s=null;const l=({state:r})=>{const o=Y(e,location),l=n.value,u=t.value;let c=0;if(r){if(n.value=o,t.value=r,s&&s===l)return void(s=null);c=u?r.position-u.position:0}else a(o);i.forEach(e=>{e(n.value,l,{delta:c,type:q.pop,direction:c?c>0?B.forward:B.back:B.unknown})})};function u(){if("hidden"===document.visibilityState){const{history:e}=window;if(!e.state)return;e.replaceState(r({},e.state,{scroll:$()}),"")}}return window.addEventListener("popstate",l),window.addEventListener("pagehide",u),document.addEventListener("visibilitychange",u),{pauseListeners:function(){s=n.value},listen:function(e){i.push(e);const t=()=>{const t=i.indexOf(e);t>-1&&i.splice(t,1)};return o.push(t),t},destroy:function(){for(const e of o)e();o=[],window.removeEventListener("popstate",l),window.removeEventListener("pagehide",u),document.removeEventListener("visibilitychange",u)}}}(e,t.state,t.location,t.replace);const a=r({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:U.bind(null,e)},t,n);return Object.defineProperty(a,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(a,"state",{enumerable:!0,get:()=>t.state.value}),a}function J(e){return"string"==typeof e||e&&"object"==typeof e}function X(e){return"string"==typeof e||"symbol"==typeof e}let ee=function(e){return e[e.MATCHER_NOT_FOUND=1]="MATCHER_NOT_FOUND",e[e.NAVIGATION_GUARD_REDIRECT=2]="NAVIGATION_GUARD_REDIRECT",e[e.NAVIGATION_ABORTED=4]="NAVIGATION_ABORTED",e[e.NAVIGATION_CANCELLED=8]="NAVIGATION_CANCELLED",e[e.NAVIGATION_DUPLICATED=16]="NAVIGATION_DUPLICATED",e}({});const te=Symbol("navigation failure");let ne=function(e){return e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated",e}({});const ae={[ee.MATCHER_NOT_FOUND]:({location:e,currentLocation:t})=>`No match for\n ${JSON.stringify(e)}${t?"\nwhile being at\n"+JSON.stringify(t):""}`,[ee.NAVIGATION_GUARD_REDIRECT]:({from:e,to:t})=>`Redirected from "${e.fullPath}" to "${function(e){if("string"==typeof e)return e;if(null!=e.path)return e.path;const t={};for(const n of oe)n in e&&(t[n]=e[n]);return JSON.stringify(t,null,2)}(t)}" via a navigation guard.`,[ee.NAVIGATION_ABORTED]:({from:e,to:t})=>`Navigation aborted from "${e.fullPath}" to "${t.fullPath}" via a navigation guard.`,[ee.NAVIGATION_CANCELLED]:({from:e,to:t})=>`Navigation cancelled from "${e.fullPath}" to "${t.fullPath}" with a new navigation.`,[ee.NAVIGATION_DUPLICATED]:({from:e,to:t})=>`Avoided redundant navigation to current location: "${e.fullPath}".`};function ie(e,t){return r(new Error(ae[e](t)),{type:e,[te]:!0},t)}function re(e,t){return e instanceof Error&&te in e&&(null==t||!!(e.type&t))}const oe=["params","query","hash"];let se=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e}({});var le=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e}(le||{});const ue={type:se.Static,value:""},ce=/[a-zA-Z0-9_]/;const de="[^/]+?",he={sensitive:!1,strict:!1,start:!0,end:!0};var pe=function(e){return e[e._multiplier=10]="_multiplier",e[e.Root=90]="Root",e[e.Segment=40]="Segment",e[e.SubSegment=30]="SubSegment",e[e.Static=40]="Static",e[e.Dynamic=20]="Dynamic",e[e.BonusCustomRegExp=10]="BonusCustomRegExp",e[e.BonusWildcard=-50]="BonusWildcard",e[e.BonusRepeatable=-20]="BonusRepeatable",e[e.BonusOptional=-8]="BonusOptional",e[e.BonusStrict=.7000000000000001]="BonusStrict",e[e.BonusCaseSensitive=.25]="BonusCaseSensitive",e}(pe||{});const fe=/[.+*?^${}()[\]/\\]/g;function me(e,t){let n=0;for(;nt.length?1===t.length&&t[0]===pe.Static+pe.Segment?1:-1:0}function _e(e,t){let n=0;const a=e.score,i=t.score;for(;n0&&t[t.length-1]<0}const ve={strict:!1,end:!0,sensitive:!1};function be(e,t,n){const a=function(e,t){const n=r({},he,t),a=[];let i=n.start?"^":"";const o=[];for(const t of e){const e=t.length?[]:[pe.Root];n.strict&&!t.length&&(i+="/");for(let a=0;a1&&("*"===s||"+"===s)&&t(`A repeatable param (${u}) must be alone in its segment. eg: '/:ids+.`),r.push({type:se.Param,value:u,regexp:c,repeatable:"*"===s||"+"===s,optional:"*"===s||"?"===s})):t("Invalid state to consume buffer"),u="")}function h(){u+=s}for(;l{o(_)}:s}function o(e){if(X(e)){const t=a.get(e);t&&(a.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(o),t.alias.forEach(o))}else{const t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&a.delete(e.record.name),e.children.forEach(o),e.alias.forEach(o))}}function l(e){const t=function(e,t){let n=0,a=t.length;for(;n!==a;){const i=n+a>>1;_e(e,t[i])<0?a=i:n=i+1}const i=function(e){let t=e;for(;t=t.parent;)if(Le(t)&&0===_e(e,t))return t}(e);i&&(a=t.lastIndexOf(i,a-1),a<0&&c(`Finding ancestor route "${i.record.path}" failed for "${e.record.path}"`));return a}(e,n);n.splice(t,0,e),e.record.name&&!Se(e)&&a.set(e.record.name,e)}return t=u(ve,t),e.forEach(e=>i(e)),{addRoute:i,resolve:function(e,t){let i,o,s,l={};if("name"in e&&e.name){if(i=a.get(e.name),!i)throw ie(ee.MATCHER_NOT_FOUND,{location:e});{const t=Object.keys(e.params||{}).filter(e=>!i.keys.find(t=>t.name===e));t.length&&c(`Discarded invalid param(s) "${t.join('", "')}" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`)}s=i.record.name,l=r(we(t.params,i.keys.filter(e=>!e.optional).concat(i.parent?i.parent.keys.filter(e=>e.optional):[]).map(e=>e.name)),e.params&&we(e.params,i.keys.map(e=>e.name))),o=i.stringify(l)}else if(null!=e.path)o=e.path,o.startsWith("/")||c(`The Matcher cannot resolve relative paths but received "${o}". Unless you directly called \`matcher.resolve("${o}")\`, this is probably a bug in vue-router. Please open an issue at https://github.com/vuejs/router/issues/new/choose.`),i=n.find(e=>e.re.test(o)),i&&(l=i.parse(o),s=i.record.name);else{if(i=t.name?a.get(t.name):n.find(e=>e.re.test(t.path)),!i)throw ie(ee.MATCHER_NOT_FOUND,{location:e,currentLocation:t});s=i.record.name,l=r({},t.params,e.params),o=i.stringify(l)}const u=[];let d=i;for(;d;)u.unshift(d.record),d=d.parent;return{name:s,path:o,params:l,matched:u,meta:Ce(u)}},removeRoute:o,clearRoutes:function(){n.length=0,a.clear()},getRoutes:function(){return n},getRecordMatcher:function(e){return a.get(e)}}}function we(e,t){const n={};for(const a of t)a in e&&(n[a]=e[a]);return n}function ke(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:xe(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function xe(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const a in e.components)t[a]="object"==typeof n?n[a]:n;return t}function Se(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Ce(e){return e.reduce((e,t)=>r(e,t.meta),{})}function Te(e,t){return e.name===t.name&&e.optional===t.optional&&e.repeatable===t.repeatable}function Pe(e,t){for(const n of e.keys)if(!n.optional&&!t.keys.find(Te.bind(null,n)))return c(`Alias "${t.record.path}" and the original record: "${e.record.path}" must have the exact same param named "${n.name}"`);for(const n of t.keys)if(!n.optional&&!e.keys.find(Te.bind(null,n)))return c(`Alias "${t.record.path}" and the original record: "${e.record.path}" must have the exact same param named "${n.name}"`)}function Ee(e,t){for(let n=t;n;n=n.parent)if(n.record.name===e.name)throw new Error(`A route named "${String(e.name)}" has been added as a ${t===n?"child":"descendant"} of a route with the same name. Route names must be unique and a nested route cannot use the same name as an ancestor.`)}function Ae(e,t){for(const n of t.keys)if(!e.keys.find(Te.bind(null,n)))return c(`Absolute path "${e.record.path}" must have the exact same param named "${n.name}" as its parent "${t.record.path}".`)}function Le({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function Me(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let e=0;ee&&T(e)):[a&&T(a)]).forEach(e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}):void 0!==a&&(t+=(t.length?"&":"")+n)}return t}function ze(e){const t={};for(const n in e){const a=e[n];void 0!==a&&(t[n]=l(a)?a.map(e=>null==e?null:""+e):null==a?a:""+a)}return t}const Ie=Symbol("router view location matched"),Ne=Symbol("router view depth"),Oe=Symbol("router"),je=Symbol("route location"),De=Symbol("router view location");function qe(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e.slice(),reset:function(){e=[]}}}function Be(e,n,a){const i=e.value;if(!i)return void c(`No active route record was found when calling \`${"updateGuards"===n?"onBeforeRouteUpdate":"onBeforeRouteLeave"}()\`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?`);let r=i;const o=()=>{r[n].delete(a)};(0,t.onUnmounted)(o),(0,t.onDeactivated)(o),(0,t.onActivated)(()=>{const t=e.value;t||c("No active route record was found when reactivating component with navigation guard. This is likely a bug in vue-router. Please report it."),t&&(r=t),r[n].add(a)}),r[n].add(a)}function Fe(e,t,n,a,i,r=e=>e()){const o=a&&(a.enterCallbacks[i]=a.enterCallbacks[i]||[]);return()=>new Promise((s,l)=>{const u=e=>{!1===e?l(ie(ee.NAVIGATION_ABORTED,{from:n,to:t})):e instanceof Error?l(e):J(e)?l(ie(ee.NAVIGATION_GUARD_REDIRECT,{from:t,to:e})):(o&&a.enterCallbacks[i]===o&&"function"==typeof e&&o.push(e),s())},d=r(()=>e.call(a&&a.instances[i],t,n,function(e){let t=!1;return function(){return t||(t=!0,c("The `next()` callback in navigation guards is deprecated. Return the value instead of calling `next(value)`.")),e.apply(this,arguments)}}(function(e,t,n){let a=0;return function(){1===a++&&c(`The "next" callback was called more than once in one navigation guard when going from "${n.fullPath}" to "${t.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`),e._called=!0,1===a&&e.apply(null,arguments)}}(u,t,n))));let h=Promise.resolve(d);if(e.length<3&&(h=h.then(u)),e.length>2){const t=`The "next" callback was never called inside of ${e.name?'"'+e.name+'"':""}:\n${e.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`;if("object"==typeof d&&"then"in d)h=h.then(e=>u._called?e:(c(t),Promise.reject(new Error("Invalid navigation guard"))));else if(void 0!==d&&!u._called)return c(t),void l(new Error("Invalid navigation guard"))}h.catch(e=>l(e))})}function Ve(e,t,n,r,o=e=>e()){const s=[];for(const l of e){l.components||!l.children||l.children.length||c(`Record with path "${l.path}" is either missing a "component(s)" or "children" property.`);for(const e in l.components){let u=l.components[e];if(!u||"object"!=typeof u&&"function"!=typeof u)throw c(`Component "${e}" in record with path "${l.path}" is not a valid component. Received "${String(u)}".`),new Error("Invalid route component");if("then"in u){c(`Component "${e}" in record with path "${l.path}" is a Promise instead of a function that returns a Promise. Did you write "import('./MyPage.vue')" instead of "() => import('./MyPage.vue')" ? This will break in production if not fixed.`);const t=u;u=()=>t}else u.__asyncLoader&&!u.__warnedDefineAsync&&(u.__warnedDefineAsync=!0,c(`Component "${e}" in record with path "${l.path}" is defined using "defineAsyncComponent()". Write "() => import('./MyPage.vue')" instead of "defineAsyncComponent(() => import('./MyPage.vue'))".`));if("beforeRouteEnter"===t||l.instances[e])if(a(u)){const a=(u.__vccOpts||u)[t];a&&s.push(Fe(a,n,r,l,e,o))}else{let a=u();"catch"in a||(c(`Component "${e}" in record with path "${l.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`),a=Promise.resolve(a)),s.push(()=>a.then(a=>{if(!a)throw new Error(`Couldn't resolve component "${e}" at "${l.path}"`);const s=i(a)?a.default:a;l.mods[e]=a,l.components[e]=s;const u=(s.__vccOpts||s)[t];return u&&Fe(u,n,r,l,e,o)()}))}}}return s}function Ue(e){const a=(0,t.inject)(Oe),i=(0,t.inject)(je);let r=!1,o=null;const u=(0,t.computed)(()=>{const n=(0,t.unref)(e.to);return r&&n===o||(J(n)||(r?c('Invalid value for prop "to" in useLink()\n- to:',n,"\n- previous to:",o,"\n- props:",e):c('Invalid value for prop "to" in useLink()\n- to:',n,"\n- props:",e)),o=n,r=!0),a.resolve(n)}),d=(0,t.computed)(()=>{const{matched:e}=u.value,{length:t}=e,n=e[t-1],a=i.matched;if(!n||!a.length)return-1;const r=a.findIndex(I.bind(null,n));if(r>-1)return r;const o=He(e[t-2]);return t>1&&He(n)===o&&a[a.length-1].path!==o?a.findIndex(I.bind(null,e[t-2])):r}),h=(0,t.computed)(()=>d.value>-1&&function(e,t){for(const n in t){const a=t[n],i=e[n];if("string"==typeof a){if(a!==i)return!1}else if(!l(i)||i.length!==a.length||a.some((e,t)=>e.valueOf()!==i[t].valueOf()))return!1}return!0}(i.params,u.value.params)),p=(0,t.computed)(()=>d.value>-1&&d.value===i.matched.length-1&&N(i.params,u.value.params));if(n){const n=(0,t.getCurrentInstance)();if(n){const a={route:u.value,isActive:h.value,isExactActive:p.value,error:null};n.__vrl_devtools=n.__vrl_devtools||[],n.__vrl_devtools.push(a),(0,t.watchEffect)(()=>{a.route=u.value,a.isActive=h.value,a.isExactActive=p.value,a.error=J((0,t.unref)(e.to))?null:'Invalid "to" value'},{flush:"post"})}}return{route:u,href:(0,t.computed)(()=>u.value.href),isActive:h,isExactActive:p,navigate:function(n={}){if(function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(n)){const n=a[(0,t.unref)(e.replace)?"replace":"push"]((0,t.unref)(e.to)).catch(s);return e.viewTransition&&"undefined"!=typeof document&&"startViewTransition"in document&&document.startViewTransition(()=>n),n}return Promise.resolve()}}}const $e=(0,t.defineComponent)({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:Ue,setup(e,{slots:n}){const a=(0,t.reactive)(Ue(e)),{options:i}=(0,t.inject)(Oe),r=(0,t.computed)(()=>({[We(e.activeClass,i.linkActiveClass,"router-link-active")]:a.isActive,[We(e.exactActiveClass,i.linkExactActiveClass,"router-link-exact-active")]:a.isExactActive}));return()=>{const i=n.default&&(1===(o=n.default(a)).length?o[0]:o);var o;return e.custom?i:(0,t.h)("a",{"aria-current":a.isExactActive?e.ariaCurrentValue:null,href:a.href,onClick:a.navigate,class:r.value},i)}}});function He(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const We=(e,t,n)=>null!=e?e:null!=t?t:n;function Ge(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const Ke=(0,t.defineComponent)({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:a,slots:i}){!function(){const e=(0,t.getCurrentInstance)(),n=e.parent&&e.parent.type.name,a=e.parent&&e.parent.subTree&&e.parent.subTree.type;if(n&&("KeepAlive"===n||n.includes("Transition"))&&"object"==typeof a&&"RouterView"===a.name){const e="KeepAlive"===n?"keep-alive":"transition";c(` can no longer be used directly inside or .\nUse slot props instead:\n\n\n <${e}>\n \n \n`)}}();const o=(0,t.inject)(De),s=(0,t.computed)(()=>e.route||o.value),u=(0,t.inject)(Ne,0),d=(0,t.computed)(()=>{let e=(0,t.unref)(u);const{matched:n}=s.value;let a;for(;(a=n[e])&&!a.components;)e++;return e}),h=(0,t.computed)(()=>s.value.matched[d.value]);(0,t.provide)(Ne,(0,t.computed)(()=>d.value+1)),(0,t.provide)(Ie,h),(0,t.provide)(De,s);const p=(0,t.ref)();return(0,t.watch)(()=>[p.value,h.value,e.name],([e,t,n],[a,i,r])=>{t&&(t.instances[n]=e,i&&i!==t&&e&&e===a&&(t.leaveGuards.size||(t.leaveGuards=i.leaveGuards),t.updateGuards.size||(t.updateGuards=i.updateGuards))),!e||!t||i&&I(t,i)&&a||(t.enterCallbacks[n]||[]).forEach(t=>t(e))},{flush:"post"}),()=>{const o=s.value,u=e.name,c=h.value,f=c&&c.components[u];if(!f)return Ge(i.default,{Component:f,route:o});const m=c.props[u],_=m?!0===m?o.params:"function"==typeof m?m(o):m:null,g=(0,t.h)(f,r({},_,a,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(c.instances[u]=null)},ref:p}));if(n&&g.ref){const e={depth:d.value,name:c.name,path:c.path,meta:c.meta};(l(g.ref)?g.ref.map(e=>e.i):[g.ref.i]).forEach(t=>{t.__vrv_devtools=e})}return Ge(i.default,{Component:g,route:o})||g}}});return e.NavigationFailureType=ne,e.RouterLink=$e,e.RouterView=Ke,e.START_LOCATION=D,e.createMemoryHistory=function(e=""){let t=[],n=[["",{}]],a=0;function i(e,t={}){a++,a!==n.length&&n.splice(a),n.push([e,t])}const r={location:"",state:{},base:e=F(e),createHref:U.bind(null,e),replace(e,t){n.splice(a--,1),i(e,t)},push(e,t){i(e,t)},listen:e=>(t.push(e),()=>{const n=t.indexOf(e);n>-1&&t.splice(n,1)}),destroy(){t=[],n=[["",{}]],a=0},go(e,i=!0){const r=this.location,o=e<0?B.back:B.forward;a=Math.max(0,Math.min(a+e,n.length-1)),i&&function(e,n,{direction:a,delta:i}){const r={direction:a,delta:i,type:q.pop};for(const a of t)a(e,n,r)}(this.location,r,{direction:o,delta:e})}};return Object.defineProperty(r,"location",{enumerable:!0,get:()=>n[a][0]}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>n[a][1]}),r},e.createRouter=function(e){const a=ye(e.routes,e),i=e.parseQuery||Me,u=e.stringifyQuery||Re,d=e.history;if(!d)throw new Error('Provide the "history" option when calling "createRouter()": https://router.vuejs.org/api/interfaces/RouterOptions.html#history');const h=qe(),p=qe(),f=qe(),m=(0,t.shallowRef)(D);let _=D;n&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const g=o.bind(null,e=>""+e),v=o.bind(null,E),y=o.bind(null,A);function k(e,t){if(t=r({},t||m.value),"string"==typeof e){const n=M(i,e,t.path),o=a.resolve({path:n.path},t),s=d.createHref(n.fullPath);return s.startsWith("//")?c(`Location "${e}" resolved to "${s}". A resolved location cannot start with multiple slashes.`):o.matched.length||c(`No match found for location with path "${e}"`),r(n,o,{params:y(o.params),redirectedFrom:void 0,href:s})}if(!J(e))return c("router.resolve() was passed an invalid location. This will fail in production.\n- Location:",e),k({});let n;if(null!=e.path)"params"in e&&!("name"in e)&&Object.keys(e.params).length&&c(`Path "${e.path}" was passed with params but they will be ignored. Use a named route alongside params instead.`),n=r({},e,{path:M(i,e.path,t.path).path});else{const a=r({},e.params);for(const e in a)null==a[e]&&delete a[e];n=r({},e,{params:v(a)}),t.params=v(t.params)}const o=a.resolve(n,t),s=e.hash||"";s&&!s.startsWith("#")&&c(`A \`hash\` should always start with the character "#". Replace "${s}" with "#${s}".`),o.params=g(y(o.params));const l=function(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(u,r({},e,{hash:(h=s,C(h).replace(w,"{").replace(x,"}").replace(b,"^")),path:o.path}));var h;const p=d.createHref(l);return p.startsWith("//")?c(`Location "${e}" resolved to "${p}". A resolved location cannot start with multiple slashes.`):o.matched.length||c(`No match found for location with path "${null!=e.path?e.path:e}"`),r({fullPath:l,hash:s,query:u===Re?ze(e.query):e.query||{}},o,{redirectedFrom:void 0,href:p})}function S(e){return"string"==typeof e?M(i,e,m.value.path):r({},e)}function T(e,t){if(_!==e)return ie(ee.NAVIGATION_CANCELLED,{from:t,to:e})}function P(e){return R(e)}function L(e,t){const n=e.matched[e.matched.length-1];if(n&&n.redirect){const{redirect:a}=n;let i="function"==typeof a?a(e,t):a;if("string"==typeof i&&(i=i.includes("?")||i.includes("#")?i=S(i):{path:i},i.params={}),null==i.path&&!("name"in i))throw c(`Invalid redirect found:\n${JSON.stringify(i,null,2)}\n when navigating to "${e.fullPath}". A redirect must contain a name or path. This will break in production.`),new Error("Invalid redirect");return r({query:e.query,hash:e.hash,params:null!=i.path?{}:e.params},i)}}function R(e,t){const n=_=k(e),a=m.value,i=e.state,o=e.force,s=!0===e.replace,l=L(n,a);if(l)return R(r(S(l),{state:"object"==typeof l?r({},i,l.state):i,force:o,replace:s}),t||n);const d=n;let h;return d.redirectedFrom=t,!o&&z(u,a,n)&&(h=ie(ee.NAVIGATION_DUPLICATED,{to:d,from:a}),ne(a,a,!0,!1)),(h?Promise.resolve(h):j(d,a)).catch(e=>re(e)?re(e,ee.NAVIGATION_GUARD_REDIRECT)?e:te(e):Z(e,d,a)).then(e=>{if(e){if(re(e,ee.NAVIGATION_GUARD_REDIRECT))return z(u,k(e.to),d)&&t&&(t._count=t._count?t._count+1:1)>30?(c(`Detected a possibly infinite redirection in a navigation guard when going from "${a.fullPath}" to "${d.fullPath}". Aborting to avoid a Stack Overflow.\n Are you always returning a new location within a navigation guard? That would lead to this error. Only return when redirecting or aborting, that should fix this. This might break in production if not fixed.`),Promise.reject(new Error("Infinite redirect in navigation guard"))):R(r({replace:s},S(e.to),{state:"object"==typeof e.to?r({},i,e.to.state):i,force:o}),t||d)}else e=F(d,a,!0,s,i);return B(d,a,e),e})}function N(e,t){const n=T(e,t);return n?Promise.reject(n):Promise.resolve()}function O(e){const t=se.values().next().value;return t&&"function"==typeof t.runWithContext?t.runWithContext(e):e()}function j(e,t){let n;const[a,i,r]=function(e,t){const n=[],a=[],i=[],r=Math.max(t.matched.length,e.matched.length);for(let o=0;oI(e,r))?a.push(r):n.push(r));const s=e.matched[o];s&&(t.matched.find(e=>I(e,s))||i.push(s))}return[n,a,i]}(e,t);n=Ve(a.reverse(),"beforeRouteLeave",e,t);for(const i of a)i.leaveGuards.forEach(a=>{n.push(Fe(a,e,t))});const o=N.bind(null,e,t);return n.push(o),ue(n).then(()=>{n=[];for(const a of h.list())n.push(Fe(a,e,t));return n.push(o),ue(n)}).then(()=>{n=Ve(i,"beforeRouteUpdate",e,t);for(const a of i)a.updateGuards.forEach(a=>{n.push(Fe(a,e,t))});return n.push(o),ue(n)}).then(()=>{n=[];for(const a of r)if(a.beforeEnter)if(l(a.beforeEnter))for(const i of a.beforeEnter)n.push(Fe(i,e,t));else n.push(Fe(a.beforeEnter,e,t));return n.push(o),ue(n)}).then(()=>(e.matched.forEach(e=>e.enterCallbacks={}),n=Ve(r,"beforeRouteEnter",e,t,O),n.push(o),ue(n))).then(()=>{n=[];for(const a of p.list())n.push(Fe(a,e,t));return n.push(o),ue(n)}).catch(e=>re(e,ee.NAVIGATION_CANCELLED)?e:Promise.reject(e))}function B(e,t,n){f.list().forEach(a=>O(()=>a(e,t,n)))}function F(e,t,a,i,o){const s=T(e,t);if(s)return s;const l=t===D,u=n?history.state:{};a&&(i||l?d.replace(e.fullPath,r({scroll:l&&u&&u.scroll},o)):d.push(e.fullPath,o)),m.value=e,ne(e,t,a,l),te()}let V;function U(){V||(V=d.listen((e,t,a)=>{if(!le.listening)return;const i=k(e),o=L(i,le.currentRoute.value);if(o)return void R(r(o,{replace:!0,force:!0}),i).catch(s);_=i;const l=m.value;var u,c;n&&(u=W(l.fullPath,a.delta),c=$(),G.set(u,c)),j(i,l).catch(e=>re(e,ee.NAVIGATION_ABORTED|ee.NAVIGATION_CANCELLED)?e:re(e,ee.NAVIGATION_GUARD_REDIRECT)?(R(r(S(e.to),{force:!0}),i).then(e=>{re(e,ee.NAVIGATION_ABORTED|ee.NAVIGATION_DUPLICATED)&&!a.delta&&a.type===q.pop&&d.go(-1,!1)}).catch(s),Promise.reject()):(a.delta&&d.go(-a.delta,!1),Z(e,i,l))).then(e=>{(e=e||F(i,l,!1))&&(a.delta&&!re(e,ee.NAVIGATION_CANCELLED)?d.go(-a.delta,!1):a.type===q.pop&&re(e,ee.NAVIGATION_ABORTED|ee.NAVIGATION_DUPLICATED)&&d.go(-1,!1)),B(i,l,e)}).catch(s)}))}let K,Y=qe(),Q=qe();function Z(e,t,n){te(e);const a=Q.list();return a.length?a.forEach(a=>a(e,t,n)):(c("uncaught error during route navigation:"),console.error(e)),Promise.reject(e)}function te(e){return K||(K=!e,U(),Y.list().forEach(([t,n])=>e?n(e):t()),Y.reset()),e}function ne(a,i,r,o){const{scrollBehavior:s}=e;if(!n||!s)return Promise.resolve();const l=!r&&function(e){const t=G.get(e);return G.delete(e),t}(W(a.fullPath,0))||(o||!r)&&history.state&&history.state.scroll||null;return(0,t.nextTick)().then(()=>s(a,i,l)).then(e=>e&&H(e)).catch(e=>Z(e,a,i))}const ae=e=>d.go(e);let oe;const se=new Set,le={currentRoute:m,listening:!0,addRoute:function(e,t){let n,i;return X(e)?(n=a.getRecordMatcher(e),n||c(`Parent route "${String(e)}" not found when adding child route`,t),i=t):i=e,a.addRoute(i,n)},removeRoute:function(e){const t=a.getRecordMatcher(e);t?a.removeRoute(t):c(`Cannot remove non-existent route "${String(e)}"`)},clearRoutes:a.clearRoutes,hasRoute:function(e){return!!a.getRecordMatcher(e)},getRoutes:function(){return a.getRoutes().map(e=>e.record)},resolve:k,options:e,push:P,replace:function(e){return P(r(S(e),{replace:!0}))},go:ae,back:()=>ae(-1),forward:()=>ae(1),beforeEach:h.add,beforeResolve:p.add,afterEach:f.add,onError:Q.add,isReady:function(){return K&&m.value!==D?Promise.resolve():new Promise((e,t)=>{Y.add([e,t])})},install(e){e.component("RouterLink",$e),e.component("RouterView",Ke),e.config.globalProperties.$router=le,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>(0,t.unref)(m)}),n&&!oe&&m.value===D&&(oe=!0,P(d.location).catch(e=>{c("Unexpected error when starting the router:",e)}));const a={};for(const e in D)Object.defineProperty(a,e,{get:()=>m.value[e],enumerable:!0});e.provide(Oe,le),e.provide(je,(0,t.shallowReactive)(a)),e.provide(De,m);const i=e.unmount;se.add(e),e.unmount=function(){se.delete(e),se.size<1&&(_=D,V&&V(),V=null,m.value=D,oe=!1,K=!1),i()}}};function ue(e){return e.reduce((e,t)=>e.then(()=>O(t)),Promise.resolve())}return le},e.createRouterMatcher=ye,e.createWebHashHistory=function(e){return(e=location.host?e||location.pathname+location.search:"").includes("#")||(e+="#"),e.endsWith("#/")||e.endsWith("#")||c(`A hash base must end with a "#":\n"${e}" should be "${e.replace(/#.*$/,"#")}".`),Z(e)},e.createWebHistory=Z,e.isNavigationFailure=re,e.loadRouteLocation=function(e){return e.matched.every(e=>e.redirect)?Promise.reject(new Error("Cannot load a route that redirects.")):Promise.all(e.matched.map(e=>e.components&&Promise.all(Object.keys(e.components).reduce((t,n)=>{const a=e.components[n];return"function"!=typeof a||"displayName"in a||t.push(a().then(t=>{if(!t)return Promise.reject(new Error(`Couldn't resolve component "${n}" at "${e.path}". Ensure you passed a function that returns a promise.`));const a=i(t)?t.default:t;e.mods[n]=t,e.components[n]=a})),t},[])))).then(()=>e)},e.matchedRouteKey=Ie,e.onBeforeRouteLeave=function(e){(0,t.getCurrentInstance)()?Be((0,t.inject)(Ie,{}),"leaveGuards",e):c("getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function")},e.onBeforeRouteUpdate=function(e){(0,t.getCurrentInstance)()?Be((0,t.inject)(Ie,{}),"updateGuards",e):c("getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function")},e.parseQuery=Me,e.routeLocationKey=je,e.routerKey=Oe,e.routerViewLocationKey=De,e.stringifyQuery=Re,e.useLink=Ue,e.useRoute=function(e){return(0,t.inject)(je)},e.useRouter=function(){return(0,t.inject)(Oe)},e.viewDepthKey=Ne,e}({},Vue); /*! - * vue-i18n v11.2.2 - * (c) 2025 kazuya kawaguchi + * vue-i18n v11.4.2 + * (c) 2026 kazuya kawaguchi * Released under the MIT License. - */!function(e,t){"object"==typeof exports&&typeof module<"u"?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e=typeof globalThis<"u"?globalThis:e||self).VueQrcodeReader={},e.Vue)}(this,function(e,t){"use strict";var n=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)},a=(e,t,a)=>(n(e,t,"read from private field"),a?a.call(e):t.get(e));const i=[["aztec","Aztec"],["code_128","Code128"],["code_39","Code39"],["code_93","Code93"],["codabar","Codabar"],["databar","DataBar"],["databar_expanded","DataBarExpanded"],["data_matrix","DataMatrix"],["dx_film_edge","DXFilmEdge"],["ean_13","EAN-13"],["ean_8","EAN-8"],["itf","ITF"],["maxi_code","MaxiCode"],["micro_qr_code","MicroQRCode"],["pdf417","PDF417"],["qr_code","QRCode"],["rm_qr_code","rMQRCode"],["upc_a","UPC-A"],["upc_e","UPC-E"],["linear_codes","Linear-Codes"],["matrix_codes","Matrix-Codes"]],o=[...i,["unknown"]].map(e=>e[0]),r=new Map(i);function s(e){for(const[t,n]of r)if(e===n)return t;return"unknown"}function l(e){try{return e instanceof HTMLImageElement}catch(e){return!1}}function u(e){try{return e instanceof SVGImageElement}catch(e){return!1}}function c(e){try{return e instanceof HTMLVideoElement}catch(e){return!1}}function d(e){try{return e instanceof HTMLCanvasElement}catch(e){return!1}}function h(e){try{return e instanceof ImageBitmap}catch(e){return!1}}function p(e){try{return e instanceof OffscreenCanvas}catch(e){return!1}}function f(e){try{return e instanceof VideoFrame}catch(e){return!1}}function m(e){try{return e instanceof Blob}catch(e){return!1}}async function g(e){if(l(e)&&!await async function(e){try{return await e.decode(),!0}catch(e){return!1}}(e))throw new DOMException("Failed to load or decode HTMLImageElement.","InvalidStateError");if(u(e)&&!await async function(e){var t;try{return await(null==(t=e.decode)?void 0:t.call(e)),!0}catch(e){return!1}}(e))throw new DOMException("Failed to load or decode SVGImageElement.","InvalidStateError");if(f(e)&&function(e){return null===e.format}(e))throw new DOMException("VideoFrame is closed.","InvalidStateError");if(c(e)&&(0===e.readyState||1===e.readyState))throw new DOMException("Invalid element or state.","InvalidStateError");if(h(e)&&function(e){return 0===e.width&&0===e.height}(e))throw new DOMException("The image source is detached.","InvalidStateError");const{width:t,height:n}=function(e){if(l(e))return{width:e.naturalWidth,height:e.naturalHeight};if(u(e))return{width:e.width.baseVal.value,height:e.height.baseVal.value};if(c(e))return{width:e.videoWidth,height:e.videoHeight};if(h(e))return{width:e.width,height:e.height};if(f(e))return{width:e.displayWidth,height:e.displayHeight};if(d(e))return{width:e.width,height:e.height};if(p(e))return{width:e.width,height:e.height};throw new TypeError("The provided value is not of type '(Blob or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or ImageData or OffscreenCanvas or SVGImageElement or VideoFrame)'.")}(e);if(0===t||0===n)return null;const a=function(e,t){try{const n=new OffscreenCanvas(e,t);if(n.getContext("2d")instanceof OffscreenCanvasRenderingContext2D)return n;throw void 0}catch(n){const a=document.createElement("canvas");return a.width=e,a.height=t,a}}(t,n).getContext("2d");a.drawImage(e,0,0);try{return a.getImageData(0,0,t,n)}catch(e){throw new DOMException("Source would taint origin.","SecurityError")}}async function _(e){if(m(e))return await async function(e){let t;try{if(globalThis.createImageBitmap)t=await createImageBitmap(e);else{if(!globalThis.Image)return e;{t=new Image;let n="";try{n=URL.createObjectURL(e),t.src=n,await t.decode()}finally{URL.revokeObjectURL(n)}}}}catch(e){throw new DOMException("Failed to load or decode Blob.","InvalidStateError")}return await g(t)}(e);if(function(e){try{return e instanceof ImageData}catch(e){return!1}}(e)){if(function(e){return 0===e.data.buffer.byteLength}(e))throw new DOMException("The image data has been detached.","InvalidStateError");return e}return d(e)||p(e)?function(e){const{width:t,height:n}=e;if(0===t||0===n)return null;const a=e.getContext("2d");try{return a.getImageData(0,0,t,n)}catch(e){throw new DOMException("Source would taint origin.","SecurityError")}}(e):await g(e)}function v(e,t){return e instanceof DOMException?new DOMException(`${t}: ${e.message}`,e.name):e instanceof Error?new e.constructor(`${t}: ${e.message}`):new Error(`${t}: ${e}`)}const b=["Aztec","Codabar","Code128","Code39","Code93","DataBar","DataBarExpanded","DataMatrix","DXFilmEdge","EAN-13","EAN-8","ITF","Linear-Codes","Matrix-Codes","MaxiCode","MicroQRCode","None","PDF417","QRCode","rMQRCode","UPC-A","UPC-E"];function y(e){return e.join("|")}function w(e){const t=k(e);let n=0,a=b.length-1;for(;n<=a;){const e=Math.floor((n+a)/2),i=b[e],o=k(i);if(o===t)return i;o{const n=e.match(/_(.+?)\.wasm$/);return n?`https://fastly.jsdelivr.net/npm/zxing-wasm@1.1.3/dist/${n[1]}/${e}`:t+e}};let z=new WeakMap;function N(e,t){var n;const a=z.get(e);if(null!=a&&a.modulePromise&&void 0===t)return a.modulePromise;const i=null!=(n=null==a?void 0:a.moduleOverrides)?n:R,o=e({...i});return z.set(e,{moduleOverrides:i,modulePromise:o}),o}var O,I,q=(O=typeof document<"u"&&document.currentScript?document.currentScript.src:void 0,function(e={}){var t,n,a=e;a.ready=new Promise((e,a)=>{t=e,n=a});var i=Object.assign({},a),o="./this.program",r="object"==typeof window,s="function"==typeof importScripts;"object"==typeof process&&"object"==typeof process.versions&&process.versions.node;var l,u="";(r||s)&&(s?u=self.location.href:typeof document<"u"&&document.currentScript&&(u=document.currentScript.src),O&&(u=O),u=0!==u.indexOf("blob:")?u.substr(0,u.replace(/[?#].*/,"").lastIndexOf("/")+1):"",s&&(l=e=>{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)})),a.print||console.log.bind(console);var c,d=a.printErr||console.error.bind(console);Object.assign(a,i),i=null,a.arguments&&a.arguments,a.thisProgram&&(o=a.thisProgram),a.quit&&a.quit,a.wasmBinary&&(c=a.wasmBinary),"object"!=typeof WebAssembly&&M("no native wasm support detected");var h,p,f,m,g,_,v,b,y,w=!1;function k(){var e=h.buffer;a.HEAP8=p=new Int8Array(e),a.HEAP16=m=new Int16Array(e),a.HEAPU8=f=new Uint8Array(e),a.HEAPU16=g=new Uint16Array(e),a.HEAP32=_=new Int32Array(e),a.HEAPU32=v=new Uint32Array(e),a.HEAPF32=b=new Float32Array(e),a.HEAPF64=y=new Float64Array(e)}var x=[],S=[],C=[];function T(e){x.unshift(e)}function P(e){C.unshift(e)}var E=0,A=null;function M(e){var t;null===(t=a.onAbort)||void 0===t||t.call(a,e),d(e="Aborted("+e+")"),w=!0,e+=". Build with -sASSERTIONS for more info.";var i=new WebAssembly.RuntimeError(e);throw n(i),i}var L,R,z=e=>e.startsWith("data:application/octet-stream;base64,");function N(e){if(e==L&&c)return new Uint8Array(c);if(l)return l(e);throw"both async and sync fetching of the wasm failed"}function I(e,t,n){return function(e){return c||!r&&!s||"function"!=typeof fetch?Promise.resolve().then(()=>N(e)):fetch(e,{credentials:"same-origin"}).then(t=>{if(!t.ok)throw"failed to load wasm binary file at '"+e+"'";return t.arrayBuffer()}).catch(()=>N(e))}(e).then(e=>WebAssembly.instantiate(e,t)).then(e=>e).then(n,e=>{d(`failed to asynchronously prepare wasm: ${e}`),M(e)})}z(L="zxing_reader.wasm")||(R=L,L=a.locateFile?a.locateFile(R,u):u+R);var q=e=>{for(;e.length>0;)e.shift()(a)};a.noExitRuntime;var D=[],j=0,B=0;function F(e){this.excPtr=e,this.ptr=e-24,this.set_type=function(e){v[this.ptr+4>>2]=e},this.get_type=function(){return v[this.ptr+4>>2]},this.set_destructor=function(e){v[this.ptr+8>>2]=e},this.get_destructor=function(){return v[this.ptr+8>>2]},this.set_caught=function(e){e=e?1:0,p[this.ptr+12|0]=e},this.get_caught=function(){return 0!=p[this.ptr+12|0]},this.set_rethrown=function(e){e=e?1:0,p[this.ptr+13|0]=e},this.get_rethrown=function(){return 0!=p[this.ptr+13|0]},this.init=function(e,t){this.set_adjusted_ptr(0),this.set_type(e),this.set_destructor(t)},this.set_adjusted_ptr=function(e){v[this.ptr+16>>2]=e},this.get_adjusted_ptr=function(){return v[this.ptr+16>>2]},this.get_exception_ptr=function(){if(Ot(this.get_type()))return v[this.excPtr>>2];var e=this.get_adjusted_ptr();return 0!==e?e:this.excPtr}}var $=e=>{var t=B;if(!t)return At(0),0;var n=new F(t);n.set_adjusted_ptr(t);var a=n.get_type();if(!a)return At(0),t;for(var i in e){var o=e[i];if(0===o||o===a)break;var r=n.ptr+16;if(Nt(o,a,r))return At(o),t}return At(a),t},V={},U=e=>{for(;e.length;){var t=e.pop();e.pop()(t)}};function H(e){return this.fromWireType(_[e>>2])}var W,G,K,Y={},Q={},Z={},J=e=>{throw new W(e)},X=(e,t,n)=>{function a(t){var a=n(t);a.length!==e.length&&J("Mismatched type converter count");for(var i=0;i{Q.hasOwnProperty(e)?i[t]=Q[e]:(o.push(e),Y.hasOwnProperty(e)||(Y[e]=[]),Y[e].push(()=>{i[t]=Q[e],++r===o.length&&a(i)}))}),0===o.length&&a(i)},ee=e=>{for(var t="",n=e;f[n];)t+=G[f[n++]];return t},te=e=>{throw new K(e)};function ne(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!("argPackAdvance"in t))throw new TypeError("registerType registeredInstance requires argPackAdvance");return function(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};var a=t.name;if(e||te(`type "${a}" must have a positive integer typeid pointer`),Q.hasOwnProperty(e)){if(n.ignoreDuplicateRegistrations)return;te(`Cannot register type '${a}' twice`)}if(Q[e]=t,delete Z[e],Y.hasOwnProperty(e)){var i=Y[e];delete Y[e],i.forEach(e=>e())}}(e,t,n)}var ae,ie=8,oe=e=>({count:e.count,deleteScheduled:e.deleteScheduled,preservePointerOnDelete:e.preservePointerOnDelete,ptr:e.ptr,ptrType:e.ptrType,smartPtr:e.smartPtr,smartPtrType:e.smartPtrType}),re=e=>{te(e.$$.ptrType.registeredClass.name+" instance already deleted")},se=!1,le=e=>{},ue=e=>{e.count.value-=1,0===e.count.value&&(e=>{e.smartPtr?e.smartPtrType.rawDestructor(e.smartPtr):e.ptrType.registeredClass.rawDestructor(e.ptr)})(e)},ce=(e,t,n)=>{if(t===n)return e;if(void 0===n.baseClass)return null;var a=ce(e,t,n.baseClass);return null===a?null:n.downcast(a)},de={},he=()=>Object.keys(_e).length,pe=()=>{var e=[];for(var t in _e)_e.hasOwnProperty(t)&&e.push(_e[t]);return e},fe=[],me=()=>{for(;fe.length;){var e=fe.pop();e.$$.deleteScheduled=!1,e.delete()}},ge=e=>{ae=e,fe.length&&ae&&ae(me)},_e={},ve=(e,t)=>(t=((e,t)=>{for(void 0===t&&te("ptr should not be undefined");e.baseClass;)t=e.upcast(t),e=e.baseClass;return t})(e,t),_e[t]),be=(e,t)=>((!t.ptrType||!t.ptr)&&J("makeClassHandle requires ptr and ptrType"),!!t.smartPtrType!=!!t.smartPtr&&J("Both smartPtrType and smartPtr must be specified"),t.count={value:1},we(Object.create(e,{$$:{value:t,writable:!0}})));function ye(e){var t=this.getPointee(e);if(!t)return this.destructor(e),null;var n=ve(this.registeredClass,t);if(void 0!==n){if(0===n.$$.count.value)return n.$$.ptr=t,n.$$.smartPtr=e,n.clone();var a=n.clone();return this.destructor(e),a}function i(){return this.isSmartPointer?be(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:t,smartPtrType:this,smartPtr:e}):be(this.registeredClass.instancePrototype,{ptrType:this,ptr:e})}var o,r=this.registeredClass.getActualType(t),s=de[r];if(!s)return i.call(this);o=this.isConst?s.constPointerType:s.pointerType;var l=ce(t,this.registeredClass,o.registeredClass);return null===l?i.call(this):this.isSmartPointer?be(o.registeredClass.instancePrototype,{ptrType:o,ptr:l,smartPtrType:this,smartPtr:e}):be(o.registeredClass.instancePrototype,{ptrType:o,ptr:l})}var we=e=>typeof FinalizationRegistry>"u"?(we=e=>e,e):(se=new FinalizationRegistry(e=>{ue(e.$$)}),le=e=>se.unregister(e),(we=e=>{var t=e.$$;if(t.smartPtr){var n={$$:t};se.register(e,n,e)}return e})(e));function ke(){}var xe=(e,t)=>Object.defineProperty(t,"name",{value:e}),Se=(e,t,n)=>{if(void 0===e[t].overloadTable){var a=e[t];e[t]=function(){return e[t].overloadTable.hasOwnProperty(arguments.length)||te(`Function '${n}' called with an invalid number of arguments (${arguments.length}) - expects one of (${e[t].overloadTable})!`),e[t].overloadTable[arguments.length].apply(this,arguments)},e[t].overloadTable=[],e[t].overloadTable[a.argCount]=a}},Ce=(e,t,n)=>{a.hasOwnProperty(e)?((void 0===n||void 0!==a[e].overloadTable&&void 0!==a[e].overloadTable[n])&&te(`Cannot register public name '${e}' twice`),Se(a,e,e),a.hasOwnProperty(n)&&te(`Cannot register multiple overloads of a function with the same number of arguments (${n})!`),a[e].overloadTable[n]=t):(a[e]=t,void 0!==n&&(a[e].numArguments=n))};function Te(e,t,n,a,i,o,r,s){this.name=e,this.constructor=t,this.instancePrototype=n,this.rawDestructor=a,this.baseClass=i,this.getActualType=o,this.upcast=r,this.downcast=s,this.pureVirtualFunctions=[]}var Pe=(e,t,n)=>{for(;t!==n;)t.upcast||te(`Expected null or instance of ${n.name}, got an instance of ${t.name}`),e=t.upcast(e),t=t.baseClass;return e};function Ee(e,t){if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),0;t.$$||te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`);var n=t.$$.ptrType.registeredClass;return Pe(t.$$.ptr,n,this.registeredClass)}function Ae(e,t){var n;if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),this.isSmartPointer?(n=this.rawConstructor(),null!==e&&e.push(this.rawDestructor,n),n):0;(!t||!t.$$)&&te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`),!this.isConst&&t.$$.ptrType.isConst&&te(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);var a=t.$$.ptrType.registeredClass;if(n=Pe(t.$$.ptr,a,this.registeredClass),this.isSmartPointer)switch(void 0===t.$$.smartPtr&&te("Passing raw pointer to smart pointer is illegal"),this.sharingPolicy){case 0:t.$$.smartPtrType===this?n=t.$$.smartPtr:te(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);break;case 1:n=t.$$.smartPtr;break;case 2:if(t.$$.smartPtrType===this)n=t.$$.smartPtr;else{var i=t.clone();n=this.rawShare(n,Ye.toHandle(()=>i.delete())),null!==e&&e.push(this.rawDestructor,n)}break;default:te("Unsupporting sharing policy")}return n}function Me(e,t){if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),0;t.$$||te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`),t.$$.ptrType.isConst&&te(`Cannot convert argument of type ${t.$$.ptrType.name} to parameter type ${this.name}`);var n=t.$$.ptrType.registeredClass;return Pe(t.$$.ptr,n,this.registeredClass)}function Le(e){return this.fromWireType(v[e>>2])}function Re(e,t,n,a,i,o,r,s,l,u,c){this.name=e,this.registeredClass=t,this.isReference=n,this.isConst=a,this.isSmartPointer=i,this.pointeeType=o,this.sharingPolicy=r,this.rawGetPointee=s,this.rawConstructor=l,this.rawShare=u,this.rawDestructor=c,i||void 0!==t.baseClass?this.toWireType=Ae:a?(this.toWireType=Ee,this.destructorFunction=null):(this.toWireType=Me,this.destructorFunction=null)}var ze,Ne,Oe=(e,t,n)=>{a.hasOwnProperty(e)||J("Replacing nonexistant public symbol"),void 0!==a[e].overloadTable&&void 0!==n?a[e].overloadTable[n]=t:(a[e]=t,a[e].argCount=n)},Ie=[],qe=e=>{var t=Ie[e];return t||(e>=Ie.length&&(Ie.length=e+1),Ie[e]=t=ze.get(e)),t},De=(e,t,n)=>e.includes("j")?((e,t,n)=>{var i=a["dynCall_"+e];return n&&n.length?i.apply(null,[t].concat(n)):i.call(null,t)})(e,t,n):qe(t).apply(null,n),je=(e,t)=>{var n=(e=ee(e)).includes("j")?((e,t)=>{var n=[];return function(){return n.length=0,Object.assign(n,arguments),De(e,t,n)}})(e,t):qe(t);return"function"!=typeof n&&te(`unknown function pointer with signature ${e}: ${t}`),n},Be=e=>{var t=Pt(e),n=ee(t);return Ct(t),n},Fe=(e,t)=>{var n=[],a={};throw t.forEach(function e(t){if(!a[t]&&!Q[t]){if(Z[t])return void Z[t].forEach(e);n.push(t),a[t]=!0}}),new Ne(`${e}: `+n.map(Be).join([", "]))},$e=(e,t)=>{for(var n=[],a=0;a>2]);return n};function Ve(e,t,n,a,i,o){var r=t.length;r<2&&te("argTypes array size mismatch! Must at least get return value and 'this' types!");var s=null!==t[1]&&null!==n,l=function(e){for(var t=1;t{const t=(e=e.trim()).indexOf("(");return-1!==t?e.substr(0,t):e};function He(){this.allocated=[void 0],this.freelist=[]}var We=new He,Ge=e=>{e>=We.reserved&&0===--We.get(e).refcount&&We.free(e)},Ke=()=>{for(var e=0,t=We.reserved;t(e||te("Cannot use deleted val. handle = "+e),We.get(e).value),toHandle:e=>{switch(e){case void 0:return 1;case null:return 2;case!0:return 3;case!1:return 4;default:return We.allocate({refcount:1,value:e})}}},Qe=(e,t,n)=>{switch(t){case 1:return n?function(e){return this.fromWireType(p[0|e])}:function(e){return this.fromWireType(f[0|e])};case 2:return n?function(e){return this.fromWireType(m[e>>1])}:function(e){return this.fromWireType(g[e>>1])};case 4:return n?function(e){return this.fromWireType(_[e>>2])}:function(e){return this.fromWireType(v[e>>2])};default:throw new TypeError(`invalid integer width (${t}): ${e}`)}},Ze=(e,t)=>{var n=Q[e];return void 0===n&&te(t+" has unknown type "+Be(e)),n},Je=e=>{if(null===e)return"null";var t=typeof e;return"object"===t||"array"===t||"function"===t?e.toString():""+e},Xe=(e,t)=>{switch(t){case 4:return function(e){return this.fromWireType(b[e>>2])};case 8:return function(e){return this.fromWireType(y[e>>3])};default:throw new TypeError(`invalid float width (${t}): ${e}`)}},et=(e,t,n)=>{switch(t){case 1:return n?e=>p[0|e]:e=>f[0|e];case 2:return n?e=>m[e>>1]:e=>g[e>>1];case 4:return n?e=>_[e>>2]:e=>v[e>>2];default:throw new TypeError(`invalid integer width (${t}): ${e}`)}},tt=(e,t,n,a)=>{if(!(a>0))return 0;for(var i=n,o=n+a-1,r=0;r=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++r)),s<=127){if(n>=o)break;t[n++]=s}else if(s<=2047){if(n+1>=o)break;t[n++]=192|s>>6,t[n++]=128|63&s}else if(s<=65535){if(n+2>=o)break;t[n++]=224|s>>12,t[n++]=128|s>>6&63,t[n++]=128|63&s}else{if(n+3>=o)break;t[n++]=240|s>>18,t[n++]=128|s>>12&63,t[n++]=128|s>>6&63,t[n++]=128|63&s}}return t[n]=0,n-i},nt=e=>{for(var t=0,n=0;n=55296&&a<=57343?(t+=4,++n):t+=3}return t},at=typeof TextDecoder<"u"?new TextDecoder("utf8"):void 0,it=(e,t)=>e?((e,t,n)=>{for(var a=t+n,i=t;e[i]&&!(i>=a);)++i;if(i-t>16&&e.buffer&&at)return at.decode(e.subarray(t,i));for(var o="";t>10,56320|1023&u)}}else o+=String.fromCharCode((31&r)<<6|s)}else o+=String.fromCharCode(r)}return o})(f,e,t):"",ot=typeof TextDecoder<"u"?new TextDecoder("utf-16le"):void 0,rt=(e,t)=>{for(var n=e,a=n>>1,i=a+t/2;!(a>=i)&&g[a];)++a;if((n=a<<1)-e>32&&ot)return ot.decode(f.subarray(e,n));for(var o="",r=0;!(r>=t/2);++r){var s=m[e+2*r>>1];if(0==s)break;o+=String.fromCharCode(s)}return o},st=(e,t,n)=>{var a;if(null!==(a=n)&&void 0!==a||(n=2147483647),n<2)return 0;for(var i=t,o=(n-=2)<2*e.length?n/2:e.length,r=0;r>1]=s,t+=2}return m[t>>1]=0,t-i},lt=e=>2*e.length,ut=(e,t)=>{for(var n=0,a="";!(n>=t/4);){var i=_[e+4*n>>2];if(0==i)break;if(++n,i>=65536){var o=i-65536;a+=String.fromCharCode(55296|o>>10,56320|1023&o)}else a+=String.fromCharCode(i)}return a},ct=(e,t,n)=>{var a;if(null!==(a=n)&&void 0!==a||(n=2147483647),n<4)return 0;for(var i=t,o=i+n-4,r=0;r=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++r)),_[t>>2]=s,(t+=4)+4>o)break}return _[t>>2]=0,t-i},dt=e=>{for(var t=0,n=0;n=55296&&a<=57343&&++n,t+=4}return t},ht=[],pt={},ft=()=>{if("object"==typeof globalThis)return globalThis;function e(e){e.$$$embind_global$$$=e;var t="object"==typeof $$$embind_global$$$&&e.$$$embind_global$$$==e;return t||delete e.$$$embind_global$$$,t}if("object"==typeof $$$embind_global$$$||("object"==typeof global&&e(global)?$$$embind_global$$$=global:"object"==typeof self&&e(self)&&($$$embind_global$$$=self),"object"==typeof $$$embind_global$$$))return $$$embind_global$$$;throw Error("unable to get global object.")},mt=Reflect.construct,gt=e=>{var t=(e-h.buffer.byteLength+65535)/65536;try{return h.grow(t),k(),1}catch(e){}},_t={},vt=()=>{if(!vt.strings){var e={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:o||"./this.program"};for(var t in _t)void 0===_t[t]?delete e[t]:e[t]=_t[t];var n=[];for(var t in e)n.push(`${t}=${e[t]}`);vt.strings=n}return vt.strings},bt=e=>e%4==0&&(e%100!=0||e%400==0),yt=[31,29,31,30,31,30,31,31,30,31,30,31],wt=[31,28,31,30,31,30,31,31,30,31,30,31],kt=(e,t,n,a)=>{var i=v[a+40>>2],o={tm_sec:_[a>>2],tm_min:_[a+4>>2],tm_hour:_[a+8>>2],tm_mday:_[a+12>>2],tm_mon:_[a+16>>2],tm_year:_[a+20>>2],tm_wday:_[a+24>>2],tm_yday:_[a+28>>2],tm_isdst:_[a+32>>2],tm_gmtoff:_[a+36>>2],tm_zone:i?it(i):""},r=it(n),s={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var l in s)r=r.replace(new RegExp(l,"g"),s[l]);var u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["January","February","March","April","May","June","July","August","September","October","November","December"];function d(e,t,n){for(var a="number"==typeof e?e.toString():e||"";a.length0?1:0}var a;return 0===(a=n(e.getFullYear()-t.getFullYear()))&&0===(a=n(e.getMonth()-t.getMonth()))&&(a=n(e.getDate()-t.getDate())),a}function m(e){switch(e.getDay()){case 0:return new Date(e.getFullYear()-1,11,29);case 1:return e;case 2:return new Date(e.getFullYear(),0,3);case 3:return new Date(e.getFullYear(),0,2);case 4:return new Date(e.getFullYear(),0,1);case 5:return new Date(e.getFullYear()-1,11,31);case 6:return new Date(e.getFullYear()-1,11,30)}}function g(e){var t=((e,t)=>{for(var n=new Date(e.getTime());t>0;){var a=bt(n.getFullYear()),i=n.getMonth(),o=(a?yt:wt)[i];if(!(t>o-n.getDate()))return n.setDate(n.getDate()+t),n;t-=o-n.getDate()+1,n.setDate(1),i<11?n.setMonth(i+1):(n.setMonth(0),n.setFullYear(n.getFullYear()+1))}return n})(new Date(e.tm_year+1900,0,1),e.tm_yday),n=new Date(t.getFullYear(),0,4),a=new Date(t.getFullYear()+1,0,4),i=m(n),o=m(a);return f(i,t)<=0?f(o,t)<=0?t.getFullYear()+1:t.getFullYear():t.getFullYear()-1}var b={"%a":e=>u[e.tm_wday].substring(0,3),"%A":e=>u[e.tm_wday],"%b":e=>c[e.tm_mon].substring(0,3),"%B":e=>c[e.tm_mon],"%C":e=>h((e.tm_year+1900)/100|0,2),"%d":e=>h(e.tm_mday,2),"%e":e=>d(e.tm_mday,2," "),"%g":e=>g(e).toString().substring(2),"%G":e=>g(e),"%H":e=>h(e.tm_hour,2),"%I":e=>{var t=e.tm_hour;return 0==t?t=12:t>12&&(t-=12),h(t,2)},"%j":e=>h(e.tm_mday+((e,t)=>{for(var n=0,a=0;a<=t;n+=e[a++]);return n})(bt(e.tm_year+1900)?yt:wt,e.tm_mon-1),3),"%m":e=>h(e.tm_mon+1,2),"%M":e=>h(e.tm_min,2),"%n":()=>"\n","%p":e=>e.tm_hour>=0&&e.tm_hour<12?"AM":"PM","%S":e=>h(e.tm_sec,2),"%t":()=>"\t","%u":e=>e.tm_wday||7,"%U":e=>{var t=e.tm_yday+7-e.tm_wday;return h(Math.floor(t/7),2)},"%V":e=>{var t=Math.floor((e.tm_yday+7-(e.tm_wday+6)%7)/7);if((e.tm_wday+371-e.tm_yday-2)%7<=2&&t++,t){if(53==t){var n=(e.tm_wday+371-e.tm_yday)%7;4!=n&&(3!=n||!bt(e.tm_year))&&(t=1)}}else{t=52;var a=(e.tm_wday+7-e.tm_yday-1)%7;(4==a||5==a&&bt(e.tm_year%400-1))&&t++}return h(t,2)},"%w":e=>e.tm_wday,"%W":e=>{var t=e.tm_yday+7-(e.tm_wday+6)%7;return h(Math.floor(t/7),2)},"%y":e=>(e.tm_year+1900).toString().substring(2),"%Y":e=>e.tm_year+1900,"%z":e=>{var t=e.tm_gmtoff;return(t>=0?"+":"-")+("0000"+(t=(t=Math.abs(t)/60)/60*100+t%60)).slice(-4)},"%Z":e=>e.tm_zone,"%%":()=>"%"};for(var l in r=r.replace(/%%/g,"\0\0"),b)r.includes(l)&&(r=r.replace(new RegExp(l,"g"),b[l](o)));var y=function(e){var t=nt(e)+1,n=new Array(t);return tt(e,n,0,n.length),n}(r=r.replace(/\0\0/g,"%"));return y.length>t?0:(((e,t)=>{p.set(e,t)})(y,e),y.length-1)};W=a.InternalError=class extends Error{constructor(e){super(e),this.name="InternalError"}},(()=>{for(var e=new Array(256),t=0;t<256;++t)e[t]=String.fromCharCode(t);G=e})(),K=a.BindingError=class extends Error{constructor(e){super(e),this.name="BindingError"}},Object.assign(ke.prototype,{isAliasOf(e){if(!(this instanceof ke&&e instanceof ke))return!1;var t=this.$$.ptrType.registeredClass,n=this.$$.ptr;e.$$=e.$$;for(var a=e.$$.ptrType.registeredClass,i=e.$$.ptr;t.baseClass;)n=t.upcast(n),t=t.baseClass;for(;a.baseClass;)i=a.upcast(i),a=a.baseClass;return t===a&&n===i},clone(){if(this.$$.ptr||re(this),this.$$.preservePointerOnDelete)return this.$$.count.value+=1,this;var e=we(Object.create(Object.getPrototypeOf(this),{$$:{value:oe(this.$$)}}));return e.$$.count.value+=1,e.$$.deleteScheduled=!1,e},delete(){this.$$.ptr||re(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&te("Object already scheduled for deletion"),le(this),ue(this.$$),this.$$.preservePointerOnDelete||(this.$$.smartPtr=void 0,this.$$.ptr=void 0)},isDeleted(){return!this.$$.ptr},deleteLater(){return this.$$.ptr||re(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&te("Object already scheduled for deletion"),fe.push(this),1===fe.length&&ae&&ae(me),this.$$.deleteScheduled=!0,this}}),a.getInheritedInstanceCount=he,a.getLiveInheritedInstances=pe,a.flushPendingDeletes=me,a.setDelayFunction=ge,Object.assign(Re.prototype,{getPointee(e){return this.rawGetPointee&&(e=this.rawGetPointee(e)),e},destructor(e){var t;null===(t=this.rawDestructor)||void 0===t||t.call(this,e)},argPackAdvance:ie,readValueFromPointer:Le,deleteObject(e){null!==e&&e.delete()},fromWireType:ye}),Ne=a.UnboundTypeError=((e,t)=>{var n=xe(t,function(e){this.name=t,this.message=e;var n=new Error(e).stack;void 0!==n&&(this.stack=this.toString()+"\n"+n.replace(/^Error(:[^\n]*)?\n/,""))});return n.prototype=Object.create(e.prototype),n.prototype.constructor=n,n.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`},n})(Error,"UnboundTypeError"),Object.assign(He.prototype,{get(e){return this.allocated[e]},has(e){return void 0!==this.allocated[e]},allocate(e){var t=this.freelist.pop()||this.allocated.length;return this.allocated[t]=e,t},free(e){this.allocated[e]=void 0,this.freelist.push(e)}}),We.allocated.push({value:void 0},{value:null},{value:!0},{value:!1}),We.reserved=We.allocated.length,a.count_emval_handles=Ke;var xt={s:e=>{var t=new F(e);return t.get_caught()||(t.set_caught(!0),j--),t.set_rethrown(!1),D.push(t),zt(t.excPtr),t.get_exception_ptr()},u:()=>{Et(0,0);var e=D.pop();Rt(e.excPtr),B=0},b:()=>$([]),g:e=>$([e]),q:(e,t)=>$([e,t]),J:()=>{var e=D.pop();e||M("no exception to throw");var t=e.excPtr;throw e.get_rethrown()||(D.push(e),e.set_rethrown(!0),e.set_caught(!1),j++),B=t},f:(e,t,n)=>{throw new F(e).init(t,n),j++,B=e},V:()=>j,d:e=>{throw B||(B=e),B},da:e=>{var t=V[e];delete V[e];var n=t.rawConstructor,a=t.rawDestructor,i=t.fields,o=i.map(e=>e.getterReturnType).concat(i.map(e=>e.setterArgumentType));X([e],o,e=>{var o={};return i.forEach((t,n)=>{var a=t.fieldName,r=e[n],s=t.getter,l=t.getterContext,u=e[n+i.length],c=t.setter,d=t.setterContext;o[a]={read:e=>r.fromWireType(s(l,e)),write:(e,t)=>{var n=[];c(d,e,u.toWireType(n,t)),U(n)}}}),[{name:t.name,fromWireType:e=>{var t={};for(var n in o)t[n]=o[n].read(e);return a(e),t},toWireType:(e,t)=>{for(var i in o)if(!(i in t))throw new TypeError(`Missing field: "${i}"`);var r=n();for(i in o)o[i].write(r,t[i]);return null!==e&&e.push(a,r),r},argPackAdvance:ie,readValueFromPointer:H,destructorFunction:a}]})},Q:(e,t,n,a,i)=>{},_:(e,t,n,a)=>{ne(e,{name:t=ee(t),fromWireType:function(e){return!!e},toWireType:function(e,t){return t?n:a},argPackAdvance:ie,readValueFromPointer:function(e){return this.fromWireType(f[e])},destructorFunction:null})},ca:(e,t,n,a,i,o,r,s,l,u,c,d,h)=>{c=ee(c),o=je(i,o),s&&(s=je(r,s)),u&&(u=je(l,u)),h=je(d,h);var p=(e=>{if(void 0===e)return"_unknown";var t=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return t>=48&&t<=57?`_${e}`:e})(c);Ce(p,function(){Fe(`Cannot construct ${c} due to unbound types`,[a])}),X([e,t,n],a?[a]:[],function(t){var n,i;t=t[0],i=a?(n=t.registeredClass).instancePrototype:ke.prototype;var r=xe(c,function(){if(Object.getPrototypeOf(this)!==l)throw new K("Use 'new' to construct "+c);if(void 0===m.constructor_body)throw new K(c+" has no accessible constructor");var e=m.constructor_body[arguments.length];if(void 0===e)throw new K(`Tried to invoke ctor of ${c} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(m.constructor_body).toString()}) parameters instead!`);return e.apply(this,arguments)}),l=Object.create(i,{constructor:{value:r}});r.prototype=l;var d,f,m=new Te(c,r,l,h,n,o,s,u);m.baseClass&&(null!==(f=(d=m.baseClass).__derivedClasses)&&void 0!==f||(d.__derivedClasses=[]),m.baseClass.__derivedClasses.push(m));var g=new Re(c,m,!0,!1,!1),_=new Re(c+"*",m,!1,!1,!1),v=new Re(c+" const*",m,!1,!0,!1);return de[e]={pointerType:_,constPointerType:v},Oe(p,r),[g,_,v]})},ba:(e,t,n,a,i,o)=>{var r=$e(t,n);i=je(a,i),X([],[e],function(e){var n=`constructor ${(e=e[0]).name}`;if(void 0===e.registeredClass.constructor_body&&(e.registeredClass.constructor_body=[]),void 0!==e.registeredClass.constructor_body[t-1])throw new K(`Cannot register multiple constructors with identical number of parameters (${t-1}) for class '${e.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);return e.registeredClass.constructor_body[t-1]=()=>{Fe(`Cannot construct ${e.name} due to unbound types`,r)},X([],r,a=>(a.splice(1,0,null),e.registeredClass.constructor_body[t-1]=Ve(n,a,null,i,o),[])),[]})},w:(e,t,n,a,i,o,r,s,l)=>{var u=$e(n,a);t=ee(t),t=Ue(t),o=je(i,o),X([],[e],function(e){var a=`${(e=e[0]).name}.${t}`;function i(){Fe(`Cannot call ${a} due to unbound types`,u)}t.startsWith("@@")&&(t=Symbol[t.substring(2)]),s&&e.registeredClass.pureVirtualFunctions.push(t);var l=e.registeredClass.instancePrototype,c=l[t];return void 0===c||void 0===c.overloadTable&&c.className!==e.name&&c.argCount===n-2?(i.argCount=n-2,i.className=e.name,l[t]=i):(Se(l,t,a),l[t].overloadTable[n-2]=i),X([],u,function(i){var s=Ve(a,i,e,o,r);return void 0===l[t].overloadTable?(s.argCount=n-2,l[t]=s):l[t].overloadTable[n-2]=s,[]}),[]})},Y:(e,t)=>{ne(e,{name:t=ee(t),fromWireType:e=>{var t=Ye.toValue(e);return Ge(e),t},toWireType:(e,t)=>Ye.toHandle(t),argPackAdvance:ie,readValueFromPointer:H,destructorFunction:null})},x:(e,t,n,a)=>{function i(){}t=ee(t),i.values={},ne(e,{name:t,constructor:i,fromWireType:function(e){return this.constructor.values[e]},toWireType:(e,t)=>t.value,argPackAdvance:ie,readValueFromPointer:Qe(t,n,a),destructorFunction:null}),Ce(t,i)},h:(e,t,n)=>{var a=Ze(e,"enum");t=ee(t);var i=a.constructor,o=Object.create(a.constructor.prototype,{value:{value:n},constructor:{value:xe(`${a.name}_${t}`,function(){})}});i.values[n]=o,i[t]=o},L:(e,t,n)=>{ne(e,{name:t=ee(t),fromWireType:e=>e,toWireType:(e,t)=>t,argPackAdvance:ie,readValueFromPointer:Xe(t,n),destructorFunction:null})},M:(e,t,n,a,i,o,r)=>{var s=$e(t,n);e=ee(e),e=Ue(e),i=je(a,i),Ce(e,function(){Fe(`Cannot call ${e} due to unbound types`,s)},t-1),X([],s,function(n){var a=[n[0],null].concat(n.slice(1));return Oe(e,Ve(e,a,null,i,o),t-1),[]})},t:(e,t,n,a,i)=>{t=ee(t);var o=e=>e;if(0===a){var r=32-8*n;o=e=>e<>>r}var s=t.includes("unsigned");ne(e,{name:t,fromWireType:o,toWireType:s?function(e,t){return this.name,t>>>0}:function(e,t){return this.name,t},argPackAdvance:ie,readValueFromPointer:et(t,n,0!==a),destructorFunction:null})},o:(e,t,n)=>{var a=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function i(e){var t=v[e>>2],n=v[e+4>>2];return new a(p.buffer,n,t)}ne(e,{name:n=ee(n),fromWireType:i,argPackAdvance:ie,readValueFromPointer:i},{ignoreDuplicateRegistrations:!0})},K:(e,t)=>{var n="std::string"===(t=ee(t));ne(e,{name:t,fromWireType(e){var t,a=v[e>>2],i=e+4;if(n)for(var o=i,r=0;r<=a;++r){var s=i+r;if(r==a||0==f[s]){var l=it(o,s-o);void 0===t?t=l:(t+="\0",t+=l),o=s+1}}else{var u=new Array(a);for(r=0;r>2]=a,n&&i)((e,t,n)=>{tt(e,f,t,n)})(t,r,a+1);else if(i)for(var s=0;s255&&(Ct(r),te("String has UTF-16 code units that do not fit in 8 bits")),f[r+s]=l}else for(s=0;s{var a,i,o,r,s;n=ee(n),2===t?(a=rt,i=st,r=lt,o=()=>g,s=1):4===t&&(a=ut,i=ct,r=dt,o=()=>v,s=2),ne(e,{name:n,fromWireType:e=>{for(var n,i=v[e>>2],r=o(),l=e+4,u=0;u<=i;++u){var c=e+4+u*t;if(u==i||0==r[c>>s]){var d=a(l,c-l);void 0===n?n=d:(n+="\0",n+=d),l=c+t}}return Ct(e),n},toWireType:(e,a)=>{"string"!=typeof a&&te(`Cannot pass non-string to C++ string type ${n}`);var o=r(a),l=Tt(4+o+t);return v[l>>2]=o>>s,i(a,l+4,o+t),null!==e&&e.push(Ct,l),l},argPackAdvance:ie,readValueFromPointer:H,destructorFunction(e){Ct(e)}})},A:(e,t,n,a,i,o)=>{V[e]={name:ee(t),rawConstructor:je(n,a),rawDestructor:je(i,o),fields:[]}},ea:(e,t,n,a,i,o,r,s,l,u)=>{V[e].fields.push({fieldName:ee(t),getterReturnType:n,getter:je(a,i),getterContext:o,setterArgumentType:r,setter:je(s,l),setterContext:u})},$:(e,t)=>{ne(e,{isVoid:!0,name:t=ee(t),argPackAdvance:0,fromWireType:()=>{},toWireType:(e,t)=>{}})},R:(e,t,n,a)=>(e=ht[e])(null,t=Ye.toValue(t),n,a),ha:Ge,fa:e=>0===e?Ye.toHandle(ft()):(e=(e=>{var t=pt[e];return void 0===t?ee(e):t})(e),Ye.toHandle(ft()[e])),Z:(e,t,n)=>{var a=((e,t)=>{for(var n=new Array(e),a=0;a>2],"parameter "+a);return n})(e,t),i=a.shift();e--;var o=new Array(e),r=`methodCaller<(${a.map(e=>e.name).join(", ")}) => ${i.name}>`;return(e=>{var t=ht.length;return ht.push(e),t})(xe(r,(t,r,s,l)=>{for(var u=0,c=0;c{var a=[],i=e.toWireType(a,n);return a.length&&(v[t>>2]=Ye.toHandle(a)),i})(i,s,d)}))},N:e=>{e>4&&(We.get(e).refcount+=1)},O:e=>{var t=Ye.toValue(e);U(t),Ge(e)},aa:(e,t)=>{var n=(e=Ze(e,"_emval_take_value")).readValueFromPointer(t);return Ye.toHandle(n)},B:()=>{M("")},X:(e,t,n)=>f.copyWithin(e,t,t+n),W:e=>{var t=f.length,n=2147483648;if((e>>>=0)>n)return!1;for(var a=(e,t)=>e+(t-e%t)%t,i=1;i<=4;i*=2){var o=t*(1+.2/i);o=Math.min(o,e+100663296);var r=Math.min(n,a(Math.max(e,o),65536));if(gt(r))return!0}return!1},T:(e,t)=>{var n=0;return vt().forEach((a,i)=>{var o=t+n;v[e+4*i>>2]=o,((e,t)=>{for(var n=0;n{var n=vt();v[e>>2]=n.length;var a=0;return n.forEach(e=>a+=e.length+1),v[t>>2]=a,0},E:function(e,t,n,a){var i=Mt();try{return qe(e)(t,n,a)}catch(e){if(Lt(i),e!==e+0)throw e;Et(1,0)}},D:function(e,t,n,a,i){var o=Mt();try{return qe(e)(t,n,a,i)}catch(e){if(Lt(o),e!==e+0)throw e;Et(1,0)}},F:function(e,t,n,a){var i=Mt();try{return qe(e)(t,n,a)}catch(e){if(Lt(i),e!==e+0)throw e;Et(1,0)}},n:function(e){var t=Mt();try{return qe(e)()}catch(e){if(Lt(t),e!==e+0)throw e;Et(1,0)}},a:function(e,t){var n=Mt();try{return qe(e)(t)}catch(e){if(Lt(n),e!==e+0)throw e;Et(1,0)}},e:function(e,t,n){var a=Mt();try{return qe(e)(t,n)}catch(e){if(Lt(a),e!==e+0)throw e;Et(1,0)}},m:function(e,t,n,a){var i=Mt();try{return qe(e)(t,n,a)}catch(e){if(Lt(i),e!==e+0)throw e;Et(1,0)}},k:function(e,t,n,a,i){var o=Mt();try{return qe(e)(t,n,a,i)}catch(e){if(Lt(o),e!==e+0)throw e;Et(1,0)}},H:function(e,t,n,a,i,o){var r=Mt();try{return qe(e)(t,n,a,i,o)}catch(e){if(Lt(r),e!==e+0)throw e;Et(1,0)}},v:function(e,t,n,a,i,o,r){var s=Mt();try{return qe(e)(t,n,a,i,o,r)}catch(e){if(Lt(s),e!==e+0)throw e;Et(1,0)}},G:function(e,t,n,a,i,o,r,s){var l=Mt();try{return qe(e)(t,n,a,i,o,r,s)}catch(e){if(Lt(l),e!==e+0)throw e;Et(1,0)}},z:function(e,t,n,a,i,o,r,s,l,u,c,d){var h=Mt();try{return qe(e)(t,n,a,i,o,r,s,l,u,c,d)}catch(e){if(Lt(h),e!==e+0)throw e;Et(1,0)}},P:function(e,t,n,a,i){var o=Mt();try{return qt(e,t,n,a,i)}catch(e){if(Lt(o),e!==e+0)throw e;Et(1,0)}},l:function(e){var t=Mt();try{qe(e)()}catch(e){if(Lt(t),e!==e+0)throw e;Et(1,0)}},j:function(e,t){var n=Mt();try{qe(e)(t)}catch(e){if(Lt(n),e!==e+0)throw e;Et(1,0)}},c:function(e,t,n){var a=Mt();try{qe(e)(t,n)}catch(e){if(Lt(a),e!==e+0)throw e;Et(1,0)}},p:function(e,t,n,a){var i=Mt();try{qe(e)(t,n,a)}catch(e){if(Lt(i),e!==e+0)throw e;Et(1,0)}},I:function(e,t,n,a,i){var o=Mt();try{qe(e)(t,n,a,i)}catch(e){if(Lt(o),e!==e+0)throw e;Et(1,0)}},r:function(e,t,n,a,i,o,r,s){var l=Mt();try{qe(e)(t,n,a,i,o,r,s)}catch(e){if(Lt(l),e!==e+0)throw e;Et(1,0)}},i:function(e,t,n,a,i,o,r,s,l,u,c){var d=Mt();try{qe(e)(t,n,a,i,o,r,s,l,u,c)}catch(e){if(Lt(d),e!==e+0)throw e;Et(1,0)}},y:function(e,t,n,a,i,o,r,s,l,u,c,d,h,p,f,m){var g=Mt();try{qe(e)(t,n,a,i,o,r,s,l,u,c,d,h,p,f,m)}catch(e){if(Lt(g),e!==e+0)throw e;Et(1,0)}},ga:e=>e,S:(e,t,n,a,i)=>kt(e,t,n,a)},St=function(){var e={a:xt};function t(e,t){return St=e.exports,h=St.ia,k(),ze=St.ma,function(e){S.unshift(e)}(St.ja),function(){var e;if(E--,null===(e=a.monitorRunDependencies)||void 0===e||e.call(a,E),0==E&&A){var t=A;A=null,t()}}(),St}if(function(){var e;E++,null===(e=a.monitorRunDependencies)||void 0===e||e.call(a,E)}(),a.instantiateWasm)try{return a.instantiateWasm(e,t)}catch(e){d(`Module.instantiateWasm callback failed with error: ${e}`),n(e)}return function(e,t,n,a){return e||"function"!=typeof WebAssembly.instantiateStreaming||z(t)||"function"!=typeof fetch?I(t,n,a):fetch(t,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,n).then(a,function(e){return d(`wasm streaming compile failed: ${e}`),d("falling back to ArrayBuffer instantiation"),I(t,n,a)}))}(c,L,e,function(e){t(e.instance)}).catch(n),{}}(),Ct=a._free=e=>(Ct=a._free=St.ka)(e),Tt=a._malloc=e=>(Tt=a._malloc=St.la)(e),Pt=e=>(Pt=St.na)(e),Et=(e,t)=>(Et=St.oa)(e,t),At=e=>(At=St.pa)(e),Mt=()=>(Mt=St.qa)(),Lt=e=>(Lt=St.ra)(e),Rt=e=>(Rt=St.sa)(e),zt=e=>(zt=St.ta)(e),Nt=(e,t,n)=>(Nt=St.ua)(e,t,n),Ot=e=>(Ot=St.va)(e);a.dynCall_viijii=(e,t,n,i,o,r,s)=>(a.dynCall_viijii=St.wa)(e,t,n,i,o,r,s);var It,qt=a.dynCall_jiiii=(e,t,n,i,o)=>(qt=a.dynCall_jiiii=St.xa)(e,t,n,i,o);function Dt(){function e(){It||(It=!0,a.calledRun=!0,!w&&(q(S),t(a),a.onRuntimeInitialized&&a.onRuntimeInitialized(),function(){if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)P(a.postRun.shift());q(C)}()))}E>0||(function(){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)T(a.preRun.shift());q(x)}(),E>0)||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1),e()},1)):e())}if(a.dynCall_iiiiij=(e,t,n,i,o,r,s)=>(a.dynCall_iiiiij=St.ya)(e,t,n,i,o,r,s),a.dynCall_iiiiijj=(e,t,n,i,o,r,s,l,u)=>(a.dynCall_iiiiijj=St.za)(e,t,n,i,o,r,s,l,u),a.dynCall_iiiiiijj=(e,t,n,i,o,r,s,l,u,c)=>(a.dynCall_iiiiiijj=St.Aa)(e,t,n,i,o,r,s,l,u,c),A=function e(){It||Dt(),It||(A=e)},a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);a.preInit.length>0;)a.preInit.pop()();return Dt(),e.ready});async function D(e,t){return async function(e,t,n=A){const a={...A,...n},i=await N(e),{size:o}=t,r=new Uint8Array(await t.arrayBuffer()),s=i._malloc(o);i.HEAPU8.set(r,s);const l=i.readBarcodesFromImage(s,o,M(i,a));i._free(s);const u=[];for(let e=0;e{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)})(this,I,void 0);try{const a=null==(t=null==e?void 0:e.formats)?void 0:t.filter(e=>"unknown"!==e);if(0===(null==a?void 0:a.length))throw new TypeError("Hint option provided, but is empty.");null==a||a.forEach(e=>{if(!r.has(e))throw new TypeError(`Failed to read the 'formats' property from 'BarcodeDetectorOptions': The provided value '${e}' is not a valid enum value of type BarcodeFormat.`)}),((e,t,a)=>{n(e,t,"write to private field"),t.set(e,a)})(this,I,null!=a?a:[]),function(e){return N(q,e)}().then(e=>{this.dispatchEvent(new CustomEvent("load",{detail:e}))}).catch(e=>{this.dispatchEvent(new CustomEvent("error",{detail:e}))})}catch(e){throw v(e,"Failed to construct 'BarcodeDetector'")}}static async getSupportedFormats(){return o.filter(e=>"unknown"!==e)}async detect(e){try{const t=await _(e);if(null===t)return[];let n;try{n=m(t)?await D(t,{tryHarder:!0,formats:a(this,I).map(e=>r.get(e))}):await j(t,{tryHarder:!0,formats:a(this,I).map(e=>r.get(e))})}catch(e){throw console.error(e),new DOMException("Barcode detection service unavailable.","NotSupportedError")}return n.map(e=>{const{topLeft:{x:t,y:n},topRight:{x:a,y:i},bottomLeft:{x:o,y:r},bottomRight:{x:l,y:u}}=e.position,c=Math.min(t,a,o,l),d=Math.min(n,i,r,u),h=Math.max(t,a,o,l),p=Math.max(n,i,r,u);return{boundingBox:new DOMRectReadOnly(c,d,h-c,p-d),rawValue:e.text,format:s(e.format),cornerPoints:[{x:t,y:n},{x:a,y:i},{x:l,y:u},{x:o,y:r}]}})}catch(e){throw v(e,"Failed to execute 'detect' on 'BarcodeDetector'")}}}I=new WeakMap;const F=(e,t,n="error")=>{let a,i;const o=new Promise((o,r)=>{a=o,i=r,e.addEventListener(t,a),e.addEventListener(n,i)});return o.finally(()=>{e.removeEventListener(t,a),e.removeEventListener(n,i)}),o},$=e=>new Promise(t=>setTimeout(t,e));class V extends Error{constructor(){super("can't process cross-origin image"),this.name="DropImageFetchError"}}class U extends Error{constructor(){super("this browser has no Stream API support"),this.name="StreamApiNotSupportedError"}}class H extends Error{constructor(){super("camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP."),this.name="InsecureContextError"}}class W extends Error{constructor(){super("Loading camera stream timed out after 6 seconds. If you are on iOS in PWA mode, this is a known issue (see https://github.com/gruhn/vue-qrcode-reader/issues/298)"),this.name="StreamLoadTimeoutError"}}let G;function K(e){G=new B({formats:e})}const Y=async(e,t=["qr_code"])=>await new B({formats:t}).detect(e),Q=async(e,t=["qr_code"])=>{const n=new B({formats:t}),a=await(async e=>{if(e.startsWith("http")&&!1===e.includes(location.host))throw new V;const t=document.createElement("img");return t.src=e,await F(t,"load"),t})(e);return await n.detect(a)};var Z={},J={};Object.defineProperty(J,"__esModule",{value:!0}),J.compactObject=function e(t){return ie(t)?Object.keys(t).reduce(function(n,a){var i=ie(t[a]),o=i?e(t[a]):t[a],r=i&&!Object.keys(o).length;return void 0===o||r?n:Object.assign(n,function(e,t,n){return t=function(e){var t=function(e,t){if("object"!==ee(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t);if("object"!==ee(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ee(t)?t:String(t)}(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}({},a,o))},{}):t},J.deprecated=function(e,t){ne&&console.warn(e+" is deprecated, please use "+t+" instead.")};var X=J.detectBrowser=function(e){var t={browser:null,version:null};if(typeof e>"u"||!e.navigator||!e.navigator.userAgent)return t.browser="Not a browser.",t;var n=e.navigator;if(n.mozGetUserMedia)t.browser="firefox",t.version=ae(n.userAgent,/Firefox\/(\d+)\./,1);else if(n.webkitGetUserMedia||!1===e.isSecureContext&&e.webkitRTCPeerConnection)t.browser="chrome",t.version=ae(n.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else{if(!e.RTCPeerConnection||!n.userAgent.match(/AppleWebKit\/(\d+)\./))return t.browser="Not a supported browser.",t;t.browser="safari",t.version=ae(n.userAgent,/AppleWebKit\/(\d+)\./,1),t.supportsUnifiedPlan=e.RTCRtpTransceiver&&"currentDirection"in e.RTCRtpTransceiver.prototype}return t};function ee(e){return(ee="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}J.disableLog=function(e){return"boolean"!=typeof e?new Error("Argument type: "+ee(e)+". Please use a boolean."):(te=e,e?"adapter.js logging disabled":"adapter.js logging enabled")},J.disableWarnings=function(e){return"boolean"!=typeof e?new Error("Argument type: "+ee(e)+". Please use a boolean."):(ne=!e,"adapter.js deprecation warnings "+(e?"disabled":"enabled"))},J.extractVersion=ae,J.filterStats=function(e,t,n){var a=n?"outbound-rtp":"inbound-rtp",i=new Map;if(null===t)return i;var o=[];return e.forEach(function(e){"track"===e.type&&e.trackIdentifier===t.id&&o.push(e)}),o.forEach(function(t){e.forEach(function(n){n.type===a&&n.trackId===t.id&&oe(e,n,i)})}),i},J.log=function(){if("object"===(typeof window>"u"?"undefined":ee(window))){if(te)return;typeof console<"u"&&"function"==typeof console.log&&console.log.apply(console,arguments)}},J.walkStats=oe,J.wrapPeerConnectionEvent=function(e,t,n){if(e.RTCPeerConnection){var a=e.RTCPeerConnection.prototype,i=a.addEventListener;a.addEventListener=function(e,a){if(e!==t)return i.apply(this,arguments);var o=function(e){var t=n(e);t&&(a.handleEvent?a.handleEvent(t):a(t))};return this._eventMap=this._eventMap||{},this._eventMap[t]||(this._eventMap[t]=new Map),this._eventMap[t].set(a,o),i.apply(this,[e,o])};var o=a.removeEventListener;a.removeEventListener=function(e,n){if(e!==t||!this._eventMap||!this._eventMap[t])return o.apply(this,arguments);if(!this._eventMap[t].has(n))return o.apply(this,arguments);var a=this._eventMap[t].get(n);return this._eventMap[t].delete(n),0===this._eventMap[t].size&&delete this._eventMap[t],0===Object.keys(this._eventMap).length&&delete this._eventMap,o.apply(this,[e,a])},Object.defineProperty(a,"on"+t,{get:function(){return this["_on"+t]},set:function(e){this["_on"+t]&&(this.removeEventListener(t,this["_on"+t]),delete this["_on"+t]),e&&this.addEventListener(t,this["_on"+t]=e)},enumerable:!0,configurable:!0})}};var te=!0,ne=!0;function ae(e,t,n){var a=e.match(t);return a&&a.length>=n&&parseInt(a[n],10)}function ie(e){return"[object Object]"===Object.prototype.toString.call(e)}function oe(e,t,n){!t||n.has(t.id)||(n.set(t.id,t),Object.keys(t).forEach(function(a){a.endsWith("Id")?oe(e,e.get(t[a]),n):a.endsWith("Ids")&&t[a].forEach(function(t){oe(e,e.get(t),n)})}))}Object.defineProperty(Z,"__esModule",{value:!0});var re=Z.shimGetUserMedia=function(e,t){var n=e&&e.navigator;if(n.mediaDevices){var a=function(e){if("object"!==ue(e)||e.mandatory||e.optional)return e;var t={};return Object.keys(e).forEach(function(n){if("require"!==n&&"advanced"!==n&&"mediaSource"!==n){var a="object"===ue(e[n])?e[n]:{ideal:e[n]};void 0!==a.exact&&"number"==typeof a.exact&&(a.min=a.max=a.exact);var i=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==a.ideal){t.optional=t.optional||[];var o={};"number"==typeof a.ideal?(o[i("min",n)]=a.ideal,t.optional.push(o),(o={})[i("max",n)]=a.ideal,t.optional.push(o)):(o[i("",n)]=a.ideal,t.optional.push(o))}void 0!==a.exact&&"number"!=typeof a.exact?(t.mandatory=t.mandatory||{},t.mandatory[i("",n)]=a.exact):["min","max"].forEach(function(e){void 0!==a[e]&&(t.mandatory=t.mandatory||{},t.mandatory[i(e,n)]=a[e])})}}),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},i=function(e,i){if(t.version>=61)return i(e);if((e=JSON.parse(JSON.stringify(e)))&&"object"===ue(e.audio)){var o=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])};o((e=JSON.parse(JSON.stringify(e))).audio,"autoGainControl","googAutoGainControl"),o(e.audio,"noiseSuppression","googNoiseSuppression"),e.audio=a(e.audio)}if(e&&"object"===ue(e.video)){var r=e.video.facingMode;r=r&&("object"===ue(r)?r:{ideal:r});var s,l=t.version<66;if(r&&("user"===r.exact||"environment"===r.exact||"user"===r.ideal||"environment"===r.ideal)&&(!n.mediaDevices.getSupportedConstraints||!n.mediaDevices.getSupportedConstraints().facingMode||l))if(delete e.video.facingMode,"environment"===r.exact||"environment"===r.ideal?s=["back","rear"]:("user"===r.exact||"user"===r.ideal)&&(s=["front"]),s)return n.mediaDevices.enumerateDevices().then(function(t){var n=(t=t.filter(function(e){return"videoinput"===e.kind})).find(function(e){return s.some(function(t){return e.label.toLowerCase().includes(t)})});return!n&&t.length&&s.includes("back")&&(n=t[t.length-1]),n&&(e.video.deviceId=r.exact?{exact:n.deviceId}:{ideal:n.deviceId}),e.video=a(e.video),ce("chrome: "+JSON.stringify(e)),i(e)});e.video=a(e.video)}return ce("chrome: "+JSON.stringify(e)),i(e)},o=function(e){return t.version>=64?e:{name:{PermissionDeniedError:"NotAllowedError",PermissionDismissedError:"NotAllowedError",InvalidStateError:"NotAllowedError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotAllowedError",MediaDeviceKillSwitchOn:"NotAllowedError",TabCaptureError:"AbortError",ScreenCaptureError:"AbortError",DeviceCaptureError:"AbortError"}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}};if(n.getUserMedia=function(e,t,a){i(e,function(e){n.webkitGetUserMedia(e,t,function(e){a&&a(o(e))})})}.bind(n),n.mediaDevices.getUserMedia){var r=n.mediaDevices.getUserMedia.bind(n.mediaDevices);n.mediaDevices.getUserMedia=function(e){return i(e,function(e){return r(e).then(function(t){if(e.audio&&!t.getAudioTracks().length||e.video&&!t.getVideoTracks().length)throw t.getTracks().forEach(function(e){e.stop()}),new DOMException("","NotFoundError");return t},function(e){return Promise.reject(o(e))})})}}}},se=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==ue(e)&&"function"!=typeof e)return{default:e};var n=le(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var r=i?Object.getOwnPropertyDescriptor(e,o):null;r&&(r.get||r.set)?Object.defineProperty(a,o,r):a[o]=e[o]}return a.default=e,n&&n.set(e,a),a}(J);function le(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(le=function(e){return e?n:t})(e)}function ue(e){return(ue="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var ce=se.log;var de={};Object.defineProperty(de,"__esModule",{value:!0});var he=de.shimGetUserMedia=function(e,t){var n=e&&e.navigator,a=e&&e.MediaStreamTrack;if(n.getUserMedia=function(e,t,a){pe.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),n.mediaDevices.getUserMedia(e).then(t,a)},!(t.version>55&&"autoGainControl"in n.mediaDevices.getSupportedConstraints())){var i=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])},o=n.mediaDevices.getUserMedia.bind(n.mediaDevices);if(n.mediaDevices.getUserMedia=function(e){return"object"===me(e)&&"object"===me(e.audio)&&(e=JSON.parse(JSON.stringify(e)),i(e.audio,"autoGainControl","mozAutoGainControl"),i(e.audio,"noiseSuppression","mozNoiseSuppression")),o(e)},a&&a.prototype.getSettings){var r=a.prototype.getSettings;a.prototype.getSettings=function(){var e=r.apply(this,arguments);return i(e,"mozAutoGainControl","autoGainControl"),i(e,"mozNoiseSuppression","noiseSuppression"),e}}if(a&&a.prototype.applyConstraints){var s=a.prototype.applyConstraints;a.prototype.applyConstraints=function(e){return"audio"===this.kind&&"object"===me(e)&&(e=JSON.parse(JSON.stringify(e)),i(e,"autoGainControl","mozAutoGainControl"),i(e,"noiseSuppression","mozNoiseSuppression")),s.apply(this,[e])}}}},pe=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==me(e)&&"function"!=typeof e)return{default:e};var n=fe(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var r=i?Object.getOwnPropertyDescriptor(e,o):null;r&&(r.get||r.set)?Object.defineProperty(a,o,r):a[o]=e[o]}return a.default=e,n&&n.set(e,a),a}(J);function fe(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(fe=function(e){return e?n:t})(e)}function me(e){return(me="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var ge={};Object.defineProperty(ge,"__esModule",{value:!0}),ge.shimAudioContext=function(e){"object"!==ye(e)||e.AudioContext||(e.AudioContext=e.webkitAudioContext)},ge.shimCallbacksAPI=function(e){if("object"===ye(e)&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype,n=t.createOffer,a=t.createAnswer,i=t.setLocalDescription,o=t.setRemoteDescription,r=t.addIceCandidate;t.createOffer=function(e,t){var a=arguments.length>=2?arguments[2]:arguments[0],i=n.apply(this,[a]);return t?(i.then(e,t),Promise.resolve()):i},t.createAnswer=function(e,t){var n=arguments.length>=2?arguments[2]:arguments[0],i=a.apply(this,[n]);return t?(i.then(e,t),Promise.resolve()):i};var s=function(e,t,n){var a=i.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a};t.setLocalDescription=s,s=function(e,t,n){var a=o.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a},t.setRemoteDescription=s,s=function(e,t,n){var a=r.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a},t.addIceCandidate=s}},ge.shimConstraints=we,ge.shimCreateOfferLegacy=function(e){var t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(e){if(e){typeof e.offerToReceiveAudio<"u"&&(e.offerToReceiveAudio=!!e.offerToReceiveAudio);var n=this.getTransceivers().find(function(e){return"audio"===e.receiver.track.kind});!1===e.offerToReceiveAudio&&n?"sendrecv"===n.direction?n.setDirection?n.setDirection("sendonly"):n.direction="sendonly":"recvonly"===n.direction&&(n.setDirection?n.setDirection("inactive"):n.direction="inactive"):!0===e.offerToReceiveAudio&&!n&&this.addTransceiver("audio",{direction:"recvonly"}),typeof e.offerToReceiveVideo<"u"&&(e.offerToReceiveVideo=!!e.offerToReceiveVideo);var a=this.getTransceivers().find(function(e){return"video"===e.receiver.track.kind});!1===e.offerToReceiveVideo&&a?"sendrecv"===a.direction?a.setDirection?a.setDirection("sendonly"):a.direction="sendonly":"recvonly"===a.direction&&(a.setDirection?a.setDirection("inactive"):a.direction="inactive"):!0===e.offerToReceiveVideo&&!a&&this.addTransceiver("video",{direction:"recvonly"})}return t.apply(this,arguments)}};var _e=ge.shimGetUserMedia=function(e){var t=e&&e.navigator;if(t.mediaDevices&&t.mediaDevices.getUserMedia){var n=t.mediaDevices,a=n.getUserMedia.bind(n);t.mediaDevices.getUserMedia=function(e){return a(we(e))}}!t.getUserMedia&&t.mediaDevices&&t.mediaDevices.getUserMedia&&(t.getUserMedia=function(e,n,a){t.mediaDevices.getUserMedia(e).then(n,a)}.bind(t))};ge.shimLocalStreamsAPI=function(e){if("object"===ye(e)&&e.RTCPeerConnection){if("getLocalStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),!("addStream"in e.RTCPeerConnection.prototype)){var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addStream=function(e){var n=this;this._localStreams||(this._localStreams=[]),this._localStreams.includes(e)||this._localStreams.push(e),e.getAudioTracks().forEach(function(a){return t.call(n,a,e)}),e.getVideoTracks().forEach(function(a){return t.call(n,a,e)})},e.RTCPeerConnection.prototype.addTrack=function(e){for(var n=this,a=arguments.length,i=new Array(a>1?a-1:0),o=1;o=0)){e._remoteStreams.push(t);var n=new Event("addstream");n.stream=t,e.dispatchEvent(n)}})}),t.apply(e,arguments)}}},ge.shimTrackEventTransceiver=function(e){"object"===ye(e)&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})};var ve=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==ye(e)&&"function"!=typeof e)return{default:e};var n=be(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&Object.prototype.hasOwnProperty.call(e,o)){var r=i?Object.getOwnPropertyDescriptor(e,o):null;r&&(r.get||r.set)?Object.defineProperty(a,o,r):a[o]=e[o]}return a.default=e,n&&n.set(e,a),a}(J);function be(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(be=function(e){return e?n:t})(e)}function ye(e){return(ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function we(e){return e&&void 0!==e.video?Object.assign({},e,{video:ve.compactObject(e.video)}):e}function ke(e,t){if(!1===e)throw new Error(null!=t?t:"assertion failure")}function xe(e){throw new Error("this code should be unreachable")}const Se=(e=>{let t,n=!1;return(...a)=>(n||(t=e(a),n=!0),t)})(()=>{const e=X(window);switch(e.browser){case"chrome":re(window,e);break;case"firefox":he(window,e);break;case"safari":_e(window,e);break;default:throw new U}});let Ce=Promise.resolve({type:"stop",data:{}});async function Te(e,t,n){var a,i,o;if(console.debug("[vue-qrcode-reader] starting camera with constraints: ",JSON.stringify(t)),!0!==window.isSecureContext)throw new H;if(void 0===(null==(a=null==navigator?void 0:navigator.mediaDevices)?void 0:a.getUserMedia))throw new U;Se(),console.debug("[vue-qrcode-reader] calling getUserMedia");const r=await navigator.mediaDevices.getUserMedia({audio:!1,video:t});void 0!==e.srcObject?e.srcObject=r:void 0!==e.mozSrcObject?e.mozSrcObject=r:window.URL.createObjectURL?e.src=window.URL.createObjectURL(r):window.webkitURL?e.src=window.webkitURL.createObjectURL(r):e.src=r.id,e.play(),console.debug("[vue-qrcode-reader] waiting for video element to load"),await Promise.race([F(e,"loadeddata"),$(6e3).then(()=>{throw new W})]),console.debug("[vue-qrcode-reader] video element loaded"),await $(500);const[s]=r.getVideoTracks(),l=null!=(o=null==(i=null==s?void 0:s.getCapabilities)?void 0:i.call(s))?o:{};let u=!1;return n&&l.torch&&(await s.applyConstraints({advanced:[{torch:!0}]}),u=!0),console.debug("[vue-qrcode-reader] camera ready"),{type:"start",data:{videoEl:e,stream:r,capabilities:l,constraints:t,isTorchOn:u}}}async function Pe(e,t,n){console.debug("[vue-qrcode-reader] stopping camera"),e.src="",e.srcObject=null,e.load(),await F(e,"error");for(const e of t.getTracks())null!=n||await e.applyConstraints({advanced:[{torch:!1}]}),t.removeTrack(e),e.stop();return{type:"stop",data:{}}}async function Ee(){if(Ce=Ce.then(e=>{if("stop"===e.type||"failed"===e.type)return e;const{data:{videoEl:t,stream:n,isTorchOn:a}}=e;return Pe(t,n,a)}),"start"===(await Ce).type)throw new Error("Something went wrong with the camera task queue (stop task).")}const Ae=t.defineComponent({__name:"QrcodeStream",props:{constraints:{default:()=>({facingMode:"environment"})},formats:{default:()=>["qr_code"]},paused:{type:Boolean,default:!1},torch:{type:Boolean,default:!1},track:{type:Function,default:void 0}},emits:["detect","camera-on","camera-off","error"],setup(e,{emit:n}){const a=e,i=n,o=t.ref(a.constraints),r=t.ref(a.formats);t.watch(()=>a.constraints,(e,t)=>{JSON.stringify(e)!==JSON.stringify(t)&&(o.value=e)},{deep:!0}),t.watch(()=>a.formats,(e,t)=>{JSON.stringify(e)!==JSON.stringify(t)&&(r.value=e)},{deep:!0});const s=t.ref(),l=t.ref(),u=t.ref(),c=t.ref(!1),d=t.ref(!1);t.onMounted(()=>{d.value=!0}),t.onUnmounted(()=>{Ee()});const h=t.computed(()=>({torch:a.torch,constraints:o.value,shouldStream:d.value&&!a.paused}));t.watch(h,async e=>{const t=u.value;ke(void 0!==t,"cameraSettings watcher should never be triggered when component is not mounted. Thus video element should always be defined.");const n=s.value;ke(void 0!==n,"cameraSettings watcher should never be triggered when component is not mounted. Thus canvas should always be defined.");const a=n.getContext("2d");if(ke(null!==a,"if cavnas is defined, canvas 2d context should also be non-null"),e.shouldStream){Ee(),c.value=!1;try{const n=await async function(e,{constraints:t,torch:n,restart:a=!1}){Ce=Ce.then(i=>{if("start"===i.type){const{data:{videoEl:o,stream:r,constraints:s,isTorchOn:l}}=i;return a||e!==o||t!==s||n!==l?Pe(o,r,l).then(()=>Te(e,t,n)):i}if("stop"===i.type||"failed"===i.type)return Te(e,t,n);xe()}).catch(e=>(console.debug(`[vue-qrcode-reader] starting camera failed with "${e}"`),{type:"failed",error:e}));const i=await Ce;if("stop"===i.type)throw new Error("Something went wrong with the camera task queue (start task).");if("failed"===i.type)throw i.error;if("start"===i.type)return i.data.capabilities;xe()}(t,e);d.value?(c.value=!0,i("camera-on",n)):await Ee()}catch(e){i("error",e)}}else n.width=t.videoWidth,n.height=t.videoHeight,a.drawImage(t,0,0,t.videoWidth,t.videoHeight),Ee(),c.value=!1,i("camera-off")},{deep:!0}),t.watch(r,e=>{d.value&&K(e)});const p=t.computed(()=>h.value.shouldStream&&c.value);t.watch(p,e=>{if(e){ke(void 0!==s.value,"shouldScan watcher should only be triggered when component is mounted. Thus pause frame canvas is defined"),f(s.value),ke(void 0!==l.value,"shouldScan watcher should only be triggered when component is mounted. Thus tracking canvas is defined"),f(l.value);const e=()=>void 0===a.track?500:40;ke(void 0!==u.value,"shouldScan watcher should only be triggered when component is mounted. Thus video element is defined"),(async(e,{detectHandler:t,locateHandler:n,minDelay:a,formats:i})=>{console.debug("[vue-qrcode-reader] start scanning"),K(i);const o=i=>async r=>{if(0===e.readyState)console.debug("[vue-qrcode-reader] stop scanning: video element readyState is 0");else{const{lastScanned:s,contentBefore:l,lastScanHadContent:u}=i;if(r-s!l.includes(e.rawValue));i&&t(a);const s=a.length>0;s&&n(a),!s&&u&&n(a);const c={lastScanned:r,lastScanHadContent:s,contentBefore:i?a.map(e=>e.rawValue):l};window.requestAnimationFrame(o(c))}}};o({lastScanned:performance.now(),contentBefore:[],lastScanHadContent:!1})(performance.now())})(u.value,{detectHandler:e=>i("detect",e),formats:r.value,locateHandler:m,minDelay:e()})}});const f=e=>{const t=e.getContext("2d");ke(null!==t,"canvas 2d context should always be non-null"),t.clearRect(0,0,e.width,e.height)},m=e=>{const t=l.value;ke(void 0!==t,"onLocate handler should only be called when component is mounted. Thus tracking canvas is always defined.");const n=u.value;if(ke(void 0!==n,"onLocate handler should only be called when component is mounted. Thus video element is always defined."),0===e.length||void 0===a.track)f(t);else{const i=n.offsetWidth,o=n.offsetHeight,r=n.videoWidth,s=n.videoHeight,l=Math.max(i/r,o/s),u=r*l,c=s*l,d=u/r,h=c/s,p=(i-u)/2,f=(o-c)/2,m=({x:e,y:t})=>({x:Math.floor(e*d),y:Math.floor(t*h)}),g=({x:e,y:t})=>({x:Math.floor(e+p),y:Math.floor(t+f)}),_=e.map(e=>{const{boundingBox:t,cornerPoints:n}=e,{x:a,y:i}=g(m({x:t.x,y:t.y})),{x:o,y:r}=m({x:t.width,y:t.height});return{...e,cornerPoints:n.map(e=>g(m(e))),boundingBox:DOMRectReadOnly.fromRect({x:a,y:i,width:o,height:r})}});t.width=n.offsetWidth,t.height=n.offsetHeight;const v=t.getContext("2d");ke(null!==v,"canvas 2d context should always be non-null"),a.track(_,v)}},g={width:"100%",height:"100%",position:"relative","z-index":"0"},_={width:"100%",height:"100%",position:"absolute",top:"0",left:"0"},v={width:"100%",height:"100%","object-fit":"cover"},b=t.computed(()=>p.value?v:{...v,visibility:"hidden",position:"absolute"});return(e,n)=>(t.openBlock(),t.createElementBlock("div",{style:g},[t.createElementVNode("video",{ref_key:"videoRef",ref:u,style:t.normalizeStyle(b.value),autoplay:"",muted:"",playsinline:""},null,4),t.withDirectives(t.createElementVNode("canvas",{id:"qrcode-stream-pause-frame",ref_key:"pauseFrameRef",ref:s,style:v},null,512),[[t.vShow,!p.value]]),t.createElementVNode("canvas",{id:"qrcode-stream-tracking-layer",ref_key:"trackingLayerRef",ref:l,style:_},null,512),t.createElementVNode("div",{style:_},[t.renderSlot(e.$slots,"default")])]))}}),Me=t.defineComponent({__name:"QrcodeCapture",props:{formats:{default:()=>["qr_code"]}},emits:["detect"],setup(e,{emit:n}){const a=e,i=n,o=e=>{if(e.target instanceof HTMLInputElement&&e.target.files)for(const t of Array.from(e.target.files))Y(t,a.formats).then(e=>{i("detect",e)})};return(e,n)=>(t.openBlock(),t.createElementBlock("input",{onChange:o,type:"file",name:"image",accept:"image/*",capture:"environment",multiple:""},null,32))}}),Le=t.defineComponent({__name:"QrcodeDropZone",props:{formats:{default:()=>["qr_code"]}},emits:["detect","dragover","error"],setup(e,{emit:n}){const a=e,i=n,o=async e=>{try{const t=await e;i("detect",t)}catch(e){i("error",e)}},r=e=>{i("dragover",e)},s=({dataTransfer:e})=>{if(!e)return;r(!1);const t=[...Array.from(e.files)],n=e.getData("text/uri-list");t.forEach(e=>{o(Y(e,a.formats))}),""!==n&&o(Q(n,a.formats))};return(e,n)=>(t.openBlock(),t.createElementBlock("div",{onDrop:t.withModifiers(s,["prevent","stop"]),onDragenter:n[0]||(n[0]=t.withModifiers(e=>r(!0),["prevent","stop"])),onDragleave:n[1]||(n[1]=t.withModifiers(e=>r(!1),["prevent","stop"])),onDragover:n[2]||(n[2]=t.withModifiers(()=>{},["prevent","stop"]))},[t.renderSlot(e.$slots,"default")],32))}});function Re(e){e.component("qrcode-stream",Ae),e.component("qrcode-capture",Me),e.component("qrcode-drop-zone",Le)}const ze={install:Re};e.QrcodeCapture=Me,e.QrcodeDropZone=Le,e.QrcodeStream=Ae,e.VueQrcodeReader=ze,e.install=Re,e.setZXingModuleOverrides=function(e){return function(e,t){z.set(e,{moduleOverrides:t})}(q,e)},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}), + */!function(e,t){"object"==typeof exports&&typeof module<"u"?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e=typeof globalThis<"u"?globalThis:e||self).VueQrcodeReader={},e.Vue)}(this,function(e,t){"use strict";var n=(e,t,n)=>{if(!t.has(e))throw TypeError("Cannot "+n)},a=(e,t,a)=>(n(e,t,"read from private field"),a?a.call(e):t.get(e));const i=[["aztec","Aztec"],["code_128","Code128"],["code_39","Code39"],["code_93","Code93"],["codabar","Codabar"],["databar","DataBar"],["databar_expanded","DataBarExpanded"],["data_matrix","DataMatrix"],["dx_film_edge","DXFilmEdge"],["ean_13","EAN-13"],["ean_8","EAN-8"],["itf","ITF"],["maxi_code","MaxiCode"],["micro_qr_code","MicroQRCode"],["pdf417","PDF417"],["qr_code","QRCode"],["rm_qr_code","rMQRCode"],["upc_a","UPC-A"],["upc_e","UPC-E"],["linear_codes","Linear-Codes"],["matrix_codes","Matrix-Codes"]],r=[...i,["unknown"]].map(e=>e[0]),o=new Map(i);function s(e){for(const[t,n]of o)if(e===n)return t;return"unknown"}function l(e){try{return e instanceof HTMLImageElement}catch(e){return!1}}function u(e){try{return e instanceof SVGImageElement}catch(e){return!1}}function c(e){try{return e instanceof HTMLVideoElement}catch(e){return!1}}function d(e){try{return e instanceof HTMLCanvasElement}catch(e){return!1}}function h(e){try{return e instanceof ImageBitmap}catch(e){return!1}}function p(e){try{return e instanceof OffscreenCanvas}catch(e){return!1}}function f(e){try{return e instanceof VideoFrame}catch(e){return!1}}function m(e){try{return e instanceof Blob}catch(e){return!1}}async function _(e){if(l(e)&&!await async function(e){try{return await e.decode(),!0}catch(e){return!1}}(e))throw new DOMException("Failed to load or decode HTMLImageElement.","InvalidStateError");if(u(e)&&!await async function(e){var t;try{return await(null==(t=e.decode)?void 0:t.call(e)),!0}catch(e){return!1}}(e))throw new DOMException("Failed to load or decode SVGImageElement.","InvalidStateError");if(f(e)&&function(e){return null===e.format}(e))throw new DOMException("VideoFrame is closed.","InvalidStateError");if(c(e)&&(0===e.readyState||1===e.readyState))throw new DOMException("Invalid element or state.","InvalidStateError");if(h(e)&&function(e){return 0===e.width&&0===e.height}(e))throw new DOMException("The image source is detached.","InvalidStateError");const{width:t,height:n}=function(e){if(l(e))return{width:e.naturalWidth,height:e.naturalHeight};if(u(e))return{width:e.width.baseVal.value,height:e.height.baseVal.value};if(c(e))return{width:e.videoWidth,height:e.videoHeight};if(h(e))return{width:e.width,height:e.height};if(f(e))return{width:e.displayWidth,height:e.displayHeight};if(d(e))return{width:e.width,height:e.height};if(p(e))return{width:e.width,height:e.height};throw new TypeError("The provided value is not of type '(Blob or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or ImageData or OffscreenCanvas or SVGImageElement or VideoFrame)'.")}(e);if(0===t||0===n)return null;const a=function(e,t){try{const n=new OffscreenCanvas(e,t);if(n.getContext("2d")instanceof OffscreenCanvasRenderingContext2D)return n;throw void 0}catch(n){const a=document.createElement("canvas");return a.width=e,a.height=t,a}}(t,n).getContext("2d");a.drawImage(e,0,0);try{return a.getImageData(0,0,t,n)}catch(e){throw new DOMException("Source would taint origin.","SecurityError")}}async function g(e){if(m(e))return await async function(e){let t;try{if(globalThis.createImageBitmap)t=await createImageBitmap(e);else{if(!globalThis.Image)return e;{t=new Image;let n="";try{n=URL.createObjectURL(e),t.src=n,await t.decode()}finally{URL.revokeObjectURL(n)}}}}catch(e){throw new DOMException("Failed to load or decode Blob.","InvalidStateError")}return await _(t)}(e);if(function(e){try{return e instanceof ImageData}catch(e){return!1}}(e)){if(function(e){return 0===e.data.buffer.byteLength}(e))throw new DOMException("The image data has been detached.","InvalidStateError");return e}return d(e)||p(e)?function(e){const{width:t,height:n}=e;if(0===t||0===n)return null;const a=e.getContext("2d");try{return a.getImageData(0,0,t,n)}catch(e){throw new DOMException("Source would taint origin.","SecurityError")}}(e):await _(e)}function v(e,t){return e instanceof DOMException?new DOMException(`${t}: ${e.message}`,e.name):e instanceof Error?new e.constructor(`${t}: ${e.message}`):new Error(`${t}: ${e}`)}const b=["Aztec","Codabar","Code128","Code39","Code93","DataBar","DataBarExpanded","DataMatrix","DXFilmEdge","EAN-13","EAN-8","ITF","Linear-Codes","Matrix-Codes","MaxiCode","MicroQRCode","None","PDF417","QRCode","rMQRCode","UPC-A","UPC-E"];function y(e){return e.join("|")}function w(e){const t=k(e);let n=0,a=b.length-1;for(;n<=a;){const e=Math.floor((n+a)/2),i=b[e],r=k(i);if(r===t)return i;r{const n=e.match(/_(.+?)\.wasm$/);return n?`https://fastly.jsdelivr.net/npm/zxing-wasm@1.1.3/dist/${n[1]}/${e}`:t+e}};let z=new WeakMap;function I(e,t){var n;const a=z.get(e);if(null!=a&&a.modulePromise&&void 0===t)return a.modulePromise;const i=null!=(n=null==a?void 0:a.moduleOverrides)?n:R,r=e({...i});return z.set(e,{moduleOverrides:i,modulePromise:r}),r}var N,O,j=(N=typeof document<"u"&&document.currentScript?document.currentScript.src:void 0,function(e={}){var t,n,a=e;a.ready=new Promise((e,a)=>{t=e,n=a});var i=Object.assign({},a),r="./this.program",o="object"==typeof window,s="function"==typeof importScripts;"object"==typeof process&&"object"==typeof process.versions&&process.versions.node;var l,u="";(o||s)&&(s?u=self.location.href:typeof document<"u"&&document.currentScript&&(u=document.currentScript.src),N&&(u=N),u=0!==u.indexOf("blob:")?u.substr(0,u.replace(/[?#].*/,"").lastIndexOf("/")+1):"",s&&(l=e=>{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)})),a.print||console.log.bind(console);var c,d=a.printErr||console.error.bind(console);Object.assign(a,i),i=null,a.arguments&&a.arguments,a.thisProgram&&(r=a.thisProgram),a.quit&&a.quit,a.wasmBinary&&(c=a.wasmBinary),"object"!=typeof WebAssembly&&L("no native wasm support detected");var h,p,f,m,_,g,v,b,y,w=!1;function k(){var e=h.buffer;a.HEAP8=p=new Int8Array(e),a.HEAP16=m=new Int16Array(e),a.HEAPU8=f=new Uint8Array(e),a.HEAPU16=_=new Uint16Array(e),a.HEAP32=g=new Int32Array(e),a.HEAPU32=v=new Uint32Array(e),a.HEAPF32=b=new Float32Array(e),a.HEAPF64=y=new Float64Array(e)}var x=[],S=[],C=[];function T(e){x.unshift(e)}function P(e){C.unshift(e)}var E=0,A=null;function L(e){var t;null===(t=a.onAbort)||void 0===t||t.call(a,e),d(e="Aborted("+e+")"),w=!0,e+=". Build with -sASSERTIONS for more info.";var i=new WebAssembly.RuntimeError(e);throw n(i),i}var M,R,z=e=>e.startsWith("data:application/octet-stream;base64,");function I(e){if(e==M&&c)return new Uint8Array(c);if(l)return l(e);throw"both async and sync fetching of the wasm failed"}function O(e,t,n){return function(e){return c||!o&&!s||"function"!=typeof fetch?Promise.resolve().then(()=>I(e)):fetch(e,{credentials:"same-origin"}).then(t=>{if(!t.ok)throw"failed to load wasm binary file at '"+e+"'";return t.arrayBuffer()}).catch(()=>I(e))}(e).then(e=>WebAssembly.instantiate(e,t)).then(e=>e).then(n,e=>{d(`failed to asynchronously prepare wasm: ${e}`),L(e)})}z(M="zxing_reader.wasm")||(R=M,M=a.locateFile?a.locateFile(R,u):u+R);var j=e=>{for(;e.length>0;)e.shift()(a)};a.noExitRuntime;var D=[],q=0,B=0;function F(e){this.excPtr=e,this.ptr=e-24,this.set_type=function(e){v[this.ptr+4>>2]=e},this.get_type=function(){return v[this.ptr+4>>2]},this.set_destructor=function(e){v[this.ptr+8>>2]=e},this.get_destructor=function(){return v[this.ptr+8>>2]},this.set_caught=function(e){e=e?1:0,p[this.ptr+12|0]=e},this.get_caught=function(){return 0!=p[this.ptr+12|0]},this.set_rethrown=function(e){e=e?1:0,p[this.ptr+13|0]=e},this.get_rethrown=function(){return 0!=p[this.ptr+13|0]},this.init=function(e,t){this.set_adjusted_ptr(0),this.set_type(e),this.set_destructor(t)},this.set_adjusted_ptr=function(e){v[this.ptr+16>>2]=e},this.get_adjusted_ptr=function(){return v[this.ptr+16>>2]},this.get_exception_ptr=function(){if(Nt(this.get_type()))return v[this.excPtr>>2];var e=this.get_adjusted_ptr();return 0!==e?e:this.excPtr}}var V=e=>{var t=B;if(!t)return At(0),0;var n=new F(t);n.set_adjusted_ptr(t);var a=n.get_type();if(!a)return At(0),t;for(var i in e){var r=e[i];if(0===r||r===a)break;var o=n.ptr+16;if(It(r,a,o))return At(r),t}return At(a),t},U={},$=e=>{for(;e.length;){var t=e.pop();e.pop()(t)}};function H(e){return this.fromWireType(g[e>>2])}var W,G,K,Y={},Q={},Z={},J=e=>{throw new W(e)},X=(e,t,n)=>{function a(t){var a=n(t);a.length!==e.length&&J("Mismatched type converter count");for(var i=0;i{Q.hasOwnProperty(e)?i[t]=Q[e]:(r.push(e),Y.hasOwnProperty(e)||(Y[e]=[]),Y[e].push(()=>{i[t]=Q[e],++o===r.length&&a(i)}))}),0===r.length&&a(i)},ee=e=>{for(var t="",n=e;f[n];)t+=G[f[n++]];return t},te=e=>{throw new K(e)};function ne(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!("argPackAdvance"in t))throw new TypeError("registerType registeredInstance requires argPackAdvance");return function(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};var a=t.name;if(e||te(`type "${a}" must have a positive integer typeid pointer`),Q.hasOwnProperty(e)){if(n.ignoreDuplicateRegistrations)return;te(`Cannot register type '${a}' twice`)}if(Q[e]=t,delete Z[e],Y.hasOwnProperty(e)){var i=Y[e];delete Y[e],i.forEach(e=>e())}}(e,t,n)}var ae,ie=8,re=e=>({count:e.count,deleteScheduled:e.deleteScheduled,preservePointerOnDelete:e.preservePointerOnDelete,ptr:e.ptr,ptrType:e.ptrType,smartPtr:e.smartPtr,smartPtrType:e.smartPtrType}),oe=e=>{te(e.$$.ptrType.registeredClass.name+" instance already deleted")},se=!1,le=e=>{},ue=e=>{e.count.value-=1,0===e.count.value&&(e=>{e.smartPtr?e.smartPtrType.rawDestructor(e.smartPtr):e.ptrType.registeredClass.rawDestructor(e.ptr)})(e)},ce=(e,t,n)=>{if(t===n)return e;if(void 0===n.baseClass)return null;var a=ce(e,t,n.baseClass);return null===a?null:n.downcast(a)},de={},he=()=>Object.keys(ge).length,pe=()=>{var e=[];for(var t in ge)ge.hasOwnProperty(t)&&e.push(ge[t]);return e},fe=[],me=()=>{for(;fe.length;){var e=fe.pop();e.$$.deleteScheduled=!1,e.delete()}},_e=e=>{ae=e,fe.length&&ae&&ae(me)},ge={},ve=(e,t)=>(t=((e,t)=>{for(void 0===t&&te("ptr should not be undefined");e.baseClass;)t=e.upcast(t),e=e.baseClass;return t})(e,t),ge[t]),be=(e,t)=>((!t.ptrType||!t.ptr)&&J("makeClassHandle requires ptr and ptrType"),!!t.smartPtrType!=!!t.smartPtr&&J("Both smartPtrType and smartPtr must be specified"),t.count={value:1},we(Object.create(e,{$$:{value:t,writable:!0}})));function ye(e){var t=this.getPointee(e);if(!t)return this.destructor(e),null;var n=ve(this.registeredClass,t);if(void 0!==n){if(0===n.$$.count.value)return n.$$.ptr=t,n.$$.smartPtr=e,n.clone();var a=n.clone();return this.destructor(e),a}function i(){return this.isSmartPointer?be(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:t,smartPtrType:this,smartPtr:e}):be(this.registeredClass.instancePrototype,{ptrType:this,ptr:e})}var r,o=this.registeredClass.getActualType(t),s=de[o];if(!s)return i.call(this);r=this.isConst?s.constPointerType:s.pointerType;var l=ce(t,this.registeredClass,r.registeredClass);return null===l?i.call(this):this.isSmartPointer?be(r.registeredClass.instancePrototype,{ptrType:r,ptr:l,smartPtrType:this,smartPtr:e}):be(r.registeredClass.instancePrototype,{ptrType:r,ptr:l})}var we=e=>typeof FinalizationRegistry>"u"?(we=e=>e,e):(se=new FinalizationRegistry(e=>{ue(e.$$)}),le=e=>se.unregister(e),(we=e=>{var t=e.$$;if(t.smartPtr){var n={$$:t};se.register(e,n,e)}return e})(e));function ke(){}var xe=(e,t)=>Object.defineProperty(t,"name",{value:e}),Se=(e,t,n)=>{if(void 0===e[t].overloadTable){var a=e[t];e[t]=function(){return e[t].overloadTable.hasOwnProperty(arguments.length)||te(`Function '${n}' called with an invalid number of arguments (${arguments.length}) - expects one of (${e[t].overloadTable})!`),e[t].overloadTable[arguments.length].apply(this,arguments)},e[t].overloadTable=[],e[t].overloadTable[a.argCount]=a}},Ce=(e,t,n)=>{a.hasOwnProperty(e)?((void 0===n||void 0!==a[e].overloadTable&&void 0!==a[e].overloadTable[n])&&te(`Cannot register public name '${e}' twice`),Se(a,e,e),a.hasOwnProperty(n)&&te(`Cannot register multiple overloads of a function with the same number of arguments (${n})!`),a[e].overloadTable[n]=t):(a[e]=t,void 0!==n&&(a[e].numArguments=n))};function Te(e,t,n,a,i,r,o,s){this.name=e,this.constructor=t,this.instancePrototype=n,this.rawDestructor=a,this.baseClass=i,this.getActualType=r,this.upcast=o,this.downcast=s,this.pureVirtualFunctions=[]}var Pe=(e,t,n)=>{for(;t!==n;)t.upcast||te(`Expected null or instance of ${n.name}, got an instance of ${t.name}`),e=t.upcast(e),t=t.baseClass;return e};function Ee(e,t){if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),0;t.$$||te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`);var n=t.$$.ptrType.registeredClass;return Pe(t.$$.ptr,n,this.registeredClass)}function Ae(e,t){var n;if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),this.isSmartPointer?(n=this.rawConstructor(),null!==e&&e.push(this.rawDestructor,n),n):0;(!t||!t.$$)&&te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`),!this.isConst&&t.$$.ptrType.isConst&&te(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);var a=t.$$.ptrType.registeredClass;if(n=Pe(t.$$.ptr,a,this.registeredClass),this.isSmartPointer)switch(void 0===t.$$.smartPtr&&te("Passing raw pointer to smart pointer is illegal"),this.sharingPolicy){case 0:t.$$.smartPtrType===this?n=t.$$.smartPtr:te(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);break;case 1:n=t.$$.smartPtr;break;case 2:if(t.$$.smartPtrType===this)n=t.$$.smartPtr;else{var i=t.clone();n=this.rawShare(n,Ye.toHandle(()=>i.delete())),null!==e&&e.push(this.rawDestructor,n)}break;default:te("Unsupporting sharing policy")}return n}function Le(e,t){if(null===t)return this.isReference&&te(`null is not a valid ${this.name}`),0;t.$$||te(`Cannot pass "${Je(t)}" as a ${this.name}`),t.$$.ptr||te(`Cannot pass deleted object as a pointer of type ${this.name}`),t.$$.ptrType.isConst&&te(`Cannot convert argument of type ${t.$$.ptrType.name} to parameter type ${this.name}`);var n=t.$$.ptrType.registeredClass;return Pe(t.$$.ptr,n,this.registeredClass)}function Me(e){return this.fromWireType(v[e>>2])}function Re(e,t,n,a,i,r,o,s,l,u,c){this.name=e,this.registeredClass=t,this.isReference=n,this.isConst=a,this.isSmartPointer=i,this.pointeeType=r,this.sharingPolicy=o,this.rawGetPointee=s,this.rawConstructor=l,this.rawShare=u,this.rawDestructor=c,i||void 0!==t.baseClass?this.toWireType=Ae:a?(this.toWireType=Ee,this.destructorFunction=null):(this.toWireType=Le,this.destructorFunction=null)}var ze,Ie,Ne=(e,t,n)=>{a.hasOwnProperty(e)||J("Replacing nonexistant public symbol"),void 0!==a[e].overloadTable&&void 0!==n?a[e].overloadTable[n]=t:(a[e]=t,a[e].argCount=n)},Oe=[],je=e=>{var t=Oe[e];return t||(e>=Oe.length&&(Oe.length=e+1),Oe[e]=t=ze.get(e)),t},De=(e,t,n)=>e.includes("j")?((e,t,n)=>{var i=a["dynCall_"+e];return n&&n.length?i.apply(null,[t].concat(n)):i.call(null,t)})(e,t,n):je(t).apply(null,n),qe=(e,t)=>{var n=(e=ee(e)).includes("j")?((e,t)=>{var n=[];return function(){return n.length=0,Object.assign(n,arguments),De(e,t,n)}})(e,t):je(t);return"function"!=typeof n&&te(`unknown function pointer with signature ${e}: ${t}`),n},Be=e=>{var t=Pt(e),n=ee(t);return Ct(t),n},Fe=(e,t)=>{var n=[],a={};throw t.forEach(function e(t){if(!a[t]&&!Q[t]){if(Z[t])return void Z[t].forEach(e);n.push(t),a[t]=!0}}),new Ie(`${e}: `+n.map(Be).join([", "]))},Ve=(e,t)=>{for(var n=[],a=0;a>2]);return n};function Ue(e,t,n,a,i,r){var o=t.length;o<2&&te("argTypes array size mismatch! Must at least get return value and 'this' types!");var s=null!==t[1]&&null!==n,l=function(e){for(var t=1;t{const t=(e=e.trim()).indexOf("(");return-1!==t?e.substr(0,t):e};function He(){this.allocated=[void 0],this.freelist=[]}var We=new He,Ge=e=>{e>=We.reserved&&0===--We.get(e).refcount&&We.free(e)},Ke=()=>{for(var e=0,t=We.reserved;t(e||te("Cannot use deleted val. handle = "+e),We.get(e).value),toHandle:e=>{switch(e){case void 0:return 1;case null:return 2;case!0:return 3;case!1:return 4;default:return We.allocate({refcount:1,value:e})}}},Qe=(e,t,n)=>{switch(t){case 1:return n?function(e){return this.fromWireType(p[0|e])}:function(e){return this.fromWireType(f[0|e])};case 2:return n?function(e){return this.fromWireType(m[e>>1])}:function(e){return this.fromWireType(_[e>>1])};case 4:return n?function(e){return this.fromWireType(g[e>>2])}:function(e){return this.fromWireType(v[e>>2])};default:throw new TypeError(`invalid integer width (${t}): ${e}`)}},Ze=(e,t)=>{var n=Q[e];return void 0===n&&te(t+" has unknown type "+Be(e)),n},Je=e=>{if(null===e)return"null";var t=typeof e;return"object"===t||"array"===t||"function"===t?e.toString():""+e},Xe=(e,t)=>{switch(t){case 4:return function(e){return this.fromWireType(b[e>>2])};case 8:return function(e){return this.fromWireType(y[e>>3])};default:throw new TypeError(`invalid float width (${t}): ${e}`)}},et=(e,t,n)=>{switch(t){case 1:return n?e=>p[0|e]:e=>f[0|e];case 2:return n?e=>m[e>>1]:e=>_[e>>1];case 4:return n?e=>g[e>>2]:e=>v[e>>2];default:throw new TypeError(`invalid integer width (${t}): ${e}`)}},tt=(e,t,n,a)=>{if(!(a>0))return 0;for(var i=n,r=n+a-1,o=0;o=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++o)),s<=127){if(n>=r)break;t[n++]=s}else if(s<=2047){if(n+1>=r)break;t[n++]=192|s>>6,t[n++]=128|63&s}else if(s<=65535){if(n+2>=r)break;t[n++]=224|s>>12,t[n++]=128|s>>6&63,t[n++]=128|63&s}else{if(n+3>=r)break;t[n++]=240|s>>18,t[n++]=128|s>>12&63,t[n++]=128|s>>6&63,t[n++]=128|63&s}}return t[n]=0,n-i},nt=e=>{for(var t=0,n=0;n=55296&&a<=57343?(t+=4,++n):t+=3}return t},at=typeof TextDecoder<"u"?new TextDecoder("utf8"):void 0,it=(e,t)=>e?((e,t,n)=>{for(var a=t+n,i=t;e[i]&&!(i>=a);)++i;if(i-t>16&&e.buffer&&at)return at.decode(e.subarray(t,i));for(var r="";t>10,56320|1023&u)}}else r+=String.fromCharCode((31&o)<<6|s)}else r+=String.fromCharCode(o)}return r})(f,e,t):"",rt=typeof TextDecoder<"u"?new TextDecoder("utf-16le"):void 0,ot=(e,t)=>{for(var n=e,a=n>>1,i=a+t/2;!(a>=i)&&_[a];)++a;if((n=a<<1)-e>32&&rt)return rt.decode(f.subarray(e,n));for(var r="",o=0;!(o>=t/2);++o){var s=m[e+2*o>>1];if(0==s)break;r+=String.fromCharCode(s)}return r},st=(e,t,n)=>{var a;if(null!==(a=n)&&void 0!==a||(n=2147483647),n<2)return 0;for(var i=t,r=(n-=2)<2*e.length?n/2:e.length,o=0;o>1]=s,t+=2}return m[t>>1]=0,t-i},lt=e=>2*e.length,ut=(e,t)=>{for(var n=0,a="";!(n>=t/4);){var i=g[e+4*n>>2];if(0==i)break;if(++n,i>=65536){var r=i-65536;a+=String.fromCharCode(55296|r>>10,56320|1023&r)}else a+=String.fromCharCode(i)}return a},ct=(e,t,n)=>{var a;if(null!==(a=n)&&void 0!==a||(n=2147483647),n<4)return 0;for(var i=t,r=i+n-4,o=0;o=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++o)),g[t>>2]=s,(t+=4)+4>r)break}return g[t>>2]=0,t-i},dt=e=>{for(var t=0,n=0;n=55296&&a<=57343&&++n,t+=4}return t},ht=[],pt={},ft=()=>{if("object"==typeof globalThis)return globalThis;function e(e){e.$$$embind_global$$$=e;var t="object"==typeof $$$embind_global$$$&&e.$$$embind_global$$$==e;return t||delete e.$$$embind_global$$$,t}if("object"==typeof $$$embind_global$$$||("object"==typeof global&&e(global)?$$$embind_global$$$=global:"object"==typeof self&&e(self)&&($$$embind_global$$$=self),"object"==typeof $$$embind_global$$$))return $$$embind_global$$$;throw Error("unable to get global object.")},mt=Reflect.construct,_t=e=>{var t=(e-h.buffer.byteLength+65535)/65536;try{return h.grow(t),k(),1}catch(e){}},gt={},vt=()=>{if(!vt.strings){var e={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:r||"./this.program"};for(var t in gt)void 0===gt[t]?delete e[t]:e[t]=gt[t];var n=[];for(var t in e)n.push(`${t}=${e[t]}`);vt.strings=n}return vt.strings},bt=e=>e%4==0&&(e%100!=0||e%400==0),yt=[31,29,31,30,31,30,31,31,30,31,30,31],wt=[31,28,31,30,31,30,31,31,30,31,30,31],kt=(e,t,n,a)=>{var i=v[a+40>>2],r={tm_sec:g[a>>2],tm_min:g[a+4>>2],tm_hour:g[a+8>>2],tm_mday:g[a+12>>2],tm_mon:g[a+16>>2],tm_year:g[a+20>>2],tm_wday:g[a+24>>2],tm_yday:g[a+28>>2],tm_isdst:g[a+32>>2],tm_gmtoff:g[a+36>>2],tm_zone:i?it(i):""},o=it(n),s={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var l in s)o=o.replace(new RegExp(l,"g"),s[l]);var u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],c=["January","February","March","April","May","June","July","August","September","October","November","December"];function d(e,t,n){for(var a="number"==typeof e?e.toString():e||"";a.length0?1:0}var a;return 0===(a=n(e.getFullYear()-t.getFullYear()))&&0===(a=n(e.getMonth()-t.getMonth()))&&(a=n(e.getDate()-t.getDate())),a}function m(e){switch(e.getDay()){case 0:return new Date(e.getFullYear()-1,11,29);case 1:return e;case 2:return new Date(e.getFullYear(),0,3);case 3:return new Date(e.getFullYear(),0,2);case 4:return new Date(e.getFullYear(),0,1);case 5:return new Date(e.getFullYear()-1,11,31);case 6:return new Date(e.getFullYear()-1,11,30)}}function _(e){var t=((e,t)=>{for(var n=new Date(e.getTime());t>0;){var a=bt(n.getFullYear()),i=n.getMonth(),r=(a?yt:wt)[i];if(!(t>r-n.getDate()))return n.setDate(n.getDate()+t),n;t-=r-n.getDate()+1,n.setDate(1),i<11?n.setMonth(i+1):(n.setMonth(0),n.setFullYear(n.getFullYear()+1))}return n})(new Date(e.tm_year+1900,0,1),e.tm_yday),n=new Date(t.getFullYear(),0,4),a=new Date(t.getFullYear()+1,0,4),i=m(n),r=m(a);return f(i,t)<=0?f(r,t)<=0?t.getFullYear()+1:t.getFullYear():t.getFullYear()-1}var b={"%a":e=>u[e.tm_wday].substring(0,3),"%A":e=>u[e.tm_wday],"%b":e=>c[e.tm_mon].substring(0,3),"%B":e=>c[e.tm_mon],"%C":e=>h((e.tm_year+1900)/100|0,2),"%d":e=>h(e.tm_mday,2),"%e":e=>d(e.tm_mday,2," "),"%g":e=>_(e).toString().substring(2),"%G":e=>_(e),"%H":e=>h(e.tm_hour,2),"%I":e=>{var t=e.tm_hour;return 0==t?t=12:t>12&&(t-=12),h(t,2)},"%j":e=>h(e.tm_mday+((e,t)=>{for(var n=0,a=0;a<=t;n+=e[a++]);return n})(bt(e.tm_year+1900)?yt:wt,e.tm_mon-1),3),"%m":e=>h(e.tm_mon+1,2),"%M":e=>h(e.tm_min,2),"%n":()=>"\n","%p":e=>e.tm_hour>=0&&e.tm_hour<12?"AM":"PM","%S":e=>h(e.tm_sec,2),"%t":()=>"\t","%u":e=>e.tm_wday||7,"%U":e=>{var t=e.tm_yday+7-e.tm_wday;return h(Math.floor(t/7),2)},"%V":e=>{var t=Math.floor((e.tm_yday+7-(e.tm_wday+6)%7)/7);if((e.tm_wday+371-e.tm_yday-2)%7<=2&&t++,t){if(53==t){var n=(e.tm_wday+371-e.tm_yday)%7;4!=n&&(3!=n||!bt(e.tm_year))&&(t=1)}}else{t=52;var a=(e.tm_wday+7-e.tm_yday-1)%7;(4==a||5==a&&bt(e.tm_year%400-1))&&t++}return h(t,2)},"%w":e=>e.tm_wday,"%W":e=>{var t=e.tm_yday+7-(e.tm_wday+6)%7;return h(Math.floor(t/7),2)},"%y":e=>(e.tm_year+1900).toString().substring(2),"%Y":e=>e.tm_year+1900,"%z":e=>{var t=e.tm_gmtoff;return(t>=0?"+":"-")+("0000"+(t=(t=Math.abs(t)/60)/60*100+t%60)).slice(-4)},"%Z":e=>e.tm_zone,"%%":()=>"%"};for(var l in o=o.replace(/%%/g,"\0\0"),b)o.includes(l)&&(o=o.replace(new RegExp(l,"g"),b[l](r)));var y=function(e){var t=nt(e)+1,n=new Array(t);return tt(e,n,0,n.length),n}(o=o.replace(/\0\0/g,"%"));return y.length>t?0:(((e,t)=>{p.set(e,t)})(y,e),y.length-1)};W=a.InternalError=class extends Error{constructor(e){super(e),this.name="InternalError"}},(()=>{for(var e=new Array(256),t=0;t<256;++t)e[t]=String.fromCharCode(t);G=e})(),K=a.BindingError=class extends Error{constructor(e){super(e),this.name="BindingError"}},Object.assign(ke.prototype,{isAliasOf(e){if(!(this instanceof ke&&e instanceof ke))return!1;var t=this.$$.ptrType.registeredClass,n=this.$$.ptr;e.$$=e.$$;for(var a=e.$$.ptrType.registeredClass,i=e.$$.ptr;t.baseClass;)n=t.upcast(n),t=t.baseClass;for(;a.baseClass;)i=a.upcast(i),a=a.baseClass;return t===a&&n===i},clone(){if(this.$$.ptr||oe(this),this.$$.preservePointerOnDelete)return this.$$.count.value+=1,this;var e=we(Object.create(Object.getPrototypeOf(this),{$$:{value:re(this.$$)}}));return e.$$.count.value+=1,e.$$.deleteScheduled=!1,e},delete(){this.$$.ptr||oe(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&te("Object already scheduled for deletion"),le(this),ue(this.$$),this.$$.preservePointerOnDelete||(this.$$.smartPtr=void 0,this.$$.ptr=void 0)},isDeleted(){return!this.$$.ptr},deleteLater(){return this.$$.ptr||oe(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&te("Object already scheduled for deletion"),fe.push(this),1===fe.length&&ae&&ae(me),this.$$.deleteScheduled=!0,this}}),a.getInheritedInstanceCount=he,a.getLiveInheritedInstances=pe,a.flushPendingDeletes=me,a.setDelayFunction=_e,Object.assign(Re.prototype,{getPointee(e){return this.rawGetPointee&&(e=this.rawGetPointee(e)),e},destructor(e){var t;null===(t=this.rawDestructor)||void 0===t||t.call(this,e)},argPackAdvance:ie,readValueFromPointer:Me,deleteObject(e){null!==e&&e.delete()},fromWireType:ye}),Ie=a.UnboundTypeError=((e,t)=>{var n=xe(t,function(e){this.name=t,this.message=e;var n=new Error(e).stack;void 0!==n&&(this.stack=this.toString()+"\n"+n.replace(/^Error(:[^\n]*)?\n/,""))});return n.prototype=Object.create(e.prototype),n.prototype.constructor=n,n.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`},n})(Error,"UnboundTypeError"),Object.assign(He.prototype,{get(e){return this.allocated[e]},has(e){return void 0!==this.allocated[e]},allocate(e){var t=this.freelist.pop()||this.allocated.length;return this.allocated[t]=e,t},free(e){this.allocated[e]=void 0,this.freelist.push(e)}}),We.allocated.push({value:void 0},{value:null},{value:!0},{value:!1}),We.reserved=We.allocated.length,a.count_emval_handles=Ke;var xt={s:e=>{var t=new F(e);return t.get_caught()||(t.set_caught(!0),q--),t.set_rethrown(!1),D.push(t),zt(t.excPtr),t.get_exception_ptr()},u:()=>{Et(0,0);var e=D.pop();Rt(e.excPtr),B=0},b:()=>V([]),g:e=>V([e]),q:(e,t)=>V([e,t]),J:()=>{var e=D.pop();e||L("no exception to throw");var t=e.excPtr;throw e.get_rethrown()||(D.push(e),e.set_rethrown(!0),e.set_caught(!1),q++),B=t},f:(e,t,n)=>{throw new F(e).init(t,n),q++,B=e},V:()=>q,d:e=>{throw B||(B=e),B},da:e=>{var t=U[e];delete U[e];var n=t.rawConstructor,a=t.rawDestructor,i=t.fields,r=i.map(e=>e.getterReturnType).concat(i.map(e=>e.setterArgumentType));X([e],r,e=>{var r={};return i.forEach((t,n)=>{var a=t.fieldName,o=e[n],s=t.getter,l=t.getterContext,u=e[n+i.length],c=t.setter,d=t.setterContext;r[a]={read:e=>o.fromWireType(s(l,e)),write:(e,t)=>{var n=[];c(d,e,u.toWireType(n,t)),$(n)}}}),[{name:t.name,fromWireType:e=>{var t={};for(var n in r)t[n]=r[n].read(e);return a(e),t},toWireType:(e,t)=>{for(var i in r)if(!(i in t))throw new TypeError(`Missing field: "${i}"`);var o=n();for(i in r)r[i].write(o,t[i]);return null!==e&&e.push(a,o),o},argPackAdvance:ie,readValueFromPointer:H,destructorFunction:a}]})},Q:(e,t,n,a,i)=>{},_:(e,t,n,a)=>{ne(e,{name:t=ee(t),fromWireType:function(e){return!!e},toWireType:function(e,t){return t?n:a},argPackAdvance:ie,readValueFromPointer:function(e){return this.fromWireType(f[e])},destructorFunction:null})},ca:(e,t,n,a,i,r,o,s,l,u,c,d,h)=>{c=ee(c),r=qe(i,r),s&&(s=qe(o,s)),u&&(u=qe(l,u)),h=qe(d,h);var p=(e=>{if(void 0===e)return"_unknown";var t=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return t>=48&&t<=57?`_${e}`:e})(c);Ce(p,function(){Fe(`Cannot construct ${c} due to unbound types`,[a])}),X([e,t,n],a?[a]:[],function(t){var n,i;t=t[0],i=a?(n=t.registeredClass).instancePrototype:ke.prototype;var o=xe(c,function(){if(Object.getPrototypeOf(this)!==l)throw new K("Use 'new' to construct "+c);if(void 0===m.constructor_body)throw new K(c+" has no accessible constructor");var e=m.constructor_body[arguments.length];if(void 0===e)throw new K(`Tried to invoke ctor of ${c} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(m.constructor_body).toString()}) parameters instead!`);return e.apply(this,arguments)}),l=Object.create(i,{constructor:{value:o}});o.prototype=l;var d,f,m=new Te(c,o,l,h,n,r,s,u);m.baseClass&&(null!==(f=(d=m.baseClass).__derivedClasses)&&void 0!==f||(d.__derivedClasses=[]),m.baseClass.__derivedClasses.push(m));var _=new Re(c,m,!0,!1,!1),g=new Re(c+"*",m,!1,!1,!1),v=new Re(c+" const*",m,!1,!0,!1);return de[e]={pointerType:g,constPointerType:v},Ne(p,o),[_,g,v]})},ba:(e,t,n,a,i,r)=>{var o=Ve(t,n);i=qe(a,i),X([],[e],function(e){var n=`constructor ${(e=e[0]).name}`;if(void 0===e.registeredClass.constructor_body&&(e.registeredClass.constructor_body=[]),void 0!==e.registeredClass.constructor_body[t-1])throw new K(`Cannot register multiple constructors with identical number of parameters (${t-1}) for class '${e.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);return e.registeredClass.constructor_body[t-1]=()=>{Fe(`Cannot construct ${e.name} due to unbound types`,o)},X([],o,a=>(a.splice(1,0,null),e.registeredClass.constructor_body[t-1]=Ue(n,a,null,i,r),[])),[]})},w:(e,t,n,a,i,r,o,s,l)=>{var u=Ve(n,a);t=ee(t),t=$e(t),r=qe(i,r),X([],[e],function(e){var a=`${(e=e[0]).name}.${t}`;function i(){Fe(`Cannot call ${a} due to unbound types`,u)}t.startsWith("@@")&&(t=Symbol[t.substring(2)]),s&&e.registeredClass.pureVirtualFunctions.push(t);var l=e.registeredClass.instancePrototype,c=l[t];return void 0===c||void 0===c.overloadTable&&c.className!==e.name&&c.argCount===n-2?(i.argCount=n-2,i.className=e.name,l[t]=i):(Se(l,t,a),l[t].overloadTable[n-2]=i),X([],u,function(i){var s=Ue(a,i,e,r,o);return void 0===l[t].overloadTable?(s.argCount=n-2,l[t]=s):l[t].overloadTable[n-2]=s,[]}),[]})},Y:(e,t)=>{ne(e,{name:t=ee(t),fromWireType:e=>{var t=Ye.toValue(e);return Ge(e),t},toWireType:(e,t)=>Ye.toHandle(t),argPackAdvance:ie,readValueFromPointer:H,destructorFunction:null})},x:(e,t,n,a)=>{function i(){}t=ee(t),i.values={},ne(e,{name:t,constructor:i,fromWireType:function(e){return this.constructor.values[e]},toWireType:(e,t)=>t.value,argPackAdvance:ie,readValueFromPointer:Qe(t,n,a),destructorFunction:null}),Ce(t,i)},h:(e,t,n)=>{var a=Ze(e,"enum");t=ee(t);var i=a.constructor,r=Object.create(a.constructor.prototype,{value:{value:n},constructor:{value:xe(`${a.name}_${t}`,function(){})}});i.values[n]=r,i[t]=r},L:(e,t,n)=>{ne(e,{name:t=ee(t),fromWireType:e=>e,toWireType:(e,t)=>t,argPackAdvance:ie,readValueFromPointer:Xe(t,n),destructorFunction:null})},M:(e,t,n,a,i,r,o)=>{var s=Ve(t,n);e=ee(e),e=$e(e),i=qe(a,i),Ce(e,function(){Fe(`Cannot call ${e} due to unbound types`,s)},t-1),X([],s,function(n){var a=[n[0],null].concat(n.slice(1));return Ne(e,Ue(e,a,null,i,r),t-1),[]})},t:(e,t,n,a,i)=>{t=ee(t);var r=e=>e;if(0===a){var o=32-8*n;r=e=>e<>>o}var s=t.includes("unsigned");ne(e,{name:t,fromWireType:r,toWireType:s?function(e,t){return this.name,t>>>0}:function(e,t){return this.name,t},argPackAdvance:ie,readValueFromPointer:et(t,n,0!==a),destructorFunction:null})},o:(e,t,n)=>{var a=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function i(e){var t=v[e>>2],n=v[e+4>>2];return new a(p.buffer,n,t)}ne(e,{name:n=ee(n),fromWireType:i,argPackAdvance:ie,readValueFromPointer:i},{ignoreDuplicateRegistrations:!0})},K:(e,t)=>{var n="std::string"===(t=ee(t));ne(e,{name:t,fromWireType(e){var t,a=v[e>>2],i=e+4;if(n)for(var r=i,o=0;o<=a;++o){var s=i+o;if(o==a||0==f[s]){var l=it(r,s-r);void 0===t?t=l:(t+="\0",t+=l),r=s+1}}else{var u=new Array(a);for(o=0;o>2]=a,n&&i)((e,t,n)=>{tt(e,f,t,n)})(t,o,a+1);else if(i)for(var s=0;s255&&(Ct(o),te("String has UTF-16 code units that do not fit in 8 bits")),f[o+s]=l}else for(s=0;s{var a,i,r,o,s;n=ee(n),2===t?(a=ot,i=st,o=lt,r=()=>_,s=1):4===t&&(a=ut,i=ct,o=dt,r=()=>v,s=2),ne(e,{name:n,fromWireType:e=>{for(var n,i=v[e>>2],o=r(),l=e+4,u=0;u<=i;++u){var c=e+4+u*t;if(u==i||0==o[c>>s]){var d=a(l,c-l);void 0===n?n=d:(n+="\0",n+=d),l=c+t}}return Ct(e),n},toWireType:(e,a)=>{"string"!=typeof a&&te(`Cannot pass non-string to C++ string type ${n}`);var r=o(a),l=Tt(4+r+t);return v[l>>2]=r>>s,i(a,l+4,r+t),null!==e&&e.push(Ct,l),l},argPackAdvance:ie,readValueFromPointer:H,destructorFunction(e){Ct(e)}})},A:(e,t,n,a,i,r)=>{U[e]={name:ee(t),rawConstructor:qe(n,a),rawDestructor:qe(i,r),fields:[]}},ea:(e,t,n,a,i,r,o,s,l,u)=>{U[e].fields.push({fieldName:ee(t),getterReturnType:n,getter:qe(a,i),getterContext:r,setterArgumentType:o,setter:qe(s,l),setterContext:u})},$:(e,t)=>{ne(e,{isVoid:!0,name:t=ee(t),argPackAdvance:0,fromWireType:()=>{},toWireType:(e,t)=>{}})},R:(e,t,n,a)=>(e=ht[e])(null,t=Ye.toValue(t),n,a),ha:Ge,fa:e=>0===e?Ye.toHandle(ft()):(e=(e=>{var t=pt[e];return void 0===t?ee(e):t})(e),Ye.toHandle(ft()[e])),Z:(e,t,n)=>{var a=((e,t)=>{for(var n=new Array(e),a=0;a>2],"parameter "+a);return n})(e,t),i=a.shift();e--;var r=new Array(e),o=`methodCaller<(${a.map(e=>e.name).join(", ")}) => ${i.name}>`;return(e=>{var t=ht.length;return ht.push(e),t})(xe(o,(t,o,s,l)=>{for(var u=0,c=0;c{var a=[],i=e.toWireType(a,n);return a.length&&(v[t>>2]=Ye.toHandle(a)),i})(i,s,d)}))},N:e=>{e>4&&(We.get(e).refcount+=1)},O:e=>{var t=Ye.toValue(e);$(t),Ge(e)},aa:(e,t)=>{var n=(e=Ze(e,"_emval_take_value")).readValueFromPointer(t);return Ye.toHandle(n)},B:()=>{L("")},X:(e,t,n)=>f.copyWithin(e,t,t+n),W:e=>{var t=f.length,n=2147483648;if((e>>>=0)>n)return!1;for(var a=(e,t)=>e+(t-e%t)%t,i=1;i<=4;i*=2){var r=t*(1+.2/i);r=Math.min(r,e+100663296);var o=Math.min(n,a(Math.max(e,r),65536));if(_t(o))return!0}return!1},T:(e,t)=>{var n=0;return vt().forEach((a,i)=>{var r=t+n;v[e+4*i>>2]=r,((e,t)=>{for(var n=0;n{var n=vt();v[e>>2]=n.length;var a=0;return n.forEach(e=>a+=e.length+1),v[t>>2]=a,0},E:function(e,t,n,a){var i=Lt();try{return je(e)(t,n,a)}catch(e){if(Mt(i),e!==e+0)throw e;Et(1,0)}},D:function(e,t,n,a,i){var r=Lt();try{return je(e)(t,n,a,i)}catch(e){if(Mt(r),e!==e+0)throw e;Et(1,0)}},F:function(e,t,n,a){var i=Lt();try{return je(e)(t,n,a)}catch(e){if(Mt(i),e!==e+0)throw e;Et(1,0)}},n:function(e){var t=Lt();try{return je(e)()}catch(e){if(Mt(t),e!==e+0)throw e;Et(1,0)}},a:function(e,t){var n=Lt();try{return je(e)(t)}catch(e){if(Mt(n),e!==e+0)throw e;Et(1,0)}},e:function(e,t,n){var a=Lt();try{return je(e)(t,n)}catch(e){if(Mt(a),e!==e+0)throw e;Et(1,0)}},m:function(e,t,n,a){var i=Lt();try{return je(e)(t,n,a)}catch(e){if(Mt(i),e!==e+0)throw e;Et(1,0)}},k:function(e,t,n,a,i){var r=Lt();try{return je(e)(t,n,a,i)}catch(e){if(Mt(r),e!==e+0)throw e;Et(1,0)}},H:function(e,t,n,a,i,r){var o=Lt();try{return je(e)(t,n,a,i,r)}catch(e){if(Mt(o),e!==e+0)throw e;Et(1,0)}},v:function(e,t,n,a,i,r,o){var s=Lt();try{return je(e)(t,n,a,i,r,o)}catch(e){if(Mt(s),e!==e+0)throw e;Et(1,0)}},G:function(e,t,n,a,i,r,o,s){var l=Lt();try{return je(e)(t,n,a,i,r,o,s)}catch(e){if(Mt(l),e!==e+0)throw e;Et(1,0)}},z:function(e,t,n,a,i,r,o,s,l,u,c,d){var h=Lt();try{return je(e)(t,n,a,i,r,o,s,l,u,c,d)}catch(e){if(Mt(h),e!==e+0)throw e;Et(1,0)}},P:function(e,t,n,a,i){var r=Lt();try{return jt(e,t,n,a,i)}catch(e){if(Mt(r),e!==e+0)throw e;Et(1,0)}},l:function(e){var t=Lt();try{je(e)()}catch(e){if(Mt(t),e!==e+0)throw e;Et(1,0)}},j:function(e,t){var n=Lt();try{je(e)(t)}catch(e){if(Mt(n),e!==e+0)throw e;Et(1,0)}},c:function(e,t,n){var a=Lt();try{je(e)(t,n)}catch(e){if(Mt(a),e!==e+0)throw e;Et(1,0)}},p:function(e,t,n,a){var i=Lt();try{je(e)(t,n,a)}catch(e){if(Mt(i),e!==e+0)throw e;Et(1,0)}},I:function(e,t,n,a,i){var r=Lt();try{je(e)(t,n,a,i)}catch(e){if(Mt(r),e!==e+0)throw e;Et(1,0)}},r:function(e,t,n,a,i,r,o,s){var l=Lt();try{je(e)(t,n,a,i,r,o,s)}catch(e){if(Mt(l),e!==e+0)throw e;Et(1,0)}},i:function(e,t,n,a,i,r,o,s,l,u,c){var d=Lt();try{je(e)(t,n,a,i,r,o,s,l,u,c)}catch(e){if(Mt(d),e!==e+0)throw e;Et(1,0)}},y:function(e,t,n,a,i,r,o,s,l,u,c,d,h,p,f,m){var _=Lt();try{je(e)(t,n,a,i,r,o,s,l,u,c,d,h,p,f,m)}catch(e){if(Mt(_),e!==e+0)throw e;Et(1,0)}},ga:e=>e,S:(e,t,n,a,i)=>kt(e,t,n,a)},St=function(){var e={a:xt};function t(e,t){return St=e.exports,h=St.ia,k(),ze=St.ma,function(e){S.unshift(e)}(St.ja),function(){var e;if(E--,null===(e=a.monitorRunDependencies)||void 0===e||e.call(a,E),0==E&&A){var t=A;A=null,t()}}(),St}if(function(){var e;E++,null===(e=a.monitorRunDependencies)||void 0===e||e.call(a,E)}(),a.instantiateWasm)try{return a.instantiateWasm(e,t)}catch(e){d(`Module.instantiateWasm callback failed with error: ${e}`),n(e)}return function(e,t,n,a){return e||"function"!=typeof WebAssembly.instantiateStreaming||z(t)||"function"!=typeof fetch?O(t,n,a):fetch(t,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,n).then(a,function(e){return d(`wasm streaming compile failed: ${e}`),d("falling back to ArrayBuffer instantiation"),O(t,n,a)}))}(c,M,e,function(e){t(e.instance)}).catch(n),{}}(),Ct=a._free=e=>(Ct=a._free=St.ka)(e),Tt=a._malloc=e=>(Tt=a._malloc=St.la)(e),Pt=e=>(Pt=St.na)(e),Et=(e,t)=>(Et=St.oa)(e,t),At=e=>(At=St.pa)(e),Lt=()=>(Lt=St.qa)(),Mt=e=>(Mt=St.ra)(e),Rt=e=>(Rt=St.sa)(e),zt=e=>(zt=St.ta)(e),It=(e,t,n)=>(It=St.ua)(e,t,n),Nt=e=>(Nt=St.va)(e);a.dynCall_viijii=(e,t,n,i,r,o,s)=>(a.dynCall_viijii=St.wa)(e,t,n,i,r,o,s);var Ot,jt=a.dynCall_jiiii=(e,t,n,i,r)=>(jt=a.dynCall_jiiii=St.xa)(e,t,n,i,r);function Dt(){function e(){Ot||(Ot=!0,a.calledRun=!0,!w&&(j(S),t(a),a.onRuntimeInitialized&&a.onRuntimeInitialized(),function(){if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)P(a.postRun.shift());j(C)}()))}E>0||(function(){if(a.preRun)for("function"==typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)T(a.preRun.shift());j(x)}(),E>0)||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1),e()},1)):e())}if(a.dynCall_iiiiij=(e,t,n,i,r,o,s)=>(a.dynCall_iiiiij=St.ya)(e,t,n,i,r,o,s),a.dynCall_iiiiijj=(e,t,n,i,r,o,s,l,u)=>(a.dynCall_iiiiijj=St.za)(e,t,n,i,r,o,s,l,u),a.dynCall_iiiiiijj=(e,t,n,i,r,o,s,l,u,c)=>(a.dynCall_iiiiiijj=St.Aa)(e,t,n,i,r,o,s,l,u,c),A=function e(){Ot||Dt(),Ot||(A=e)},a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);a.preInit.length>0;)a.preInit.pop()();return Dt(),e.ready});async function D(e,t){return async function(e,t,n=A){const a={...A,...n},i=await I(e),{size:r}=t,o=new Uint8Array(await t.arrayBuffer()),s=i._malloc(r);i.HEAPU8.set(o,s);const l=i.readBarcodesFromImage(s,r,L(i,a));i._free(s);const u=[];for(let e=0;e{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,n)})(this,O,void 0);try{const a=null==(t=null==e?void 0:e.formats)?void 0:t.filter(e=>"unknown"!==e);if(0===(null==a?void 0:a.length))throw new TypeError("Hint option provided, but is empty.");null==a||a.forEach(e=>{if(!o.has(e))throw new TypeError(`Failed to read the 'formats' property from 'BarcodeDetectorOptions': The provided value '${e}' is not a valid enum value of type BarcodeFormat.`)}),((e,t,a)=>{n(e,t,"write to private field"),t.set(e,a)})(this,O,null!=a?a:[]),function(e){return I(j,e)}().then(e=>{this.dispatchEvent(new CustomEvent("load",{detail:e}))}).catch(e=>{this.dispatchEvent(new CustomEvent("error",{detail:e}))})}catch(e){throw v(e,"Failed to construct 'BarcodeDetector'")}}static async getSupportedFormats(){return r.filter(e=>"unknown"!==e)}async detect(e){try{const t=await g(e);if(null===t)return[];let n;try{n=m(t)?await D(t,{tryHarder:!0,formats:a(this,O).map(e=>o.get(e))}):await q(t,{tryHarder:!0,formats:a(this,O).map(e=>o.get(e))})}catch(e){throw console.error(e),new DOMException("Barcode detection service unavailable.","NotSupportedError")}return n.map(e=>{const{topLeft:{x:t,y:n},topRight:{x:a,y:i},bottomLeft:{x:r,y:o},bottomRight:{x:l,y:u}}=e.position,c=Math.min(t,a,r,l),d=Math.min(n,i,o,u),h=Math.max(t,a,r,l),p=Math.max(n,i,o,u);return{boundingBox:new DOMRectReadOnly(c,d,h-c,p-d),rawValue:e.text,format:s(e.format),cornerPoints:[{x:t,y:n},{x:a,y:i},{x:l,y:u},{x:r,y:o}]}})}catch(e){throw v(e,"Failed to execute 'detect' on 'BarcodeDetector'")}}}O=new WeakMap;const F=(e,t,n="error")=>{let a,i;const r=new Promise((r,o)=>{a=r,i=o,e.addEventListener(t,a),e.addEventListener(n,i)});return r.finally(()=>{e.removeEventListener(t,a),e.removeEventListener(n,i)}),r},V=e=>new Promise(t=>setTimeout(t,e));class U extends Error{constructor(){super("can't process cross-origin image"),this.name="DropImageFetchError"}}class $ extends Error{constructor(){super("this browser has no Stream API support"),this.name="StreamApiNotSupportedError"}}class H extends Error{constructor(){super("camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP."),this.name="InsecureContextError"}}class W extends Error{constructor(){super("Loading camera stream timed out after 6 seconds. If you are on iOS in PWA mode, this is a known issue (see https://github.com/gruhn/vue-qrcode-reader/issues/298)"),this.name="StreamLoadTimeoutError"}}let G;function K(e){G=new B({formats:e})}const Y=async(e,t=["qr_code"])=>await new B({formats:t}).detect(e),Q=async(e,t=["qr_code"])=>{const n=new B({formats:t}),a=await(async e=>{if(e.startsWith("http")&&!1===e.includes(location.host))throw new U;const t=document.createElement("img");return t.src=e,await F(t,"load"),t})(e);return await n.detect(a)};var Z={},J={};Object.defineProperty(J,"__esModule",{value:!0}),J.compactObject=function e(t){return ie(t)?Object.keys(t).reduce(function(n,a){var i=ie(t[a]),r=i?e(t[a]):t[a],o=i&&!Object.keys(r).length;return void 0===r||o?n:Object.assign(n,function(e,t,n){return t=function(e){var t=function(e,t){if("object"!==ee(e)||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t);if("object"!==ee(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"===ee(t)?t:String(t)}(t),t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}({},a,r))},{}):t},J.deprecated=function(e,t){ne&&console.warn(e+" is deprecated, please use "+t+" instead.")};var X=J.detectBrowser=function(e){var t={browser:null,version:null};if(typeof e>"u"||!e.navigator||!e.navigator.userAgent)return t.browser="Not a browser.",t;var n=e.navigator;if(n.mozGetUserMedia)t.browser="firefox",t.version=ae(n.userAgent,/Firefox\/(\d+)\./,1);else if(n.webkitGetUserMedia||!1===e.isSecureContext&&e.webkitRTCPeerConnection)t.browser="chrome",t.version=ae(n.userAgent,/Chrom(e|ium)\/(\d+)\./,2);else{if(!e.RTCPeerConnection||!n.userAgent.match(/AppleWebKit\/(\d+)\./))return t.browser="Not a supported browser.",t;t.browser="safari",t.version=ae(n.userAgent,/AppleWebKit\/(\d+)\./,1),t.supportsUnifiedPlan=e.RTCRtpTransceiver&&"currentDirection"in e.RTCRtpTransceiver.prototype}return t};function ee(e){return(ee="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}J.disableLog=function(e){return"boolean"!=typeof e?new Error("Argument type: "+ee(e)+". Please use a boolean."):(te=e,e?"adapter.js logging disabled":"adapter.js logging enabled")},J.disableWarnings=function(e){return"boolean"!=typeof e?new Error("Argument type: "+ee(e)+". Please use a boolean."):(ne=!e,"adapter.js deprecation warnings "+(e?"disabled":"enabled"))},J.extractVersion=ae,J.filterStats=function(e,t,n){var a=n?"outbound-rtp":"inbound-rtp",i=new Map;if(null===t)return i;var r=[];return e.forEach(function(e){"track"===e.type&&e.trackIdentifier===t.id&&r.push(e)}),r.forEach(function(t){e.forEach(function(n){n.type===a&&n.trackId===t.id&&re(e,n,i)})}),i},J.log=function(){if("object"===(typeof window>"u"?"undefined":ee(window))){if(te)return;typeof console<"u"&&"function"==typeof console.log&&console.log.apply(console,arguments)}},J.walkStats=re,J.wrapPeerConnectionEvent=function(e,t,n){if(e.RTCPeerConnection){var a=e.RTCPeerConnection.prototype,i=a.addEventListener;a.addEventListener=function(e,a){if(e!==t)return i.apply(this,arguments);var r=function(e){var t=n(e);t&&(a.handleEvent?a.handleEvent(t):a(t))};return this._eventMap=this._eventMap||{},this._eventMap[t]||(this._eventMap[t]=new Map),this._eventMap[t].set(a,r),i.apply(this,[e,r])};var r=a.removeEventListener;a.removeEventListener=function(e,n){if(e!==t||!this._eventMap||!this._eventMap[t])return r.apply(this,arguments);if(!this._eventMap[t].has(n))return r.apply(this,arguments);var a=this._eventMap[t].get(n);return this._eventMap[t].delete(n),0===this._eventMap[t].size&&delete this._eventMap[t],0===Object.keys(this._eventMap).length&&delete this._eventMap,r.apply(this,[e,a])},Object.defineProperty(a,"on"+t,{get:function(){return this["_on"+t]},set:function(e){this["_on"+t]&&(this.removeEventListener(t,this["_on"+t]),delete this["_on"+t]),e&&this.addEventListener(t,this["_on"+t]=e)},enumerable:!0,configurable:!0})}};var te=!0,ne=!0;function ae(e,t,n){var a=e.match(t);return a&&a.length>=n&&parseInt(a[n],10)}function ie(e){return"[object Object]"===Object.prototype.toString.call(e)}function re(e,t,n){!t||n.has(t.id)||(n.set(t.id,t),Object.keys(t).forEach(function(a){a.endsWith("Id")?re(e,e.get(t[a]),n):a.endsWith("Ids")&&t[a].forEach(function(t){re(e,e.get(t),n)})}))}Object.defineProperty(Z,"__esModule",{value:!0});var oe=Z.shimGetUserMedia=function(e,t){var n=e&&e.navigator;if(n.mediaDevices){var a=function(e){if("object"!==ue(e)||e.mandatory||e.optional)return e;var t={};return Object.keys(e).forEach(function(n){if("require"!==n&&"advanced"!==n&&"mediaSource"!==n){var a="object"===ue(e[n])?e[n]:{ideal:e[n]};void 0!==a.exact&&"number"==typeof a.exact&&(a.min=a.max=a.exact);var i=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==a.ideal){t.optional=t.optional||[];var r={};"number"==typeof a.ideal?(r[i("min",n)]=a.ideal,t.optional.push(r),(r={})[i("max",n)]=a.ideal,t.optional.push(r)):(r[i("",n)]=a.ideal,t.optional.push(r))}void 0!==a.exact&&"number"!=typeof a.exact?(t.mandatory=t.mandatory||{},t.mandatory[i("",n)]=a.exact):["min","max"].forEach(function(e){void 0!==a[e]&&(t.mandatory=t.mandatory||{},t.mandatory[i(e,n)]=a[e])})}}),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},i=function(e,i){if(t.version>=61)return i(e);if((e=JSON.parse(JSON.stringify(e)))&&"object"===ue(e.audio)){var r=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])};r((e=JSON.parse(JSON.stringify(e))).audio,"autoGainControl","googAutoGainControl"),r(e.audio,"noiseSuppression","googNoiseSuppression"),e.audio=a(e.audio)}if(e&&"object"===ue(e.video)){var o=e.video.facingMode;o=o&&("object"===ue(o)?o:{ideal:o});var s,l=t.version<66;if(o&&("user"===o.exact||"environment"===o.exact||"user"===o.ideal||"environment"===o.ideal)&&(!n.mediaDevices.getSupportedConstraints||!n.mediaDevices.getSupportedConstraints().facingMode||l))if(delete e.video.facingMode,"environment"===o.exact||"environment"===o.ideal?s=["back","rear"]:("user"===o.exact||"user"===o.ideal)&&(s=["front"]),s)return n.mediaDevices.enumerateDevices().then(function(t){var n=(t=t.filter(function(e){return"videoinput"===e.kind})).find(function(e){return s.some(function(t){return e.label.toLowerCase().includes(t)})});return!n&&t.length&&s.includes("back")&&(n=t[t.length-1]),n&&(e.video.deviceId=o.exact?{exact:n.deviceId}:{ideal:n.deviceId}),e.video=a(e.video),ce("chrome: "+JSON.stringify(e)),i(e)});e.video=a(e.video)}return ce("chrome: "+JSON.stringify(e)),i(e)},r=function(e){return t.version>=64?e:{name:{PermissionDeniedError:"NotAllowedError",PermissionDismissedError:"NotAllowedError",InvalidStateError:"NotAllowedError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotAllowedError",MediaDeviceKillSwitchOn:"NotAllowedError",TabCaptureError:"AbortError",ScreenCaptureError:"AbortError",DeviceCaptureError:"AbortError"}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}};if(n.getUserMedia=function(e,t,a){i(e,function(e){n.webkitGetUserMedia(e,t,function(e){a&&a(r(e))})})}.bind(n),n.mediaDevices.getUserMedia){var o=n.mediaDevices.getUserMedia.bind(n.mediaDevices);n.mediaDevices.getUserMedia=function(e){return i(e,function(e){return o(e).then(function(t){if(e.audio&&!t.getAudioTracks().length||e.video&&!t.getVideoTracks().length)throw t.getTracks().forEach(function(e){e.stop()}),new DOMException("","NotFoundError");return t},function(e){return Promise.reject(r(e))})})}}}},se=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==ue(e)&&"function"!=typeof e)return{default:e};var n=le(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var r in e)if("default"!==r&&Object.prototype.hasOwnProperty.call(e,r)){var o=i?Object.getOwnPropertyDescriptor(e,r):null;o&&(o.get||o.set)?Object.defineProperty(a,r,o):a[r]=e[r]}return a.default=e,n&&n.set(e,a),a}(J);function le(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(le=function(e){return e?n:t})(e)}function ue(e){return(ue="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var ce=se.log;var de={};Object.defineProperty(de,"__esModule",{value:!0});var he=de.shimGetUserMedia=function(e,t){var n=e&&e.navigator,a=e&&e.MediaStreamTrack;if(n.getUserMedia=function(e,t,a){pe.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),n.mediaDevices.getUserMedia(e).then(t,a)},!(t.version>55&&"autoGainControl"in n.mediaDevices.getSupportedConstraints())){var i=function(e,t,n){t in e&&!(n in e)&&(e[n]=e[t],delete e[t])},r=n.mediaDevices.getUserMedia.bind(n.mediaDevices);if(n.mediaDevices.getUserMedia=function(e){return"object"===me(e)&&"object"===me(e.audio)&&(e=JSON.parse(JSON.stringify(e)),i(e.audio,"autoGainControl","mozAutoGainControl"),i(e.audio,"noiseSuppression","mozNoiseSuppression")),r(e)},a&&a.prototype.getSettings){var o=a.prototype.getSettings;a.prototype.getSettings=function(){var e=o.apply(this,arguments);return i(e,"mozAutoGainControl","autoGainControl"),i(e,"mozNoiseSuppression","noiseSuppression"),e}}if(a&&a.prototype.applyConstraints){var s=a.prototype.applyConstraints;a.prototype.applyConstraints=function(e){return"audio"===this.kind&&"object"===me(e)&&(e=JSON.parse(JSON.stringify(e)),i(e,"autoGainControl","mozAutoGainControl"),i(e,"noiseSuppression","mozNoiseSuppression")),s.apply(this,[e])}}}},pe=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==me(e)&&"function"!=typeof e)return{default:e};var n=fe(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var r in e)if("default"!==r&&Object.prototype.hasOwnProperty.call(e,r)){var o=i?Object.getOwnPropertyDescriptor(e,r):null;o&&(o.get||o.set)?Object.defineProperty(a,r,o):a[r]=e[r]}return a.default=e,n&&n.set(e,a),a}(J);function fe(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(fe=function(e){return e?n:t})(e)}function me(e){return(me="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var _e={};Object.defineProperty(_e,"__esModule",{value:!0}),_e.shimAudioContext=function(e){"object"!==ye(e)||e.AudioContext||(e.AudioContext=e.webkitAudioContext)},_e.shimCallbacksAPI=function(e){if("object"===ye(e)&&e.RTCPeerConnection){var t=e.RTCPeerConnection.prototype,n=t.createOffer,a=t.createAnswer,i=t.setLocalDescription,r=t.setRemoteDescription,o=t.addIceCandidate;t.createOffer=function(e,t){var a=arguments.length>=2?arguments[2]:arguments[0],i=n.apply(this,[a]);return t?(i.then(e,t),Promise.resolve()):i},t.createAnswer=function(e,t){var n=arguments.length>=2?arguments[2]:arguments[0],i=a.apply(this,[n]);return t?(i.then(e,t),Promise.resolve()):i};var s=function(e,t,n){var a=i.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a};t.setLocalDescription=s,s=function(e,t,n){var a=r.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a},t.setRemoteDescription=s,s=function(e,t,n){var a=o.apply(this,[e]);return n?(a.then(t,n),Promise.resolve()):a},t.addIceCandidate=s}},_e.shimConstraints=we,_e.shimCreateOfferLegacy=function(e){var t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(e){if(e){typeof e.offerToReceiveAudio<"u"&&(e.offerToReceiveAudio=!!e.offerToReceiveAudio);var n=this.getTransceivers().find(function(e){return"audio"===e.receiver.track.kind});!1===e.offerToReceiveAudio&&n?"sendrecv"===n.direction?n.setDirection?n.setDirection("sendonly"):n.direction="sendonly":"recvonly"===n.direction&&(n.setDirection?n.setDirection("inactive"):n.direction="inactive"):!0===e.offerToReceiveAudio&&!n&&this.addTransceiver("audio",{direction:"recvonly"}),typeof e.offerToReceiveVideo<"u"&&(e.offerToReceiveVideo=!!e.offerToReceiveVideo);var a=this.getTransceivers().find(function(e){return"video"===e.receiver.track.kind});!1===e.offerToReceiveVideo&&a?"sendrecv"===a.direction?a.setDirection?a.setDirection("sendonly"):a.direction="sendonly":"recvonly"===a.direction&&(a.setDirection?a.setDirection("inactive"):a.direction="inactive"):!0===e.offerToReceiveVideo&&!a&&this.addTransceiver("video",{direction:"recvonly"})}return t.apply(this,arguments)}};var ge=_e.shimGetUserMedia=function(e){var t=e&&e.navigator;if(t.mediaDevices&&t.mediaDevices.getUserMedia){var n=t.mediaDevices,a=n.getUserMedia.bind(n);t.mediaDevices.getUserMedia=function(e){return a(we(e))}}!t.getUserMedia&&t.mediaDevices&&t.mediaDevices.getUserMedia&&(t.getUserMedia=function(e,n,a){t.mediaDevices.getUserMedia(e).then(n,a)}.bind(t))};_e.shimLocalStreamsAPI=function(e){if("object"===ye(e)&&e.RTCPeerConnection){if("getLocalStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams}),!("addStream"in e.RTCPeerConnection.prototype)){var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addStream=function(e){var n=this;this._localStreams||(this._localStreams=[]),this._localStreams.includes(e)||this._localStreams.push(e),e.getAudioTracks().forEach(function(a){return t.call(n,a,e)}),e.getVideoTracks().forEach(function(a){return t.call(n,a,e)})},e.RTCPeerConnection.prototype.addTrack=function(e){for(var n=this,a=arguments.length,i=new Array(a>1?a-1:0),r=1;r=0)){e._remoteStreams.push(t);var n=new Event("addstream");n.stream=t,e.dispatchEvent(n)}})}),t.apply(e,arguments)}}},_e.shimTrackEventTransceiver=function(e){"object"===ye(e)&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})};var ve=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!==ye(e)&&"function"!=typeof e)return{default:e};var n=be(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var r in e)if("default"!==r&&Object.prototype.hasOwnProperty.call(e,r)){var o=i?Object.getOwnPropertyDescriptor(e,r):null;o&&(o.get||o.set)?Object.defineProperty(a,r,o):a[r]=e[r]}return a.default=e,n&&n.set(e,a),a}(J);function be(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(be=function(e){return e?n:t})(e)}function ye(e){return(ye="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function we(e){return e&&void 0!==e.video?Object.assign({},e,{video:ve.compactObject(e.video)}):e}function ke(e,t){if(!1===e)throw new Error(null!=t?t:"assertion failure")}function xe(e){throw new Error("this code should be unreachable")}const Se=(e=>{let t,n=!1;return(...a)=>(n||(t=e(a),n=!0),t)})(()=>{const e=X(window);switch(e.browser){case"chrome":oe(window,e);break;case"firefox":he(window,e);break;case"safari":ge(window,e);break;default:throw new $}});let Ce=Promise.resolve({type:"stop",data:{}});async function Te(e,t,n){var a,i,r;if(console.debug("[vue-qrcode-reader] starting camera with constraints: ",JSON.stringify(t)),!0!==window.isSecureContext)throw new H;if(void 0===(null==(a=null==navigator?void 0:navigator.mediaDevices)?void 0:a.getUserMedia))throw new $;Se(),console.debug("[vue-qrcode-reader] calling getUserMedia");const o=await navigator.mediaDevices.getUserMedia({audio:!1,video:t});void 0!==e.srcObject?e.srcObject=o:void 0!==e.mozSrcObject?e.mozSrcObject=o:window.URL.createObjectURL?e.src=window.URL.createObjectURL(o):window.webkitURL?e.src=window.webkitURL.createObjectURL(o):e.src=o.id,e.play(),console.debug("[vue-qrcode-reader] waiting for video element to load"),await Promise.race([F(e,"loadeddata"),V(6e3).then(()=>{throw new W})]),console.debug("[vue-qrcode-reader] video element loaded"),await V(500);const[s]=o.getVideoTracks(),l=null!=(r=null==(i=null==s?void 0:s.getCapabilities)?void 0:i.call(s))?r:{};let u=!1;return n&&l.torch&&(await s.applyConstraints({advanced:[{torch:!0}]}),u=!0),console.debug("[vue-qrcode-reader] camera ready"),{type:"start",data:{videoEl:e,stream:o,capabilities:l,constraints:t,isTorchOn:u}}}async function Pe(e,t,n){console.debug("[vue-qrcode-reader] stopping camera"),e.src="",e.srcObject=null,e.load(),await F(e,"error");for(const e of t.getTracks())null!=n||await e.applyConstraints({advanced:[{torch:!1}]}),t.removeTrack(e),e.stop();return{type:"stop",data:{}}}async function Ee(){if(Ce=Ce.then(e=>{if("stop"===e.type||"failed"===e.type)return e;const{data:{videoEl:t,stream:n,isTorchOn:a}}=e;return Pe(t,n,a)}),"start"===(await Ce).type)throw new Error("Something went wrong with the camera task queue (stop task).")}const Ae=t.defineComponent({__name:"QrcodeStream",props:{constraints:{default:()=>({facingMode:"environment"})},formats:{default:()=>["qr_code"]},paused:{type:Boolean,default:!1},torch:{type:Boolean,default:!1},track:{type:Function,default:void 0}},emits:["detect","camera-on","camera-off","error"],setup(e,{emit:n}){const a=e,i=n,r=t.ref(a.constraints),o=t.ref(a.formats);t.watch(()=>a.constraints,(e,t)=>{JSON.stringify(e)!==JSON.stringify(t)&&(r.value=e)},{deep:!0}),t.watch(()=>a.formats,(e,t)=>{JSON.stringify(e)!==JSON.stringify(t)&&(o.value=e)},{deep:!0});const s=t.ref(),l=t.ref(),u=t.ref(),c=t.ref(!1),d=t.ref(!1);t.onMounted(()=>{d.value=!0}),t.onUnmounted(()=>{Ee()});const h=t.computed(()=>({torch:a.torch,constraints:r.value,shouldStream:d.value&&!a.paused}));t.watch(h,async e=>{const t=u.value;ke(void 0!==t,"cameraSettings watcher should never be triggered when component is not mounted. Thus video element should always be defined.");const n=s.value;ke(void 0!==n,"cameraSettings watcher should never be triggered when component is not mounted. Thus canvas should always be defined.");const a=n.getContext("2d");if(ke(null!==a,"if cavnas is defined, canvas 2d context should also be non-null"),e.shouldStream){Ee(),c.value=!1;try{const n=await async function(e,{constraints:t,torch:n,restart:a=!1}){Ce=Ce.then(i=>{if("start"===i.type){const{data:{videoEl:r,stream:o,constraints:s,isTorchOn:l}}=i;return a||e!==r||t!==s||n!==l?Pe(r,o,l).then(()=>Te(e,t,n)):i}if("stop"===i.type||"failed"===i.type)return Te(e,t,n);xe()}).catch(e=>(console.debug(`[vue-qrcode-reader] starting camera failed with "${e}"`),{type:"failed",error:e}));const i=await Ce;if("stop"===i.type)throw new Error("Something went wrong with the camera task queue (start task).");if("failed"===i.type)throw i.error;if("start"===i.type)return i.data.capabilities;xe()}(t,e);d.value?(c.value=!0,i("camera-on",n)):await Ee()}catch(e){i("error",e)}}else n.width=t.videoWidth,n.height=t.videoHeight,a.drawImage(t,0,0,t.videoWidth,t.videoHeight),Ee(),c.value=!1,i("camera-off")},{deep:!0}),t.watch(o,e=>{d.value&&K(e)});const p=t.computed(()=>h.value.shouldStream&&c.value);t.watch(p,e=>{if(e){ke(void 0!==s.value,"shouldScan watcher should only be triggered when component is mounted. Thus pause frame canvas is defined"),f(s.value),ke(void 0!==l.value,"shouldScan watcher should only be triggered when component is mounted. Thus tracking canvas is defined"),f(l.value);const e=()=>void 0===a.track?500:40;ke(void 0!==u.value,"shouldScan watcher should only be triggered when component is mounted. Thus video element is defined"),(async(e,{detectHandler:t,locateHandler:n,minDelay:a,formats:i})=>{console.debug("[vue-qrcode-reader] start scanning"),K(i);const r=i=>async o=>{if(0===e.readyState)console.debug("[vue-qrcode-reader] stop scanning: video element readyState is 0");else{const{lastScanned:s,contentBefore:l,lastScanHadContent:u}=i;if(o-s!l.includes(e.rawValue));i&&t(a);const s=a.length>0;s&&n(a),!s&&u&&n(a);const c={lastScanned:o,lastScanHadContent:s,contentBefore:i?a.map(e=>e.rawValue):l};window.requestAnimationFrame(r(c))}}};r({lastScanned:performance.now(),contentBefore:[],lastScanHadContent:!1})(performance.now())})(u.value,{detectHandler:e=>i("detect",e),formats:o.value,locateHandler:m,minDelay:e()})}});const f=e=>{const t=e.getContext("2d");ke(null!==t,"canvas 2d context should always be non-null"),t.clearRect(0,0,e.width,e.height)},m=e=>{const t=l.value;ke(void 0!==t,"onLocate handler should only be called when component is mounted. Thus tracking canvas is always defined.");const n=u.value;if(ke(void 0!==n,"onLocate handler should only be called when component is mounted. Thus video element is always defined."),0===e.length||void 0===a.track)f(t);else{const i=n.offsetWidth,r=n.offsetHeight,o=n.videoWidth,s=n.videoHeight,l=Math.max(i/o,r/s),u=o*l,c=s*l,d=u/o,h=c/s,p=(i-u)/2,f=(r-c)/2,m=({x:e,y:t})=>({x:Math.floor(e*d),y:Math.floor(t*h)}),_=({x:e,y:t})=>({x:Math.floor(e+p),y:Math.floor(t+f)}),g=e.map(e=>{const{boundingBox:t,cornerPoints:n}=e,{x:a,y:i}=_(m({x:t.x,y:t.y})),{x:r,y:o}=m({x:t.width,y:t.height});return{...e,cornerPoints:n.map(e=>_(m(e))),boundingBox:DOMRectReadOnly.fromRect({x:a,y:i,width:r,height:o})}});t.width=n.offsetWidth,t.height=n.offsetHeight;const v=t.getContext("2d");ke(null!==v,"canvas 2d context should always be non-null"),a.track(g,v)}},_={width:"100%",height:"100%",position:"relative","z-index":"0"},g={width:"100%",height:"100%",position:"absolute",top:"0",left:"0"},v={width:"100%",height:"100%","object-fit":"cover"},b=t.computed(()=>p.value?v:{...v,visibility:"hidden",position:"absolute"});return(e,n)=>(t.openBlock(),t.createElementBlock("div",{style:_},[t.createElementVNode("video",{ref_key:"videoRef",ref:u,style:t.normalizeStyle(b.value),autoplay:"",muted:"",playsinline:""},null,4),t.withDirectives(t.createElementVNode("canvas",{id:"qrcode-stream-pause-frame",ref_key:"pauseFrameRef",ref:s,style:v},null,512),[[t.vShow,!p.value]]),t.createElementVNode("canvas",{id:"qrcode-stream-tracking-layer",ref_key:"trackingLayerRef",ref:l,style:g},null,512),t.createElementVNode("div",{style:g},[t.renderSlot(e.$slots,"default")])]))}}),Le=t.defineComponent({__name:"QrcodeCapture",props:{formats:{default:()=>["qr_code"]}},emits:["detect"],setup(e,{emit:n}){const a=e,i=n,r=e=>{if(e.target instanceof HTMLInputElement&&e.target.files)for(const t of Array.from(e.target.files))Y(t,a.formats).then(e=>{i("detect",e)})};return(e,n)=>(t.openBlock(),t.createElementBlock("input",{onChange:r,type:"file",name:"image",accept:"image/*",capture:"environment",multiple:""},null,32))}}),Me=t.defineComponent({__name:"QrcodeDropZone",props:{formats:{default:()=>["qr_code"]}},emits:["detect","dragover","error"],setup(e,{emit:n}){const a=e,i=n,r=async e=>{try{const t=await e;i("detect",t)}catch(e){i("error",e)}},o=e=>{i("dragover",e)},s=({dataTransfer:e})=>{if(!e)return;o(!1);const t=[...Array.from(e.files)],n=e.getData("text/uri-list");t.forEach(e=>{r(Y(e,a.formats))}),""!==n&&r(Q(n,a.formats))};return(e,n)=>(t.openBlock(),t.createElementBlock("div",{onDrop:t.withModifiers(s,["prevent","stop"]),onDragenter:n[0]||(n[0]=t.withModifiers(e=>o(!0),["prevent","stop"])),onDragleave:n[1]||(n[1]=t.withModifiers(e=>o(!1),["prevent","stop"])),onDragover:n[2]||(n[2]=t.withModifiers(()=>{},["prevent","stop"]))},[t.renderSlot(e.$slots,"default")],32))}});function Re(e){e.component("qrcode-stream",Ae),e.component("qrcode-capture",Le),e.component("qrcode-drop-zone",Me)}const ze={install:Re};e.QrcodeCapture=Le,e.QrcodeDropZone=Me,e.QrcodeStream=Ae,e.VueQrcodeReader=ze,e.install=Re,e.setZXingModuleOverrides=function(e){return function(e,t){z.set(e,{moduleOverrides:t})}(j,e)},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}), /*! - * qrcode.vue v3.6.0 + * qrcode.vue v3.9.0 * A Vue.js component to generate QRCode. Both support Vue 2 and Vue 3 * © 2017-PRESENT @scopewu(https://github.com/scopewu) * MIT License. */ -function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).QrcodeVue={},e.Vue)}(this,function(e,t){"use strict";var n,a=function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;nt.MAX_VERSION)throw new RangeError("Version value out of range");if(o<-1||o>7)throw new RangeError("Mask value out of range");this.size=4*e+17;for(var r=[],s=0;s7)throw new RangeError("Invalid value");var c,d;for(c=r;;c++){var h=8*t.getNumDataCodewords(c,a),p=o.getTotalBits(e,c);if(p<=h){d=p;break}if(c>=s)throw new RangeError("Data too long")}for(var f=0,m=[t.Ecc.MEDIUM,t.Ecc.QUARTILE,t.Ecc.HIGH];f>>3]|=e<<7-(7&t)}),new t(c,a,T,l)},t.prototype.getModule=function(e,t){return 0<=e&&e>>9);var r=21522^(t<<10|n);i(r>>>15==0);for(o=0;o<=5;o++)this.setFunctionModule(8,o,a(r,o));this.setFunctionModule(8,7,a(r,6)),this.setFunctionModule(8,8,a(r,7)),this.setFunctionModule(7,8,a(r,8));for(o=9;o<15;o++)this.setFunctionModule(14-o,8,a(r,o));for(o=0;o<8;o++)this.setFunctionModule(this.size-1-o,8,a(r,o));for(o=8;o<15;o++)this.setFunctionModule(8,this.size-15+o,a(r,o));this.setFunctionModule(8,this.size-8,!0)},t.prototype.drawVersion=function(){if(!(this.version<7)){for(var e=this.version,t=0;t<12;t++)e=e<<1^7973*(e>>>11);var n=this.version<<12|e;i(n>>>18==0);for(t=0;t<18;t++){var o=a(n,t),r=this.size-11+t%3,s=Math.floor(t/3);this.setFunctionModule(r,s,o),this.setFunctionModule(s,r,o)}}},t.prototype.drawFinderPattern=function(e,t){for(var n=-4;n<=4;n++)for(var a=-4;a<=4;a++){var i=Math.max(Math.abs(a),Math.abs(n)),o=e+a,r=t+n;0<=o&&o=l)&&g.push(t[e])})};for(h=0;h=1;o-=2){6==o&&(o=5);for(var r=0;r>>3],7-(7&n)),n++)}}i(n==8*e.length)},t.prototype.applyMask=function(e){if(e<0||e>7)throw new RangeError("Mask value out of range");for(var t=0;t5&&e++:(this.finderPenaltyAddHistory(o,r),a||(e+=this.finderPenaltyCountPatterns(r)*t.PENALTY_N3),a=this.modules[n][s],o=1);e+=this.finderPenaltyTerminateAndCount(a,o,r)*t.PENALTY_N3}for(s=0;s5&&e++:(this.finderPenaltyAddHistory(l,r),a||(e+=this.finderPenaltyCountPatterns(r)*t.PENALTY_N3),a=this.modules[n][s],l=1);e+=this.finderPenaltyTerminateAndCount(a,l,r)*t.PENALTY_N3}for(n=0;nt.MAX_VERSION)throw new RangeError("Version number out of range");var n=(16*e+128)*e+64;if(e>=2){var a=Math.floor(e/7)+2;n-=(25*a-10)*a-55,e>=7&&(n-=36)}return i(208<=n&&n<=29648),n},t.getNumDataCodewords=function(e,n){return Math.floor(t.getNumRawDataModules(e)/8)-t.ECC_CODEWORDS_PER_BLOCK[n.ordinal][e]*t.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][e]},t.reedSolomonComputeDivisor=function(e){if(e<1||e>255)throw new RangeError("Degree out of range");for(var n=[],a=0;a>>8!=0||t>>>8!=0)throw new RangeError("Byte out of range");for(var n=0,a=7;a>=0;a--)n=n<<1^285*(n>>>7),n^=(t>>>a&1)*e;return i(n>>>8==0),n},t.prototype.finderPenaltyCountPatterns=function(e){var t=e[1];i(t<=3*this.size);var n=t>0&&e[2]==t&&e[3]==3*t&&e[4]==t&&e[5]==t;return(n&&e[0]>=4*t&&e[6]>=t?1:0)+(n&&e[6]>=4*t&&e[0]>=t?1:0)},t.prototype.finderPenaltyTerminateAndCount=function(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),t+=this.size,this.finderPenaltyAddHistory(t,n),this.finderPenaltyCountPatterns(n)},t.prototype.finderPenaltyAddHistory=function(e,t){0==t[0]&&(e+=this.size),t.pop(),t.unshift(e)},t.MIN_VERSION=1,t.MAX_VERSION=40,t.PENALTY_N1=3,t.PENALTY_N2=3,t.PENALTY_N3=40,t.PENALTY_N4=10,t.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],t.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],t}();function n(e,t,n){if(t<0||t>31||e>>>t!=0)throw new RangeError("Value out of range");for(var a=t-1;a>=0;a--)n.push(e>>>a&1)}function a(e,t){return!!(e>>>t&1)}function i(e){if(!e)throw new Error("Assertion error")}e.QrCode=t;var o=function(){function e(e,t,n){if(this.mode=e,this.numChars=t,this.bitData=n,t<0)throw new RangeError("Invalid argument");this.bitData=n.slice()}return e.makeBytes=function(t){for(var a=[],i=0,o=t;i=1<=t.y+t.h?e:e.map(function(e,n){return(n=t.x+t.w)&&e})})}var d={value:{type:String,required:!0,default:""},size:{type:Number,default:100},level:{type:String,default:"L",validator:function(e){return s(e)}},background:{type:String,default:"#fff"},foreground:{type:String,default:"#000"},margin:{type:Number,required:!1,default:0},imageSettings:{type:Object,required:!1,default:function(){return{}}},gradient:{type:Boolean,required:!1,default:!1},gradientType:{type:String,required:!1,default:"linear",validator:function(e){return["linear","radial"].indexOf(e)>-1}},gradientStartColor:{type:String,required:!1,default:"#000"},gradientEndColor:{type:String,required:!1,default:"#fff"}},h=a(a({},d),{renderAs:{type:String,required:!1,default:"canvas",validator:function(e){return["canvas","svg"].indexOf(e)>-1}}}),p=t.defineComponent({name:"QRCodeSvg",props:d,setup:function(e){var n,r=t.ref(0),d=t.ref(""),h=function(){var t=e.value,a=e.level,h=e.margin>>>0,p=s(a)?a:"L",f=i.QrCode.encodeText(t,o[p]).getModules();if(r.value=f.length+2*h,e.imageSettings.src){var m=u(f,e.size,h,e.imageSettings);n={x:m.x+h,y:m.y+h,width:m.w,height:m.h},m.excavation&&(f=c(f,m.excavation))}d.value=l(f,h)},p=function(){if(!e.gradient)return null;var n="linear"===e.gradientType?{x1:"0%",y1:"0%",x2:"100%",y2:"100%"}:{cx:"50%",cy:"50%",r:"50%",fx:"50%",fy:"50%"};return t.h("linear"===e.gradientType?"linearGradient":"radialGradient",a({id:"qr-gradient"},n),[t.h("stop",{offset:"0%",style:{stopColor:e.gradientStartColor}}),t.h("stop",{offset:"100%",style:{stopColor:e.gradientEndColor}})])};return h(),t.onUpdated(h),function(){return t.h("svg",{width:e.size,height:e.size,"shape-rendering":"crispEdges",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 ".concat(r.value," ").concat(r.value)},[t.h("defs",{},[p()]),t.h("rect",{width:"100%",height:"100%",fill:e.background}),t.h("path",{fill:e.gradient?"url(#qr-gradient)":e.foreground,d:d.value}),e.imageSettings.src&&t.h("image",a({href:e.imageSettings.src},n))])}}}),f=t.defineComponent({name:"QRCodeCanvas",props:d,setup:function(e,n){var d=t.ref(null),h=t.ref(null),p=function(){var t=e.value,n=e.level,a=e.size,p=e.margin,f=e.background,m=e.foreground,g=e.gradient,_=e.gradientType,v=e.gradientStartColor,b=e.gradientEndColor,y=p>>>0,w=s(n)?n:"L",k=d.value;if(k){var x=k.getContext("2d");if(x){var S=i.QrCode.encodeText(t,o[w]).getModules(),C=S.length+2*y,T=h.value,P={x:0,y:0,width:0,height:0},E=e.imageSettings.src&&null!=T&&0!==T.naturalWidth&&0!==T.naturalHeight;if(E){var A=u(S,e.size,y,e.imageSettings);P={x:A.x+y,y:A.y+y,width:A.w,height:A.h},A.excavation&&(S=c(S,A.excavation))}var M=window.devicePixelRatio||1,L=a/C*M;if(k.height=k.width=a*M,x.scale(L,L),x.fillStyle=f,x.fillRect(0,0,C,C),g){var R=void 0;(R="linear"===_?x.createLinearGradient(0,0,C,C):x.createRadialGradient(C/2,C/2,0,C/2,C/2,C/2)).addColorStop(0,v),R.addColorStop(1,b),x.fillStyle=R}else x.fillStyle=m;r?x.fill(new Path2D(l(S,y))):S.forEach(function(e,t){e.forEach(function(e,n){e&&x.fillRect(n+y,t+y,1,1)})}),E&&x.drawImage(T,P.x,P.y,P.width,P.height)}}};t.onMounted(p),t.onUpdated(p);var f=n.attrs.style;return function(){return t.h(t.Fragment,[t.h("canvas",a(a({},n.attrs),{ref:d,style:a(a({},f),{width:"".concat(e.size,"px"),height:"".concat(e.size,"px")})})),e.imageSettings.src&&t.h("img",{ref:h,src:e.imageSettings.src,style:{display:"none"},onLoad:p})])}}}),m=t.defineComponent({name:"Qrcode",render:function(){var e=this.$props,n=e.renderAs,a=e.value,i=e.size,o=e.margin,r=e.level,s=e.background,l=e.foreground,u=e.imageSettings,c=e.gradient,d=e.gradientType,h=e.gradientStartColor,m=e.gradientEndColor;return t.h("svg"===n?p:f,{value:a,size:i,margin:o,level:r,background:s,foreground:l,imageSettings:u,gradient:c,gradientType:d,gradientStartColor:h,gradientEndColor:m})},props:h});e.QrcodeCanvas=f,e.QrcodeSvg=p,e.default=m,Object.defineProperty(e,"__esModule",{value:!0})}),function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Chart=t()}(this,function(){"use strict";var e=Object.freeze({__proto__:null,get Colors(){return No},get Decimation(){return qo},get Filler(){return tr},get Legend(){return or},get SubTitle(){return ur},get Title(){return sr},get Tooltip(){return Sr}});function t(){}const n=(()=>{let e=0;return()=>e++})();function a(e){return null==e}function i(e){if(Array.isArray&&Array.isArray(e))return!0;const t=Object.prototype.toString.call(e);return"[object"===t.slice(0,7)&&"Array]"===t.slice(-6)}function o(e){return null!==e&&"[object Object]"===Object.prototype.toString.call(e)}function r(e){return("number"==typeof e||e instanceof Number)&&isFinite(+e)}function s(e,t){return r(e)?e:t}function l(e,t){return void 0===e?t:e}const u=(e,t)=>"string"==typeof e&&e.endsWith("%")?parseFloat(e)/100:+e/t,c=(e,t)=>"string"==typeof e&&e.endsWith("%")?parseFloat(e)/100*t:+e;function d(e,t,n){if(e&&"function"==typeof e.call)return e.apply(n,t)}function h(e,t,n,a){let r,s,l;if(i(e))if(s=e.length,a)for(r=s-1;r>=0;r--)t.call(n,e[r],r);else for(r=0;re,x:e=>e.x,y:e=>e.y};function w(e){const t=e.split("."),n=[];let a="";for(const e of t)a+=e,a.endsWith("\\")?a=a.slice(0,-1)+".":(n.push(a),a="");return n}function k(e,t){const n=y[t]||(y[t]=function(e){const t=w(e);return e=>{for(const n of t){if(""===n)break;e=e&&e[n]}return e}}(t));return n(e)}function x(e){return e.charAt(0).toUpperCase()+e.slice(1)}const S=e=>void 0!==e,C=e=>"function"==typeof e,T=(e,t)=>{if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0};function P(e){return"mouseup"===e.type||"click"===e.type||"contextmenu"===e.type}const E=Math.PI,A=2*E,M=A+E,L=Number.POSITIVE_INFINITY,R=E/180,z=E/2,N=E/4,O=2*E/3,I=Math.log10,q=Math.sign;function D(e,t,n){return Math.abs(e-t)e-t).pop(),t}function F(e){return!function(e){return"symbol"==typeof e||"object"==typeof e&&null!==e&&!(Symbol.toPrimitive in e||"toString"in e||"valueOf"in e)}(e)&&!isNaN(parseFloat(e))&&isFinite(e)}function $(e,t){const n=Math.round(e);return n-t<=e&&n+t>=e}function V(e,t,n){let a,i,o;for(a=0,i=e.length;al&&u=Math.min(t,n)-a&&e<=Math.max(t,n)+a}function te(e,t,n){n=n||(n=>e[n]1;)a=o+i>>1,n(a)?o=a:i=a;return{lo:o,hi:i}}const ne=(e,t,n,a)=>te(e,n,a?a=>{const i=e[a][t];return ie[a][t]te(e,n,a=>e[a][t]>=n);function ie(e,t,n){let a=0,i=e.length;for(;aa&&e[i-1]>n;)i--;return a>0||i{const n="_onData"+x(t),a=e[t];Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value(...t){const i=a.apply(this,t);return e._chartjs.listeners.forEach(e=>{"function"==typeof e[n]&&e[n](...t)}),i}})}))}function se(e,t){const n=e._chartjs;if(!n)return;const a=n.listeners,i=a.indexOf(t);-1!==i&&a.splice(i,1),a.length>0||(oe.forEach(t=>{delete e[t]}),delete e._chartjs)}function le(e){const t=new Set(e);return t.size===e.length?e:Array.from(t)}const ue="undefined"==typeof window?function(e){return e()}:window.requestAnimationFrame;function ce(e,t){let n=[],a=!1;return function(...i){n=i,a||(a=!0,ue.call(window,()=>{a=!1,e.apply(t,n)}))}}function de(e,t){let n;return function(...a){return t?(clearTimeout(n),n=setTimeout(e,t,a)):e.apply(this,a),t}}const he=e=>"start"===e?"left":"end"===e?"right":"center",pe=(e,t,n)=>"start"===e?t:"end"===e?n:(t+n)/2,fe=(e,t,n,a)=>e===(a?"left":"right")?n:"center"===e?(t+n)/2:t;function me(e,t,n){const i=t.length;let o=0,r=i;if(e._sorted){const{iScale:s,vScale:l,_parsed:u}=e,c=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null,d=s.axis,{min:h,max:p,minDefined:f,maxDefined:m}=s.getUserBounds();if(f){if(o=Math.min(ne(u,d,h).lo,n?i:ne(t,d,s.getPixelForValue(h)).lo),c){const e=u.slice(0,o+1).reverse().findIndex(e=>!a(e[l.axis]));o-=Math.max(0,e)}o=J(o,0,i-1)}if(m){let e=Math.max(ne(u,s.axis,p,!0).hi+1,n?0:ne(t,d,s.getPixelForValue(p),!0).hi+1);if(c){const t=u.slice(e-1).findIndex(e=>!a(e[l.axis]));e+=Math.max(0,t)}r=J(e,o,i)-o}else r=i-o}return{start:o,count:r}}function ge(e){const{xScale:t,yScale:n,_scaleRanges:a}=e,i={xmin:t.min,xmax:t.max,ymin:n.min,ymax:n.max};if(!a)return e._scaleRanges=i,!0;const o=a.xmin!==t.min||a.xmax!==t.max||a.ymin!==n.min||a.ymax!==n.max;return Object.assign(a,i),o}var _e=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(e,t,n,a){const i=t.listeners[a],o=t.duration;i.forEach(a=>a({chart:e,initial:t.initial,numSteps:o,currentStep:Math.min(n-t.start,o)}))}_refresh(){this._request||(this._running=!0,this._request=ue.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(e=Date.now()){let t=0;this._charts.forEach((n,a)=>{if(!n.running||!n.items.length)return;const i=n.items;let o,r=i.length-1,s=!1;for(;r>=0;--r)o=i[r],o._active?(o._total>n.duration&&(n.duration=o._total),o.tick(e),s=!0):(i[r]=i[i.length-1],i.pop());s&&(a.draw(),this._notify(a,n,e,"progress")),i.length||(n.running=!1,this._notify(a,n,e,"complete"),n.initial=!1),t+=i.length}),this._lastDate=e,0===t&&(this._running=!1)}_getAnims(e){const t=this._charts;let n=t.get(e);return n||(n={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},t.set(e,n)),n}listen(e,t,n){this._getAnims(e).listeners[t].push(n)}add(e,t){t&&t.length&&this._getAnims(e).items.push(...t)}has(e){return this._getAnims(e).items.length>0}start(e){const t=this._charts.get(e);t&&(t.running=!0,t.start=Date.now(),t.duration=t.items.reduce((e,t)=>Math.max(e,t._duration),0),this._refresh())}running(e){if(!this._running)return!1;const t=this._charts.get(e);return!!(t&&t.running&&t.items.length)}stop(e){const t=this._charts.get(e);if(!t||!t.items.length)return;const n=t.items;let a=n.length-1;for(;a>=0;--a)n[a].cancel();t.items=[],this._notify(e,t,Date.now(),"complete")}remove(e){return this._charts.delete(e)}}; +function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).QrcodeVue={},e.Vue)}(this,function(e,t){"use strict";var n,a=function(){return a=Object.assign||function(e){for(var t,n=1,a=arguments.length;nt.MAX_VERSION)throw new RangeError("Version value out of range");if(r<-1||r>7)throw new RangeError("Mask value out of range");this.size=4*e+17;for(var o=[],s=0;s7)throw new RangeError("Invalid value");var c,d;for(c=o;;c++){var h=8*t.getNumDataCodewords(c,a),p=r.getTotalBits(e,c);if(p<=h){d=p;break}if(c>=s)throw new RangeError("Data too long")}for(var f=0,m=[t.Ecc.MEDIUM,t.Ecc.QUARTILE,t.Ecc.HIGH];f>>3]|=e<<7-(7&t)}),new t(c,a,T,l)},t.prototype.getModule=function(e,t){return 0<=e&&e>>9);var o=21522^(t<<10|n);i(o>>>15==0);for(r=0;r<=5;r++)this.setFunctionModule(8,r,a(o,r));this.setFunctionModule(8,7,a(o,6)),this.setFunctionModule(8,8,a(o,7)),this.setFunctionModule(7,8,a(o,8));for(r=9;r<15;r++)this.setFunctionModule(14-r,8,a(o,r));for(r=0;r<8;r++)this.setFunctionModule(this.size-1-r,8,a(o,r));for(r=8;r<15;r++)this.setFunctionModule(8,this.size-15+r,a(o,r));this.setFunctionModule(8,this.size-8,!0)},t.prototype.drawVersion=function(){if(!(this.version<7)){for(var e=this.version,t=0;t<12;t++)e=e<<1^7973*(e>>>11);var n=this.version<<12|e;i(n>>>18==0);for(t=0;t<18;t++){var r=a(n,t),o=this.size-11+t%3,s=Math.floor(t/3);this.setFunctionModule(o,s,r),this.setFunctionModule(s,o,r)}}},t.prototype.drawFinderPattern=function(e,t){for(var n=-4;n<=4;n++)for(var a=-4;a<=4;a++){var i=Math.max(Math.abs(a),Math.abs(n)),r=e+a,o=t+n;0<=r&&r=l)&&_.push(t[e])})};for(h=0;h=1;r-=2){6==r&&(r=5);for(var o=0;o>>3],7-(7&n)),n++)}}i(n==8*e.length)},t.prototype.applyMask=function(e){if(e<0||e>7)throw new RangeError("Mask value out of range");for(var t=0;t5&&e++:(this.finderPenaltyAddHistory(r,o),a||(e+=this.finderPenaltyCountPatterns(o)*t.PENALTY_N3),a=this.modules[n][s],r=1);e+=this.finderPenaltyTerminateAndCount(a,r,o)*t.PENALTY_N3}for(s=0;s5&&e++:(this.finderPenaltyAddHistory(l,o),a||(e+=this.finderPenaltyCountPatterns(o)*t.PENALTY_N3),a=this.modules[n][s],l=1);e+=this.finderPenaltyTerminateAndCount(a,l,o)*t.PENALTY_N3}for(n=0;nt.MAX_VERSION)throw new RangeError("Version number out of range");var n=(16*e+128)*e+64;if(e>=2){var a=Math.floor(e/7)+2;n-=(25*a-10)*a-55,e>=7&&(n-=36)}return i(208<=n&&n<=29648),n},t.getNumDataCodewords=function(e,n){return Math.floor(t.getNumRawDataModules(e)/8)-t.ECC_CODEWORDS_PER_BLOCK[n.ordinal][e]*t.NUM_ERROR_CORRECTION_BLOCKS[n.ordinal][e]},t.reedSolomonComputeDivisor=function(e){if(e<1||e>255)throw new RangeError("Degree out of range");for(var n=[],a=0;a>>8!=0||t>>>8!=0)throw new RangeError("Byte out of range");for(var n=0,a=7;a>=0;a--)n=n<<1^285*(n>>>7),n^=(t>>>a&1)*e;return i(n>>>8==0),n},t.prototype.finderPenaltyCountPatterns=function(e){var t=e[1];i(t<=3*this.size);var n=t>0&&e[2]==t&&e[3]==3*t&&e[4]==t&&e[5]==t;return(n&&e[0]>=4*t&&e[6]>=t?1:0)+(n&&e[6]>=4*t&&e[0]>=t?1:0)},t.prototype.finderPenaltyTerminateAndCount=function(e,t,n){return e&&(this.finderPenaltyAddHistory(t,n),t=0),t+=this.size,this.finderPenaltyAddHistory(t,n),this.finderPenaltyCountPatterns(n)},t.prototype.finderPenaltyAddHistory=function(e,t){0==t[0]&&(e+=this.size),t.pop(),t.unshift(e)},t.MIN_VERSION=1,t.MAX_VERSION=40,t.PENALTY_N1=3,t.PENALTY_N2=3,t.PENALTY_N3=40,t.PENALTY_N4=10,t.ECC_CODEWORDS_PER_BLOCK=[[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]],t.NUM_ERROR_CORRECTION_BLOCKS=[[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]],t}();function n(e,t,n){if(t<0||t>31||e>>>t!=0)throw new RangeError("Value out of range");for(var a=t-1;a>=0;a--)n.push(e>>>a&1)}function a(e,t){return!!(e>>>t&1)}function i(e){if(!e)throw new Error("Assertion error")}e.QrCode=t;var r=function(){function e(e,t,n){if(this.mode=e,this.numChars=t,this.bitData=n,t<0)throw new RangeError("Invalid argument");this.bitData=n.slice()}return e.makeBytes=function(t){for(var a=[],i=0,r=t;i=1<0&&e[t-1][n],i=t0&&e[t][n-1],o=n>>0}),a=t.computed(function(){var t=l(e.level)?e.level:"L";return i.QrCode.encodeText(e.value,o[t]).getModules()}),r=t.computed(function(){return a.value.length+2*n.value}),s=t.computed(function(){return e.radius>0?function(e,t,n){void 0===t&&(t=0),void 0===n&&(n=0);for(var a=[],i=Math.min(n,.5),r=0;r-1}},gradientStartColor:{type:String,required:!1,default:"#000"},gradientEndColor:{type:String,required:!1,default:"#fff"},radius:{type:Number,required:!1,default:0,validator:function(e){return!isNaN(e)&&e>=0&&e<=.5}}},h=a(a({},d),{renderAs:{type:String,required:!1,default:"canvas",validator:function(e){return["canvas","svg"].indexOf(e)>-1}}}),p=t.defineComponent({name:"QRCodeSvg",props:d,setup:function(e){var n=c(e),i=n.numCells,o=n.fgPath,s=n.imageProps,l=n.imageBorderProps,u="function"==typeof t.useId?"".concat(t.useId(),"-").concat(r++):"vue-".concat(Math.random().toString(36).slice(2),"-").concat(r++),d="qrcode.vue-gradient-".concat(u),h="qrcode.vue-logo-clip-path-".concat(u),p=t.computed(function(){if(!e.gradient)return null;var n="linear"===e.gradientType?{x1:"0%",y1:"0%",x2:"100%",y2:"100%"}:{cx:"50%",cy:"50%",r:"50%",fx:"50%",fy:"50%"};return t.h("linear"===e.gradientType?"linearGradient":"radialGradient",a({id:d},n),[t.h("stop",{offset:"0%",style:{stopColor:e.gradientStartColor}}),t.h("stop",{offset:"100%",style:{stopColor:e.gradientEndColor}})])}),f=t.computed(function(){if(!s.value)return null;var e=s.value.borderRadius;return e<=0?null:t.h("clipPath",{id:h},[t.h("rect",{x:s.value.x,y:s.value.y,width:s.value.width,height:s.value.height,rx:e,ry:e})])});return function(){return t.h("svg",{width:e.size,height:e.size,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 ".concat(i.value," ").concat(i.value),role:"img","aria-label":e.value},[t.h("defs",{},[p.value,f.value]),t.h("rect",{width:"100%",height:"100%",fill:e.background}),t.h("path",{fill:e.gradient?"url(#".concat(d,")"):e.foreground,d:o.value}),l.value&&t.h("rect",{x:l.value.x,y:l.value.y,width:l.value.width,height:l.value.height,fill:e.background,rx:l.value.borderRadius,ry:l.value.borderRadius}),e.imageSettings.src&&s.value&&t.h("image",a(a({href:e.imageSettings.src},s.value),s.value.borderRadius>0?{"clip-path":"url(#".concat(h,")")}:{}))])}}}),f=t.defineComponent({name:"QRCodeCanvas",props:d,setup:function(e,n){var i=c(e),r=i.margin,o=i.cells,l=i.numCells,u=i.fgPath,d=i.imageProps,h=i.imageBorderProps,p=t.ref(null),f=t.ref(null),m=function(e,t,n,a,i,r){e.beginPath(),e.roundRect?e.roundRect(t,n,a,i,r):e.rect(t,n,a,i)},_=function(){var t=e.size,n=e.background,a=e.foreground,i=e.gradient,c=e.gradientType,_=e.gradientStartColor,g=e.gradientEndColor,v=p.value;if(v){var b=v.getContext("2d");if(b){var y=f.value,w="undefined"!=typeof window&&window.devicePixelRatio||1,k=t/l.value*w;if(v.height=v.width=t*w,b.setTransform(k,0,0,k,0,0),b.fillStyle=n,b.fillRect(0,0,l.value,l.value),i){var x=void 0;(x="linear"===c?b.createLinearGradient(0,0,l.value,l.value):b.createRadialGradient(l.value/2,l.value/2,0,l.value/2,l.value/2,l.value/2)).addColorStop(0,_),x.addColorStop(1,g),b.fillStyle=x}else b.fillStyle=a;if(s?b.fill(new Path2D(u.value)):o.value.forEach(function(e,t){e.forEach(function(e,n){e&&b.fillRect(n+r.value,t+r.value,1,1)})}),e.imageSettings.src&&y&&0!==y.naturalWidth&&0!==y.naturalHeight&&d.value){if(h.value){var S=h.value;b.fillStyle=e.background,m(b,S.x,S.y,S.width,S.height,S.borderRadius),b.fill()}var C=d.value.borderRadius;C>0?(b.save(),m(b,d.value.x,d.value.y,d.value.width,d.value.height,C),b.clip(),b.drawImage(y,d.value.x,d.value.y,d.value.width,d.value.height),b.restore()):b.drawImage(y,d.value.x,d.value.y,d.value.width,d.value.height)}}}};return t.onMounted(_),t.watchEffect(_),function(){return t.h(t.Fragment,[t.h("canvas",a(a({},n.attrs),{ref:p,role:"img","aria-label":e.value,style:a(a({},n.attrs.style),{width:"".concat(e.size,"px"),height:"".concat(e.size,"px")})})),e.imageSettings.src&&t.h("img",{ref:f,src:e.imageSettings.src,style:{display:"none"},onLoad:_})])}}}),m=t.defineComponent({name:"Qrcode",props:h,setup:function(e){return function(){return t.h("svg"===e.renderAs?p:f,{value:e.value,size:e.size,margin:e.margin,level:e.level,background:e.background,foreground:e.foreground,imageSettings:e.imageSettings,gradient:e.gradient,gradientType:e.gradientType,gradientStartColor:e.gradientStartColor,gradientEndColor:e.gradientEndColor,radius:e.radius})}}});e.QrcodeCanvas=f,e.QrcodeSvg=p,e.default=m,Object.defineProperty(e,"__esModule",{value:!0})}),function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Chart=t()}(this,function(){"use strict";var e=Object.freeze({__proto__:null,get Colors(){return zr},get Decimation(){return Or},get Filler(){return eo},get Legend(){return io},get SubTitle(){return lo},get Title(){return oo},get Tooltip(){return So}});function t(){}const n=(()=>{let e=0;return()=>e++})();function a(e){return null==e}function i(e){if(Array.isArray&&Array.isArray(e))return!0;const t=Object.prototype.toString.call(e);return"[object"===t.slice(0,7)&&"Array]"===t.slice(-6)}function r(e){return null!==e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e){return("number"==typeof e||e instanceof Number)&&isFinite(+e)}function s(e,t){return o(e)?e:t}function l(e,t){return void 0===e?t:e}const u=(e,t)=>"string"==typeof e&&e.endsWith("%")?parseFloat(e)/100:+e/t,c=(e,t)=>"string"==typeof e&&e.endsWith("%")?parseFloat(e)/100*t:+e;function d(e,t,n){if(e&&"function"==typeof e.call)return e.apply(n,t)}function h(e,t,n,a){let o,s,l;if(i(e))if(s=e.length,a)for(o=s-1;o>=0;o--)t.call(n,e[o],o);else for(o=0;oe,x:e=>e.x,y:e=>e.y};function w(e){const t=e.split("."),n=[];let a="";for(const e of t)a+=e,a.endsWith("\\")?a=a.slice(0,-1)+".":(n.push(a),a="");return n}function k(e,t){const n=y[t]||(y[t]=function(e){const t=w(e);return e=>{for(const n of t){if(""===n)break;e=e&&e[n]}return e}}(t));return n(e)}function x(e){return e.charAt(0).toUpperCase()+e.slice(1)}const S=e=>void 0!==e,C=e=>"function"==typeof e,T=(e,t)=>{if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0};function P(e){return"mouseup"===e.type||"click"===e.type||"contextmenu"===e.type}const E=Math.PI,A=2*E,L=A+E,M=Number.POSITIVE_INFINITY,R=E/180,z=E/2,I=E/4,N=2*E/3,O=Math.log10,j=Math.sign;function D(e,t,n){return Math.abs(e-t)e-t).pop(),t}function F(e){return!function(e){return"symbol"==typeof e||"object"==typeof e&&null!==e&&!(Symbol.toPrimitive in e||"toString"in e||"valueOf"in e)}(e)&&!isNaN(parseFloat(e))&&isFinite(e)}function V(e,t){const n=Math.round(e);return n-t<=e&&n+t>=e}function U(e,t,n){let a,i,r;for(a=0,i=e.length;al&&u=Math.min(t,n)-a&&e<=Math.max(t,n)+a}function te(e,t,n){n=n||(n=>e[n]1;)a=r+i>>1,n(a)?r=a:i=a;return{lo:r,hi:i}}const ne=(e,t,n,a)=>te(e,n,a?a=>{const i=e[a][t];return ie[a][t]te(e,n,a=>e[a][t]>=n);function ie(e,t,n){let a=0,i=e.length;for(;aa&&e[i-1]>n;)i--;return a>0||i{const n="_onData"+x(t),a=e[t];Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value(...t){const i=a.apply(this,t);return e._chartjs.listeners.forEach(e=>{"function"==typeof e[n]&&e[n](...t)}),i}})}))}function se(e,t){const n=e._chartjs;if(!n)return;const a=n.listeners,i=a.indexOf(t);-1!==i&&a.splice(i,1),a.length>0||(re.forEach(t=>{delete e[t]}),delete e._chartjs)}function le(e){const t=new Set(e);return t.size===e.length?e:Array.from(t)}const ue="undefined"==typeof window?function(e){return e()}:window.requestAnimationFrame;function ce(e,t){let n=[],a=!1;return function(...i){n=i,a||(a=!0,ue.call(window,()=>{a=!1,e.apply(t,n)}))}}function de(e,t){let n;return function(...a){return t?(clearTimeout(n),n=setTimeout(e,t,a)):e.apply(this,a),t}}const he=e=>"start"===e?"left":"end"===e?"right":"center",pe=(e,t,n)=>"start"===e?t:"end"===e?n:(t+n)/2,fe=(e,t,n,a)=>e===(a?"left":"right")?n:"center"===e?(t+n)/2:t;function me(e,t,n){const i=t.length;let r=0,o=i;if(e._sorted){const{iScale:s,vScale:l,_parsed:u}=e,c=e.dataset&&e.dataset.options?e.dataset.options.spanGaps:null,d=s.axis,{min:h,max:p,minDefined:f,maxDefined:m}=s.getUserBounds();if(f){if(r=Math.min(ne(u,d,h).lo,n?i:ne(t,d,s.getPixelForValue(h)).lo),c){const e=u.slice(0,r+1).reverse().findIndex(e=>!a(e[l.axis]));r-=Math.max(0,e)}r=J(r,0,i-1)}if(m){let e=Math.max(ne(u,s.axis,p,!0).hi+1,n?0:ne(t,d,s.getPixelForValue(p),!0).hi+1);if(c){const t=u.slice(e-1).findIndex(e=>!a(e[l.axis]));e+=Math.max(0,t)}o=J(e,r,i)-r}else o=i-r}return{start:r,count:o}}function _e(e){const{xScale:t,yScale:n,_scaleRanges:a}=e,i={xmin:t.min,xmax:t.max,ymin:n.min,ymax:n.max};if(!a)return e._scaleRanges=i,!0;const r=a.xmin!==t.min||a.xmax!==t.max||a.ymin!==n.min||a.ymax!==n.max;return Object.assign(a,i),r}var ge=new class{constructor(){this._request=null,this._charts=new Map,this._running=!1,this._lastDate=void 0}_notify(e,t,n,a){const i=t.listeners[a],r=t.duration;i.forEach(a=>a({chart:e,initial:t.initial,numSteps:r,currentStep:Math.min(n-t.start,r)}))}_refresh(){this._request||(this._running=!0,this._request=ue.call(window,()=>{this._update(),this._request=null,this._running&&this._refresh()}))}_update(e=Date.now()){let t=0;this._charts.forEach((n,a)=>{if(!n.running||!n.items.length)return;const i=n.items;let r,o=i.length-1,s=!1;for(;o>=0;--o)r=i[o],r._active?(r._total>n.duration&&(n.duration=r._total),r.tick(e),s=!0):(i[o]=i[i.length-1],i.pop());s&&(a.draw(),this._notify(a,n,e,"progress")),i.length||(n.running=!1,this._notify(a,n,e,"complete"),n.initial=!1),t+=i.length}),this._lastDate=e,0===t&&(this._running=!1)}_getAnims(e){const t=this._charts;let n=t.get(e);return n||(n={running:!1,initial:!0,items:[],listeners:{complete:[],progress:[]}},t.set(e,n)),n}listen(e,t,n){this._getAnims(e).listeners[t].push(n)}add(e,t){t&&t.length&&this._getAnims(e).items.push(...t)}has(e){return this._getAnims(e).items.length>0}start(e){const t=this._charts.get(e);t&&(t.running=!0,t.start=Date.now(),t.duration=t.items.reduce((e,t)=>Math.max(e,t._duration),0),this._refresh())}running(e){if(!this._running)return!1;const t=this._charts.get(e);return!!(t&&t.running&&t.items.length)}stop(e){const t=this._charts.get(e);if(!t||!t.items.length)return;const n=t.items;let a=n.length-1;for(;a>=0;--a)n[a].cancel();t.items=[],this._notify(e,t,Date.now(),"complete")}remove(e){return this._charts.delete(e)}}; /*! * @kurkle/color v0.3.2 * https://github.com/kurkle/color#readme * (c) 2023 Jukka Kurkela * Released under the MIT License - */function ve(e){return e+.5|0}const be=(e,t,n)=>Math.max(Math.min(e,n),t);function ye(e){return be(ve(2.55*e),0,255)}function we(e){return be(ve(255*e),0,255)}function ke(e){return be(ve(e/2.55)/100,0,1)}function xe(e){return be(ve(100*e),0,100)}const Se={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Ce=[..."0123456789ABCDEF"],Te=e=>Ce[15&e],Pe=e=>Ce[(240&e)>>4]+Ce[15&e],Ee=e=>(240&e)>>4==(15&e);const Ae=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Me(e,t,n){const a=t*Math.min(n,1-n),i=(t,i=(t+e/30)%12)=>n-a*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]}function Le(e,t,n){const a=(a,i=(a+e/60)%6)=>n-n*t*Math.max(Math.min(i,4-i,1),0);return[a(5),a(3),a(1)]}function Re(e,t,n){const a=Me(e,1,.5);let i;for(t+n>1&&(i=1/(t+n),t*=i,n*=i),i=0;i<3;i++)a[i]*=1-t-n,a[i]+=t;return a}function ze(e){const t=e.r/255,n=e.g/255,a=e.b/255,i=Math.max(t,n,a),o=Math.min(t,n,a),r=(i+o)/2;let s,l,u;return i!==o&&(u=i-o,l=r>.5?u/(2-i-o):u/(i+o),s=function(e,t,n,a,i){return e===i?(t-n)/a+(te<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055,$e=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);function Ve(e,t,n){if(e){let a=ze(e);a[t]=Math.max(0,Math.min(a[t]+a[t]*n,0===t?360:1)),a=Oe(a),e.r=a[0],e.g=a[1],e.b=a[2]}}function Ue(e,t){return e?Object.assign(t||{},e):e}function He(e){var t={r:0,g:0,b:0,a:255};return Array.isArray(e)?e.length>=3&&(t={r:e[0],g:e[1],b:e[2],a:255},e.length>3&&(t.a=we(e[3]))):(t=Ue(e,{r:0,g:0,b:0,a:1})).a=we(t.a),t}function We(e){return"r"===e.charAt(0)?function(e){const t=Be.exec(e);let n,a,i,o=255;if(t){if(t[7]!==n){const e=+t[7];o=t[8]?ye(e):be(255*e,0,255)}return n=+t[1],a=+t[3],i=+t[5],n=255&(t[2]?ye(n):be(n,0,255)),a=255&(t[4]?ye(a):be(a,0,255)),i=255&(t[6]?ye(i):be(i,0,255)),{r:n,g:a,b:i,a:o}}}(e):function(e){const t=Ae.exec(e);let n,a=255;if(!t)return;t[5]!==n&&(a=t[6]?ye(+t[5]):we(+t[5]));const i=Ie(+t[2]),o=+t[3]/100,r=+t[4]/100;return n="hwb"===t[1]?function(e,t,n){return Ne(Re,e,t,n)}(i,o,r):"hsv"===t[1]?function(e,t,n){return Ne(Le,e,t,n)}(i,o,r):Oe(i,o,r),{r:n[0],g:n[1],b:n[2],a:a}}(e)}class Ge{constructor(e){if(e instanceof Ge)return e;const t=typeof e;let n;var a,i,o;"object"===t?n=He(e):"string"===t&&(o=(a=e).length,"#"===a[0]&&(4===o||5===o?i={r:255&17*Se[a[1]],g:255&17*Se[a[2]],b:255&17*Se[a[3]],a:5===o?17*Se[a[4]]:255}:7!==o&&9!==o||(i={r:Se[a[1]]<<4|Se[a[2]],g:Se[a[3]]<<4|Se[a[4]],b:Se[a[5]]<<4|Se[a[6]],a:9===o?Se[a[7]]<<4|Se[a[8]]:255})),n=i||function(e){je||(je=function(){const e={},t=Object.keys(De),n=Object.keys(qe);let a,i,o,r,s;for(a=0;a>16&255,o>>8&255,255&o]}return e}(),je.transparent=[0,0,0,0]);const t=je[e.toLowerCase()];return t&&{r:t[0],g:t[1],b:t[2],a:4===t.length?t[3]:255}}(e)||We(e)),this._rgb=n,this._valid=!!n}get valid(){return this._valid}get rgb(){var e=Ue(this._rgb);return e&&(e.a=ke(e.a)),e}set rgb(e){this._rgb=He(e)}rgbString(){return this._valid?(e=this._rgb)&&(e.a<255?`rgba(${e.r}, ${e.g}, ${e.b}, ${ke(e.a)})`:`rgb(${e.r}, ${e.g}, ${e.b})`):void 0;var e}hexString(){return this._valid?function(e){var t=(e=>Ee(e.r)&&Ee(e.g)&&Ee(e.b)&&Ee(e.a))(e)?Te:Pe;return e?"#"+t(e.r)+t(e.g)+t(e.b)+((e,t)=>e<255?t(e):"")(e.a,t):void 0}(this._rgb):void 0}hslString(){return this._valid?function(e){if(!e)return;const t=ze(e),n=t[0],a=xe(t[1]),i=xe(t[2]);return e.a<255?`hsla(${n}, ${a}%, ${i}%, ${ke(e.a)})`:`hsl(${n}, ${a}%, ${i}%)`}(this._rgb):void 0}mix(e,t){if(e){const n=this.rgb,a=e.rgb;let i;const o=t===i?.5:t,r=2*o-1,s=n.a-a.a,l=((r*s==-1?r:(r+s)/(1+r*s))+1)/2;i=1-l,n.r=255&l*n.r+i*a.r+.5,n.g=255&l*n.g+i*a.g+.5,n.b=255&l*n.b+i*a.b+.5,n.a=o*n.a+(1-o)*a.a,this.rgb=n}return this}interpolate(e,t){return e&&(this._rgb=function(e,t,n){const a=$e(ke(e.r)),i=$e(ke(e.g)),o=$e(ke(e.b));return{r:we(Fe(a+n*($e(ke(t.r))-a))),g:we(Fe(i+n*($e(ke(t.g))-i))),b:we(Fe(o+n*($e(ke(t.b))-o))),a:e.a+n*(t.a-e.a)}}(this._rgb,e._rgb,t)),this}clone(){return new Ge(this.rgb)}alpha(e){return this._rgb.a=we(e),this}clearer(e){return this._rgb.a*=1-e,this}greyscale(){const e=this._rgb,t=ve(.3*e.r+.59*e.g+.11*e.b);return e.r=e.g=e.b=t,this}opaquer(e){return this._rgb.a*=1+e,this}negate(){const e=this._rgb;return e.r=255-e.r,e.g=255-e.g,e.b=255-e.b,this}lighten(e){return Ve(this._rgb,2,e),this}darken(e){return Ve(this._rgb,2,-e),this}saturate(e){return Ve(this._rgb,1,e),this}desaturate(e){return Ve(this._rgb,1,-e),this}rotate(e){return function(e,t){var n=ze(e);n[0]=Ie(n[0]+t),n=Oe(n),e.r=n[0],e.g=n[1],e.b=n[2]}(this._rgb,e),this}}function Ke(e){if(e&&"object"==typeof e){const t=e.toString();return"[object CanvasPattern]"===t||"[object CanvasGradient]"===t}return!1}function Ye(e){return Ke(e)?e:new Ge(e)}function Qe(e){return Ke(e)?e:new Ge(e).saturate(.5).darken(.1).hexString()}const Ze=["x","y","borderWidth","radius","tension"],Je=["color","borderColor","backgroundColor"],Xe=new Map;function et(e,t,n){return function(e,t){t=t||{};const n=e+JSON.stringify(t);let a=Xe.get(n);return a||(a=new Intl.NumberFormat(e,t),Xe.set(n,a)),a}(t,n).format(e)}const tt={values:e=>i(e)?e:""+e,numeric(e,t,n){if(0===e)return"0";const a=this.chart.options.locale;let i,o=e;if(n.length>1){const t=Math.max(Math.abs(n[0].value),Math.abs(n[n.length-1].value));(t<1e-4||t>1e15)&&(i="scientific"),o=function(e,t){let n=t.length>3?t[2].value-t[1].value:t[1].value-t[0].value;return Math.abs(n)>=1&&e!==Math.floor(e)&&(n=e-Math.floor(e)),n}(e,n)}const r=I(Math.abs(o)),s=isNaN(r)?1:Math.max(Math.min(-1*Math.floor(r),20),0),l={notation:i,minimumFractionDigits:s,maximumFractionDigits:s};return Object.assign(l,this.options.ticks.format),et(e,a,l)},logarithmic(e,t,n){if(0===e)return"0";const a=n[t].significand||e/Math.pow(10,Math.floor(I(e)));return[1,2,3,5,10,15].includes(a)||t>.8*n.length?tt.numeric.call(this,e,t,n):""}};var nt={formatters:tt};const at=Object.create(null),it=Object.create(null);function ot(e,t){if(!t)return e;const n=t.split(".");for(let t=0,a=n.length;te.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(e,t)=>Qe(t.backgroundColor),this.hoverBorderColor=(e,t)=>Qe(t.borderColor),this.hoverColor=(e,t)=>Qe(t.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(e),this.apply(t)}set(e,t){return rt(this,e,t)}get(e){return ot(this,e)}describe(e,t){return rt(it,e,t)}override(e,t){return rt(at,e,t)}route(e,t,n,a){const i=ot(this,e),r=ot(this,n),s="_"+t;Object.defineProperties(i,{[s]:{value:i[t],writable:!0},[t]:{enumerable:!0,get(){const e=this[s],t=r[a];return o(e)?Object.assign({},t,e):l(e,t)},set(e){this[s]=e}}})}apply(e){e.forEach(e=>e(this))}}({_scriptable:e=>!e.startsWith("on"),_indexable:e=>"events"!==e,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(e){e.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),e.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:e=>"onProgress"!==e&&"onComplete"!==e&&"fn"!==e}),e.set("animations",{colors:{type:"color",properties:Je},numbers:{type:"number",properties:Ze}}),e.describe("animations",{_fallback:"animation"}),e.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:e=>0|e}}}})},function(e){e.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(e){e.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(e,t)=>t.lineWidth,tickColor:(e,t)=>t.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:nt.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),e.route("scale.ticks","color","","color"),e.route("scale.grid","color","","borderColor"),e.route("scale.border","color","","borderColor"),e.route("scale.title","color","","color"),e.describe("scale",{_fallback:!1,_scriptable:e=>!e.startsWith("before")&&!e.startsWith("after")&&"callback"!==e&&"parser"!==e,_indexable:e=>"borderDash"!==e&&"tickBorderDash"!==e&&"dash"!==e}),e.describe("scales",{_fallback:"scale"}),e.describe("scale.ticks",{_scriptable:e=>"backdropPadding"!==e&&"callback"!==e,_indexable:e=>"backdropPadding"!==e})}]);function lt(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ut(e){let t=e.parentNode;return t&&"[object ShadowRoot]"===t.toString()&&(t=t.host),t}function ct(e,t,n){let a;return"string"==typeof e?(a=parseInt(e,10),-1!==e.indexOf("%")&&(a=a/100*t.parentNode[n])):a=e,a}const dt=e=>e.ownerDocument.defaultView.getComputedStyle(e,null);function ht(e,t){return dt(e).getPropertyValue(t)}const pt=["top","right","bottom","left"];function ft(e,t,n){const a={};n=n?"-"+n:"";for(let i=0;i<4;i++){const o=pt[i];a[o]=parseFloat(e[t+"-"+o+n])||0}return a.width=a.left+a.right,a.height=a.top+a.bottom,a}function mt(e,t){if("native"in e)return e;const{canvas:n,currentDevicePixelRatio:a}=t,i=dt(n),o="border-box"===i.boxSizing,r=ft(i,"padding"),s=ft(i,"border","width"),{x:l,y:u,box:c}=function(e,t){const n=e.touches,a=n&&n.length?n[0]:e,{offsetX:i,offsetY:o}=a;let r,s,l=!1;if(((e,t,n)=>(e>0||t>0)&&(!n||!n.shadowRoot))(i,o,e.target))r=i,s=o;else{const e=t.getBoundingClientRect();r=a.clientX-e.left,s=a.clientY-e.top,l=!0}return{x:r,y:s,box:l}}(e,n),d=r.left+(c&&s.left),h=r.top+(c&&s.top);let{width:p,height:f}=t;return o&&(p-=r.width+s.width,f-=r.height+s.height),{x:Math.round((l-d)/p*n.width/a),y:Math.round((u-h)/f*n.height/a)}}const gt=e=>Math.round(10*e)/10;function _t(e,t,n,a){const i=dt(e),o=ft(i,"margin"),r=ct(i.maxWidth,e,"clientWidth")||L,s=ct(i.maxHeight,e,"clientHeight")||L,l=function(e,t,n){let a,i;if(void 0===t||void 0===n){const o=e&&ut(e);if(o){const e=o.getBoundingClientRect(),r=dt(o),s=ft(r,"border","width"),l=ft(r,"padding");t=e.width-l.width-s.width,n=e.height-l.height-s.height,a=ct(r.maxWidth,o,"clientWidth"),i=ct(r.maxHeight,o,"clientHeight")}else t=e.clientWidth,n=e.clientHeight}return{width:t,height:n,maxWidth:a||L,maxHeight:i||L}}(e,t,n);let{width:u,height:c}=l;if("content-box"===i.boxSizing){const e=ft(i,"border","width"),t=ft(i,"padding");u-=t.width+e.width,c-=t.height+e.height}return u=Math.max(0,u-o.width),c=Math.max(0,a?u/a:c-o.height),u=gt(Math.min(u,r,l.maxWidth)),c=gt(Math.min(c,s,l.maxHeight)),u&&!c&&(c=gt(u/2)),(void 0!==t||void 0!==n)&&a&&l.height&&c>l.height&&(c=l.height,u=gt(Math.floor(c*a))),{width:u,height:c}}function vt(e,t,n){const a=t||1,i=gt(e.height*a),o=gt(e.width*a);e.height=gt(e.height),e.width=gt(e.width);const r=e.canvas;return r.style&&(n||!r.style.height&&!r.style.width)&&(r.style.height=`${e.height}px`,r.style.width=`${e.width}px`),(e.currentDevicePixelRatio!==a||r.height!==i||r.width!==o)&&(e.currentDevicePixelRatio=a,r.height=i,r.width=o,e.ctx.setTransform(a,0,0,a,0,0),!0)}const bt=function(){let e=!1;try{const t={get passive(){return e=!0,!1}};lt()&&(window.addEventListener("test",null,t),window.removeEventListener("test",null,t))}catch(e){}return e}();function yt(e,t){const n=ht(e,t),a=n&&n.match(/^(\d+)(\.\d+)?px$/);return a?+a[1]:void 0}function wt(e){return!e||a(e.size)||a(e.family)?null:(e.style?e.style+" ":"")+(e.weight?e.weight+" ":"")+e.size+"px "+e.family}function kt(e,t,n,a,i){let o=t[i];return o||(o=t[i]=e.measureText(i).width,n.push(i)),o>a&&(a=o),a}function xt(e,t,n,a){let o=(a=a||{}).data=a.data||{},r=a.garbageCollect=a.garbageCollect||[];a.font!==t&&(o=a.data={},r=a.garbageCollect=[],a.font=t),e.save(),e.font=t;let s=0;const l=n.length;let u,c,d,h,p;for(u=0;un.length){for(u=0;u0&&e.stroke()}}function Et(e,t,n){return n=n||.5,!t||e&&e.x>t.left-n&&e.xt.top-n&&e.y0&&""!==s.strokeColor;let c,d;for(e.save(),e.font=r.string,function(e,t){t.translation&&e.translate(t.translation[0],t.translation[1]),a(t.rotation)||e.rotate(t.rotation),t.color&&(e.fillStyle=t.color),t.textAlign&&(e.textAlign=t.textAlign),t.textBaseline&&(e.textBaseline=t.textBaseline)}(e,s),c=0;ce[0]){const o=n||e;void 0===a&&(a=Kt("_fallback",e));const r={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:e,_rootScopes:o,_fallback:a,_getTarget:i,override:n=>qt([n,...e],t,o,a)};return new Proxy(r,{deleteProperty:(t,n)=>(delete t[n],delete t._keys,delete e[0][n],!0),get:(n,a)=>$t(n,a,()=>function(e,t,n,a){let i;for(const o of t)if(i=Kt(Bt(o,e),n),void 0!==i)return Ft(e,i)?Wt(n,a,e,i):i}(a,t,e,n)),getOwnPropertyDescriptor:(e,t)=>Reflect.getOwnPropertyDescriptor(e._scopes[0],t),getPrototypeOf:()=>Reflect.getPrototypeOf(e[0]),has:(e,t)=>Yt(e).includes(t),ownKeys:e=>Yt(e),set(e,t,n){const a=e._storage||(e._storage=i());return e[t]=a[t]=n,delete e._keys,!0}})}function Dt(e,t,n,a){const r={_cacheable:!1,_proxy:e,_context:t,_subProxy:n,_stack:new Set,_descriptors:jt(e,a),setContext:t=>Dt(e,t,n,a),override:i=>Dt(e.override(i),t,n,a)};return new Proxy(r,{deleteProperty:(t,n)=>(delete t[n],delete e[n],!0),get:(e,t,n)=>$t(e,t,()=>function(e,t,n){const{_proxy:a,_context:r,_subProxy:s,_descriptors:l}=e;let u=a[t];return C(u)&&l.isScriptable(t)&&(u=function(e,t,n,a){const{_proxy:i,_context:o,_subProxy:r,_stack:s}=n;if(s.has(e))throw new Error("Recursion detected: "+Array.from(s).join("->")+"->"+e);s.add(e);let l=t(o,r||a);return s.delete(e),Ft(e,l)&&(l=Wt(i._scopes,i,e,l)),l}(t,u,e,n)),i(u)&&u.length&&(u=function(e,t,n,a){const{_proxy:i,_context:r,_subProxy:s,_descriptors:l}=n;if(void 0!==r.index&&a(e))return t[r.index%t.length];if(o(t[0])){const n=t,a=i._scopes.filter(e=>e!==n);t=[];for(const o of n){const n=Wt(a,i,e,o);t.push(Dt(n,r,s&&s[e],l))}}return t}(t,u,e,l.isIndexable)),Ft(t,u)&&(u=Dt(u,r,s&&s[t],l)),u}(e,t,n)),getOwnPropertyDescriptor:(t,n)=>t._descriptors.allKeys?Reflect.has(e,n)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(e,n),getPrototypeOf:()=>Reflect.getPrototypeOf(e),has:(t,n)=>Reflect.has(e,n),ownKeys:()=>Reflect.ownKeys(e),set:(t,n,a)=>(e[n]=a,delete t[n],!0)})}function jt(e,t={scriptable:!0,indexable:!0}){const{_scriptable:n=t.scriptable,_indexable:a=t.indexable,_allKeys:i=t.allKeys}=e;return{allKeys:i,scriptable:n,indexable:a,isScriptable:C(n)?n:()=>n,isIndexable:C(a)?a:()=>a}}const Bt=(e,t)=>e?e+x(t):t,Ft=(e,t)=>o(t)&&"adapters"!==e&&(null===Object.getPrototypeOf(t)||t.constructor===Object);function $t(e,t,n){if(Object.prototype.hasOwnProperty.call(e,t)||"constructor"===t)return e[t];const a=n();return e[t]=a,a}function Vt(e,t,n){return C(e)?e(t,n):e}const Ut=(e,t)=>!0===e?t:"string"==typeof e?k(t,e):void 0;function Ht(e,t,n,a,i){for(const o of t){const t=Ut(n,o);if(t){e.add(t);const o=Vt(t._fallback,n,i);if(void 0!==o&&o!==n&&o!==a)return o}else if(!1===t&&void 0!==a&&n!==a)return null}return!1}function Wt(e,t,n,a){const r=t._rootScopes,s=Vt(t._fallback,n,a),l=[...e,...r],u=new Set;u.add(a);let c=Gt(u,l,n,s||n,a);return null!==c&&(void 0===s||s===n||(c=Gt(u,l,s,c,a),null!==c))&&qt(Array.from(u),[""],r,s,()=>function(e,t,n){const a=e._getTarget();t in a||(a[t]={});const r=a[t];return i(r)&&o(n)?n:r||{}}(t,n,a))}function Gt(e,t,n,a,i){for(;n;)n=Ht(e,t,n,a,i);return n}function Kt(e,t){for(const n of t){if(!n)continue;const t=n[e];if(void 0!==t)return t}}function Yt(e){let t=e._keys;return t||(t=e._keys=function(e){const t=new Set;for(const n of e)for(const e of Object.keys(n).filter(e=>!e.startsWith("_")))t.add(e);return Array.from(t)}(e._scopes)),t}function Qt(e,t,n,a){const{iScale:i}=e,{key:o="r"}=this._parsing,r=new Array(a);let s,l,u,c;for(s=0,l=a;st"x"===e?"y":"x";function en(e,t,n,a){const i=e.skip?t:e,o=t,r=n.skip?t:n,s=K(o,i),l=K(r,o);let u=s/(s+l),c=l/(s+l);u=isNaN(u)?0:u,c=isNaN(c)?0:c;const d=a*u,h=a*c;return{previous:{x:o.x-d*(r.x-i.x),y:o.y-d*(r.y-i.y)},next:{x:o.x+h*(r.x-i.x),y:o.y+h*(r.y-i.y)}}}function tn(e,t="x"){const n=Xt(t),a=e.length,i=Array(a).fill(0),o=Array(a);let r,s,l,u=Jt(e,0);for(r=0;r!e.skip)),"monotone"===t.cubicInterpolationMode)tn(e,i);else{let n=a?e[e.length-1]:e[0];for(o=0,r=e.length;o0===e||1===e,rn=(e,t,n)=>-Math.pow(2,10*(e-=1))*Math.sin((e-t)*A/n),sn=(e,t,n)=>Math.pow(2,-10*e)*Math.sin((e-t)*A/n)+1,ln={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>-e*(e-2),easeInOutQuad:e=>(e/=.5)<1?.5*e*e:-.5*(--e*(e-2)-1),easeInCubic:e=>e*e*e,easeOutCubic:e=>(e-=1)*e*e+1,easeInOutCubic:e=>(e/=.5)<1?.5*e*e*e:.5*((e-=2)*e*e+2),easeInQuart:e=>e*e*e*e,easeOutQuart:e=>-((e-=1)*e*e*e-1),easeInOutQuart:e=>(e/=.5)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2),easeInQuint:e=>e*e*e*e*e,easeOutQuint:e=>(e-=1)*e*e*e*e+1,easeInOutQuint:e=>(e/=.5)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2),easeInSine:e=>1-Math.cos(e*z),easeOutSine:e=>Math.sin(e*z),easeInOutSine:e=>-.5*(Math.cos(E*e)-1),easeInExpo:e=>0===e?0:Math.pow(2,10*(e-1)),easeOutExpo:e=>1===e?1:1-Math.pow(2,-10*e),easeInOutExpo:e=>on(e)?e:e<.5?.5*Math.pow(2,10*(2*e-1)):.5*(2-Math.pow(2,-10*(2*e-1))),easeInCirc:e=>e>=1?e:-(Math.sqrt(1-e*e)-1),easeOutCirc:e=>Math.sqrt(1-(e-=1)*e),easeInOutCirc:e=>(e/=.5)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1),easeInElastic:e=>on(e)?e:rn(e,.075,.3),easeOutElastic:e=>on(e)?e:sn(e,.075,.3),easeInOutElastic(e){const t=.1125;return on(e)?e:e<.5?.5*rn(2*e,t,.45):.5+.5*sn(2*e-1,t,.45)},easeInBack(e){const t=1.70158;return e*e*((t+1)*e-t)},easeOutBack(e){const t=1.70158;return(e-=1)*e*((t+1)*e+t)+1},easeInOutBack(e){let t=1.70158;return(e/=.5)<1?e*e*((1+(t*=1.525))*e-t)*.5:.5*((e-=2)*e*((1+(t*=1.525))*e+t)+2)},easeInBounce:e=>1-ln.easeOutBounce(1-e),easeOutBounce(e){const t=7.5625,n=2.75;return e<1/n?t*e*e:e<2/n?t*(e-=1.5/n)*e+.75:e<2.5/n?t*(e-=2.25/n)*e+.9375:t*(e-=2.625/n)*e+.984375},easeInOutBounce:e=>e<.5?.5*ln.easeInBounce(2*e):.5*ln.easeOutBounce(2*e-1)+.5};function un(e,t,n,a){return{x:e.x+n*(t.x-e.x),y:e.y+n*(t.y-e.y)}}function cn(e,t,n,a){return{x:e.x+n*(t.x-e.x),y:"middle"===a?n<.5?e.y:t.y:"after"===a?n<1?e.y:t.y:n>0?t.y:e.y}}function dn(e,t,n,a){const i={x:e.cp2x,y:e.cp2y},o={x:t.cp1x,y:t.cp1y},r=un(e,i,n),s=un(i,o,n),l=un(o,t,n),u=un(r,s,n),c=un(s,l,n);return un(u,c,n)}const hn=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,pn=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function fn(e,t){const n=(""+e).match(hn);if(!n||"normal"===n[1])return 1.2*t;switch(e=+n[2],n[3]){case"px":return e;case"%":e/=100}return t*e}const mn=e=>+e||0;function gn(e,t){const n={},a=o(t),i=a?Object.keys(t):t,r=o(e)?a?n=>l(e[n],e[t[n]]):t=>e[t]:()=>e;for(const e of i)n[e]=mn(r(e));return n}function _n(e){return gn(e,{top:"y",right:"x",bottom:"y",left:"x"})}function vn(e){return gn(e,["topLeft","topRight","bottomLeft","bottomRight"])}function bn(e){const t=_n(e);return t.width=t.left+t.right,t.height=t.top+t.bottom,t}function yn(e,t){e=e||{},t=t||st.font;let n=l(e.size,t.size);"string"==typeof n&&(n=parseInt(n,10));let a=l(e.style,t.style);a&&!(""+a).match(pn)&&(console.warn('Invalid font style specified: "'+a+'"'),a=void 0);const i={family:l(e.family,t.family),lineHeight:fn(l(e.lineHeight,t.lineHeight),n),size:n,style:a,weight:l(e.weight,t.weight),string:""};return i.string=wt(i),i}function wn(e,t,n,a){let o,r,s,l=!0;for(o=0,r=e.length;on&&0===e?0:e+t;return{min:r(a,-Math.abs(o)),max:r(i,o)}}function xn(e,t){return Object.assign(Object.create(e),t)}function Sn(e,t,n){return e?function(e,t){return{x:n=>e+e+t-n,setWidth(e){t=e},textAlign:e=>"center"===e?e:"right"===e?"left":"right",xPlus:(e,t)=>e-t,leftForLtr:(e,t)=>e-t}}(t,n):{x:e=>e,setWidth(e){},textAlign:e=>e,xPlus:(e,t)=>e+t,leftForLtr:(e,t)=>e}}function Cn(e,t){let n,a;"ltr"!==t&&"rtl"!==t||(n=e.canvas.style,a=[n.getPropertyValue("direction"),n.getPropertyPriority("direction")],n.setProperty("direction",t,"important"),e.prevTextDirection=a)}function Tn(e,t){void 0!==t&&(delete e.prevTextDirection,e.canvas.style.setProperty("direction",t[0],t[1]))}function Pn(e){return"angle"===e?{between:Z,compare:Y,normalize:Q}:{between:ee,compare:(e,t)=>e-t,normalize:e=>e}}function En({start:e,end:t,count:n,loop:a,style:i}){return{start:e%n,end:t%n,loop:a&&(t-e+1)%n==0,style:i}}function An(e,t,n){if(!n)return[e];const{property:a,start:i,end:o}=n,r=t.length,{compare:s,between:l,normalize:u}=Pn(a),{start:c,end:d,loop:h,style:p}=function(e,t,n){const{property:a,start:i,end:o}=n,{between:r,normalize:s}=Pn(a),l=t.length;let u,c,{start:d,end:h,loop:p}=e;if(p){for(d+=l,h+=l,u=0,c=l;uv||l(i,_,m)&&0!==s(i,_),w=()=>!v||0===s(o,m)||l(o,_,m);for(let e=c,n=c;e<=d;++e)g=t[e%r],g.skip||(m=u(g[a]),m!==_&&(v=l(m,i,o),null===b&&y()&&(b=0===s(m,i)?e:n),null!==b&&w()&&(f.push(En({start:b,end:e,loop:h,count:r,style:p})),b=null),n=e,_=m));return null!==b&&f.push(En({start:b,end:d,loop:h,count:r,style:p})),f}function Mn(e,t){const n=[],a=e.segments;for(let i=0;ii&&e[o%t].skip;)o--;return o%=t,{start:i,end:o}}(n,i,o,a);return Rn(e,!0===a?[{start:r,end:s,loop:o}]:function(e,t,n,a){const i=e.length,o=[];let r,s=t,l=e[t];for(r=t+1;r<=n;++r){const n=e[r%i];n.skip||n.stop?l.skip||(a=!1,o.push({start:t%i,end:(r-1)%i,loop:a}),t=s=n.stop?r:null):(s=r,l.skip&&(t=r)),l=n}return null!==s&&o.push({start:t%i,end:s%i,loop:a}),o}(n,r,s!a(e[t.axis]));i.lo-=Math.max(0,r);const s=n.slice(i.hi).findIndex(e=>!a(e[t.axis]));i.hi+=Math.max(0,s)}return i}if(o._sharedOptions){const e=r[0],a="function"==typeof e.getRange&&e.getRange(t);if(a){const e=s(r,t,n-a),i=s(r,t,n+a);return{lo:e.lo,hi:i.hi}}}}return{lo:0,hi:r.length-1}}function jn(e,t,n,a,i){const o=e.getSortedVisibleDatasetMetas(),r=n[t];for(let e=0,n=o.length;e{e[r]&&e[r](t[n],i)&&(o.push({element:e,datasetIndex:a,index:l}),s=s||e.inRange(t.x,t.y,i))}),a&&!s?[]:o}var Vn={evaluateInteractionItems:jn,modes:{index(e,t,n,a){const i=mt(t,e),o=n.axis||"x",r=n.includeInvisible||!1,s=n.intersect?Bn(e,i,o,a,r):Fn(e,i,o,!1,a,r),l=[];return s.length?(e.getSortedVisibleDatasetMetas().forEach(e=>{const t=s[0].index,n=e.data[t];n&&!n.skip&&l.push({element:n,datasetIndex:e.index,index:t})}),l):[]},dataset(e,t,n,a){const i=mt(t,e),o=n.axis||"xy",r=n.includeInvisible||!1;let s=n.intersect?Bn(e,i,o,a,r):Fn(e,i,o,!1,a,r);if(s.length>0){const t=s[0].datasetIndex,n=e.getDatasetMeta(t).data;s=[];for(let e=0;eBn(e,mt(t,e),n.axis||"xy",a,n.includeInvisible||!1),nearest(e,t,n,a){const i=mt(t,e),o=n.axis||"xy",r=n.includeInvisible||!1;return Fn(e,i,o,n.intersect,a,r)},x:(e,t,n,a)=>$n(e,mt(t,e),"x",n.intersect,a),y:(e,t,n,a)=>$n(e,mt(t,e),"y",n.intersect,a)}};const Un=["left","top","right","bottom"];function Hn(e,t){return e.filter(e=>e.pos===t)}function Wn(e,t){return e.filter(e=>-1===Un.indexOf(e.pos)&&e.box.axis===t)}function Gn(e,t){return e.sort((e,n)=>{const a=t?n:e,i=t?e:n;return a.weight===i.weight?a.index-i.index:a.weight-i.weight})}function Kn(e,t,n,a){return Math.max(e[n],t[n])+Math.max(e[a],t[a])}function Yn(e,t){e.top=Math.max(e.top,t.top),e.left=Math.max(e.left,t.left),e.bottom=Math.max(e.bottom,t.bottom),e.right=Math.max(e.right,t.right)}function Qn(e,t,n,a){const{pos:i,box:r}=n,s=e.maxPadding;if(!o(i)){n.size&&(e[i]-=n.size);const t=a[n.stack]||{size:0,count:1};t.size=Math.max(t.size,n.horizontal?r.height:r.width),n.size=t.size/t.count,e[i]+=n.size}r.getPadding&&Yn(s,r.getPadding());const l=Math.max(0,t.outerWidth-Kn(s,e,"left","right")),u=Math.max(0,t.outerHeight-Kn(s,e,"top","bottom")),c=l!==e.w,d=u!==e.h;return e.w=l,e.h=u,n.horizontal?{same:c,other:d}:{same:d,other:c}}function Zn(e,t){const n=t.maxPadding;return function(e){const a={left:0,top:0,right:0,bottom:0};return e.forEach(e=>{a[e]=Math.max(t[e],n[e])}),a}(e?["left","right"]:["top","bottom"])}function Jn(e,t,n,a){const i=[];let o,r,s,l,u,c;for(o=0,r=e.length,u=0;oe.box.fullSize),!0),a=Gn(Hn(t,"left"),!0),i=Gn(Hn(t,"right")),o=Gn(Hn(t,"top"),!0),r=Gn(Hn(t,"bottom")),s=Wn(t,"x"),l=Wn(t,"y");return{fullSize:n,leftAndTop:a.concat(o),rightAndBottom:i.concat(l).concat(r).concat(s),chartArea:Hn(t,"chartArea"),vertical:a.concat(i).concat(l),horizontal:o.concat(r).concat(s)}}(e.boxes),l=s.vertical,u=s.horizontal;h(e.boxes,e=>{"function"==typeof e.beforeLayout&&e.beforeLayout()});const c=l.reduce((e,t)=>t.box.options&&!1===t.box.options.display?e:e+1,0)||1,d=Object.freeze({outerWidth:t,outerHeight:n,padding:i,availableWidth:o,availableHeight:r,vBoxMaxWidth:o/2/c,hBoxMaxHeight:r/2}),p=Object.assign({},i);Yn(p,bn(a));const f=Object.assign({maxPadding:p,w:o,h:r,x:i.left,y:i.top},i),m=function(e,t){const n=function(e){const t={};for(const n of e){const{stack:e,pos:a,stackWeight:i}=n;if(!e||!Un.includes(a))continue;const o=t[e]||(t[e]={count:0,placed:0,weight:0,size:0});o.count++,o.weight+=i}return t}(e),{vBoxMaxWidth:a,hBoxMaxHeight:i}=t;let o,r,s;for(o=0,r=e.length;o{const n=t.box;Object.assign(n,e.chartArea),n.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})})}};class na{acquireContext(e,t){}releaseContext(e){return!1}addEventListener(e,t,n){}removeEventListener(e,t,n){}getDevicePixelRatio(){return 1}getMaximumSize(e,t,n,a){return t=Math.max(0,t||e.width),n=n||e.height,{width:t,height:Math.max(0,a?Math.floor(t/a):n)}}isAttached(e){return!0}updateConfig(e){}}class aa extends na{acquireContext(e){return e&&e.getContext&&e.getContext("2d")||null}updateConfig(e){e.options.animation=!1}}const ia="$chartjs",oa={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},ra=e=>null===e||""===e,sa=!!bt&&{passive:!0};function la(e,t,n){e&&e.canvas&&e.canvas.removeEventListener(t,n,sa)}function ua(e,t){for(const n of e)if(n===t||n.contains(t))return!0}function ca(e,t,n){const a=e.canvas,i=new MutationObserver(e=>{let t=!1;for(const n of e)t=t||ua(n.addedNodes,a),t=t&&!ua(n.removedNodes,a);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}function da(e,t,n){const a=e.canvas,i=new MutationObserver(e=>{let t=!1;for(const n of e)t=t||ua(n.removedNodes,a),t=t&&!ua(n.addedNodes,a);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}const ha=new Map;let pa=0;function fa(){const e=window.devicePixelRatio;e!==pa&&(pa=e,ha.forEach((t,n)=>{n.currentDevicePixelRatio!==e&&t()}))}function ma(e,t,n){const a=e.canvas,i=a&&ut(a);if(!i)return;const o=ce((e,t)=>{const a=i.clientWidth;n(e,t),a{const t=e[0],n=t.contentRect.width,a=t.contentRect.height;0===n&&0===a||o(n,a)});return r.observe(i),function(e,t){ha.size||window.addEventListener("resize",fa),ha.set(e,t)}(e,o),r}function ga(e,t,n){n&&n.disconnect(),"resize"===t&&function(e){ha.delete(e),ha.size||window.removeEventListener("resize",fa)}(e)}function _a(e,t,n){const a=e.canvas,i=ce(t=>{null!==e.ctx&&n(function(e,t){const n=oa[e.type]||e.type,{x:a,y:i}=mt(e,t);return{type:n,chart:t,native:e,x:void 0!==a?a:null,y:void 0!==i?i:null}}(t,e))},e);return function(e,t,n){e&&e.addEventListener(t,n,sa)}(a,t,i),i}class va extends na{acquireContext(e,t){const n=e&&e.getContext&&e.getContext("2d");return n&&n.canvas===e?(function(e,t){const n=e.style,a=e.getAttribute("height"),i=e.getAttribute("width");if(e[ia]={initial:{height:a,width:i,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",n.boxSizing=n.boxSizing||"border-box",ra(i)){const t=yt(e,"width");void 0!==t&&(e.width=t)}if(ra(a))if(""===e.style.height)e.height=e.width/(t||2);else{const t=yt(e,"height");void 0!==t&&(e.height=t)}}(e,t),n):null}releaseContext(e){const t=e.canvas;if(!t[ia])return!1;const n=t[ia].initial;["height","width"].forEach(e=>{const i=n[e];a(i)?t.removeAttribute(e):t.setAttribute(e,i)});const i=n.style||{};return Object.keys(i).forEach(e=>{t.style[e]=i[e]}),t.width=t.width,delete t[ia],!0}addEventListener(e,t,n){this.removeEventListener(e,t);const a=e.$proxies||(e.$proxies={}),i={attach:ca,detach:da,resize:ma}[t]||_a;a[t]=i(e,t,n)}removeEventListener(e,t){const n=e.$proxies||(e.$proxies={}),a=n[t];a&&(({attach:ga,detach:ga,resize:ga}[t]||la)(e,t,a),n[t]=void 0)}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(e,t,n,a){return _t(e,t,n,a)}isAttached(e){const t=e&&ut(e);return!(!t||!t.isConnected)}}function ba(e){return!lt()||"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas?aa:va}var ya=Object.freeze({__proto__:null,BasePlatform:na,BasicPlatform:aa,DomPlatform:va,_detectPlatform:ba});const wa="transparent",ka={boolean:(e,t,n)=>n>.5?t:e,color(e,t,n){const a=Ye(e||wa),i=a.valid&&Ye(t||wa);return i&&i.valid?i.mix(a,n).hexString():t},number:(e,t,n)=>e+(t-e)*n};class xa{constructor(e,t,n,a){const i=t[n];a=wn([e.to,a,i,e.from]);const o=wn([e.from,i,a]);this._active=!0,this._fn=e.fn||ka[e.type||typeof o],this._easing=ln[e.easing]||ln.linear,this._start=Math.floor(Date.now()+(e.delay||0)),this._duration=this._total=Math.floor(e.duration),this._loop=!!e.loop,this._target=t,this._prop=n,this._from=o,this._to=a,this._promises=void 0}active(){return this._active}update(e,t,n){if(this._active){this._notify(!1);const a=this._target[this._prop],i=n-this._start,o=this._duration-i;this._start=n,this._duration=Math.floor(Math.max(o,e.duration)),this._total+=i,this._loop=!!e.loop,this._to=wn([e.to,t,a,e.from]),this._from=wn([e.from,a,t])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(e){const t=e-this._start,n=this._duration,a=this._prop,i=this._from,o=this._loop,r=this._to;let s;if(this._active=i!==r&&(o||t1?2-s:s,s=this._easing(Math.min(1,Math.max(0,s))),this._target[a]=this._fn(i,r,s))}wait(){const e=this._promises||(this._promises=[]);return new Promise((t,n)=>{e.push({res:t,rej:n})})}_notify(e){const t=e?"res":"rej",n=this._promises||[];for(let e=0;e{const r=e[a];if(!o(r))return;const s={};for(const e of t)s[e]=r[e];(i(r.properties)&&r.properties||[a]).forEach(e=>{e!==a&&n.has(e)||n.set(e,s)})})}_animateOptions(e,t){const n=t.options,a=function(e,t){if(!t)return;let n=e.options;if(n)return n.$shared&&(e.options=n=Object.assign({},n,{$shared:!1,$animations:{}})),n;e.options=t}(e,n);if(!a)return[];const i=this._createAnimations(a,n);return n.$shared&&function(e,t){const n=[],a=Object.keys(t);for(let t=0;t{e.options=n},()=>{}),i}_createAnimations(e,t){const n=this._properties,a=[],i=e.$animations||(e.$animations={}),o=Object.keys(t),r=Date.now();let s;for(s=o.length-1;s>=0;--s){const l=o[s];if("$"===l.charAt(0))continue;if("options"===l){a.push(...this._animateOptions(e,t));continue}const u=t[l];let c=i[l];const d=n.get(l);if(c){if(d&&c.active()){c.update(d,u,r);continue}c.cancel()}d&&d.duration?(i[l]=c=new xa(d,e,l,u),a.push(c)):e[l]=u}return a}update(e,t){if(0===this._properties.size)return void Object.assign(e,t);const n=this._createAnimations(e,t);return n.length?(_e.add(this._chart,n),!0):void 0}}function Ca(e,t){const n=e&&e.options||{},a=n.reverse,i=void 0===n.min?t:0,o=void 0===n.max?t:0;return{start:a?o:i,end:a?i:o}}function Ta(e,t){const n=[],a=e._getSortedDatasetMetas(t);let i,o;for(i=0,o=a.length;i0||!n&&t<0)return i.index}return null}function La(e,t){const{chart:n,_cachedMeta:a}=e,i=n._stacks||(n._stacks={}),{iScale:o,vScale:r,index:s}=a,l=o.axis,u=r.axis,c=function(e,t,n){return`${e.id}.${t.id}.${n.stack||n.type}`}(o,r,a),d=t.length;let h;for(let e=0;en[e].axis===t).shift()}function za(e,t){const n=e.controller.index,a=e.vScale&&e.vScale.axis;if(a){t=t||e._parsed;for(const e of t){const t=e._stacks;if(!t||void 0===t[a]||void 0===t[a][n])return;delete t[a][n],void 0!==t[a]._visualValues&&void 0!==t[a]._visualValues[n]&&delete t[a]._visualValues[n]}}}const Na=e=>"reset"===e||"none"===e,Oa=(e,t)=>t?e:Object.assign({},e);class Ia{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(e,t){this.chart=e,this._ctx=e.ctx,this.index=t,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const e=this._cachedMeta;this.configure(),this.linkScales(),e._stacked=Ea(e.vScale,e),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(e){this.index!==e&&za(this._cachedMeta),this.index=e}linkScales(){const e=this.chart,t=this._cachedMeta,n=this.getDataset(),a=(e,t,n,a)=>"x"===e?t:"r"===e?a:n,i=t.xAxisID=l(n.xAxisID,Ra(e,"x")),o=t.yAxisID=l(n.yAxisID,Ra(e,"y")),r=t.rAxisID=l(n.rAxisID,Ra(e,"r")),s=t.indexAxis,u=t.iAxisID=a(s,i,o,r),c=t.vAxisID=a(s,o,i,r);t.xScale=this.getScaleForId(i),t.yScale=this.getScaleForId(o),t.rScale=this.getScaleForId(r),t.iScale=this.getScaleForId(u),t.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(e){return this.chart.scales[e]}_getOtherScale(e){const t=this._cachedMeta;return e===t.iScale?t.vScale:t.iScale}reset(){this._update("reset")}_destroy(){const e=this._cachedMeta;this._data&&se(this._data,this),e._stacked&&za(e)}_dataCheck(){const e=this.getDataset(),t=e.data||(e.data=[]),n=this._data;if(o(t)){const e=this._cachedMeta;this._data=function(e,t){const{iScale:n,vScale:a}=t,i="x"===n.axis?"x":"y",o="x"===a.axis?"x":"y",r=Object.keys(e),s=new Array(r.length);let l,u,c;for(l=0,u=r.length;l0&&n._parsed[e-1];if(!1===this._parsing)n._parsed=a,n._sorted=!0,d=a;else{d=i(a[e])?this.parseArrayData(n,a,e,t):o(a[e])?this.parseObjectData(n,a,e,t):this.parsePrimitiveData(n,a,e,t);const r=()=>null===c[l]||p&&c[l]e&&!t.hidden&&t._stacked&&{keys:Ta(n,!0),values:null})(t,n,this.chart),u={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(e){const{min:t,max:n,minDefined:a,maxDefined:i}=e.getUserBounds();return{min:a?t:Number.NEGATIVE_INFINITY,max:i?n:Number.POSITIVE_INFINITY}}(s);let h,p;function f(){p=a[h];const t=p[s.axis];return!r(p[e.axis])||c>t||d=0;--h)if(!f()){this.updateRangeFromParsed(u,e,p,l);break}return u}getAllParsedValues(e){const t=this._cachedMeta._parsed,n=[];let a,i,o;for(a=0,i=t.length;a=0&&ethis.getContext(n,a,t),c);return p.$shared&&(p.$shared=s,i[o]=Object.freeze(Oa(p,s))),p}_resolveAnimations(e,t,n){const a=this.chart,i=this._cachedDataOpts,o=`animation-${t}`,r=i[o];if(r)return r;let s;if(!1!==a.options.animation){const a=this.chart.config,i=a.datasetAnimationScopeKeys(this._type,t),o=a.getOptionScopes(this.getDataset(),i);s=a.createResolver(o,this.getContext(e,n,t))}const l=new Sa(a,s&&s.animations);return s&&s._cacheable&&(i[o]=Object.freeze(l)),l}getSharedOptions(e){if(e.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},e))}includeOptions(e,t){return!t||Na(e)||this.chart._animationsDisabled}_getSharedOptions(e,t){const n=this.resolveDataElementOptions(e,t),a=this._sharedOptions,i=this.getSharedOptions(n),o=this.includeOptions(t,i)||i!==a;return this.updateSharedOptions(i,t,n),{sharedOptions:i,includeOptions:o}}updateElement(e,t,n,a){Na(a)?Object.assign(e,n):this._resolveAnimations(t,a).update(e,n)}updateSharedOptions(e,t,n){e&&!Na(t)&&this._resolveAnimations(void 0,t).update(e,n)}_setStyle(e,t,n,a){e.active=a;const i=this.getStyle(t,a);this._resolveAnimations(t,n,a).update(e,{options:!a&&this.getSharedOptions(i)||i})}removeHoverStyle(e,t,n){this._setStyle(e,n,"active",!1)}setHoverStyle(e,t,n){this._setStyle(e,n,"active",!0)}_removeDatasetHoverStyle(){const e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,"active",!1)}_setDatasetHoverStyle(){const e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,"active",!0)}_resyncElements(e){const t=this._data,n=this._cachedMeta.data;for(const[e,t,n]of this._syncList)this[e](t,n);this._syncList=[];const a=n.length,i=t.length,o=Math.min(i,a);o&&this.parse(0,o),i>a?this._insertElements(a,i-a,e):i{for(e.length+=t,r=e.length-1;r>=o;r--)e[r]=e[r-t]};for(s(i),r=e;r{a[e]=n[e]&&n[e].active()?n[e]._to:this[e]}),a}}function Da(e,t){const n=e.options.ticks,i=function(e){const t=e.options.offset,n=e._tickSize(),a=e._length/n+(t?0:1),i=e._maxLength/n;return Math.floor(Math.min(a,i))}(e),o=Math.min(n.maxTicksLimit||i,i),r=n.major.enabled?function(e){const t=[];let n,a;for(n=0,a=e.length;no)return function(e,t,n,a){let i,o=0,r=n[0];for(a=Math.ceil(a),i=0;ii)return t}return Math.max(i,1)}(r,t,o);if(s>0){let e,n;const i=s>1?Math.round((u-l)/(s-1)):null;for(ja(t,c,d,a(i)?0:l-i,l),e=0,n=s-1;e"top"===t||"left"===t?e[t]+n:e[t]-n,Fa=(e,t)=>Math.min(t||e,e);function $a(e,t){const n=[],a=e.length/t,i=e.length;let o=0;for(;or+s)))return u}function Ua(e){return e.drawTicks?e.tickLength:0}function Ha(e,t){if(!e.display)return 0;const n=yn(e.font,t),a=bn(e.padding);return(i(e.text)?e.text.length:1)*n.lineHeight+a.height}function Wa(e,t,n){let a=he(e);return(n&&"right"!==t||!n&&"right"===t)&&(a=(e=>"left"===e?"right":"right"===e?"left":e)(a)),a}class Ga extends qa{constructor(e){super(),this.id=e.id,this.type=e.type,this.options=void 0,this.ctx=e.ctx,this.chart=e.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(e){this.options=e.setContext(this.getContext()),this.axis=e.axis,this._userMin=this.parse(e.min),this._userMax=this.parse(e.max),this._suggestedMin=this.parse(e.suggestedMin),this._suggestedMax=this.parse(e.suggestedMax)}parse(e,t){return e}getUserBounds(){let{_userMin:e,_userMax:t,_suggestedMin:n,_suggestedMax:a}=this;return e=s(e,Number.POSITIVE_INFINITY),t=s(t,Number.NEGATIVE_INFINITY),n=s(n,Number.POSITIVE_INFINITY),a=s(a,Number.NEGATIVE_INFINITY),{min:s(e,n),max:s(t,a),minDefined:r(e),maxDefined:r(t)}}getMinMax(e){let t,{min:n,max:a,minDefined:i,maxDefined:o}=this.getUserBounds();if(i&&o)return{min:n,max:a};const r=this.getMatchingVisibleMetas();for(let s=0,l=r.length;sa?a:n,a=i&&n>a?n:a,{min:s(n,s(a,n)),max:s(a,s(n,a))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const e=this.chart.data;return this.options.labels||(this.isHorizontal()?e.xLabels:e.yLabels)||e.labels||[]}getLabelItems(e=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(e))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(e,t,n){const{beginAtZero:a,grace:i,ticks:o}=this.options,r=o.sampleSize;this.beforeUpdate(),this.maxWidth=e,this.maxHeight=t,this._margins=n=Object.assign({left:0,right:0,top:0,bottom:0},n),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+n.left+n.right:this.height+n.top+n.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=kn(this,i,a),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const s=r=i||n<=1||!this.isHorizontal())return void(this.labelRotation=a);const u=this._getLabelSizes(),c=u.widest.width,d=u.highest.height,h=J(this.chart.width-c,0,this.maxWidth);o=e.offset?this.maxWidth/n:h/(n-1),c+6>o&&(o=h/(n-(e.offset?.5:1)),r=this.maxHeight-Ua(e.grid)-t.padding-Ha(e.title,this.chart.options.font),s=Math.sqrt(c*c+d*d),l=H(Math.min(Math.asin(J((u.highest.height+6)/o,-1,1)),Math.asin(J(r/s,-1,1))-Math.asin(J(d/s,-1,1)))),l=Math.max(a,Math.min(i,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const e={width:0,height:0},{chart:t,options:{ticks:n,title:a,grid:i}}=this,o=this._isVisible(),r=this.isHorizontal();if(o){const o=Ha(a,t.options.font);if(r?(e.width=this.maxWidth,e.height=Ua(i)+o):(e.height=this.maxHeight,e.width=Ua(i)+o),n.display&&this.ticks.length){const{first:t,last:a,widest:i,highest:o}=this._getLabelSizes(),s=2*n.padding,l=U(this.labelRotation),u=Math.cos(l),c=Math.sin(l);if(r){const t=n.mirror?0:c*i.width+u*o.height;e.height=Math.min(this.maxHeight,e.height+t+s)}else{const t=n.mirror?0:u*i.width+c*o.height;e.width=Math.min(this.maxWidth,e.width+t+s)}this._calculatePadding(t,a,c,u)}}this._handleMargins(),r?(this.width=this._length=t.width-this._margins.left-this._margins.right,this.height=e.height):(this.width=e.width,this.height=this._length=t.height-this._margins.top-this._margins.bottom)}_calculatePadding(e,t,n,a){const{ticks:{align:i,padding:o},position:r}=this.options,s=0!==this.labelRotation,l="top"!==r&&"x"===this.axis;if(this.isHorizontal()){const r=this.getPixelForTick(0)-this.left,u=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;s?l?(c=a*e.width,d=n*t.height):(c=n*e.height,d=a*t.width):"start"===i?d=t.width:"end"===i?c=e.width:"inner"!==i&&(c=e.width/2,d=t.width/2),this.paddingLeft=Math.max((c-r+o)*this.width/(this.width-r),0),this.paddingRight=Math.max((d-u+o)*this.width/(this.width-u),0)}else{let n=t.height/2,a=e.height/2;"start"===i?(n=0,a=e.height):"end"===i&&(n=t.height,a=0),this.paddingTop=n+o,this.paddingBottom=a+o}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:e,position:t}=this.options;return"top"===t||"bottom"===t||"x"===e}isFullSize(){return this.options.fullSize}_convertTicksToLabels(e){let t,n;for(this.beforeTickToLabelConversion(),this.generateTickLabels(e),t=0,n=e.length;t{const n=e.gc,a=n.length/2;let i;if(a>t){for(i=0;i({width:s[e]||0,height:l[e]||0});return{first:T(0),last:T(t-1),widest:T(S),highest:T(C),widths:s,heights:l}}getLabelForValue(e){return e}getPixelForValue(e,t){return NaN}getValueForPixel(e){}getPixelForTick(e){const t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e].value)}getPixelForDecimal(e){this._reversePixels&&(e=1-e);const t=this._startPixel+e*this._length;return X(this._alignToPixels?St(this.chart,t,0):t)}getDecimalForPixel(e){const t=(e-this._startPixel)/this._length;return this._reversePixels?1-t:t}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:e,max:t}=this;return e<0&&t<0?t:e>0&&t>0?e:0}getContext(e){const t=this.ticks||[];if(e>=0&&er*a?r/n:s/a:s*a0}_computeGridLineItems(e){const t=this.axis,n=this.chart,a=this.options,{grid:i,position:r,border:s}=a,u=i.offset,c=this.isHorizontal(),d=this.ticks.length+(u?1:0),h=Ua(i),p=[],f=s.setContext(this.getContext()),m=f.display?f.width:0,g=m/2,_=function(e){return St(n,e,m)};let v,b,y,w,k,x,S,C,T,P,E,A;if("top"===r)v=_(this.bottom),x=this.bottom-h,C=v-g,P=_(e.top)+g,A=e.bottom;else if("bottom"===r)v=_(this.top),P=e.top,A=_(e.bottom)-g,x=v+g,C=this.top+h;else if("left"===r)v=_(this.right),k=this.right-h,S=v-g,T=_(e.left)+g,E=e.right;else if("right"===r)v=_(this.left),T=e.left,E=_(e.right)-g,k=v+g,S=this.left+h;else if("x"===t){if("center"===r)v=_((e.top+e.bottom)/2+.5);else if(o(r)){const e=Object.keys(r)[0],t=r[e];v=_(this.chart.scales[e].getPixelForValue(t))}P=e.top,A=e.bottom,x=v+g,C=x+h}else if("y"===t){if("center"===r)v=_((e.left+e.right)/2);else if(o(r)){const e=Object.keys(r)[0],t=r[e];v=_(this.chart.scales[e].getPixelForValue(t))}k=v-g,S=k-h,T=e.left,E=e.right}const M=l(a.ticks.maxTicksLimit,d),L=Math.max(1,Math.ceil(d/M));for(b=0;b0&&(o-=a/2)}d={left:o,top:i,width:a+t.width,height:n+t.height,color:e.backdropColor}}_.push({label:w,font:T,textOffset:A,options:{rotation:g,color:n,strokeColor:o,strokeWidth:u,textAlign:p,textBaseline:M,translation:[k,x],backdrop:d}})}return _}_getXAxisLabelAlignment(){const{position:e,ticks:t}=this.options;if(-U(this.labelRotation))return"top"===e?"left":"right";let n="center";return"start"===t.align?n="left":"end"===t.align?n="right":"inner"===t.align&&(n="inner"),n}_getYAxisLabelAlignment(e){const{position:t,ticks:{crossAlign:n,mirror:a,padding:i}}=this.options,o=e+i,r=this._getLabelSizes().widest.width;let s,l;return"left"===t?a?(l=this.right+i,"near"===n?s="left":"center"===n?(s="center",l+=r/2):(s="right",l+=r)):(l=this.right-o,"near"===n?s="right":"center"===n?(s="center",l-=r/2):(s="left",l=this.left)):"right"===t?a?(l=this.left+i,"near"===n?s="right":"center"===n?(s="center",l-=r/2):(s="left",l-=r)):(l=this.left+o,"near"===n?s="left":"center"===n?(s="center",l+=r/2):(s="right",l=this.right)):s="right",{textAlign:s,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const e=this.chart,t=this.options.position;return"left"===t||"right"===t?{top:0,left:this.left,bottom:e.height,right:this.right}:"top"===t||"bottom"===t?{top:this.top,left:0,bottom:this.bottom,right:e.width}:void 0}drawBackground(){const{ctx:e,options:{backgroundColor:t},left:n,top:a,width:i,height:o}=this;t&&(e.save(),e.fillStyle=t,e.fillRect(n,a,i,o),e.restore())}getLineWidthForValue(e){const t=this.options.grid;if(!this._isVisible()||!t.display)return 0;const n=this.ticks.findIndex(t=>t.value===e);return n>=0?t.setContext(this.getContext(n)).lineWidth:0}drawGrid(e){const t=this.options.grid,n=this.ctx,a=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(e));let i,o;const r=(e,t,a)=>{a.width&&a.color&&(n.save(),n.lineWidth=a.width,n.strokeStyle=a.color,n.setLineDash(a.borderDash||[]),n.lineDashOffset=a.borderDashOffset,n.beginPath(),n.moveTo(e.x,e.y),n.lineTo(t.x,t.y),n.stroke(),n.restore())};if(t.display)for(i=0,o=a.length;i{this.drawBackground(),this.drawGrid(e),this.drawTitle()}},{z:a,draw:()=>{this.drawBorder()}},{z:t,draw:e=>{this.drawLabels(e)}}]:[{z:t,draw:e=>{this.draw(e)}}]}getMatchingVisibleMetas(e){const t=this.chart.getSortedVisibleDatasetMetas(),n=this.axis+"AxisID",a=[];let i,o;for(i=0,o=t.length;i{const a=n.split("."),i=a.pop(),o=[e].concat(a).join("."),r=t[n].split("."),s=r.pop(),l=r.join(".");st.route(o,i,l,s)})}(t,e.defaultRoutes),e.descriptors&&st.describe(t,e.descriptors)}(e,o,n),this.override&&st.override(e.id,e.overrides)),o}get(e){return this.items[e]}unregister(e){const t=this.items,n=e.id,a=this.scope;n in t&&delete t[n],a&&n in st[a]&&(delete st[a][n],this.override&&delete at[n])}}var Ya=new class{constructor(){this.controllers=new Ka(Ia,"datasets",!0),this.elements=new Ka(qa,"elements"),this.plugins=new Ka(Object,"plugins"),this.scales=new Ka(Ga,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...e){this._each("register",e)}remove(...e){this._each("unregister",e)}addControllers(...e){this._each("register",e,this.controllers)}addElements(...e){this._each("register",e,this.elements)}addPlugins(...e){this._each("register",e,this.plugins)}addScales(...e){this._each("register",e,this.scales)}getController(e){return this._get(e,this.controllers,"controller")}getElement(e){return this._get(e,this.elements,"element")}getPlugin(e){return this._get(e,this.plugins,"plugin")}getScale(e){return this._get(e,this.scales,"scale")}removeControllers(...e){this._each("unregister",e,this.controllers)}removeElements(...e){this._each("unregister",e,this.elements)}removePlugins(...e){this._each("unregister",e,this.plugins)}removeScales(...e){this._each("unregister",e,this.scales)}_each(e,t,n){[...t].forEach(t=>{const a=n||this._getRegistryForType(t);n||a.isForType(t)||a===this.plugins&&t.id?this._exec(e,a,t):h(t,t=>{const a=n||this._getRegistryForType(t);this._exec(e,a,t)})})}_exec(e,t,n){const a=x(e);d(n["before"+a],[],n),t[e](n),d(n["after"+a],[],n)}_getRegistryForType(e){for(let t=0;te.filter(e=>!t.some(t=>e.plugin.id===t.plugin.id));this._notify(a(t,n),e,"stop"),this._notify(a(n,t),e,"start")}}function Za(e,t){return t||!1!==e?!0===e?{}:e:null}function Ja(e,{plugin:t,local:n},a,i){const o=e.pluginScopeKeys(t),r=e.getOptionScopes(a,o);return n&&t.defaults&&r.push(t.defaults),e.createResolver(r,i,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function Xa(e,t){const n=st.datasets[e]||{};return((t.datasets||{})[e]||{}).indexAxis||t.indexAxis||n.indexAxis||"x"}function ei(e){if("x"===e||"y"===e||"r"===e)return e}function ti(e,...t){if(ei(e))return e;for(const a of t){const t=a.axis||("top"===(n=a.position)||"bottom"===n?"x":"left"===n||"right"===n?"y":void 0)||e.length>1&&ei(e[0].toLowerCase());if(t)return t}var n;throw new Error(`Cannot determine type of '${e}' axis. Please provide 'axis' or 'position' option.`)}function ni(e,t,n){if(n[t+"AxisID"]===e)return{axis:t}}function ai(e){const t=e.options||(e.options={});t.plugins=l(t.plugins,{}),t.scales=function(e,t){const n=at[e.type]||{scales:{}},a=t.scales||{},i=Xa(e.type,t),r=Object.create(null);return Object.keys(a).forEach(t=>{const s=a[t];if(!o(s))return console.error(`Invalid scale configuration for scale: ${t}`);if(s._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);const l=ti(t,s,function(e,t){if(t.data&&t.data.datasets){const n=t.data.datasets.filter(t=>t.xAxisID===e||t.yAxisID===e);if(n.length)return ni(e,"x",n[0])||ni(e,"y",n[0])}return{}}(t,e),st.scales[s.type]),u=function(e,t){return e===t?"_index_":"_value_"}(l,i),c=n.scales||{};r[t]=v(Object.create(null),[{axis:l},s,c[l],c[u]])}),e.data.datasets.forEach(n=>{const i=n.type||e.type,o=n.indexAxis||Xa(i,t),s=(at[i]||{}).scales||{};Object.keys(s).forEach(e=>{const t=function(e,t){let n=e;return"_index_"===e?n=t:"_value_"===e&&(n="x"===t?"y":"x"),n}(e,o),i=n[t+"AxisID"]||t;r[i]=r[i]||Object.create(null),v(r[i],[{axis:t},a[i],s[e]])})}),Object.keys(r).forEach(e=>{const t=r[e];v(t,[st.scales[t.type],st.scale])}),r}(e,t)}function ii(e){return(e=e||{}).datasets=e.datasets||[],e.labels=e.labels||[],e}const oi=new Map,ri=new Set;function si(e,t){let n=oi.get(e);return n||(n=t(),oi.set(e,n),ri.add(n)),n}const li=(e,t,n)=>{const a=k(t,n);void 0!==a&&e.add(a)};class ui{constructor(e){this._config=function(e){return(e=e||{}).data=ii(e.data),ai(e),e}(e),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(e){this._config.type=e}get data(){return this._config.data}set data(e){this._config.data=ii(e)}get options(){return this._config.options}set options(e){this._config.options=e}get plugins(){return this._config.plugins}update(){const e=this._config;this.clearCache(),ai(e)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(e){return si(e,()=>[[`datasets.${e}`,""]])}datasetAnimationScopeKeys(e,t){return si(`${e}.transition.${t}`,()=>[[`datasets.${e}.transitions.${t}`,`transitions.${t}`],[`datasets.${e}`,""]])}datasetElementScopeKeys(e,t){return si(`${e}-${t}`,()=>[[`datasets.${e}.elements.${t}`,`datasets.${e}`,`elements.${t}`,""]])}pluginScopeKeys(e){const t=e.id;return si(`${this.type}-plugin-${t}`,()=>[[`plugins.${t}`,...e.additionalOptionScopes||[]]])}_cachedScopes(e,t){const n=this._scopeCache;let a=n.get(e);return a&&!t||(a=new Map,n.set(e,a)),a}getOptionScopes(e,t,n){const{options:a,type:i}=this,o=this._cachedScopes(e,n),r=o.get(t);if(r)return r;const s=new Set;t.forEach(t=>{e&&(s.add(e),t.forEach(t=>li(s,e,t))),t.forEach(e=>li(s,a,e)),t.forEach(e=>li(s,at[i]||{},e)),t.forEach(e=>li(s,st,e)),t.forEach(e=>li(s,it,e))});const l=Array.from(s);return 0===l.length&&l.push(Object.create(null)),ri.has(t)&&o.set(t,l),l}chartOptionScopes(){const{options:e,type:t}=this;return[e,at[t]||{},st.datasets[t]||{},{type:t},st,it]}resolveNamedOptions(e,t,n,a=[""]){const o={$shared:!0},{resolver:r,subPrefixes:s}=ci(this._resolverCache,e,a);let l=r;(function(e,t){const{isScriptable:n,isIndexable:a}=jt(e);for(const o of t){const t=n(o),r=a(o),s=(r||t)&&e[o];if(t&&(C(s)||di(s))||r&&i(s))return!0}return!1})(r,t)&&(o.$shared=!1,l=Dt(r,n=C(n)?n():n,this.createResolver(e,n,s)));for(const e of t)o[e]=l[e];return o}createResolver(e,t,n=[""],a){const{resolver:i}=ci(this._resolverCache,e,n);return o(t)?Dt(i,t,void 0,a):i}}function ci(e,t,n){let a=e.get(t);a||(a=new Map,e.set(t,a));const i=n.join();let o=a.get(i);return o||(o={resolver:qt(t,n),subPrefixes:n.filter(e=>!e.toLowerCase().includes("hover"))},a.set(i,o)),o}const di=e=>o(e)&&Object.getOwnPropertyNames(e).some(t=>C(e[t])),hi=["top","bottom","left","right","chartArea"];function pi(e,t){return"top"===e||"bottom"===e||-1===hi.indexOf(e)&&"x"===t}function fi(e,t){return function(n,a){return n[e]===a[e]?n[t]-a[t]:n[e]-a[e]}}function mi(e){const t=e.chart,n=t.options.animation;t.notifyPlugins("afterRender"),d(n&&n.onComplete,[e],t)}function gi(e){const t=e.chart,n=t.options.animation;d(n&&n.onProgress,[e],t)}function _i(e){return lt()&&"string"==typeof e?e=document.getElementById(e):e&&e.length&&(e=e[0]),e&&e.canvas&&(e=e.canvas),e}const vi={},bi=e=>{const t=_i(e);return Object.values(vi).filter(e=>e.canvas===t).pop()};function yi(e,t,n){const a=Object.keys(e);for(const i of a){const a=+i;if(a>=t){const o=e[i];delete e[i],(n>0||a>t)&&(e[a+n]=o)}}}class wi{static defaults=st;static instances=vi;static overrides=at;static registry=Ya;static version="4.5.1";static getChart=bi;static register(...e){Ya.add(...e),ki()}static unregister(...e){Ya.remove(...e),ki()}constructor(e,t){const a=this.config=new ui(t),i=_i(e),o=bi(i);if(o)throw new Error("Canvas is already in use. Chart with ID '"+o.id+"' must be destroyed before the canvas with ID '"+o.canvas.id+"' can be reused.");const r=a.createResolver(a.chartOptionScopes(),this.getContext());this.platform=new(a.platform||ba(i)),this.platform.updateConfig(a);const s=this.platform.acquireContext(i,r.aspectRatio),l=s&&s.canvas,u=l&&l.height,c=l&&l.width;this.id=n(),this.ctx=s,this.canvas=l,this.width=c,this.height=u,this._options=r,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Qa,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=de(e=>this.update(e),r.resizeDelay||0),this._dataChanges=[],vi[this.id]=this,s&&l?(_e.listen(this,"complete",mi),_e.listen(this,"progress",gi),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:e,maintainAspectRatio:t},width:n,height:i,_aspectRatio:o}=this;return a(e)?t&&o?o:i?n/i:null:e}get data(){return this.config.data}set data(e){this.config.data=e}get options(){return this._options}set options(e){this.config.options=e}get registry(){return Ya}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():vt(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Ct(this.canvas,this.ctx),this}stop(){return _e.stop(this),this}resize(e,t){_e.running(this)?this._resizeBeforeDraw={width:e,height:t}:this._resize(e,t)}_resize(e,t){const n=this.options,a=this.canvas,i=n.maintainAspectRatio&&this.aspectRatio,o=this.platform.getMaximumSize(a,e,t,i),r=n.devicePixelRatio||this.platform.getDevicePixelRatio(),s=this.width?"resize":"attach";this.width=o.width,this.height=o.height,this._aspectRatio=this.aspectRatio,vt(this,r,!0)&&(this.notifyPlugins("resize",{size:o}),d(n.onResize,[this,o],this),this.attached&&this._doResize(s)&&this.render())}ensureScalesHaveIDs(){h(this.options.scales||{},(e,t)=>{e.id=t})}buildOrUpdateScales(){const e=this.options,t=e.scales,n=this.scales,a=Object.keys(n).reduce((e,t)=>(e[t]=!1,e),{});let i=[];t&&(i=i.concat(Object.keys(t).map(e=>{const n=t[e],a=ti(e,n),i="r"===a,o="x"===a;return{options:n,dposition:i?"chartArea":o?"bottom":"left",dtype:i?"radialLinear":o?"category":"linear"}}))),h(i,t=>{const i=t.options,o=i.id,r=ti(o,i),s=l(i.type,t.dtype);void 0!==i.position&&pi(i.position,r)===pi(t.dposition)||(i.position=t.dposition),a[o]=!0;let u=null;o in n&&n[o].type===s?u=n[o]:(u=new(Ya.getScale(s))({id:o,type:s,ctx:this.ctx,chart:this}),n[u.id]=u),u.init(i,e)}),h(a,(e,t)=>{e||delete n[t]}),h(n,e=>{ta.configure(this,e,e.options),ta.addBox(this,e)})}_updateMetasets(){const e=this._metasets,t=this.data.datasets.length,n=e.length;if(e.sort((e,t)=>e.index-t.index),n>t){for(let e=t;et.length&&delete this._stacks,e.forEach((e,n)=>{0===t.filter(t=>t===e._dataset).length&&this._destroyDatasetMeta(n)})}buildOrUpdateControllers(){const e=[],t=this.data.datasets;let n,a;for(this._removeUnreferencedMetasets(),n=0,a=t.length;n{this.getDatasetMeta(t).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(e){const t=this.config;t.update();const n=this._options=t.createResolver(t.chartOptionScopes(),this.getContext()),a=this._animationsDisabled=!n.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:e,cancelable:!0}))return;const i=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let o=0;for(let e=0,t=this.data.datasets.length;e{e.reset()}),this._updateDatasets(e),this.notifyPlugins("afterUpdate",{mode:e}),this._layers.sort(fi("z","_idx"));const{_active:r,_lastEvent:s}=this;s?this._eventHandler(s,!0):r.length&&this._updateHoverStyles(r,r,!0),this.render()}_updateScales(){h(this.scales,e=>{ta.removeBox(this,e)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const e=this.options,t=new Set(Object.keys(this._listeners)),n=new Set(e.events);T(t,n)&&!!this._responsiveListeners===e.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:e}=this,t=this._getUniformDataChanges()||[];for(const{method:n,start:a,count:i}of t)yi(e,a,"_removeElements"===n?-i:i)}_getUniformDataChanges(){const e=this._dataChanges;if(!e||!e.length)return;this._dataChanges=[];const t=this.data.datasets.length,n=t=>new Set(e.filter(e=>e[0]===t).map((e,t)=>t+","+e.splice(1).join(","))),a=n(0);for(let e=1;ee.split(",")).map(e=>({method:e[1],start:+e[2],count:+e[3]}))}_updateLayout(e){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ta.update(this,this.width,this.height,e);const t=this.chartArea,n=t.width<=0||t.height<=0;this._layers=[],h(this.boxes,e=>{n&&"chartArea"===e.position||(e.configure&&e.configure(),this._layers.push(...e._layers()))},this),this._layers.forEach((e,t)=>{e._idx=t}),this.notifyPlugins("afterLayout")}_updateDatasets(e){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:e,cancelable:!0})){for(let e=0,t=this.data.datasets.length;e=0;--t)this._drawDataset(e[t]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(e){const t=this.ctx,n={meta:e,index:e.index,cancelable:!0},a=In(this,e);!1!==this.notifyPlugins("beforeDatasetDraw",n)&&(a&&At(t,a),e.controller.draw(),a&&Mt(t),n.cancelable=!1,this.notifyPlugins("afterDatasetDraw",n))}isPointInArea(e){return Et(e,this.chartArea,this._minPadding)}getElementsAtEventForMode(e,t,n,a){const i=Vn.modes[t];return"function"==typeof i?i(this,e,n,a):[]}getDatasetMeta(e){const t=this.data.datasets[e],n=this._metasets;let a=n.filter(e=>e&&e._dataset===t).pop();return a||(a={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:t&&t.order||0,index:e,_dataset:t,_parsed:[],_sorted:!1},n.push(a)),a}getContext(){return this.$context||(this.$context=xn(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(e){const t=this.data.datasets[e];if(!t)return!1;const n=this.getDatasetMeta(e);return"boolean"==typeof n.hidden?!n.hidden:!t.hidden}setDatasetVisibility(e,t){this.getDatasetMeta(e).hidden=!t}toggleDataVisibility(e){this._hiddenIndices[e]=!this._hiddenIndices[e]}getDataVisibility(e){return!this._hiddenIndices[e]}_updateVisibility(e,t,n){const a=n?"show":"hide",i=this.getDatasetMeta(e),o=i.controller._resolveAnimations(void 0,a);S(t)?(i.data[t].hidden=!n,this.update()):(this.setDatasetVisibility(e,n),o.update(i,{visible:n}),this.update(t=>t.datasetIndex===e?a:void 0))}hide(e,t){this._updateVisibility(e,t,!1)}show(e,t){this._updateVisibility(e,t,!0)}_destroyDatasetMeta(e){const t=this._metasets[e];t&&t.controller&&t.controller._destroy(),delete this._metasets[e]}_stop(){let e,t;for(this.stop(),_e.remove(this),e=0,t=this.data.datasets.length;e{t.addEventListener(this,n,a),e[n]=a},a=(e,t,n)=>{e.offsetX=t,e.offsetY=n,this._eventHandler(e)};h(this.options.events,e=>n(e,a))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const e=this._responsiveListeners,t=this.platform,n=(n,a)=>{t.addEventListener(this,n,a),e[n]=a},a=(n,a)=>{e[n]&&(t.removeEventListener(this,n,a),delete e[n])},i=(e,t)=>{this.canvas&&this.resize(e,t)};let o;const r=()=>{a("attach",r),this.attached=!0,this.resize(),n("resize",i),n("detach",o)};o=()=>{this.attached=!1,a("resize",i),this._stop(),this._resize(0,0),n("attach",r)},t.isAttached(this.canvas)?r():o()}unbindEvents(){h(this._listeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._listeners={},h(this._responsiveListeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._responsiveListeners=void 0}updateHoverStyle(e,t,n){const a=n?"set":"remove";let i,o,r,s;for("dataset"===t&&(i=this.getDatasetMeta(e[0].datasetIndex),i.controller["_"+a+"DatasetHoverStyle"]()),r=0,s=e.length;r{const n=this.getDatasetMeta(e);if(!n)throw new Error("No dataset found at index "+e);return{datasetIndex:e,element:n.data[t],index:t}});!p(n,t)&&(this._active=n,this._lastEvent=null,this._updateHoverStyles(n,t))}notifyPlugins(e,t,n){return this._plugins.notify(this,e,t,n)}isPluginEnabled(e){return 1===this._plugins._cache.filter(t=>t.plugin.id===e).length}_updateHoverStyles(e,t,n){const a=this.options.hover,i=(e,t)=>e.filter(e=>!t.some(t=>e.datasetIndex===t.datasetIndex&&e.index===t.index)),o=i(t,e),r=n?e:i(e,t);o.length&&this.updateHoverStyle(o,a.mode,!1),r.length&&a.mode&&this.updateHoverStyle(r,a.mode,!0)}_eventHandler(e,t){const n={event:e,replay:t,cancelable:!0,inChartArea:this.isPointInArea(e)},a=t=>(t.options.events||this.options.events).includes(e.native.type);if(!1===this.notifyPlugins("beforeEvent",n,a))return;const i=this._handleEvent(e,t,n.inChartArea);return n.cancelable=!1,this.notifyPlugins("afterEvent",n,a),(i||n.changed)&&this.render(),this}_handleEvent(e,t,n){const{_active:a=[],options:i}=this,o=t,r=this._getActiveElements(e,a,n,o),s=P(e),l=function(e,t,n,a){return n&&"mouseout"!==e.type?a?t:e:null}(e,this._lastEvent,n,s);n&&(this._lastEvent=null,d(i.onHover,[e,r,this],this),s&&d(i.onClick,[e,r,this],this));const u=!p(r,a);return(u||t)&&(this._active=r,this._updateHoverStyles(r,a,t)),this._lastEvent=l,u}_getActiveElements(e,t,n,a){if("mouseout"===e.type)return[];if(!n)return t;const i=this.options.hover;return this.getElementsAtEventForMode(e,i.mode,i,a)}}function ki(){return h(wi.instances,e=>e._plugins.invalidate())}function xi(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Si{static override(e){Object.assign(Si.prototype,e)}options;constructor(e){this.options=e||{}}init(){}formats(){return xi()}parse(){return xi()}format(){return xi()}add(){return xi()}diff(){return xi()}startOf(){return xi()}endOf(){return xi()}}var Ci={_date:Si};function Ti(e){const t=e.iScale,n=function(e,t){if(!e._cache.$bar){const n=e.getMatchingVisibleMetas(t);let a=[];for(let t=0,i=n.length;te-t))}return e._cache.$bar}(t,e.type);let a,i,o,r,s=t._length;const l=()=>{32767!==o&&-32768!==o&&(S(r)&&(s=Math.min(s,Math.abs(o-r)||s)),r=o)};for(a=0,i=n.length;aMath.abs(s)&&(l=s,u=r),t[n.axis]=u,t._custom={barStart:l,barEnd:u,start:i,end:o,min:r,max:s}}(e,t,n,a):t[n.axis]=n.parse(e,a),t}function Ei(e,t,n,a){const i=e.iScale,o=e.vScale,r=i.getLabels(),s=i===o,l=[];let u,c,d,h;for(u=n,c=n+a;ue.x,n="left",a="right"):(t=e.base"spacing"!==e,_indexable:e=>"spacing"!==e&&!e.startsWith("borderDash")&&!e.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(e){const t=e.data,{labels:{pointStyle:n,textAlign:a,color:i,useBorderRadius:o,borderRadius:r}}=e.legend.options;return t.labels.length&&t.datasets.length?t.labels.map((t,s)=>{const l=e.getDatasetMeta(0).controller.getStyle(s);return{text:t,fillStyle:l.backgroundColor,fontColor:i,hidden:!e.getDataVisibility(s),lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:l.borderWidth,strokeStyle:l.borderColor,textAlign:a,pointStyle:n,borderRadius:o&&(r||l.borderRadius),index:s}}):[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}}};constructor(e,t){super(e,t),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(e,t){const n=this.getDataset().data,a=this._cachedMeta;if(!1===this._parsing)a._parsed=n;else{let i,r,s=e=>+n[e];if(o(n[e])){const{key:e="value"}=this._parsing;s=t=>+k(n[t],e)}for(i=e,r=e+t;iZ(e,s,l,!0)?1:Math.max(t,t*n,a,a*n),f=(e,t,a)=>Z(e,s,l,!0)?-1:Math.min(t,t*n,a,a*n),m=p(0,u,d),g=p(z,c,h),_=f(E,u,d),v=f(E+z,c,h);a=(m-_)/2,i=(g-v)/2,o=-(m+_)/2,r=-(g+v)/2}return{ratioX:a,ratioY:i,offsetX:o,offsetY:r}}(h,d,s),_=(n.width-o)/p,v=(n.height-o)/f,b=Math.max(Math.min(_,v)/2,0),y=c(this.options.radius,b),w=(y-Math.max(y*s,0))/this._getVisibleDatasetWeightTotal();this.offsetX=m*y,this.offsetY=g*y,a.total=this.calculateTotal(),this.outerRadius=y-w*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-w*l,0),this.updateElements(i,0,i.length,e)}_circumference(e,t){const n=this.options,a=this._cachedMeta,i=this._getCircumference();return t&&n.animation.animateRotate||!this.chart.getDataVisibility(e)||null===a._parsed[e]||a.data[e].hidden?0:this.calculateCircumference(a._parsed[e]*i/A)}updateElements(e,t,n,a){const i="reset"===a,o=this.chart,r=o.chartArea,s=o.options.animation,l=(r.left+r.right)/2,u=(r.top+r.bottom)/2,c=i&&s.animateScale,d=c?0:this.innerRadius,h=c?0:this.outerRadius,{sharedOptions:p,includeOptions:f}=this._getSharedOptions(t,a);let m,g=this._getRotation();for(m=0;m0&&!isNaN(e)?A*(Math.abs(e)/t):0}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart,a=n.data.labels||[],i=et(t._parsed[e],n.options.locale);return{label:a[e]||"",value:i}}getMaxBorderWidth(e){let t=0;const n=this.chart;let a,i,o,r,s;if(!e)for(a=0,i=n.data.datasets.length;a{const o=e.getDatasetMeta(0).controller.getStyle(i);return{text:t,fillStyle:o.backgroundColor,strokeStyle:o.borderColor,fontColor:a,lineWidth:o.borderWidth,pointStyle:n,hidden:!e.getDataVisibility(i),index:i}})}return[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(e,t){super(e,t),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart,a=n.data.labels||[],i=et(t._parsed[e].r,n.options.locale);return{label:a[e]||"",value:i}}parseObjectData(e,t,n,a){return Qt.bind(this)(e,t,n,a)}update(e){const t=this._cachedMeta.data;this._updateRadius(),this.updateElements(t,0,t.length,e)}getMinMax(){const e=this._cachedMeta,t={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return e.data.forEach((e,n)=>{const a=this.getParsed(n).r;!isNaN(a)&&this.chart.getDataVisibility(n)&&(at.max&&(t.max=a))}),t}_updateRadius(){const e=this.chart,t=e.chartArea,n=e.options,a=Math.min(t.right-t.left,t.bottom-t.top),i=Math.max(a/2,0),o=(i-Math.max(n.cutoutPercentage?i/100*n.cutoutPercentage:1,0))/e.getVisibleDatasetCount();this.outerRadius=i-o*this.index,this.innerRadius=this.outerRadius-o}updateElements(e,t,n,a){const i="reset"===a,o=this.chart,r=o.options.animation,s=this._cachedMeta.rScale,l=s.xCenter,u=s.yCenter,c=s.getIndexAngle(0)-.5*E;let d,h=c;const p=360/this.countVisibleElements();for(d=0;d{!isNaN(this.getParsed(n).r)&&this.chart.getDataVisibility(n)&&t++}),t}_computeAngle(e,t,n){return this.chart.getDataVisibility(e)?U(this.resolveDataElementOptions(e,t).angle||n):0}}var Ii=Object.freeze({__proto__:null,BarController:class extends Ia{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(e,t,n,a){return Ei(e,t,n,a)}parseArrayData(e,t,n,a){return Ei(e,t,n,a)}parseObjectData(e,t,n,a){const{iScale:i,vScale:o}=e,{xAxisKey:r="x",yAxisKey:s="y"}=this._parsing,l="x"===i.axis?r:s,u="x"===o.axis?r:s,c=[];let d,h,p,f;for(d=n,h=n+a;de.controller.options.grouped),o=n.options.stacked,r=[],s=this._cachedMeta.controller.getParsed(t),l=s&&s[n.axis],u=e=>{const t=e._parsed.find(e=>e[n.axis]===l),i=t&&t[e.vScale.axis];if(a(i)||isNaN(i))return!0};for(const n of i)if((void 0===t||!u(n))&&((!1===o||-1===r.indexOf(n.stack)||void 0===o&&void 0===n.stack)&&r.push(n.stack),n.index===e))break;return r.length||r.push(void 0),r}_getStackCount(e){return this._getStacks(void 0,e).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){const e=this.chart.scales,t=this.chart.options.indexAxis;return Object.keys(e).filter(n=>e[n].axis===t).shift()}_getAxis(){const e={},t=this.getFirstScaleIdForIndexAxis();for(const n of this.chart.data.datasets)e[l("x"===this.chart.options.indexAxis?n.xAxisID:n.yAxisID,t)]=!0;return Object.keys(e)}_getStackIndex(e,t,n){const a=this._getStacks(e,n),i=void 0!==t?a.indexOf(t):-1;return-1===i?a.length-1:i}_getRuler(){const e=this.options,t=this._cachedMeta,n=t.iScale,a=[];let i,o;for(i=0,o=t.data.length;i=n?1:-1)}(h,t,s)*r,p===s&&(_-=h/2);const e=t.getPixelForDecimal(0),a=t.getPixelForDecimal(1),o=Math.min(e,a),u=Math.max(e,a);_=Math.max(Math.min(_,u),o),d=_+h,n&&!c&&(l._stacks[t.axis]._visualValues[i]=t.getValueForPixel(d)-t.getValueForPixel(_))}if(_===t.getPixelForValue(s)){const e=q(h)*t.getLineWidthForValue(s)/2;_+=e,h-=e}return{size:h,base:_,head:d,center:d+h/2}}_calculateBarIndexPixels(e,t){const n=t.scale,i=this.options,o=i.skipNull,r=l(i.maxBarThickness,1/0);let s,u;const c=this._getAxisCount();if(t.grouped){const n=o?this._getStackCount(e):t.stackCount,d="flex"===i.barThickness?function(e,t,n,a){const i=t.pixels,o=i[e];let r=e>0?i[e-1]:null,s=e=0;--n)t=Math.max(t,e[n].size(this.resolveDataElementOptions(n))/2);return t>0&&t}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart.data.labels||[],{xScale:a,yScale:i}=t,o=this.getParsed(e),r=a.getLabelForValue(o.x),s=i.getLabelForValue(o.y),l=o._custom;return{label:n[e]||"",value:"("+r+", "+s+(l?", "+l:"")+")"}}update(e){const t=this._cachedMeta.data;this.updateElements(t,0,t.length,e)}updateElements(e,t,n,a){const i="reset"===a,{iScale:o,vScale:r}=this._cachedMeta,{sharedOptions:s,includeOptions:l}=this._getSharedOptions(t,a),u=o.axis,c=r.axis;for(let d=t;d0&&this.getParsed(t-1);for(let n=0;n=v){b.skip=!0;continue}const w=this.getParsed(n),k=a(w[p]),x=b[h]=r.getPixelForValue(w[h],n),S=b[p]=o||k?s.getBasePixel():s.getPixelForValue(l?this.applyStack(s,w,l):w[p],n);b.skip=isNaN(x)||isNaN(S)||k,b.stop=n>0&&Math.abs(w[h]-y[h])>g,m&&(b.parsed=w,b.raw=u.data[n]),d&&(b.options=c||this.resolveDataElementOptions(n,f.active?"active":i)),_||this.updateElement(f,n,b,i),y=w}}getMaxOverflow(){const e=this._cachedMeta,t=e.dataset,n=t.options&&t.options.borderWidth||0,a=e.data||[];if(!a.length)return n;const i=a[0].size(this.resolveDataElementOptions(0)),o=a[a.length-1].size(this.resolveDataElementOptions(a.length-1));return Math.max(n,i,o)/2}draw(){const e=this._cachedMeta;e.dataset.updateControlPoints(this.chart.chartArea,e.iScale.axis),super.draw()}},PieController:class extends Ni{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:Oi,RadarController:class extends Ia{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(e){const t=this._cachedMeta.vScale,n=this.getParsed(e);return{label:t.getLabels()[e],value:""+t.getLabelForValue(n[t.axis])}}parseObjectData(e,t,n,a){return Qt.bind(this)(e,t,n,a)}update(e){const t=this._cachedMeta,n=t.dataset,a=t.data||[],i=t.iScale.getLabels();if(n.points=a,"resize"!==e){const t=this.resolveDatasetElementOptions(e);this.options.showLine||(t.borderWidth=0);const o={_loop:!0,_fullLoop:i.length===a.length,options:t};this.updateElement(n,void 0,o,e)}this.updateElements(a,0,a.length,e)}updateElements(e,t,n,a){const i=this._cachedMeta.rScale,o="reset"===a;for(let r=t;r0&&this.getParsed(t-1);for(let c=t;c0&&Math.abs(n[p]-b[p])>_,g&&(m.parsed=n,m.raw=u.data[c]),h&&(m.options=d||this.resolveDataElementOptions(c,t.active?"active":i)),v||this.updateElement(t,c,m,i),b=n}this.updateSharedOptions(d,i,c)}getMaxOverflow(){const e=this._cachedMeta,t=e.data||[];if(!this.options.showLine){let e=0;for(let n=t.length-1;n>=0;--n)e=Math.max(e,t[n].size(this.resolveDataElementOptions(n))/2);return e>0&&e}const n=e.dataset,a=n.options&&n.options.borderWidth||0;if(!t.length)return a;const i=t[0].size(this.resolveDataElementOptions(0)),o=t[t.length-1].size(this.resolveDataElementOptions(t.length-1));return Math.max(a,i,o)/2}}});function qi(e,t,n,a){return{x:n+e*Math.cos(t),y:a+e*Math.sin(t)}}function Di(e,t,n,a,i,o){const{x:r,y:s,startAngle:l,pixelMargin:u,innerRadius:c}=t,d=Math.max(t.outerRadius+a+n-u,0),h=c>0?c+a+n+u:0;let p=0;const f=i-l;if(a){const e=((c>0?c-a:0)+(d>0?d-a:0))/2;p=(f-(0!==e?f*e/(e+a):f))/2}const m=(f-Math.max(.001,f*d-n/E)/d)/2,g=l+m+p,_=i-m-p,{outerStart:v,outerEnd:b,innerStart:y,innerEnd:w}=function(e,t,n,a){const i=gn(e.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]),o=(n-t)/2,r=Math.min(o,a*t/2),s=e=>{const t=(n-Math.min(o,e))*a/2;return J(e,0,Math.min(o,t))};return{outerStart:s(i.outerStart),outerEnd:s(i.outerEnd),innerStart:J(i.innerStart,0,r),innerEnd:J(i.innerEnd,0,r)}}(t,h,d,_-g),k=d-v,x=d-b,S=g+v/k,C=_-b/x,T=h+y,P=h+w,A=g+y/T,M=_-w/P;if(e.beginPath(),o){const t=(S+C)/2;if(e.arc(r,s,d,S,t),e.arc(r,s,d,t,C),b>0){const t=qi(x,C,r,s);e.arc(t.x,t.y,b,C,_+z)}const n=qi(P,_,r,s);if(e.lineTo(n.x,n.y),w>0){const t=qi(P,M,r,s);e.arc(t.x,t.y,w,_+z,M+Math.PI)}const a=(_-w/h+(g+y/h))/2;if(e.arc(r,s,h,_-w/h,a,!0),e.arc(r,s,h,a,g+y/h,!0),y>0){const t=qi(T,A,r,s);e.arc(t.x,t.y,y,A+Math.PI,g-z)}const i=qi(k,g,r,s);if(e.lineTo(i.x,i.y),v>0){const t=qi(k,S,r,s);e.arc(t.x,t.y,v,g-z,S)}}else{e.moveTo(r,s);const t=Math.cos(S)*d+r,n=Math.sin(S)*d+s;e.lineTo(t,n);const a=Math.cos(C)*d+r,i=Math.sin(C)*d+s;e.lineTo(a,i)}e.closePath()}function ji(e,t,n=t){e.lineCap=l(n.borderCapStyle,t.borderCapStyle),e.setLineDash(l(n.borderDash,t.borderDash)),e.lineDashOffset=l(n.borderDashOffset,t.borderDashOffset),e.lineJoin=l(n.borderJoinStyle,t.borderJoinStyle),e.lineWidth=l(n.borderWidth,t.borderWidth),e.strokeStyle=l(n.borderColor,t.borderColor)}function Bi(e,t,n){e.lineTo(n.x,n.y)}function Fi(e,t,n={}){const a=e.length,{start:i=0,end:o=a-1}=n,{start:r,end:s}=t,l=Math.max(i,r),u=Math.min(o,s),c=is&&o>s;return{count:a,start:l,loop:t.loop,ilen:u(r+(u?s-e:e))%o,b=()=>{p!==f&&(e.lineTo(g,f),e.lineTo(g,p),e.lineTo(g,m))};for(l&&(d=i[v(0)],e.moveTo(d.x,d.y)),c=0;c<=s;++c){if(d=i[v(c)],d.skip)continue;const t=d.x,n=d.y,a=0|t;a===h?(nf&&(f=n),g=(_*g+t)/++_):(b(),e.lineTo(t,n),h=a,_=0,p=f=n),m=n}b()}function Ui(e){const t=e.options,n=t.borderDash&&t.borderDash.length;return e._decimated||e._loop||t.tension||"monotone"===t.cubicInterpolationMode||t.stepped||n?$i:Vi}const Hi="function"==typeof Path2D;class Wi extends qa{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:e=>"borderDash"!==e&&"fill"!==e};constructor(e){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,e&&Object.assign(this,e)}updateControlPoints(e,t){const n=this.options;if((n.tension||"monotone"===n.cubicInterpolationMode)&&!n.stepped&&!this._pointsUpdated){const a=n.spanGaps?this._loop:this._fullLoop;an(this._points,n,e,a,t),this._pointsUpdated=!0}}set points(e){this._points=e,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Ln(this,this.options.segment))}first(){const e=this.segments,t=this.points;return e.length&&t[e[0].start]}last(){const e=this.segments,t=this.points,n=e.length;return n&&t[e[n-1].end]}interpolate(e,t){const n=this.options,a=e[t],i=this.points,o=Mn(this,{property:t,start:a,end:a});if(!o.length)return;const r=[],s=function(e){return e.stepped?cn:e.tension||"monotone"===e.cubicInterpolationMode?dn:un}(n);let l,u;for(l=0,u=o.length;l"borderDash"!==e};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(e){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,e&&Object.assign(this,e)}inRange(e,t,n){const a=this.getProps(["x","y"],n),{angle:i,distance:o}=G(a,{x:e,y:t}),{startAngle:r,endAngle:s,innerRadius:u,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],n),h=(this.options.spacing+this.options.borderWidth)/2,p=l(d,s-r),f=Z(i,r,s)&&r!==s,m=p>=A||f,g=ee(o,u+h,c+h);return m&&g}getCenterPoint(e){const{x:t,y:n,startAngle:a,endAngle:i,innerRadius:o,outerRadius:r}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],e),{offset:s,spacing:l}=this.options,u=(a+i)/2,c=(o+r+l+s)/2;return{x:t+Math.cos(u)*c,y:n+Math.sin(u)*c}}tooltipPosition(e){return this.getCenterPoint(e)}draw(e){const{options:t,circumference:n}=this,a=(t.offset||0)/4,i=(t.spacing||0)/2,o=t.circular;if(this.pixelMargin="inner"===t.borderAlign?.33:0,this.fullCircles=n>A?Math.floor(n/A):0,0===n||this.innerRadius<0||this.outerRadius<0)return;e.save();const r=(this.startAngle+this.endAngle)/2;e.translate(Math.cos(r)*a,Math.sin(r)*a);const s=a*(1-Math.sin(Math.min(E,n||0)));e.fillStyle=t.backgroundColor,e.strokeStyle=t.borderColor,function(e,t,n,a,i){const{fullCircles:o,startAngle:r,circumference:s}=t;let l=t.endAngle;if(o){Di(e,t,n,a,l,i);for(let t=0;ti?(u=i/l,e.arc(o,r,l,n+u,a-u,!0)):e.arc(o,r,i,n+z,a-z),e.closePath(),e.clip()}(e,t,m),l.selfJoin&&m-r>=E&&0===p&&"miter"!==c&&function(e,t,n){const{startAngle:a,x:i,y:o,outerRadius:r,innerRadius:s,options:l}=t,{borderWidth:u,borderJoinStyle:c}=l,d=Math.min(u/r,Q(a-n));if(e.beginPath(),e.arc(i,o,r-u/2,a+d/2,n-d/2),s>0){const t=Math.min(u/s,Q(a-n));e.arc(i,o,s+u/2,n-t/2,a+t/2,!0)}else{const t=Math.min(u/2,r*Q(a-n));if("round"===c)e.arc(i,o,t,n-E/2,a+E/2,!0);else if("bevel"===c){const r=2*t*t,s=-r*Math.cos(n+E/2)+i,l=-r*Math.sin(n+E/2)+o,u=r*Math.cos(a+E/2)+i,c=r*Math.sin(a+E/2)+o;e.lineTo(s,l),e.lineTo(u,c)}}e.closePath(),e.moveTo(0,0),e.rect(0,0,e.canvas.width,e.canvas.height),e.clip("evenodd")}(e,t,m),o||(Di(e,t,n,a,m,i),e.stroke())}(e,this,s,i,o),e.restore()}},BarElement:class extends qa{static id="bar";static defaults={borderSkipped:"start",borderWidth:0,borderRadius:0,inflateAmount:"auto",pointStyle:void 0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(e){super(),this.options=void 0,this.horizontal=void 0,this.base=void 0,this.width=void 0,this.height=void 0,this.inflateAmount=void 0,e&&Object.assign(this,e)}draw(e){const{inflateAmount:t,options:{borderColor:n,backgroundColor:a}}=this,{inner:i,outer:o}=Qi(this),r=(s=o.radius).topLeft||s.topRight||s.bottomLeft||s.bottomRight?It:Ji;var s;e.save(),o.w===i.w&&o.h===i.h||(e.beginPath(),r(e,Xi(o,t,i)),e.clip(),r(e,Xi(i,-t,o)),e.fillStyle=n,e.fill("evenodd")),e.beginPath(),r(e,Xi(i,t)),e.fillStyle=a,e.fill(),e.restore()}inRange(e,t,n){return Zi(this,e,t,n)}inXRange(e,t){return Zi(this,e,null,t)}inYRange(e,t){return Zi(this,null,e,t)}getCenterPoint(e){const{x:t,y:n,base:a,horizontal:i}=this.getProps(["x","y","base","horizontal"],e);return{x:i?(t+a)/2:t,y:i?n:(n+a)/2}}getRange(e){return"x"===e?this.width/2:this.height/2}},LineElement:Wi,PointElement:class extends qa{static id="point";parsed;skip;stop;static defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3,rotation:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(e){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,e&&Object.assign(this,e)}inRange(e,t,n){const a=this.options,{x:i,y:o}=this.getProps(["x","y"],n);return Math.pow(e-i,2)+Math.pow(t-o,2)=0&&ea=t?a:e,r=e=>i=n?i:e;if(e){const e=q(a),t=q(i);e<0&&t<0?r(0):e>0&&t>0&&o(0)}if(a===i){let t=0===i?1:Math.abs(.05*i);r(i+t),e||o(a-t)}this.min=a,this.max=i}getTickLimit(){const e=this.options.ticks;let t,{maxTicksLimit:n,stepSize:a}=e;return a?(t=Math.ceil(this.max/a)-Math.floor(this.min/a)+1,t>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${a} would result generating up to ${t} ticks. Limiting to 1000.`),t=1e3)):(t=this.computeTickLimit(),n=n||11),n&&(t=Math.min(n,t)),t}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const e=this.options,t=e.ticks;let n=this.getTickLimit();n=Math.max(2,n);const i=function(e,t){const n=[],{bounds:i,step:o,min:r,max:s,precision:l,count:u,maxTicks:c,maxDigits:d,includeBounds:h}=e,p=o||1,f=c-1,{min:m,max:g}=t,_=!a(r),v=!a(s),b=!a(u),y=(g-m)/(d+1);let w,k,x,S,C=j((g-m)/f/p)*p;if(C<1e-14&&!_&&!v)return[{value:m},{value:g}];S=Math.ceil(g/C)-Math.floor(m/C),S>f&&(C=j(S*C/f/p)*p),a(l)||(w=Math.pow(10,l),C=Math.ceil(C*w)/w),"ticks"===i?(k=Math.floor(m/C)*C,x=Math.ceil(g/C)*C):(k=m,x=g),_&&v&&o&&$((s-r)/o,C/1e3)?(S=Math.round(Math.min((s-r)/C,c)),C=(s-r)/S,k=r,x=s):b?(k=_?r:k,x=v?s:x,S=u-1,C=(x-k)/S):(S=(x-k)/C,S=D(S,Math.round(S),C/1e3)?Math.round(S):Math.ceil(S));const T=Math.max(W(C),W(k));w=Math.pow(10,a(l)?T:l),k=Math.round(k*w)/w,x=Math.round(x*w)/w;let P=0;for(_&&(h&&k!==r?(n.push({value:r}),ks)break;n.push({value:e})}return v&&h&&x!==s?n.length&&D(n[n.length-1].value,s,no(s,y,e))?n[n.length-1].value=s:n.push({value:s}):v&&x!==s||n.push({value:x}),n}({maxTicks:n,bounds:e.bounds,min:e.min,max:e.max,precision:t.precision,step:t.stepSize,count:t.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:t.minRotation||0,includeBounds:!1!==t.includeBounds},this._range||this);return"ticks"===e.bounds&&V(i,this,"value"),e.reverse?(i.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),i}configure(){const e=this.ticks;let t=this.min,n=this.max;if(super.configure(),this.options.offset&&e.length){const a=(n-t)/Math.max(e.length-1,1)/2;t-=a,n+=a}this._startValue=t,this._endValue=n,this._valueRange=n-t}getLabelForValue(e){return et(e,this.chart.options.locale,this.options.ticks.format)}}class io extends ao{static id="linear";static defaults={ticks:{callback:nt.formatters.numeric}};determineDataLimits(){const{min:e,max:t}=this.getMinMax(!0);this.min=r(e)?e:0,this.max=r(t)?t:1,this.handleTickRangeOptions()}computeTickLimit(){const e=this.isHorizontal(),t=e?this.width:this.height,n=U(this.options.ticks.minRotation),a=(e?Math.sin(n):Math.cos(n))||.001,i=this._resolveTickFontOptions(0);return Math.ceil(t/Math.min(40,i.lineHeight/a))}getPixelForValue(e){return null===e?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getValueForPixel(e){return this._startValue+this.getDecimalForPixel(e)*this._valueRange}}const oo=e=>Math.floor(I(e)),ro=(e,t)=>Math.pow(10,oo(e)+t);function so(e){return 1===e/Math.pow(10,oo(e))}function lo(e,t,n){const a=Math.pow(10,n),i=Math.floor(e/a);return Math.ceil(t/a)-i}class uo extends Ga{static id="logarithmic";static defaults={ticks:{callback:nt.formatters.logarithmic,major:{enabled:!0}}};constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(e,t){const n=ao.prototype.parse.apply(this,[e,t]);if(0!==n)return r(n)&&n>0?n:null;this._zero=!0}determineDataLimits(){const{min:e,max:t}=this.getMinMax(!0);this.min=r(e)?Math.max(0,e):null,this.max=r(t)?Math.max(0,t):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!r(this._userMin)&&(this.min=e===ro(this.min,0)?ro(this.min,-1):ro(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:e,maxDefined:t}=this.getUserBounds();let n=this.min,a=this.max;const i=t=>n=e?n:t,o=e=>a=t?a:e;n===a&&(n<=0?(i(1),o(10)):(i(ro(n,-1)),o(ro(a,1)))),n<=0&&i(ro(a,-1)),a<=0&&o(ro(n,1)),this.min=n,this.max=a}buildTicks(){const e=this.options,t=function(e,{min:t,max:n}){t=s(e.min,t);const a=[],i=oo(t);let o=function(e,t){let n=oo(t-e);for(;lo(e,t,n)>10;)n++;for(;lo(e,t,n)<10;)n--;return Math.min(n,oo(e))}(t,n),r=o<0?Math.pow(10,Math.abs(o)):1;const l=Math.pow(10,o),u=i>o?Math.pow(10,i):0,c=Math.round((t-u)*r)/r,d=Math.floor((t-u)/l/10)*l*10;let h=Math.floor((c-d)/Math.pow(10,o)),p=s(e.min,Math.round((u+d+h*Math.pow(10,o))*r)/r);for(;p=10?h=h<15?15:20:h++,h>=20&&(o++,h=2,r=o>=0?1:r),p=Math.round((u+d+h*Math.pow(10,o))*r)/r;const f=s(e.max,p);return a.push({value:f,major:so(f),significand:h}),a}({min:this._userMin,max:this._userMax},this);return"ticks"===e.bounds&&V(t,this,"value"),e.reverse?(t.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),t}getLabelForValue(e){return void 0===e?"0":et(e,this.chart.options.locale,this.options.ticks.format)}configure(){const e=this.min;super.configure(),this._startValue=I(e),this._valueRange=I(this.max)-I(e)}getPixelForValue(e){return void 0!==e&&0!==e||(e=this.min),null===e||isNaN(e)?NaN:this.getPixelForDecimal(e===this.min?0:(I(e)-this._startValue)/this._valueRange)}getValueForPixel(e){const t=this.getDecimalForPixel(e);return Math.pow(10,this._startValue+t*this._valueRange)}}function co(e){const t=e.ticks;if(t.display&&e.display){const e=bn(t.backdropPadding);return l(t.font&&t.font.size,st.font.size)+e.height}return 0}function ho(e,t,n,a,i){return e===a||e===i?{start:t-n/2,end:t+n/2}:ei?{start:t-n,end:t}:{start:t,end:t+n}}function po(e,t,n,a,i){const o=Math.abs(Math.sin(n)),r=Math.abs(Math.cos(n));let s=0,l=0;a.startt.r&&(s=(a.end-t.r)/o,e.r=Math.max(e.r,t.r+s)),i.startt.b&&(l=(i.end-t.b)/r,e.b=Math.max(e.b,t.b+l))}function fo(e,t,n){const a=e.drawingArea,{extra:i,additionalAngle:o,padding:r,size:s}=n,l=e.getPointPosition(t,a+i+r,o),u=Math.round(H(Q(l.angle+z))),c=function(e,t,n){return 90===n||270===n?e-=t/2:(n>270||n<90)&&(e-=t),e}(l.y,s.h,u),d=function(e){return 0===e||180===e?"center":e<180?"left":"right"}(u),h=function(e,t,n){return"right"===n?e-=t:"center"===n&&(e-=t/2),e}(l.x,s.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:h,top:c,right:h+s.w,bottom:c+s.h}}function mo(e,t){if(!t)return!0;const{left:n,top:a,right:i,bottom:o}=e;return!(Et({x:n,y:a},t)||Et({x:n,y:o},t)||Et({x:i,y:a},t)||Et({x:i,y:o},t))}function go(e,t,n){const{left:i,top:o,right:r,bottom:s}=n,{backdropColor:l}=t;if(!a(l)){const n=vn(t.borderRadius),a=bn(t.backdropPadding);e.fillStyle=l;const u=i-a.left,c=o-a.top,d=r-i+a.width,h=s-o+a.height;Object.values(n).some(e=>0!==e)?(e.beginPath(),It(e,{x:u,y:c,w:d,h:h,radius:n}),e.fill()):e.fillRect(u,c,d,h)}}function _o(e,t,n,a){const{ctx:i}=e;if(n)i.arc(e.xCenter,e.yCenter,t,0,A);else{let n=e.getPointPosition(0,t);i.moveTo(n.x,n.y);for(let o=1;oe,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(e){super(e),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const e=this._padding=bn(co(this.options)/2),t=this.width=this.maxWidth-e.width,n=this.height=this.maxHeight-e.height;this.xCenter=Math.floor(this.left+t/2+e.left),this.yCenter=Math.floor(this.top+n/2+e.top),this.drawingArea=Math.floor(Math.min(t,n)/2)}determineDataLimits(){const{min:e,max:t}=this.getMinMax(!1);this.min=r(e)&&!isNaN(e)?e:0,this.max=r(t)&&!isNaN(t)?t:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/co(this.options))}generateTickLabels(e){ao.prototype.generateTickLabels.call(this,e),this._pointLabels=this.getLabels().map((e,t)=>{const n=d(this.options.pointLabels.callback,[e,t],this);return n||0===n?n:""}).filter((e,t)=>this.chart.getDataVisibility(t))}fit(){const e=this.options;e.display&&e.pointLabels.display?function(e){const t={l:e.left+e._padding.left,r:e.right-e._padding.right,t:e.top+e._padding.top,b:e.bottom-e._padding.bottom},n=Object.assign({},t),a=[],o=[],r=e._pointLabels.length,s=e.options.pointLabels,l=s.centerPointLabels?E/r:0;for(let h=0;h=0&&e=0;i--){const t=e._pointLabelItems[i];if(!t.visible)continue;const o=a.setContext(e.getPointLabelContext(i));go(n,o,t);const r=yn(o.font),{x:s,y:l,textAlign:u}=t;Ot(n,e._pointLabels[i],s,l+r.lineHeight/2,r,{color:o.color,textAlign:u,textBaseline:"middle"})}}(this,o),a.display&&this.ticks.forEach((e,t)=>{if(0!==t||0===t&&this.min<0){s=this.getDistanceFromCenterForValue(e.value);const n=this.getContext(t),r=a.setContext(n),l=i.setContext(n);!function(e,t,n,a,i){const o=e.ctx,r=t.circular,{color:s,lineWidth:l}=t;!r&&!a||!s||!l||n<0||(o.save(),o.strokeStyle=s,o.lineWidth=l,o.setLineDash(i.dash||[]),o.lineDashOffset=i.dashOffset,o.beginPath(),_o(e,n,r,a),o.closePath(),o.stroke(),o.restore())}(this,r,s,o,l)}}),n.display){for(e.save(),r=o-1;r>=0;r--){const a=n.setContext(this.getPointLabelContext(r)),{color:i,lineWidth:o}=a;o&&i&&(e.lineWidth=o,e.strokeStyle=i,e.setLineDash(a.borderDash),e.lineDashOffset=a.borderDashOffset,s=this.getDistanceFromCenterForValue(t.reverse?this.min:this.max),l=this.getPointPosition(r,s),e.beginPath(),e.moveTo(this.xCenter,this.yCenter),e.lineTo(l.x,l.y),e.stroke())}e.restore()}}drawBorder(){}drawLabels(){const e=this.ctx,t=this.options,n=t.ticks;if(!n.display)return;const a=this.getIndexAngle(0);let i,o;e.save(),e.translate(this.xCenter,this.yCenter),e.rotate(a),e.textAlign="center",e.textBaseline="middle",this.ticks.forEach((a,r)=>{if(0===r&&this.min>=0&&!t.reverse)return;const s=n.setContext(this.getContext(r)),l=yn(s.font);if(i=this.getDistanceFromCenterForValue(this.ticks[r].value),s.showLabelBackdrop){e.font=l.string,o=e.measureText(a.label).width,e.fillStyle=s.backdropColor;const t=bn(s.backdropPadding);e.fillRect(-o/2-t.left,-i-l.size/2-t.top,o+t.width,l.size+t.height)}Ot(e,a.label,0,-i,l,{color:s.color,strokeColor:s.textStrokeColor,strokeWidth:s.textStrokeWidth})}),e.restore()}drawTitle(){}}const bo={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},yo=Object.keys(bo);function wo(e,t){return e-t}function ko(e,t){if(a(t))return null;const n=e._adapter,{parser:i,round:o,isoWeekday:s}=e._parseOpts;let l=t;return"function"==typeof i&&(l=i(l)),r(l)||(l="string"==typeof i?n.parse(l,i):n.parse(l)),null===l?null:(o&&(l="week"!==o||!F(s)&&!0!==s?n.startOf(l,o):n.startOf(l,"isoWeek",s)),+l)}function xo(e,t,n,a){const i=yo.length;for(let o=yo.indexOf(e);o=t?n[a]:n[i]]=!0}}else e[t]=!0}function Co(e,t,n){const a=[],i={},o=t.length;let r,s;for(r=0;r=0&&(t[l].major=!0);return t}(e,a,i,n):a}class To extends Ga{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(e){super(e),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(e,t={}){const n=e.time||(e.time={}),a=this._adapter=new Ci._date(e.adapters.date);a.init(t),v(n.displayFormats,a.formats()),this._parseOpts={parser:n.parser,round:n.round,isoWeekday:n.isoWeekday},super.init(e),this._normalized=t.normalized}parse(e,t){return void 0===e?null:ko(this,e)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const e=this.options,t=this._adapter,n=e.time.unit||"day";let{min:a,max:i,minDefined:o,maxDefined:s}=this.getUserBounds();function l(e){o||isNaN(e.min)||(a=Math.min(a,e.min)),s||isNaN(e.max)||(i=Math.max(i,e.max))}o&&s||(l(this._getLabelBounds()),"ticks"===e.bounds&&"labels"===e.ticks.source||l(this.getMinMax(!1))),a=r(a)&&!isNaN(a)?a:+t.startOf(Date.now(),n),i=r(i)&&!isNaN(i)?i:+t.endOf(Date.now(),n)+1,this.min=Math.min(a,i-1),this.max=Math.max(a+1,i)}_getLabelBounds(){const e=this.getLabelTimestamps();let t=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;return e.length&&(t=e[0],n=e[e.length-1]),{min:t,max:n}}buildTicks(){const e=this.options,t=e.time,n=e.ticks,a="labels"===n.source?this.getLabelTimestamps():this._generate();"ticks"===e.bounds&&a.length&&(this.min=this._userMin||a[0],this.max=this._userMax||a[a.length-1]);const i=this.min,o=ie(a,i,this.max);return this._unit=t.unit||(n.autoSkip?xo(t.minUnit,this.min,this.max,this._getLabelCapacity(i)):function(e,t,n,a,i){for(let o=yo.length-1;o>=yo.indexOf(n);o--){const n=yo[o];if(bo[n].common&&e._adapter.diff(i,a,n)>=t-1)return n}return yo[n?yo.indexOf(n):0]}(this,o.length,t.minUnit,this.min,this.max)),this._majorUnit=n.major.enabled&&"year"!==this._unit?function(e){for(let t=yo.indexOf(e)+1,n=yo.length;t+e.value))}initOffsets(e=[]){let t,n,a=0,i=0;this.options.offset&&e.length&&(t=this.getDecimalForValue(e[0]),a=1===e.length?1-t:(this.getDecimalForValue(e[1])-t)/2,n=this.getDecimalForValue(e[e.length-1]),i=1===e.length?n:(n-this.getDecimalForValue(e[e.length-2]))/2);const o=e.length<3?.5:.25;a=J(a,0,o),i=J(i,0,o),this._offsets={start:a,end:i,factor:1/(a+1+i)}}_generate(){const e=this._adapter,t=this.min,n=this.max,a=this.options,i=a.time,o=i.unit||xo(i.minUnit,t,n,this._getLabelCapacity(t)),r=l(a.ticks.stepSize,1),s="week"===o&&i.isoWeekday,u=F(s)||!0===s,c={};let d,h,p=t;if(u&&(p=+e.startOf(p,"isoWeek",s)),p=+e.startOf(p,u?"day":o),e.diff(n,t,o)>1e5*r)throw new Error(t+" and "+n+" are too far apart with stepSize of "+r+" "+o);const f="data"===a.ticks.source&&this.getDataTimestamps();for(d=p,h=0;d+e)}getLabelForValue(e){const t=this._adapter,n=this.options.time;return n.tooltipFormat?t.format(e,n.tooltipFormat):t.format(e,n.displayFormats.datetime)}format(e,t){const n=this.options.time.displayFormats,a=this._unit,i=t||n[a];return this._adapter.format(e,i)}_tickFormatFunction(e,t,n,a){const i=this.options,o=i.ticks.callback;if(o)return d(o,[e,t,n],this);const r=i.time.displayFormats,s=this._unit,l=this._majorUnit,u=s&&r[s],c=l&&r[l],h=n[t],p=l&&c&&h&&h.major;return this._adapter.format(e,a||(p?c:u))}generateTickLabels(e){let t,n,a;for(t=0,n=e.length;t0?r:1}getDataTimestamps(){let e,t,n=this._cache.data||[];if(n.length)return n;const a=this.getMatchingVisibleMetas();if(this._normalized&&a.length)return this._cache.data=a[0].controller.getAllParsedValues(this);for(e=0,t=a.length;e=e[s].pos&&t<=e[l].pos&&({lo:s,hi:l}=ne(e,"pos",t)),({pos:a,time:o}=e[s]),({pos:i,time:r}=e[l])):(t>=e[s].time&&t<=e[l].time&&({lo:s,hi:l}=ne(e,"time",t)),({time:a,pos:o}=e[s]),({time:i,pos:r}=e[l]));const u=i-a;return u?o+(r-o)*(t-a)/u:o}var Eo=Object.freeze({__proto__:null,CategoryScale:class extends Ga{static id="category";static defaults={ticks:{callback:to}};constructor(e){super(e),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(e){const t=this._addedLabels;if(t.length){const e=this.getLabels();for(const{index:n,label:a}of t)e[n]===a&&e.splice(n,1);this._addedLabels=[]}super.init(e)}parse(e,t){if(a(e))return null;const n=this.getLabels();return((e,t)=>null===e?null:J(Math.round(e),0,t))(t=isFinite(t)&&n[t]===e?t:function(e,t,n,a){const i=e.indexOf(t);return-1===i?((e,t,n,a)=>("string"==typeof t?(n=e.push(t)-1,a.unshift({index:n,label:t})):isNaN(t)&&(n=null),n))(e,t,n,a):i!==e.lastIndexOf(t)?n:i}(n,e,l(t,e),this._addedLabels),n.length-1)}determineDataLimits(){const{minDefined:e,maxDefined:t}=this.getUserBounds();let{min:n,max:a}=this.getMinMax(!0);"ticks"===this.options.bounds&&(e||(n=0),t||(a=this.getLabels().length-1)),this.min=n,this.max=a}buildTicks(){const e=this.min,t=this.max,n=this.options.offset,a=[];let i=this.getLabels();i=0===e&&t===i.length-1?i:i.slice(e,t+1),this._valueRange=Math.max(i.length-(n?0:1),1),this._startValue=this.min-(n?.5:0);for(let n=e;n<=t;n++)a.push({value:n});return a}getLabelForValue(e){return to.call(this,e)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(e){return"number"!=typeof e&&(e=this.parse(e)),null===e?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getPixelForTick(e){const t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e].value)}getValueForPixel(e){return Math.round(this._startValue+this.getDecimalForPixel(e)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:io,LogarithmicScale:uo,RadialLinearScale:vo,TimeScale:To,TimeSeriesScale:class extends To{static id="timeseries";static defaults=To.defaults;constructor(e){super(e),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const e=this._getTimestampsForTable(),t=this._table=this.buildLookupTable(e);this._minPos=Po(t,this.min),this._tableRange=Po(t,this.max)-this._minPos,super.initOffsets(e)}buildLookupTable(e){const{min:t,max:n}=this,a=[],i=[];let o,r,s,l,u;for(o=0,r=e.length;o=t&&l<=n&&a.push(l);if(a.length<2)return[{time:t,pos:0},{time:n,pos:1}];for(o=0,r=a.length;oe-t)}_getTimestampsForTable(){let e=this._cache.all||[];if(e.length)return e;const t=this.getDataTimestamps(),n=this.getLabelTimestamps();return e=t.length&&n.length?this.normalize(t.concat(n)):t.length?t:n,e=this._cache.all=e,e}getDecimalForValue(e){return(Po(this._table,e)-this._minPos)/this._tableRange}getValueForPixel(e){const t=this._offsets,n=this.getDecimalForPixel(e)/t.factor-t.end;return Po(this._table,n*this._tableRange+this._minPos,!0)}}});const Ao=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Mo=Ao.map(e=>e.replace("rgb(","rgba(").replace(")",", 0.5)"));function Lo(e){return Ao[e%Ao.length]}function Ro(e){return Mo[e%Mo.length]}function zo(e){let t;for(t in e)if(e[t].borderColor||e[t].backgroundColor)return!0;return!1}var No={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(e,t,n){if(!n.enabled)return;const{data:{datasets:a},options:i}=e.config,{elements:o}=i,r=zo(a)||(s=i)&&(s.borderColor||s.backgroundColor)||o&&zo(o)||"rgba(0,0,0,0.1)"!==st.borderColor||"rgba(0,0,0,0.1)"!==st.backgroundColor;var s;if(!n.forceOverride&&r)return;const l=function(e){let t=0;return(n,a)=>{const i=e.getDatasetMeta(a).controller;i instanceof Ni?t=function(e,t){return e.backgroundColor=e.data.map(()=>Lo(t++)),t}(n,t):i instanceof Oi?t=function(e,t){return e.backgroundColor=e.data.map(()=>Ro(t++)),t}(n,t):i&&(t=function(e,t){return e.borderColor=Lo(t),e.backgroundColor=Ro(t),++t}(n,t))}}(e);a.forEach(l)}};function Oo(e){if(e._decimated){const t=e._data;delete e._decimated,delete e._data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,writable:!0,value:t})}}function Io(e){e.data.datasets.forEach(e=>{Oo(e)})}var qo={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(e,t,n)=>{if(!n.enabled)return void Io(e);const i=e.width;e.data.datasets.forEach((t,o)=>{const{_data:r,indexAxis:s}=t,l=e.getDatasetMeta(o),u=r||t.data;if("y"===wn([s,e.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=e.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(e.options.parsing)return;let d,{start:h,count:p}=function(e,t){const n=t.length;let a,i=0;const{iScale:o}=e,{min:r,max:s,minDefined:l,maxDefined:u}=o.getUserBounds();return l&&(i=J(ne(t,o.axis,r).lo,0,n-1)),a=u?J(ne(t,o.axis,s).hi+1,i,n)-i:n-i,{start:i,count:a}}(l,u);if(p<=(n.threshold||4*i))Oo(t);else{switch(a(r)&&(t._data=u,delete t.data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(e){this._data=e}})),n.algorithm){case"lttb":d=function(e,t,n,a,i){const o=i.samples||a;if(o>=n)return e.slice(t,t+n);const r=[],s=(n-2)/(o-2);let l=0;const u=t+n-1;let c,d,h,p,f,m=t;for(r[l++]=e[m],c=0;ch&&(h=p,d=e[a],f=a);r[l++]=d,m=f}return r[l++]=e[u],r}(u,h,p,i,n);break;case"min-max":d=function(e,t,n,i){let o,r,s,l,u,c,d,h,p,f,m=0,g=0;const _=[],v=t+n-1,b=e[t].x,y=e[v].x-b;for(o=t;of&&(f=l,d=o),m=(g*m+r.x)/++g;else{const n=o-1;if(!a(c)&&!a(d)){const t=Math.min(c,d),a=Math.max(c,d);t!==h&&t!==n&&_.push({...e[t],x:m}),a!==h&&a!==n&&_.push({...e[a],x:m})}o>0&&n!==h&&_.push(e[n]),_.push(r),u=t,g=0,p=f=l,c=d=h=o}}return _}(u,h,p,i);break;default:throw new Error(`Unsupported decimation algorithm '${n.algorithm}'`)}t._decimated=d}})},destroy(e){Io(e)}};function Do(e,t,n,a){if(a)return;let i=t[e],o=n[e];return"angle"===e&&(i=Q(i),o=Q(o)),{property:e,start:i,end:o}}function jo(e,t,n){for(;t>e;t--){const e=n[t];if(!isNaN(e.x)&&!isNaN(e.y))break}return t}function Bo(e,t,n,a){return e&&t?a(e[n],t[n]):e?e[n]:t?t[n]:0}function Fo(e,t){let n=[],a=!1;return i(e)?(a=!0,n=e):n=function(e,t){const{x:n=null,y:a=null}=e||{},i=t.points,o=[];return t.segments.forEach(({start:e,end:t})=>{t=jo(e,t,i);const r=i[e],s=i[t];null!==a?(o.push({x:r.x,y:a}),o.push({x:s.x,y:a})):null!==n&&(o.push({x:n,y:r.y}),o.push({x:n,y:s.y}))}),o}(e,t),n.length?new Wi({points:n,options:{tension:0},_loop:a,_fullLoop:a}):null}function $o(e){return e&&!1!==e.fill}function Vo(e,t,n){let a=e[t].fill;const i=[t];let o;if(!n)return a;for(;!1!==a&&-1===i.indexOf(a);){if(!r(a))return a;if(o=e[a],!o)return!1;if(o.visible)return a;i.push(a),a=o.fill}return!1}function Uo(e,t,n){const a=function(e){const t=e.options,n=t.fill;let a=l(n&&n.target,n);return void 0===a&&(a=!!t.backgroundColor),!1!==a&&null!==a&&(!0===a?"origin":a)}(e);if(o(a))return!isNaN(a.value)&&a;let i=parseFloat(a);return r(i)&&Math.floor(i)===i?function(e,t,n,a){return"-"!==e&&"+"!==e||(n=t+n),!(n===t||n<0||n>=a)&&n}(a[0],t,i,n):["origin","start","end","stack","shape"].indexOf(a)>=0&&a}function Ho(e,t,n){const a=[];for(let i=0;i=0;--t){const n=i[t].$filler;n&&(n.line.updateControlPoints(o,n.axis),a&&n.fill&&Yo(e.ctx,n,o))}},beforeDatasetsDraw(e,t,n){if("beforeDatasetsDraw"!==n.drawTime)return;const a=e.getSortedVisibleDatasetMetas();for(let t=a.length-1;t>=0;--t){const n=a[t].$filler;$o(n)&&Yo(e.ctx,n,e.chartArea)}},beforeDatasetDraw(e,t,n){const a=t.meta.$filler;$o(a)&&"beforeDatasetDraw"===n.drawTime&&Yo(e.ctx,a,e.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const nr=(e,t)=>{let{boxHeight:n=t,boxWidth:a=t}=e;return e.usePointStyle&&(n=Math.min(n,t),a=e.pointStyleWidth||Math.min(a,t)),{boxWidth:a,boxHeight:n,itemHeight:Math.max(t,n)}};class ar extends qa{constructor(e){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=e.chart,this.options=e.options,this.ctx=e.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(e,t,n){this.maxWidth=e,this.maxHeight=t,this._margins=n,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const e=this.options.labels||{};let t=d(e.generateLabels,[this.chart],this)||[];e.filter&&(t=t.filter(t=>e.filter(t,this.chart.data))),e.sort&&(t=t.sort((t,n)=>e.sort(t,n,this.chart.data))),this.options.reverse&&t.reverse(),this.legendItems=t}fit(){const{options:e,ctx:t}=this;if(!e.display)return void(this.width=this.height=0);const n=e.labels,a=yn(n.font),i=a.size,o=this._computeTitleHeight(),{boxWidth:r,itemHeight:s}=nr(n,i);let l,u;t.font=a.string,this.isHorizontal()?(l=this.maxWidth,u=this._fitRows(o,i,r,s)+10):(u=this.maxHeight,l=this._fitCols(o,a,r,s)+10),this.width=Math.min(l,e.maxWidth||this.maxWidth),this.height=Math.min(u,e.maxHeight||this.maxHeight)}_fitRows(e,t,n,a){const{ctx:i,maxWidth:o,options:{labels:{padding:r}}}=this,s=this.legendHitBoxes=[],l=this.lineWidths=[0],u=a+r;let c=e;i.textAlign="left",i.textBaseline="middle";let d=-1,h=-u;return this.legendItems.forEach((e,p)=>{const f=n+t/2+i.measureText(e.text).width;(0===p||l[l.length-1]+f+2*r>o)&&(c+=u,l[l.length-(p>0?0:1)]=0,h+=u,d++),s[p]={left:0,top:h,row:d,width:f,height:a},l[l.length-1]+=f+r}),c}_fitCols(e,t,n,a){const{ctx:i,maxHeight:o,options:{labels:{padding:r}}}=this,s=this.legendHitBoxes=[],l=this.columnSizes=[],u=o-e;let c=r,d=0,h=0,p=0,f=0;return this.legendItems.forEach((e,o)=>{const{itemWidth:m,itemHeight:g}=function(e,t,n,a,i){const o=function(e,t,n,a){let i=e.text;return i&&"string"!=typeof i&&(i=i.reduce((e,t)=>e.length>t.length?e:t)),t+n.size/2+a.measureText(i).width}(a,e,t,n),r=function(e,t,n){let a=e;return"string"!=typeof t.text&&(a=ir(t,n)),a}(i,a,t.lineHeight);return{itemWidth:o,itemHeight:r}}(n,t,i,e,a);o>0&&h+g+2*r>u&&(c+=d+r,l.push({width:d,height:h}),p+=d+r,f++,d=h=0),s[o]={left:p,top:h,col:f,width:m,height:g},d=Math.max(d,m),h+=g+r}),c+=d,l.push({width:d,height:h}),c}adjustHitBoxes(){if(!this.options.display)return;const e=this._computeTitleHeight(),{legendHitBoxes:t,options:{align:n,labels:{padding:a},rtl:i}}=this,o=Sn(i,this.left,this.width);if(this.isHorizontal()){let i=0,r=pe(n,this.left+a,this.right-this.lineWidths[i]);for(const s of t)i!==s.row&&(i=s.row,r=pe(n,this.left+a,this.right-this.lineWidths[i])),s.top+=this.top+e+a,s.left=o.leftForLtr(o.x(r),s.width),r+=s.width+a}else{let i=0,r=pe(n,this.top+e+a,this.bottom-this.columnSizes[i].height);for(const s of t)s.col!==i&&(i=s.col,r=pe(n,this.top+e+a,this.bottom-this.columnSizes[i].height)),s.top=r,s.left+=this.left+a,s.left=o.leftForLtr(o.x(s.left),s.width),r+=s.height+a}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const e=this.ctx;At(e,this),this._draw(),Mt(e)}}_draw(){const{options:e,columnSizes:t,lineWidths:n,ctx:a}=this,{align:i,labels:o}=e,r=st.color,s=Sn(e.rtl,this.left,this.width),u=yn(o.font),{padding:c}=o,d=u.size,h=d/2;let p;this.drawTitle(),a.textAlign=s.textAlign("left"),a.textBaseline="middle",a.lineWidth=.5,a.font=u.string;const{boxWidth:f,boxHeight:m,itemHeight:g}=nr(o,d),_=this.isHorizontal(),v=this._computeTitleHeight();p=_?{x:pe(i,this.left+c,this.right-n[0]),y:this.top+c+v,line:0}:{x:this.left+c,y:pe(i,this.top+v+c,this.bottom-t[0].height),line:0},Cn(this.ctx,e.textDirection);const b=g+c;this.legendItems.forEach((y,w)=>{a.strokeStyle=y.fontColor,a.fillStyle=y.fontColor;const k=a.measureText(y.text).width,x=s.textAlign(y.textAlign||(y.textAlign=o.textAlign)),S=f+h+k;let C=p.x,T=p.y;if(s.setWidth(this.width),_?w>0&&C+S+c>this.right&&(T=p.y+=b,p.line++,C=p.x=pe(i,this.left+c,this.right-n[p.line])):w>0&&T+b>this.bottom&&(C=p.x=C+t[p.line].width+c,p.line++,T=p.y=pe(i,this.top+v+c,this.bottom-t[p.line].height)),function(e,t,n){if(isNaN(f)||f<=0||isNaN(m)||m<0)return;a.save();const i=l(n.lineWidth,1);if(a.fillStyle=l(n.fillStyle,r),a.lineCap=l(n.lineCap,"butt"),a.lineDashOffset=l(n.lineDashOffset,0),a.lineJoin=l(n.lineJoin,"miter"),a.lineWidth=i,a.strokeStyle=l(n.strokeStyle,r),a.setLineDash(l(n.lineDash,[])),o.usePointStyle){const r={radius:m*Math.SQRT2/2,pointStyle:n.pointStyle,rotation:n.rotation,borderWidth:i},l=s.xPlus(e,f/2);Pt(a,r,l,t+h,o.pointStyleWidth&&f)}else{const o=t+Math.max((d-m)/2,0),r=s.leftForLtr(e,f),l=vn(n.borderRadius);a.beginPath(),Object.values(l).some(e=>0!==e)?It(a,{x:r,y:o,w:f,h:m,radius:l}):a.rect(r,o,f,m),a.fill(),0!==i&&a.stroke()}a.restore()}(s.x(C),T,y),C=fe(x,C+f+h,_?C+S:this.right,e.rtl),function(e,t,n){Ot(a,n.text,e,t+g/2,u,{strikethrough:n.hidden,textAlign:s.textAlign(n.textAlign)})}(s.x(C),T,y),_)p.x+=S+c;else if("string"!=typeof y.text){const e=u.lineHeight;p.y+=ir(y,e)+c}else p.y+=b}),Tn(this.ctx,e.textDirection)}drawTitle(){const e=this.options,t=e.title,n=yn(t.font),a=bn(t.padding);if(!t.display)return;const i=Sn(e.rtl,this.left,this.width),o=this.ctx,r=t.position,s=n.size/2,l=a.top+s;let u,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),u=this.top+l,c=pe(e.align,c,this.right-d);else{const t=this.columnSizes.reduce((e,t)=>Math.max(e,t.height),0);u=l+pe(e.align,this.top,this.bottom-t-e.labels.padding-this._computeTitleHeight())}const h=pe(r,c,c+d);o.textAlign=i.textAlign(he(r)),o.textBaseline="middle",o.strokeStyle=t.color,o.fillStyle=t.color,o.font=n.string,Ot(o,t.text,h,u,n)}_computeTitleHeight(){const e=this.options.title,t=yn(e.font),n=bn(e.padding);return e.display?t.lineHeight+n.height:0}_getLegendItemAt(e,t){let n,a,i;if(ee(e,this.left,this.right)&&ee(t,this.top,this.bottom))for(i=this.legendHitBoxes,n=0;ne.chart.options.color,boxWidth:40,padding:10,generateLabels(e){const t=e.data.datasets,{labels:{usePointStyle:n,pointStyle:a,textAlign:i,color:o,useBorderRadius:r,borderRadius:s}}=e.legend.options;return e._getSortedDatasetMetas().map(e=>{const l=e.controller.getStyle(n?0:void 0),u=bn(l.borderWidth);return{text:t[e.index].label,fillStyle:l.backgroundColor,fontColor:o,hidden:!e.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(u.width+u.height)/4,strokeStyle:l.borderColor,pointStyle:a||l.pointStyle,rotation:l.rotation,textAlign:i||l.textAlign,borderRadius:r&&(s||l.borderRadius),datasetIndex:e.index}},this)}},title:{color:e=>e.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:e=>!e.startsWith("on"),labels:{_scriptable:e=>!["generateLabels","filter","sort"].includes(e)}}};class rr extends qa{constructor(e){super(),this.chart=e.chart,this.options=e.options,this.ctx=e.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(e,t){const n=this.options;if(this.left=0,this.top=0,!n.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=e,this.height=this.bottom=t;const a=i(n.text)?n.text.length:1;this._padding=bn(n.padding);const o=a*yn(n.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=o:this.width=o}isHorizontal(){const e=this.options.position;return"top"===e||"bottom"===e}_drawArgs(e){const{top:t,left:n,bottom:a,right:i,options:o}=this,r=o.align;let s,l,u,c=0;return this.isHorizontal()?(l=pe(r,n,i),u=t+e,s=i-n):("left"===o.position?(l=n+e,u=pe(r,a,t),c=-.5*E):(l=i-e,u=pe(r,t,a),c=.5*E),s=a-t),{titleX:l,titleY:u,maxWidth:s,rotation:c}}draw(){const e=this.ctx,t=this.options;if(!t.display)return;const n=yn(t.font),a=n.lineHeight/2+this._padding.top,{titleX:i,titleY:o,maxWidth:r,rotation:s}=this._drawArgs(a);Ot(e,t.text,0,0,n,{color:t.color,maxWidth:r,rotation:s,textAlign:he(t.align),textBaseline:"middle",translation:[i,o]})}}var sr={id:"title",_element:rr,start(e,t,n){!function(e,t){const n=new rr({ctx:e.ctx,options:t,chart:e});ta.configure(e,n,t),ta.addBox(e,n),e.titleBlock=n}(e,n)},stop(e){const t=e.titleBlock;ta.removeBox(e,t),delete e.titleBlock},beforeUpdate(e,t,n){const a=e.titleBlock;ta.configure(e,a,n),a.options=n},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const lr=new WeakMap;var ur={id:"subtitle",start(e,t,n){const a=new rr({ctx:e.ctx,options:n,chart:e});ta.configure(e,a,n),ta.addBox(e,a),lr.set(e,a)},stop(e){ta.removeBox(e,lr.get(e)),lr.delete(e)},beforeUpdate(e,t,n){const a=lr.get(e);ta.configure(e,a,n),a.options=n},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const cr={average(e){if(!e.length)return!1;let t,n,a=new Set,i=0,o=0;for(t=0,n=e.length;te+t)/a.size,y:i/o}},nearest(e,t){if(!e.length)return!1;let n,a,i,o=t.x,r=t.y,s=Number.POSITIVE_INFINITY;for(n=0,a=e.length;n-1?e.split("\n"):e}function pr(e,t){const{element:n,datasetIndex:a,index:i}=t,o=e.getDatasetMeta(a).controller,{label:r,value:s}=o.getLabelAndValue(i);return{chart:e,label:r,parsed:o.getParsed(i),raw:e.data.datasets[a].data[i],formattedValue:s,dataset:o.getDataset(),dataIndex:i,datasetIndex:a,element:n}}function fr(e,t){const n=e.chart.ctx,{body:a,footer:i,title:o}=e,{boxWidth:r,boxHeight:s}=t,l=yn(t.bodyFont),u=yn(t.titleFont),c=yn(t.footerFont),d=o.length,p=i.length,f=a.length,m=bn(t.padding);let g=m.height,_=0,v=a.reduce((e,t)=>e+t.before.length+t.lines.length+t.after.length,0);v+=e.beforeBody.length+e.afterBody.length,d&&(g+=d*u.lineHeight+(d-1)*t.titleSpacing+t.titleMarginBottom),v&&(g+=f*(t.displayColors?Math.max(s,l.lineHeight):l.lineHeight)+(v-f)*l.lineHeight+(v-1)*t.bodySpacing),p&&(g+=t.footerMarginTop+p*c.lineHeight+(p-1)*t.footerSpacing);let b=0;const y=function(e){_=Math.max(_,n.measureText(e).width+b)};return n.save(),n.font=u.string,h(e.title,y),n.font=l.string,h(e.beforeBody.concat(e.afterBody),y),b=t.displayColors?r+2+t.boxPadding:0,h(a,e=>{h(e.before,y),h(e.lines,y),h(e.after,y)}),b=0,n.font=c.string,h(e.footer,y),n.restore(),_+=m.width,{width:_,height:g}}function mr(e,t,n,a){const{x:i,width:o}=n,{width:r,chartArea:{left:s,right:l}}=e;let u="center";return"center"===a?u=i<=(s+l)/2?"left":"right":i<=o/2?u="left":i>=r-o/2&&(u="right"),function(e,t,n,a){const{x:i,width:o}=a,r=n.caretSize+n.caretPadding;return"left"===e&&i+o+r>t.width||"right"===e&&i-o-r<0||void 0}(u,e,t,n)&&(u="center"),u}function gr(e,t,n){const a=n.yAlign||t.yAlign||function(e,t){const{y:n,height:a}=t;return ne.height-a/2?"bottom":"center"}(e,n);return{xAlign:n.xAlign||t.xAlign||mr(e,t,n,a),yAlign:a}}function _r(e,t,n,a){const{caretSize:i,caretPadding:o,cornerRadius:r}=e,{xAlign:s,yAlign:l}=n,u=i+o,{topLeft:c,topRight:d,bottomLeft:h,bottomRight:p}=vn(r);let f=function(e,t){let{x:n,width:a}=e;return"right"===t?n-=a:"center"===t&&(n-=a/2),n}(t,s);const m=function(e,t,n){let{y:a,height:i}=e;return"top"===t?a+=n:a-="bottom"===t?i+n:i/2,a}(t,l,u);return"center"===l?"left"===s?f+=u:"right"===s&&(f-=u):"left"===s?f-=Math.max(c,h)+i:"right"===s&&(f+=Math.max(d,p)+i),{x:J(f,0,a.width-t.width),y:J(m,0,a.height-t.height)}}function vr(e,t,n){const a=bn(n.padding);return"center"===t?e.x+e.width/2:"right"===t?e.x+e.width-a.right:e.x+a.left}function br(e){return dr([],hr(e))}function yr(e,t){const n=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return n?e.override(n):e}const wr={beforeTitle:t,title(e){if(e.length>0){const t=e[0],n=t.chart.data.labels,a=n?n.length:0;if(this&&this.options&&"dataset"===this.options.mode)return t.dataset.label||"";if(t.label)return t.label;if(a>0&&t.dataIndex{const t={before:[],lines:[],after:[]},i=yr(n,e);dr(t.before,hr(kr(i,"beforeLabel",this,e))),dr(t.lines,kr(i,"label",this,e)),dr(t.after,hr(kr(i,"afterLabel",this,e))),a.push(t)}),a}getAfterBody(e,t){return br(kr(t.callbacks,"afterBody",this,e))}getFooter(e,t){const{callbacks:n}=t,a=kr(n,"beforeFooter",this,e),i=kr(n,"footer",this,e),o=kr(n,"afterFooter",this,e);let r=[];return r=dr(r,hr(a)),r=dr(r,hr(i)),r=dr(r,hr(o)),r}_createItems(e){const t=this._active,n=this.chart.data,a=[],i=[],o=[];let r,s,l=[];for(r=0,s=t.length;re.filter(t,a,i,n))),e.itemSort&&(l=l.sort((t,a)=>e.itemSort(t,a,n))),h(l,t=>{const n=yr(e.callbacks,t);a.push(kr(n,"labelColor",this,t)),i.push(kr(n,"labelPointStyle",this,t)),o.push(kr(n,"labelTextColor",this,t))}),this.labelColors=a,this.labelPointStyles=i,this.labelTextColors=o,this.dataPoints=l,l}update(e,t){const n=this.options.setContext(this.getContext()),a=this._active;let i,o=[];if(a.length){const e=cr[n.position].call(this,a,this._eventPosition);o=this._createItems(n),this.title=this.getTitle(o,n),this.beforeBody=this.getBeforeBody(o,n),this.body=this.getBody(o,n),this.afterBody=this.getAfterBody(o,n),this.footer=this.getFooter(o,n);const t=this._size=fr(this,n),r=Object.assign({},e,t),s=gr(this.chart,n,r),l=_r(n,r,s,this.chart);this.xAlign=s.xAlign,this.yAlign=s.yAlign,i={opacity:1,x:l.x,y:l.y,width:t.width,height:t.height,caretX:e.x,caretY:e.y}}else 0!==this.opacity&&(i={opacity:0});this._tooltipItems=o,this.$context=void 0,i&&this._resolveAnimations().update(this,i),e&&n.external&&n.external.call(this,{chart:this.chart,tooltip:this,replay:t})}drawCaret(e,t,n,a){const i=this.getCaretPosition(e,n,a);t.lineTo(i.x1,i.y1),t.lineTo(i.x2,i.y2),t.lineTo(i.x3,i.y3)}getCaretPosition(e,t,n){const{xAlign:a,yAlign:i}=this,{caretSize:o,cornerRadius:r}=n,{topLeft:s,topRight:l,bottomLeft:u,bottomRight:c}=vn(r),{x:d,y:h}=e,{width:p,height:f}=t;let m,g,_,v,b,y;return"center"===i?(b=h+f/2,"left"===a?(m=d,g=m-o,v=b+o,y=b-o):(m=d+p,g=m+o,v=b-o,y=b+o),_=m):(g="left"===a?d+Math.max(s,u)+o:"right"===a?d+p-Math.max(l,c)-o:this.caretX,"top"===i?(v=h,b=v-o,m=g-o,_=g+o):(v=h+f,b=v+o,m=g+o,_=g-o),y=v),{x1:m,x2:g,x3:_,y1:v,y2:b,y3:y}}drawTitle(e,t,n){const a=this.title,i=a.length;let o,r,s;if(i){const l=Sn(n.rtl,this.x,this.width);for(e.x=vr(this,n.titleAlign,n),t.textAlign=l.textAlign(n.titleAlign),t.textBaseline="middle",o=yn(n.titleFont),r=n.titleSpacing,t.fillStyle=n.titleColor,t.font=o.string,s=0;s0!==e)?(e.beginPath(),e.fillStyle=i.multiKeyBackground,It(e,{x:t,y:f,w:u,h:l,radius:s}),e.fill(),e.stroke(),e.fillStyle=r.backgroundColor,e.beginPath(),It(e,{x:n,y:f+1,w:u-2,h:l-2,radius:s}),e.fill()):(e.fillStyle=i.multiKeyBackground,e.fillRect(t,f,u,l),e.strokeRect(t,f,u,l),e.fillStyle=r.backgroundColor,e.fillRect(n,f+1,u-2,l-2))}e.fillStyle=this.labelTextColors[n]}drawBody(e,t,n){const{body:a}=this,{bodySpacing:i,bodyAlign:o,displayColors:r,boxHeight:s,boxWidth:l,boxPadding:u}=n,c=yn(n.bodyFont);let d=c.lineHeight,p=0;const f=Sn(n.rtl,this.x,this.width),m=function(n){t.fillText(n,f.x(e.x+p),e.y+d/2),e.y+=d+i},g=f.textAlign(o);let _,v,b,y,w,k,x;for(t.textAlign=o,t.textBaseline="middle",t.font=c.string,e.x=vr(this,g,n),t.fillStyle=n.bodyColor,h(this.beforeBody,m),p=r&&"right"!==g?"center"===o?l/2+u:l+2+u:0,y=0,k=a.length;y0&&t.stroke()}_updateAnimationTarget(e){const t=this.chart,n=this.$animations,a=n&&n.x,i=n&&n.y;if(a||i){const n=cr[e.position].call(this,this._active,this._eventPosition);if(!n)return;const o=this._size=fr(this,e),r=Object.assign({},n,this._size),s=gr(t,e,r),l=_r(e,r,s,t);a._to===l.x&&i._to===l.y||(this.xAlign=s.xAlign,this.yAlign=s.yAlign,this.width=o.width,this.height=o.height,this.caretX=n.x,this.caretY=n.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(e){const t=this.options.setContext(this.getContext());let n=this.opacity;if(!n)return;this._updateAnimationTarget(t);const a={width:this.width,height:this.height},i={x:this.x,y:this.y};n=Math.abs(n)<.001?0:n;const o=bn(t.padding),r=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;t.enabled&&r&&(e.save(),e.globalAlpha=n,this.drawBackground(i,e,a,t),Cn(e,t.textDirection),i.y+=o.top,this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),Tn(e,t.textDirection),e.restore())}getActiveElements(){return this._active||[]}setActiveElements(e,t){const n=this._active,a=e.map(({datasetIndex:e,index:t})=>{const n=this.chart.getDatasetMeta(e);if(!n)throw new Error("Cannot find a dataset at index "+e);return{datasetIndex:e,element:n.data[t],index:t}}),i=!p(n,a),o=this._positionChanged(a,t);(i||o)&&(this._active=a,this._eventPosition=t,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(e,t,n=!0){if(t&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const a=this.options,i=this._active||[],o=this._getActiveElements(e,i,t,n),r=this._positionChanged(o,e),s=t||!p(o,i)||r;return s&&(this._active=o,(a.enabled||a.external)&&(this._eventPosition={x:e.x,y:e.y},this.update(!0,t))),s}_getActiveElements(e,t,n,a){const i=this.options;if("mouseout"===e.type)return[];if(!a)return t.filter(e=>this.chart.data.datasets[e.datasetIndex]&&void 0!==this.chart.getDatasetMeta(e.datasetIndex).controller.getParsed(e.index));const o=this.chart.getElementsAtEventForMode(e,i.mode,i,n);return i.reverse&&o.reverse(),o}_positionChanged(e,t){const{caretX:n,caretY:a,options:i}=this,o=cr[i.position].call(this,e,t);return!1!==o&&(n!==o.x||a!==o.y)}}var Sr={id:"tooltip",_element:xr,positioners:cr,afterInit(e,t,n){n&&(e.tooltip=new xr({chart:e,options:n}))},beforeUpdate(e,t,n){e.tooltip&&e.tooltip.initialize(n)},reset(e,t,n){e.tooltip&&e.tooltip.initialize(n)},afterDraw(e){const t=e.tooltip;if(t&&t._willRender()){const n={tooltip:t};if(!1===e.notifyPlugins("beforeTooltipDraw",{...n,cancelable:!0}))return;t.draw(e.ctx),e.notifyPlugins("afterTooltipDraw",n)}},afterEvent(e,t){if(e.tooltip){const n=t.replay;e.tooltip.handleEvent(t.event,n,t.inChartArea)&&(t.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(e,t)=>t.bodyFont.size,boxWidth:(e,t)=>t.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:wr},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:e=>"filter"!==e&&"itemSort"!==e&&"external"!==e,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return wi.register(Ii,Eo,eo,e),wi.helpers={...qn},wi._adapters=Ci,wi.Animation=xa,wi.Animations=Sa,wi.animator=_e,wi.controllers=Ya.controllers.items,wi.DatasetController=Ia,wi.Element=qa,wi.elements=eo,wi.Interaction=Vn,wi.layouts=ta,wi.platforms=ya,wi.Scale=Ga,wi.Ticks=nt,Object.assign(wi,Ii,Eo,eo,e,ya),wi.Chart=wi,"undefined"!=typeof window&&(window.Chart=wi),wi}),/*! showdown v 2.1.0 - 21-04-2022 */ -function(){function e(e){"use strict";var t={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,describe:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,describe:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,describe:"Parses simple line breaks as
(GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,describe:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,describe:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",describe:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,describe:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,describe:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,describe:"Support for HTML Tag escaping. ex:
foo
",type:"boolean"},emoji:{defaultValue:!1,describe:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,describe:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``",type:"boolean"},ellipsis:{defaultValue:!0,describe:"Replaces three dots with the ellipsis unicode character",type:"boolean"},completeHTMLDocument:{defaultValue:!1,describe:"Outputs a complete html document, including ``, `` and `` tags",type:"boolean"},metadata:{defaultValue:!1,describe:"Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,describe:"Split adjacent blockquote blocks",type:"boolean"}};if(!1===e)return JSON.parse(JSON.stringify(t));var n={};for(var a in t)t.hasOwnProperty(a)&&(n[a]=t[a].defaultValue);return n}var t={},n={},a={},i=e(!0),o="vanilla",r={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:e(!0),allOn:function(){"use strict";var t=e(!0),n={};for(var a in t)t.hasOwnProperty(a)&&(n[a]=!0);return n}()};function s(e,n){"use strict";var a=n?"Error in "+n+" extension->":"Error in unnamed extension",i={valid:!0,error:""};t.helper.isArray(e)||(e=[e]);for(var o=0;o").replace(/&/g,"&")};var u=function(e,t,n,a){"use strict";var i,o,r,s,l,u=a||"",c=u.indexOf("g")>-1,d=new RegExp(t+"|"+n,"g"+u.replace(/g/g,"")),h=new RegExp(t,u.replace(/g/g,"")),p=[];do{for(i=0;r=d.exec(e);)if(h.test(r[0]))i++||(s=(o=d.lastIndex)-r[0].length);else if(i&&! --i){l=r.index+r[0].length;var f={left:{start:s,end:o},match:{start:o,end:r.index},right:{start:r.index,end:l},wholeMatch:{start:s,end:l}};if(p.push(f),!c)return p}}while(i&&(d.lastIndex=o));return p};t.helper.matchRecursiveRegExp=function(e,t,n,a){"use strict";for(var i=u(e,t,n,a),o=[],r=0;r0){var d=[];0!==s[0].wholeMatch.start&&d.push(e.slice(0,s[0].wholeMatch.start));for(var h=0;h=0?i+(a||0):i},t.helper.splitAtIndex=function(e,n){"use strict";if(!t.helper.isString(e))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";return[e.substring(0,n),e.substring(n)]},t.helper.encodeEmailAddress=function(e){"use strict";var t=[function(e){return"&#"+e.charCodeAt(0)+";"},function(e){return"&#x"+e.charCodeAt(0).toString(16)+";"},function(e){return e}];return e=e.replace(/./g,function(e){if("@"===e)e=t[Math.floor(2*Math.random())](e);else{var n=Math.random();e=n>.9?t[2](e):n>.45?t[1](e):t[0](e)}return e})},t.helper.padEnd=function(e,t,n){"use strict";return t|=0,n=String(n||" "),e.length>t?String(e):((t-=e.length)>n.length&&(n+=n.repeat(t/n.length)),String(e)+n.slice(0,t))},"undefined"==typeof console&&(console={warn:function(e){"use strict";alert(e)},log:function(e){"use strict";alert(e)},error:function(e){"use strict";throw e}}),t.helper.regexes={asteriskDashAndColon:/([*_:~])/g},t.helper.emojis={"+1":"👍","-1":"👎",100:"💯",1234:"🔢","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉","8ball":"🎱",a:"🅰️",ab:"🆎",abc:"🔤",abcd:"🔡",accept:"🉑",aerial_tramway:"🚡",airplane:"✈️",alarm_clock:"⏰",alembic:"⚗️",alien:"👽",ambulance:"🚑",amphora:"🏺",anchor:"⚓️",angel:"👼",anger:"💢",angry:"😠",anguished:"😧",ant:"🐜",apple:"🍎",aquarius:"♒️",aries:"♈️",arrow_backward:"◀️",arrow_double_down:"⏬",arrow_double_up:"⏫",arrow_down:"⬇️",arrow_down_small:"🔽",arrow_forward:"▶️",arrow_heading_down:"⤵️",arrow_heading_up:"⤴️",arrow_left:"⬅️",arrow_lower_left:"↙️",arrow_lower_right:"↘️",arrow_right:"➡️",arrow_right_hook:"↪️",arrow_up:"⬆️",arrow_up_down:"↕️",arrow_up_small:"🔼",arrow_upper_left:"↖️",arrow_upper_right:"↗️",arrows_clockwise:"🔃",arrows_counterclockwise:"🔄",art:"🎨",articulated_lorry:"🚛",artificial_satellite:"🛰",astonished:"😲",athletic_shoe:"👟",atm:"🏧",atom_symbol:"⚛️",avocado:"🥑",b:"🅱️",baby:"👶",baby_bottle:"🍼",baby_chick:"🐤",baby_symbol:"🚼",back:"🔙",bacon:"🥓",badminton:"🏸",baggage_claim:"🛄",baguette_bread:"🥖",balance_scale:"⚖️",balloon:"🎈",ballot_box:"🗳",ballot_box_with_check:"☑️",bamboo:"🎍",banana:"🍌",bangbang:"‼️",bank:"🏦",bar_chart:"📊",barber:"💈",baseball:"⚾️",basketball:"🏀",basketball_man:"⛹️",basketball_woman:"⛹️‍♀️",bat:"🦇",bath:"🛀",bathtub:"🛁",battery:"🔋",beach_umbrella:"🏖",bear:"🐻",bed:"🛏",bee:"🐝",beer:"🍺",beers:"🍻",beetle:"🐞",beginner:"🔰",bell:"🔔",bellhop_bell:"🛎",bento:"🍱",biking_man:"🚴",bike:"🚲",biking_woman:"🚴‍♀️",bikini:"👙",biohazard:"☣️",bird:"🐦",birthday:"🎂",black_circle:"⚫️",black_flag:"🏴",black_heart:"🖤",black_joker:"🃏",black_large_square:"⬛️",black_medium_small_square:"◾️",black_medium_square:"◼️",black_nib:"✒️",black_small_square:"▪️",black_square_button:"🔲",blonde_man:"👱",blonde_woman:"👱‍♀️",blossom:"🌼",blowfish:"🐡",blue_book:"📘",blue_car:"🚙",blue_heart:"💙",blush:"😊",boar:"🐗",boat:"⛵️",bomb:"💣",book:"📖",bookmark:"🔖",bookmark_tabs:"📑",books:"📚",boom:"💥",boot:"👢",bouquet:"💐",bowing_man:"🙇",bow_and_arrow:"🏹",bowing_woman:"🙇‍♀️",bowling:"🎳",boxing_glove:"🥊",boy:"👦",bread:"🍞",bride_with_veil:"👰",bridge_at_night:"🌉",briefcase:"💼",broken_heart:"💔",bug:"🐛",building_construction:"🏗",bulb:"💡",bullettrain_front:"🚅",bullettrain_side:"🚄",burrito:"🌯",bus:"🚌",business_suit_levitating:"🕴",busstop:"🚏",bust_in_silhouette:"👤",busts_in_silhouette:"👥",butterfly:"🦋",cactus:"🌵",cake:"🍰",calendar:"📆",call_me_hand:"🤙",calling:"📲",camel:"🐫",camera:"📷",camera_flash:"📸",camping:"🏕",cancer:"♋️",candle:"🕯",candy:"🍬",canoe:"🛶",capital_abcd:"🔠",capricorn:"♑️",car:"🚗",card_file_box:"🗃",card_index:"📇",card_index_dividers:"🗂",carousel_horse:"🎠",carrot:"🥕",cat:"🐱",cat2:"🐈",cd:"💿",chains:"⛓",champagne:"🍾",chart:"💹",chart_with_downwards_trend:"📉",chart_with_upwards_trend:"📈",checkered_flag:"🏁",cheese:"🧀",cherries:"🍒",cherry_blossom:"🌸",chestnut:"🌰",chicken:"🐔",children_crossing:"🚸",chipmunk:"🐿",chocolate_bar:"🍫",christmas_tree:"🎄",church:"⛪️",cinema:"🎦",circus_tent:"🎪",city_sunrise:"🌇",city_sunset:"🌆",cityscape:"🏙",cl:"🆑",clamp:"🗜",clap:"👏",clapper:"🎬",classical_building:"🏛",clinking_glasses:"🥂",clipboard:"📋",clock1:"🕐",clock10:"🕙",clock1030:"🕥",clock11:"🕚",clock1130:"🕦",clock12:"🕛",clock1230:"🕧",clock130:"🕜",clock2:"🕑",clock230:"🕝",clock3:"🕒",clock330:"🕞",clock4:"🕓",clock430:"🕟",clock5:"🕔",clock530:"🕠",clock6:"🕕",clock630:"🕡",clock7:"🕖",clock730:"🕢",clock8:"🕗",clock830:"🕣",clock9:"🕘",clock930:"🕤",closed_book:"📕",closed_lock_with_key:"🔐",closed_umbrella:"🌂",cloud:"☁️",cloud_with_lightning:"🌩",cloud_with_lightning_and_rain:"⛈",cloud_with_rain:"🌧",cloud_with_snow:"🌨",clown_face:"🤡",clubs:"♣️",cocktail:"🍸",coffee:"☕️",coffin:"⚰️",cold_sweat:"😰",comet:"☄️",computer:"💻",computer_mouse:"🖱",confetti_ball:"🎊",confounded:"😖",confused:"😕",congratulations:"㊗️",construction:"🚧",construction_worker_man:"👷",construction_worker_woman:"👷‍♀️",control_knobs:"🎛",convenience_store:"🏪",cookie:"🍪",cool:"🆒",policeman:"👮",copyright:"©️",corn:"🌽",couch_and_lamp:"🛋",couple:"👫",couple_with_heart_woman_man:"💑",couple_with_heart_man_man:"👨‍❤️‍👨",couple_with_heart_woman_woman:"👩‍❤️‍👩",couplekiss_man_man:"👨‍❤️‍💋‍👨",couplekiss_man_woman:"💏",couplekiss_woman_woman:"👩‍❤️‍💋‍👩",cow:"🐮",cow2:"🐄",cowboy_hat_face:"🤠",crab:"🦀",crayon:"🖍",credit_card:"💳",crescent_moon:"🌙",cricket:"🏏",crocodile:"🐊",croissant:"🥐",crossed_fingers:"🤞",crossed_flags:"🎌",crossed_swords:"⚔️",crown:"👑",cry:"😢",crying_cat_face:"😿",crystal_ball:"🔮",cucumber:"🥒",cupid:"💘",curly_loop:"➰",currency_exchange:"💱",curry:"🍛",custard:"🍮",customs:"🛃",cyclone:"🌀",dagger:"🗡",dancer:"💃",dancing_women:"👯",dancing_men:"👯‍♂️",dango:"🍡",dark_sunglasses:"🕶",dart:"🎯",dash:"💨",date:"📅",deciduous_tree:"🌳",deer:"🦌",department_store:"🏬",derelict_house:"🏚",desert:"🏜",desert_island:"🏝",desktop_computer:"🖥",male_detective:"🕵️",diamond_shape_with_a_dot_inside:"💠",diamonds:"♦️",disappointed:"😞",disappointed_relieved:"😥",dizzy:"💫",dizzy_face:"😵",do_not_litter:"🚯",dog:"🐶",dog2:"🐕",dollar:"💵",dolls:"🎎",dolphin:"🐬",door:"🚪",doughnut:"🍩",dove:"🕊",dragon:"🐉",dragon_face:"🐲",dress:"👗",dromedary_camel:"🐪",drooling_face:"🤤",droplet:"💧",drum:"🥁",duck:"🦆",dvd:"📀","e-mail":"📧",eagle:"🦅",ear:"👂",ear_of_rice:"🌾",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",egg:"🥚",eggplant:"🍆",eight_pointed_black_star:"✴️",eight_spoked_asterisk:"✳️",electric_plug:"🔌",elephant:"🐘",email:"✉️",end:"🔚",envelope_with_arrow:"📩",euro:"💶",european_castle:"🏰",european_post_office:"🏤",evergreen_tree:"🌲",exclamation:"❗️",expressionless:"😑",eye:"👁",eye_speech_bubble:"👁‍🗨",eyeglasses:"👓",eyes:"👀",face_with_head_bandage:"🤕",face_with_thermometer:"🤒",fist_oncoming:"👊",factory:"🏭",fallen_leaf:"🍂",family_man_woman_boy:"👪",family_man_boy:"👨‍👦",family_man_boy_boy:"👨‍👦‍👦",family_man_girl:"👨‍👧",family_man_girl_boy:"👨‍👧‍👦",family_man_girl_girl:"👨‍👧‍👧",family_man_man_boy:"👨‍👨‍👦",family_man_man_boy_boy:"👨‍👨‍👦‍👦",family_man_man_girl:"👨‍👨‍👧",family_man_man_girl_boy:"👨‍👨‍👧‍👦",family_man_man_girl_girl:"👨‍👨‍👧‍👧",family_man_woman_boy_boy:"👨‍👩‍👦‍👦",family_man_woman_girl:"👨‍👩‍👧",family_man_woman_girl_boy:"👨‍👩‍👧‍👦",family_man_woman_girl_girl:"👨‍👩‍👧‍👧",family_woman_boy:"👩‍👦",family_woman_boy_boy:"👩‍👦‍👦",family_woman_girl:"👩‍👧",family_woman_girl_boy:"👩‍👧‍👦",family_woman_girl_girl:"👩‍👧‍👧",family_woman_woman_boy:"👩‍👩‍👦",family_woman_woman_boy_boy:"👩‍👩‍👦‍👦",family_woman_woman_girl:"👩‍👩‍👧",family_woman_woman_girl_boy:"👩‍👩‍👧‍👦",family_woman_woman_girl_girl:"👩‍👩‍👧‍👧",fast_forward:"⏩",fax:"📠",fearful:"😨",feet:"🐾",female_detective:"🕵️‍♀️",ferris_wheel:"🎡",ferry:"⛴",field_hockey:"🏑",file_cabinet:"🗄",file_folder:"📁",film_projector:"📽",film_strip:"🎞",fire:"🔥",fire_engine:"🚒",fireworks:"🎆",first_quarter_moon:"🌓",first_quarter_moon_with_face:"🌛",fish:"🐟",fish_cake:"🍥",fishing_pole_and_fish:"🎣",fist_raised:"✊",fist_left:"🤛",fist_right:"🤜",flags:"🎏",flashlight:"🔦",fleur_de_lis:"⚜️",flight_arrival:"🛬",flight_departure:"🛫",floppy_disk:"💾",flower_playing_cards:"🎴",flushed:"😳",fog:"🌫",foggy:"🌁",football:"🏈",footprints:"👣",fork_and_knife:"🍴",fountain:"⛲️",fountain_pen:"🖋",four_leaf_clover:"🍀",fox_face:"🦊",framed_picture:"🖼",free:"🆓",fried_egg:"🍳",fried_shrimp:"🍤",fries:"🍟",frog:"🐸",frowning:"😦",frowning_face:"☹️",frowning_man:"🙍‍♂️",frowning_woman:"🙍",middle_finger:"🖕",fuelpump:"⛽️",full_moon:"🌕",full_moon_with_face:"🌝",funeral_urn:"⚱️",game_die:"🎲",gear:"⚙️",gem:"💎",gemini:"♊️",ghost:"👻",gift:"🎁",gift_heart:"💝",girl:"👧",globe_with_meridians:"🌐",goal_net:"🥅",goat:"🐐",golf:"⛳️",golfing_man:"🏌️",golfing_woman:"🏌️‍♀️",gorilla:"🦍",grapes:"🍇",green_apple:"🍏",green_book:"📗",green_heart:"💚",green_salad:"🥗",grey_exclamation:"❕",grey_question:"❔",grimacing:"😬",grin:"😁",grinning:"😀",guardsman:"💂",guardswoman:"💂‍♀️",guitar:"🎸",gun:"🔫",haircut_woman:"💇",haircut_man:"💇‍♂️",hamburger:"🍔",hammer:"🔨",hammer_and_pick:"⚒",hammer_and_wrench:"🛠",hamster:"🐹",hand:"✋",handbag:"👜",handshake:"🤝",hankey:"💩",hatched_chick:"🐥",hatching_chick:"🐣",headphones:"🎧",hear_no_evil:"🙉",heart:"❤️",heart_decoration:"💟",heart_eyes:"😍",heart_eyes_cat:"😻",heartbeat:"💓",heartpulse:"💗",hearts:"♥️",heavy_check_mark:"✔️",heavy_division_sign:"➗",heavy_dollar_sign:"💲",heavy_heart_exclamation:"❣️",heavy_minus_sign:"➖",heavy_multiplication_x:"✖️",heavy_plus_sign:"➕",helicopter:"🚁",herb:"🌿",hibiscus:"🌺",high_brightness:"🔆",high_heel:"👠",hocho:"🔪",hole:"🕳",honey_pot:"🍯",horse:"🐴",horse_racing:"🏇",hospital:"🏥",hot_pepper:"🌶",hotdog:"🌭",hotel:"🏨",hotsprings:"♨️",hourglass:"⌛️",hourglass_flowing_sand:"⏳",house:"🏠",house_with_garden:"🏡",houses:"🏘",hugs:"🤗",hushed:"😯",ice_cream:"🍨",ice_hockey:"🏒",ice_skate:"⛸",icecream:"🍦",id:"🆔",ideograph_advantage:"🉐",imp:"👿",inbox_tray:"📥",incoming_envelope:"📨",tipping_hand_woman:"💁",information_source:"ℹ️",innocent:"😇",interrobang:"⁉️",iphone:"📱",izakaya_lantern:"🏮",jack_o_lantern:"🎃",japan:"🗾",japanese_castle:"🏯",japanese_goblin:"👺",japanese_ogre:"👹",jeans:"👖",joy:"😂",joy_cat:"😹",joystick:"🕹",kaaba:"🕋",key:"🔑",keyboard:"⌨️",keycap_ten:"🔟",kick_scooter:"🛴",kimono:"👘",kiss:"💋",kissing:"😗",kissing_cat:"😽",kissing_closed_eyes:"😚",kissing_heart:"😘",kissing_smiling_eyes:"😙",kiwi_fruit:"🥝",koala:"🐨",koko:"🈁",label:"🏷",large_blue_circle:"🔵",large_blue_diamond:"🔷",large_orange_diamond:"🔶",last_quarter_moon:"🌗",last_quarter_moon_with_face:"🌜",latin_cross:"✝️",laughing:"😆",leaves:"🍃",ledger:"📒",left_luggage:"🛅",left_right_arrow:"↔️",leftwards_arrow_with_hook:"↩️",lemon:"🍋",leo:"♌️",leopard:"🐆",level_slider:"🎚",libra:"♎️",light_rail:"🚈",link:"🔗",lion:"🦁",lips:"👄",lipstick:"💄",lizard:"🦎",lock:"🔒",lock_with_ink_pen:"🔏",lollipop:"🍭",loop:"➿",loud_sound:"🔊",loudspeaker:"📢",love_hotel:"🏩",love_letter:"💌",low_brightness:"🔅",lying_face:"🤥",m:"Ⓜ️",mag:"🔍",mag_right:"🔎",mahjong:"🀄️",mailbox:"📫",mailbox_closed:"📪",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",man:"👨",man_artist:"👨‍🎨",man_astronaut:"👨‍🚀",man_cartwheeling:"🤸‍♂️",man_cook:"👨‍🍳",man_dancing:"🕺",man_facepalming:"🤦‍♂️",man_factory_worker:"👨‍🏭",man_farmer:"👨‍🌾",man_firefighter:"👨‍🚒",man_health_worker:"👨‍⚕️",man_in_tuxedo:"🤵",man_judge:"👨‍⚖️",man_juggling:"🤹‍♂️",man_mechanic:"👨‍🔧",man_office_worker:"👨‍💼",man_pilot:"👨‍✈️",man_playing_handball:"🤾‍♂️",man_playing_water_polo:"🤽‍♂️",man_scientist:"👨‍🔬",man_shrugging:"🤷‍♂️",man_singer:"👨‍🎤",man_student:"👨‍🎓",man_teacher:"👨‍🏫",man_technologist:"👨‍💻",man_with_gua_pi_mao:"👲",man_with_turban:"👳",tangerine:"🍊",mans_shoe:"👞",mantelpiece_clock:"🕰",maple_leaf:"🍁",martial_arts_uniform:"🥋",mask:"😷",massage_woman:"💆",massage_man:"💆‍♂️",meat_on_bone:"🍖",medal_military:"🎖",medal_sports:"🏅",mega:"📣",melon:"🍈",memo:"📝",men_wrestling:"🤼‍♂️",menorah:"🕎",mens:"🚹",metal:"🤘",metro:"🚇",microphone:"🎤",microscope:"🔬",milk_glass:"🥛",milky_way:"🌌",minibus:"🚐",minidisc:"💽",mobile_phone_off:"📴",money_mouth_face:"🤑",money_with_wings:"💸",moneybag:"💰",monkey:"🐒",monkey_face:"🐵",monorail:"🚝",moon:"🌔",mortar_board:"🎓",mosque:"🕌",motor_boat:"🛥",motor_scooter:"🛵",motorcycle:"🏍",motorway:"🛣",mount_fuji:"🗻",mountain:"⛰",mountain_biking_man:"🚵",mountain_biking_woman:"🚵‍♀️",mountain_cableway:"🚠",mountain_railway:"🚞",mountain_snow:"🏔",mouse:"🐭",mouse2:"🐁",movie_camera:"🎥",moyai:"🗿",mrs_claus:"🤶",muscle:"💪",mushroom:"🍄",musical_keyboard:"🎹",musical_note:"🎵",musical_score:"🎼",mute:"🔇",nail_care:"💅",name_badge:"📛",national_park:"🏞",nauseated_face:"🤢",necktie:"👔",negative_squared_cross_mark:"❎",nerd_face:"🤓",neutral_face:"😐",new:"🆕",new_moon:"🌑",new_moon_with_face:"🌚",newspaper:"📰",newspaper_roll:"🗞",next_track_button:"⏭",ng:"🆖",no_good_man:"🙅‍♂️",no_good_woman:"🙅",night_with_stars:"🌃",no_bell:"🔕",no_bicycles:"🚳",no_entry:"⛔️",no_entry_sign:"🚫",no_mobile_phones:"📵",no_mouth:"😶",no_pedestrians:"🚷",no_smoking:"🚭","non-potable_water":"🚱",nose:"👃",notebook:"📓",notebook_with_decorative_cover:"📔",notes:"🎶",nut_and_bolt:"🔩",o:"⭕️",o2:"🅾️",ocean:"🌊",octopus:"🐙",oden:"🍢",office:"🏢",oil_drum:"🛢",ok:"🆗",ok_hand:"👌",ok_man:"🙆‍♂️",ok_woman:"🙆",old_key:"🗝",older_man:"👴",older_woman:"👵",om:"🕉",on:"🔛",oncoming_automobile:"🚘",oncoming_bus:"🚍",oncoming_police_car:"🚔",oncoming_taxi:"🚖",open_file_folder:"📂",open_hands:"👐",open_mouth:"😮",open_umbrella:"☂️",ophiuchus:"⛎",orange_book:"📙",orthodox_cross:"☦️",outbox_tray:"📤",owl:"🦉",ox:"🐂",package:"📦",page_facing_up:"📄",page_with_curl:"📃",pager:"📟",paintbrush:"🖌",palm_tree:"🌴",pancakes:"🥞",panda_face:"🐼",paperclip:"📎",paperclips:"🖇",parasol_on_ground:"⛱",parking:"🅿️",part_alternation_mark:"〽️",partly_sunny:"⛅️",passenger_ship:"🛳",passport_control:"🛂",pause_button:"⏸",peace_symbol:"☮️",peach:"🍑",peanuts:"🥜",pear:"🍐",pen:"🖊",pencil2:"✏️",penguin:"🐧",pensive:"😔",performing_arts:"🎭",persevere:"😣",person_fencing:"🤺",pouting_woman:"🙎",phone:"☎️",pick:"⛏",pig:"🐷",pig2:"🐖",pig_nose:"🐽",pill:"💊",pineapple:"🍍",ping_pong:"🏓",pisces:"♓️",pizza:"🍕",place_of_worship:"🛐",plate_with_cutlery:"🍽",play_or_pause_button:"⏯",point_down:"👇",point_left:"👈",point_right:"👉",point_up:"☝️",point_up_2:"👆",police_car:"🚓",policewoman:"👮‍♀️",poodle:"🐩",popcorn:"🍿",post_office:"🏣",postal_horn:"📯",postbox:"📮",potable_water:"🚰",potato:"🥔",pouch:"👝",poultry_leg:"🍗",pound:"💷",rage:"😡",pouting_cat:"😾",pouting_man:"🙎‍♂️",pray:"🙏",prayer_beads:"📿",pregnant_woman:"🤰",previous_track_button:"⏮",prince:"🤴",princess:"👸",printer:"🖨",purple_heart:"💜",purse:"👛",pushpin:"📌",put_litter_in_its_place:"🚮",question:"❓",rabbit:"🐰",rabbit2:"🐇",racehorse:"🐎",racing_car:"🏎",radio:"📻",radio_button:"🔘",radioactive:"☢️",railway_car:"🚃",railway_track:"🛤",rainbow:"🌈",rainbow_flag:"🏳️‍🌈",raised_back_of_hand:"🤚",raised_hand_with_fingers_splayed:"🖐",raised_hands:"🙌",raising_hand_woman:"🙋",raising_hand_man:"🙋‍♂️",ram:"🐏",ramen:"🍜",rat:"🐀",record_button:"⏺",recycle:"♻️",red_circle:"🔴",registered:"®️",relaxed:"☺️",relieved:"😌",reminder_ribbon:"🎗",repeat:"🔁",repeat_one:"🔂",rescue_worker_helmet:"⛑",restroom:"🚻",revolving_hearts:"💞",rewind:"⏪",rhinoceros:"🦏",ribbon:"🎀",rice:"🍚",rice_ball:"🍙",rice_cracker:"🍘",rice_scene:"🎑",right_anger_bubble:"🗯",ring:"💍",robot:"🤖",rocket:"🚀",rofl:"🤣",roll_eyes:"🙄",roller_coaster:"🎢",rooster:"🐓",rose:"🌹",rosette:"🏵",rotating_light:"🚨",round_pushpin:"📍",rowing_man:"🚣",rowing_woman:"🚣‍♀️",rugby_football:"🏉",running_man:"🏃",running_shirt_with_sash:"🎽",running_woman:"🏃‍♀️",sa:"🈂️",sagittarius:"♐️",sake:"🍶",sandal:"👡",santa:"🎅",satellite:"📡",saxophone:"🎷",school:"🏫",school_satchel:"🎒",scissors:"✂️",scorpion:"🦂",scorpius:"♏️",scream:"😱",scream_cat:"🙀",scroll:"📜",seat:"💺",secret:"㊙️",see_no_evil:"🙈",seedling:"🌱",selfie:"🤳",shallow_pan_of_food:"🥘",shamrock:"☘️",shark:"🦈",shaved_ice:"🍧",sheep:"🐑",shell:"🐚",shield:"🛡",shinto_shrine:"⛩",ship:"🚢",shirt:"👕",shopping:"🛍",shopping_cart:"🛒",shower:"🚿",shrimp:"🦐",signal_strength:"📶",six_pointed_star:"🔯",ski:"🎿",skier:"⛷",skull:"💀",skull_and_crossbones:"☠️",sleeping:"😴",sleeping_bed:"🛌",sleepy:"😪",slightly_frowning_face:"🙁",slightly_smiling_face:"🙂",slot_machine:"🎰",small_airplane:"🛩",small_blue_diamond:"🔹",small_orange_diamond:"🔸",small_red_triangle:"🔺",small_red_triangle_down:"🔻",smile:"😄",smile_cat:"😸",smiley:"😃",smiley_cat:"😺",smiling_imp:"😈",smirk:"😏",smirk_cat:"😼",smoking:"🚬",snail:"🐌",snake:"🐍",sneezing_face:"🤧",snowboarder:"🏂",snowflake:"❄️",snowman:"⛄️",snowman_with_snow:"☃️",sob:"😭",soccer:"⚽️",soon:"🔜",sos:"🆘",sound:"🔉",space_invader:"👾",spades:"♠️",spaghetti:"🍝",sparkle:"❇️",sparkler:"🎇",sparkles:"✨",sparkling_heart:"💖",speak_no_evil:"🙊",speaker:"🔈",speaking_head:"🗣",speech_balloon:"💬",speedboat:"🚤",spider:"🕷",spider_web:"🕸",spiral_calendar:"🗓",spiral_notepad:"🗒",spoon:"🥄",squid:"🦑",stadium:"🏟",star:"⭐️",star2:"🌟",star_and_crescent:"☪️",star_of_david:"✡️",stars:"🌠",station:"🚉",statue_of_liberty:"🗽",steam_locomotive:"🚂",stew:"🍲",stop_button:"⏹",stop_sign:"🛑",stopwatch:"⏱",straight_ruler:"📏",strawberry:"🍓",stuck_out_tongue:"😛",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue_winking_eye:"😜",studio_microphone:"🎙",stuffed_flatbread:"🥙",sun_behind_large_cloud:"🌥",sun_behind_rain_cloud:"🌦",sun_behind_small_cloud:"🌤",sun_with_face:"🌞",sunflower:"🌻",sunglasses:"😎",sunny:"☀️",sunrise:"🌅",sunrise_over_mountains:"🌄",surfing_man:"🏄",surfing_woman:"🏄‍♀️",sushi:"🍣",suspension_railway:"🚟",sweat:"😓",sweat_drops:"💦",sweat_smile:"😅",sweet_potato:"🍠",swimming_man:"🏊",swimming_woman:"🏊‍♀️",symbols:"🔣",synagogue:"🕍",syringe:"💉",taco:"🌮",tada:"🎉",tanabata_tree:"🎋",taurus:"♉️",taxi:"🚕",tea:"🍵",telephone_receiver:"📞",telescope:"🔭",tennis:"🎾",tent:"⛺️",thermometer:"🌡",thinking:"🤔",thought_balloon:"💭",ticket:"🎫",tickets:"🎟",tiger:"🐯",tiger2:"🐅",timer_clock:"⏲",tipping_hand_man:"💁‍♂️",tired_face:"😫",tm:"™️",toilet:"🚽",tokyo_tower:"🗼",tomato:"🍅",tongue:"👅",top:"🔝",tophat:"🎩",tornado:"🌪",trackball:"🖲",tractor:"🚜",traffic_light:"🚥",train:"🚋",train2:"🚆",tram:"🚊",triangular_flag_on_post:"🚩",triangular_ruler:"📐",trident:"🔱",triumph:"😤",trolleybus:"🚎",trophy:"🏆",tropical_drink:"🍹",tropical_fish:"🐠",truck:"🚚",trumpet:"🎺",tulip:"🌷",tumbler_glass:"🥃",turkey:"🦃",turtle:"🐢",tv:"📺",twisted_rightwards_arrows:"🔀",two_hearts:"💕",two_men_holding_hands:"👬",two_women_holding_hands:"👭",u5272:"🈹",u5408:"🈴",u55b6:"🈺",u6307:"🈯️",u6708:"🈷️",u6709:"🈶",u6e80:"🈵",u7121:"🈚️",u7533:"🈸",u7981:"🈲",u7a7a:"🈳",umbrella:"☔️",unamused:"😒",underage:"🔞",unicorn:"🦄",unlock:"🔓",up:"🆙",upside_down_face:"🙃",v:"✌️",vertical_traffic_light:"🚦",vhs:"📼",vibration_mode:"📳",video_camera:"📹",video_game:"🎮",violin:"🎻",virgo:"♍️",volcano:"🌋",volleyball:"🏐",vs:"🆚",vulcan_salute:"🖖",walking_man:"🚶",walking_woman:"🚶‍♀️",waning_crescent_moon:"🌘",waning_gibbous_moon:"🌖",warning:"⚠️",wastebasket:"🗑",watch:"⌚️",water_buffalo:"🐃",watermelon:"🍉",wave:"👋",wavy_dash:"〰️",waxing_crescent_moon:"🌒",wc:"🚾",weary:"😩",wedding:"💒",weight_lifting_man:"🏋️",weight_lifting_woman:"🏋️‍♀️",whale:"🐳",whale2:"🐋",wheel_of_dharma:"☸️",wheelchair:"♿️",white_check_mark:"✅",white_circle:"⚪️",white_flag:"🏳️",white_flower:"💮",white_large_square:"⬜️",white_medium_small_square:"◽️",white_medium_square:"◻️",white_small_square:"▫️",white_square_button:"🔳",wilted_flower:"🥀",wind_chime:"🎐",wind_face:"🌬",wine_glass:"🍷",wink:"😉",wolf:"🐺",woman:"👩",woman_artist:"👩‍🎨",woman_astronaut:"👩‍🚀",woman_cartwheeling:"🤸‍♀️",woman_cook:"👩‍🍳",woman_facepalming:"🤦‍♀️",woman_factory_worker:"👩‍🏭",woman_farmer:"👩‍🌾",woman_firefighter:"👩‍🚒",woman_health_worker:"👩‍⚕️",woman_judge:"👩‍⚖️",woman_juggling:"🤹‍♀️",woman_mechanic:"👩‍🔧",woman_office_worker:"👩‍💼",woman_pilot:"👩‍✈️",woman_playing_handball:"🤾‍♀️",woman_playing_water_polo:"🤽‍♀️",woman_scientist:"👩‍🔬",woman_shrugging:"🤷‍♀️",woman_singer:"👩‍🎤",woman_student:"👩‍🎓",woman_teacher:"👩‍🏫",woman_technologist:"👩‍💻",woman_with_turban:"👳‍♀️",womans_clothes:"👚",womans_hat:"👒",women_wrestling:"🤼‍♀️",womens:"🚺",world_map:"🗺",worried:"😟",wrench:"🔧",writing_hand:"✍️",x:"❌",yellow_heart:"💛",yen:"💴",yin_yang:"☯️",yum:"😋",zap:"⚡️",zipper_mouth_face:"🤐",zzz:"💤",octocat:':octocat:',showdown:"S"},t.Converter=function(e){"use strict";var n={},l=[],u=[],c={},d=o,h={parsed:{},raw:"",format:""};function p(e,n){if(n=n||null,t.helper.isString(e)){if(n=e=t.helper.stdExtName(e),t.extensions[e])return console.warn("DEPRECATION WARNING: "+e+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!"),void function(e,n){"function"==typeof e&&(e=e(new t.Converter));t.helper.isArray(e)||(e=[e]);var a=s(e,n);if(!a.valid)throw Error(a.error);for(var i=0;i[ \t]+¨NBSP;<"),!n){if(!window||!window.document)throw new Error("HTMLParser is undefined. If in a webworker or nodejs environment, you need to provide a WHATWG DOM and HTML such as JSDOM");n=window.document}var a=n.createElement("div");a.innerHTML=e;var i={preList:function(e){for(var n=e.querySelectorAll("pre"),a=[],i=0;i'}else a.push(n[i].innerHTML),n[i].innerHTML="",n[i].setAttribute("prenum",i.toString());return a}(a)};!function e(t){for(var n=0;n? ?(['"].*['"])?\)$/m)>-1)r="";else if(!r){if(o||(o=i.toLowerCase().replace(/ ?\n/g," ")),r="#"+o,t.helper.isUndefined(a.gUrls[o]))return e;r=a.gUrls[o],t.helper.isUndefined(a.gTitles[o])||(u=a.gTitles[o])}var c='
"};return e=(e=(e=(e=(e=a.converter._dispatch("anchors.before",e,n,a)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,i)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,i)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,i)).replace(/\[([^\[\]]+)]()()()()()/g,i),n.ghMentions&&(e=e.replace(/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d.-]+?[a-z\d]+)*))/gim,function(e,a,i,o,r){if("\\"===i)return a+o;if(!t.helper.isString(n.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");var s=n.ghMentionsLink.replace(/\{u}/g,r),l="";return n.openLinksInNewWindow&&(l=' rel="noopener noreferrer" target="¨E95Eblank"'),a+'"+o+""})),e=a.converter._dispatch("anchors.after",e,n,a)});var c=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,d=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,h=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,p=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,f=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,m=function(e){"use strict";return function(n,a,i,o,r,s,l){var u=i=i.replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback),c="",d="",h=a||"",p=l||"";return/^www\./i.test(i)&&(i=i.replace(/^www\./i,"http://www.")),e.excludeTrailingPunctuationFromURLs&&s&&(c=s),e.openLinksInNewWindow&&(d=' rel="noopener noreferrer" target="¨E95Eblank"'),h+'"+u+""+c+p}},g=function(e,n){"use strict";return function(a,i,o){var r="mailto:";return i=i||"",o=t.subParser("unescapeSpecialChars")(o,e,n),e.encodeEmails?(r=t.helper.encodeEmailAddress(r+o),o=t.helper.encodeEmailAddress(o)):r+=o,i+''+o+""}};t.subParser("autoLinks",function(e,t,n){"use strict";return e=(e=(e=n.converter._dispatch("autoLinks.before",e,t,n)).replace(h,m(t))).replace(f,g(t,n)),e=n.converter._dispatch("autoLinks.after",e,t,n)}),t.subParser("simplifiedAutoLinks",function(e,t,n){"use strict";return t.simplifiedAutoLink?(e=n.converter._dispatch("simplifiedAutoLinks.before",e,t,n),e=(e=t.excludeTrailingPunctuationFromURLs?e.replace(d,m(t)):e.replace(c,m(t))).replace(p,g(t,n)),e=n.converter._dispatch("simplifiedAutoLinks.after",e,t,n)):e}),t.subParser("blockGamut",function(e,n,a){"use strict";return e=a.converter._dispatch("blockGamut.before",e,n,a),e=t.subParser("blockQuotes")(e,n,a),e=t.subParser("headers")(e,n,a),e=t.subParser("horizontalRule")(e,n,a),e=t.subParser("lists")(e,n,a),e=t.subParser("codeBlocks")(e,n,a),e=t.subParser("tables")(e,n,a),e=t.subParser("hashHTMLBlocks")(e,n,a),e=t.subParser("paragraphs")(e,n,a),e=a.converter._dispatch("blockGamut.after",e,n,a)}),t.subParser("blockQuotes",function(e,n,a){"use strict";e=a.converter._dispatch("blockQuotes.before",e,n,a),e+="\n\n";var i=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return n.splitAdjacentBlockquotes&&(i=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),e=e.replace(i,function(e){return e=(e=(e=e.replace(/^[ \t]*>[ \t]?/gm,"")).replace(/¨0/g,"")).replace(/^[ \t]+$/gm,""),e=t.subParser("githubCodeBlocks")(e,n,a),e=(e=(e=t.subParser("blockGamut")(e,n,a)).replace(/(^|\n)/g,"$1 ")).replace(/(\s*
[^\r]+?<\/pre>)/gm,function(e,t){var n=t;return n=(n=n.replace(/^  /gm,"¨0")).replace(/¨0/g,"")}),t.subParser("hashBlock")("
\n"+e+"\n
",n,a)}),e=a.converter._dispatch("blockQuotes.after",e,n,a)}),t.subParser("codeBlocks",function(e,n,a){"use strict";e=a.converter._dispatch("codeBlocks.before",e,n,a);return e=(e=(e+="¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g,function(e,i,o){var r=i,s=o,l="\n";return r=t.subParser("outdent")(r,n,a),r=t.subParser("encodeCode")(r,n,a),r=(r=(r=t.subParser("detab")(r,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,""),n.omitExtraWLInCodeBlocks&&(l=""),r="
"+r+l+"
",t.subParser("hashBlock")(r,n,a)+s})).replace(/¨0/,""),e=a.converter._dispatch("codeBlocks.after",e,n,a)}),t.subParser("codeSpans",function(e,n,a){"use strict";return void 0===(e=a.converter._dispatch("codeSpans.before",e,n,a))&&(e=""),e=e.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,i,o,r){var s=r;return s=(s=s.replace(/^([ \t]*)/g,"")).replace(/[ \t]*$/g,""),s=i+""+(s=t.subParser("encodeCode")(s,n,a))+"",s=t.subParser("hashHTMLSpans")(s,n,a)}),e=a.converter._dispatch("codeSpans.after",e,n,a)}),t.subParser("completeHTMLDocument",function(e,t,n){"use strict";if(!t.completeHTMLDocument)return e;e=n.converter._dispatch("completeHTMLDocument.before",e,t,n);var a="html",i="\n",o="",r='\n',s="",l="";for(var u in void 0!==n.metadata.parsed.doctype&&(i="\n","html"!==(a=n.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==a||(r='')),n.metadata.parsed)if(n.metadata.parsed.hasOwnProperty(u))switch(u.toLowerCase()){case"doctype":break;case"title":o=""+n.metadata.parsed.title+"\n";break;case"charset":r="html"===a||"html5"===a?'\n':'\n';break;case"language":case"lang":s=' lang="'+n.metadata.parsed[u]+'"',l+='\n';break;default:l+='\n'}return e=i+"\n\n"+o+r+l+"\n\n"+e.trim()+"\n\n",e=n.converter._dispatch("completeHTMLDocument.after",e,t,n)}),t.subParser("detab",function(e,t,n){"use strict";return e=(e=(e=(e=(e=(e=n.converter._dispatch("detab.before",e,t,n)).replace(/\t(?=\t)/g," ")).replace(/\t/g,"¨A¨B")).replace(/¨B(.+?)¨A/g,function(e,t){for(var n=t,a=4-n.length%4,i=0;i/g,">"),e=n.converter._dispatch("encodeAmpsAndAngles.after",e,t,n)}),t.subParser("encodeBackslashEscapes",function(e,n,a){"use strict";return e=(e=(e=a.converter._dispatch("encodeBackslashEscapes.before",e,n,a)).replace(/\\(\\)/g,t.helper.escapeCharactersCallback)).replace(/\\([`*_{}\[\]()>#+.!~=|:-])/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("encodeBackslashEscapes.after",e,n,a)}),t.subParser("encodeCode",function(e,n,a){"use strict";return e=(e=a.converter._dispatch("encodeCode.before",e,n,a)).replace(/&/g,"&").replace(//g,">").replace(/([*_{}\[\]\\=~-])/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("encodeCode.after",e,n,a)}),t.subParser("escapeSpecialCharsWithinTagAttributes",function(e,n,a){"use strict";return e=(e=(e=a.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",e,n,a)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(e){return e.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)})).replace(/-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(e){return e.replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)}),e=a.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",e,n,a)}),t.subParser("githubCodeBlocks",function(e,n,a){"use strict";return n.ghCodeBlocks?(e=a.converter._dispatch("githubCodeBlocks.before",e,n,a),e=(e=(e+="¨0").replace(/(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\s`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g,function(e,i,o,r){var s=n.omitExtraWLInCodeBlocks?"":"\n";return r=t.subParser("encodeCode")(r,n,a),r="
"+(r=(r=(r=t.subParser("detab")(r,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+s+"
",r=t.subParser("hashBlock")(r,n,a),"\n\n¨G"+(a.ghCodeBlocks.push({text:e,codeblock:r})-1)+"G\n\n"})).replace(/¨0/,""),a.converter._dispatch("githubCodeBlocks.after",e,n,a)):e}),t.subParser("hashBlock",function(e,t,n){"use strict";return e=(e=n.converter._dispatch("hashBlock.before",e,t,n)).replace(/(^\n+|\n+$)/g,""),e="\n\n¨K"+(n.gHtmlBlocks.push(e)-1)+"K\n\n",e=n.converter._dispatch("hashBlock.after",e,t,n)}),t.subParser("hashCodeTags",function(e,n,a){"use strict";e=a.converter._dispatch("hashCodeTags.before",e,n,a);return e=t.helper.replaceRecursiveRegExp(e,function(e,i,o,r){var s=o+t.subParser("encodeCode")(i,n,a)+r;return"¨C"+(a.gHtmlSpans.push(s)-1)+"C"},"]*>","","gim"),e=a.converter._dispatch("hashCodeTags.after",e,n,a)}),t.subParser("hashElement",function(e,t,n){"use strict";return function(e,t){var a=t;return a=(a=(a=a.replace(/\n\n/g,"\n")).replace(/^\n/,"")).replace(/\n+$/g,""),a="\n\n¨K"+(n.gHtmlBlocks.push(a)-1)+"K\n\n"}}),t.subParser("hashHTMLBlocks",function(e,n,a){"use strict";e=a.converter._dispatch("hashHTMLBlocks.before",e,n,a);var i=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],o=function(e,t,n,i){var o=e;return-1!==n.search(/\bmarkdown\b/)&&(o=n+a.converter.makeHtml(t)+i),"\n\n¨K"+(a.gHtmlBlocks.push(o)-1)+"K\n\n"};n.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(e,t){return"<"+t+">"}));for(var r=0;r]*>)","im"),u="<"+i[r]+"\\b[^>]*>",c="";-1!==(s=t.helper.regexIndexOf(e,l));){var d=t.helper.splitAtIndex(e,s),h=t.helper.replaceRecursiveRegExp(d[1],o,u,c,"im");if(h===d[1])break;e=d[0].concat(h)}return e=e.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,n,a)),e=(e=t.helper.replaceRecursiveRegExp(e,function(e){return"\n\n¨K"+(a.gHtmlBlocks.push(e)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm")).replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,n,a)),e=a.converter._dispatch("hashHTMLBlocks.after",e,n,a)}),t.subParser("hashHTMLSpans",function(e,t,n){"use strict";function a(e){return"¨C"+(n.gHtmlSpans.push(e)-1)+"C"}return e=(e=(e=(e=(e=n.converter._dispatch("hashHTMLSpans.before",e,t,n)).replace(/<[^>]+?\/>/gi,function(e){return a(e)})).replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(e){return a(e)})).replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(e){return a(e)})).replace(/<[^>]+?>/gi,function(e){return a(e)}),e=n.converter._dispatch("hashHTMLSpans.after",e,t,n)}),t.subParser("unhashHTMLSpans",function(e,t,n){"use strict";e=n.converter._dispatch("unhashHTMLSpans.before",e,t,n);for(var a=0;a]*>\\s*]*>","^ {0,3}\\s*
","gim"),e=a.converter._dispatch("hashPreCodeTags.after",e,n,a)}),t.subParser("headers",function(e,n,a){"use strict";e=a.converter._dispatch("headers.before",e,n,a);var i=isNaN(parseInt(n.headerLevelStart))?1:parseInt(n.headerLevelStart),o=n.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,r=n.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;e=(e=e.replace(o,function(e,o){var r=t.subParser("spanGamut")(o,n,a),s=n.noHeaderId?"":' id="'+l(o)+'"',u=""+r+"";return t.subParser("hashBlock")(u,n,a)})).replace(r,function(e,o){var r=t.subParser("spanGamut")(o,n,a),s=n.noHeaderId?"":' id="'+l(o)+'"',u=i+1,c=""+r+"";return t.subParser("hashBlock")(c,n,a)});var s=n.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;function l(e){var i,o;if(n.customizedHeaderId){var r=e.match(/\{([^{]+?)}\s*$/);r&&r[1]&&(e=r[1])}return i=e,o=t.helper.isString(n.prefixHeaderId)?n.prefixHeaderId:!0===n.prefixHeaderId?"section-":"",n.rawPrefixHeaderId||(i=o+i),i=n.ghCompatibleHeaderId?i.replace(/ /g,"-").replace(/&/g,"").replace(/¨T/g,"").replace(/¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():n.rawHeaderId?i.replace(/ /g,"-").replace(/&/g,"&").replace(/¨T/g,"¨").replace(/¨D/g,"$").replace(/["']/g,"-").toLowerCase():i.replace(/[^\w]/g,"").toLowerCase(),n.rawPrefixHeaderId&&(i=o+i),a.hashLinkCounts[i]?i=i+"-"+a.hashLinkCounts[i]++:a.hashLinkCounts[i]=1,i}return e=e.replace(s,function(e,o,r){var s=r;n.customizedHeaderId&&(s=r.replace(/\s?\{([^{]+?)}\s*$/,""));var u=t.subParser("spanGamut")(s,n,a),c=n.noHeaderId?"":' id="'+l(r)+'"',d=i-1+o.length,h=""+u+"";return t.subParser("hashBlock")(h,n,a)}),e=a.converter._dispatch("headers.after",e,n,a)}),t.subParser("horizontalRule",function(e,n,a){"use strict";e=a.converter._dispatch("horizontalRule.before",e,n,a);var i=t.subParser("hashBlock")("
",n,a);return e=(e=(e=e.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,i)).replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,i)).replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,i),e=a.converter._dispatch("horizontalRule.after",e,n,a)}),t.subParser("images",function(e,n,a){"use strict";function i(e,n,i,o,r,s,l,u){var c=a.gUrls,d=a.gTitles,h=a.gDimensions;if(i=i.toLowerCase(),u||(u=""),e.search(/\(? ?(['"].*['"])?\)$/m)>-1)o="";else if(""===o||null===o){if(""!==i&&null!==i||(i=n.toLowerCase().replace(/ ?\n/g," ")),o="#"+i,t.helper.isUndefined(c[i]))return e;o=c[i],t.helper.isUndefined(d[i])||(u=d[i]),t.helper.isUndefined(h[i])||(r=h[i].width,s=h[i].height)}n=n.replace(/"/g,""").replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback);var p=''+n+'"}return e=(e=(e=(e=(e=(e=a.converter._dispatch("images.before",e,n,a)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,i)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(e,t,n,a,o,r,s,l){return i(e,t,n,a=a.replace(/\s/g,""),o,r,s,l)})).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,i)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,i)).replace(/!\[([^\[\]]+)]()()()()()/g,i),e=a.converter._dispatch("images.after",e,n,a)}),t.subParser("italicsAndBold",function(e,t,n){"use strict";function a(e,t,n){return t+e+n}return e=n.converter._dispatch("italicsAndBold.before",e,t,n),e=t.literalMidWordUnderscores?(e=(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,t){return a(t,"","")})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,t){return a(t,"","")})).replace(/\b_(\S[\s\S]*?)_\b/g,function(e,t){return a(t,"","")}):(e=(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/__(\S[\s\S]*?)__/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/_([^\s_][\s\S]*?)_/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e}),e=t.literalMidWordAsterisks?(e=(e=e.replace(/([^*]|^)\B\*\*\*(\S[\s\S]*?)\*\*\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")})).replace(/([^*]|^)\B\*\*(\S[\s\S]*?)\*\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")})).replace(/([^*]|^)\B\*(\S[\s\S]*?)\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")}):(e=(e=e.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/\*([^\s*][\s\S]*?)\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e}),e=n.converter._dispatch("italicsAndBold.after",e,t,n)}),t.subParser("lists",function(e,n,a){"use strict";function i(e,i){a.gListLevel++,e=e.replace(/\n{2,}$/,"\n");var o=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,r=/\n[ \t]*\n(?!¨0)/.test(e+="¨0");return n.disableForced4SpacesIndentedSublists&&(o=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm),e=(e=e.replace(o,function(e,i,o,s,l,u,c){c=c&&""!==c.trim();var d=t.subParser("outdent")(l,n,a),h="";return u&&n.tasklists&&(h=' class="task-list-item" style="list-style-type: none;"',d=d.replace(/^[ \t]*\[(x|X| )?]/m,function(){var e='-1?(d=t.subParser("githubCodeBlocks")(d,n,a),d=t.subParser("blockGamut")(d,n,a)):(d=(d=t.subParser("lists")(d,n,a)).replace(/\n$/,""),d=(d=t.subParser("hashHTMLBlocks")(d,n,a)).replace(/\n\n+/g,"\n\n"),d=r?t.subParser("paragraphs")(d,n,a):t.subParser("spanGamut")(d,n,a)),d=""+(d=d.replace("¨A",""))+"\n"})).replace(/¨0/g,""),a.gListLevel--,i&&(e=e.replace(/\s+$/,"")),e}function o(e,t){if("ol"===t){var n=e.match(/^ *(\d+)\./);if(n&&"1"!==n[1])return' start="'+n[1]+'"'}return""}function r(e,t,a){var r=n.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,s=n.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,l="ul"===t?r:s,u="";if(-1!==e.search(l))!function n(c){var d=c.search(l),h=o(e,t);-1!==d?(u+="\n\n<"+t+h+">\n"+i(c.slice(0,d),!!a)+"\n",l="ul"===(t="ul"===t?"ol":"ul")?r:s,n(c.slice(d))):u+="\n\n<"+t+h+">\n"+i(c,!!a)+"\n"}(e);else{var c=o(e,t);u="\n\n<"+t+c+">\n"+i(e,!!a)+"\n"}return u}return e=a.converter._dispatch("lists.before",e,n,a),e+="¨0",e=(e=a.gListLevel?e.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,t,n){return r(t,n.search(/[*+-]/g)>-1?"ul":"ol",!0)}):e.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,t,n,a){return r(n,a.search(/[*+-]/g)>-1?"ul":"ol",!1)})).replace(/¨0/,""),e=a.converter._dispatch("lists.after",e,n,a)}),t.subParser("metadata",function(e,t,n){"use strict";if(!t.metadata)return e;function a(e){n.metadata.raw=e,(e=(e=e.replace(/&/g,"&").replace(/"/g,""")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(e,t,a){return n.metadata.parsed[t]=a,""})}return e=(e=(e=(e=n.converter._dispatch("metadata.before",e,t,n)).replace(/^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/,function(e,t,n){return a(n),"¨M"})).replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(e,t,i){return t&&(n.metadata.format=t),a(i),"¨M"})).replace(/¨M/g,""),e=n.converter._dispatch("metadata.after",e,t,n)}),t.subParser("outdent",function(e,t,n){"use strict";return e=(e=(e=n.converter._dispatch("outdent.before",e,t,n)).replace(/^(\t|[ ]{1,4})/gm,"¨0")).replace(/¨0/g,""),e=n.converter._dispatch("outdent.after",e,t,n)}),t.subParser("paragraphs",function(e,n,a){"use strict";for(var i=(e=(e=(e=a.converter._dispatch("paragraphs.before",e,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),o=[],r=i.length,s=0;s=0?o.push(l):l.search(/\S/)>=0&&(l=(l=t.subParser("spanGamut")(l,n,a)).replace(/^([ \t]*)/g,"

"),l+="

",o.push(l))}for(r=o.length,s=0;s]*>\s*]*>/.test(c)&&(d=!0)}o[s]=c}return e=(e=(e=o.join("\n")).replace(/^\n+/g,"")).replace(/\n+$/g,""),a.converter._dispatch("paragraphs.after",e,n,a)}),t.subParser("runExtension",function(e,t,n,a){"use strict";if(e.filter)t=e.filter(t,a.converter,n);else if(e.regex){var i=e.regex;i instanceof RegExp||(i=new RegExp(i,"g")),t=t.replace(i,e.replace)}return t}),t.subParser("spanGamut",function(e,n,a){"use strict";return e=a.converter._dispatch("spanGamut.before",e,n,a),e=t.subParser("codeSpans")(e,n,a),e=t.subParser("escapeSpecialCharsWithinTagAttributes")(e,n,a),e=t.subParser("encodeBackslashEscapes")(e,n,a),e=t.subParser("images")(e,n,a),e=t.subParser("anchors")(e,n,a),e=t.subParser("autoLinks")(e,n,a),e=t.subParser("simplifiedAutoLinks")(e,n,a),e=t.subParser("emoji")(e,n,a),e=t.subParser("underline")(e,n,a),e=t.subParser("italicsAndBold")(e,n,a),e=t.subParser("strikethrough")(e,n,a),e=t.subParser("ellipsis")(e,n,a),e=t.subParser("hashHTMLSpans")(e,n,a),e=t.subParser("encodeAmpsAndAngles")(e,n,a),n.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,"
\n")):e=e.replace(/ +\n/g,"
\n"),e=a.converter._dispatch("spanGamut.after",e,n,a)}),t.subParser("strikethrough",function(e,n,a){"use strict";return n.strikethrough&&(e=(e=a.converter._dispatch("strikethrough.before",e,n,a)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(e,i){return function(e){return n.simplifiedAutoLink&&(e=t.subParser("simplifiedAutoLinks")(e,n,a)),""+e+""}(i)}),e=a.converter._dispatch("strikethrough.after",e,n,a)),e}),t.subParser("stripLinkDefinitions",function(e,n,a){"use strict";var i=function(i,o,r,s,l,u,c){return o=o.toLowerCase(),e.toLowerCase().split(o).length-1<2?i:(r.match(/^data:.+?\/.+?;base64,/)?a.gUrls[o]=r.replace(/\s/g,""):a.gUrls[o]=t.subParser("encodeAmpsAndAngles")(r,n,a),u?u+c:(c&&(a.gTitles[o]=c.replace(/"|'/g,""")),n.parseImgDimensions&&s&&l&&(a.gDimensions[o]={width:s,height:l}),""))};return e=(e=(e=(e+="¨0").replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm,i)).replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,i)).replace(/¨0/,"")}),t.subParser("tables",function(e,n,a){"use strict";if(!n.tables)return e;function i(e){return/^:[ \t]*--*$/.test(e)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(e)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(e)?' style="text-align:center;"':""}function o(e,i){var o="";return e=e.trim(),(n.tablesHeaderId||n.tableHeaderId)&&(o=' id="'+e.replace(/ /g,"_").toLowerCase()+'"'),""+(e=t.subParser("spanGamut")(e,n,a))+"\n"}function r(e,i){return""+t.subParser("spanGamut")(e,n,a)+"\n"}function s(e){var s,l=e.split("\n");for(s=0;s\n\n\n",i=0;i\n";for(var o=0;o\n"}return n+"\n\n"}(h,f)}return e=(e=(e=(e=a.converter._dispatch("tables.before",e,n,a)).replace(/\\(\|)/g,t.helper.escapeCharactersCallback)).replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,s)).replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm,s),e=a.converter._dispatch("tables.after",e,n,a)}),t.subParser("underline",function(e,n,a){"use strict";return n.underline?(e=a.converter._dispatch("underline.before",e,n,a),e=(e=n.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,t){return""+t+""})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,t){return""+t+""}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/__(\S[\s\S]*?)__/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/(_)/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("underline.after",e,n,a)):e}),t.subParser("unescapeSpecialChars",function(e,t,n){"use strict";return e=(e=n.converter._dispatch("unescapeSpecialChars.before",e,t,n)).replace(/¨E(\d+)E/g,function(e,t){var n=parseInt(t);return String.fromCharCode(n)}),e=n.converter._dispatch("unescapeSpecialChars.after",e,t,n)}),t.subParser("makeMarkdown.blockquote",function(e,n){"use strict";var a="";if(e.hasChildNodes())for(var i=e.childNodes,o=i.length,r=0;r ")}),t.subParser("makeMarkdown.codeBlock",function(e,t){"use strict";var n=e.getAttribute("language"),a=e.getAttribute("precodenum");return"```"+n+"\n"+t.preList[a]+"\n```"}),t.subParser("makeMarkdown.codeSpan",function(e){"use strict";return"`"+e.innerHTML+"`"}),t.subParser("makeMarkdown.emphasis",function(e,n){"use strict";var a="";if(e.hasChildNodes()){a+="*";for(var i=e.childNodes,o=i.length,r=0;r",e.hasAttribute("width")&&e.hasAttribute("height")&&(t+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(t+=' "'+e.getAttribute("title")+'"'),t+=")"),t}),t.subParser("makeMarkdown.links",function(e,n){"use strict";var a="";if(e.hasChildNodes()&&e.hasAttribute("href")){var i=e.childNodes,o=i.length;a="[";for(var r=0;r",e.hasAttribute("title")&&(a+=' "'+e.getAttribute("title")+'"'),a+=")"}return a}),t.subParser("makeMarkdown.list",function(e,n,a){"use strict";var i="";if(!e.hasChildNodes())return"";for(var o=e.childNodes,r=o.length,s=e.getAttribute("start")||1,l=0;l"+t.preList[n]+""}),t.subParser("makeMarkdown.strikethrough",function(e,n){"use strict";var a="";if(e.hasChildNodes()){a+="~~";for(var i=e.childNodes,o=i.length,r=0;rtr>th"),l=e.querySelectorAll("tbody>tr");for(a=0;af&&(f=m)}for(a=0;a/g,"\\$1>")).replace(/^#/gm,"\\#")).replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3")).replace(/^( {0,3}\d+)\./gm,"$1\\.")).replace(/^( {0,3})([+-])/gm,"$1\\$2")).replace(/]([\s]*)\(/g,"\\]$1\\(")).replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")});"function"==typeof define&&define.amd?define(function(){"use strict";return t}):"undefined"!=typeof module&&module.exports?module.exports=t:this.showdown=t}.call(this);var NostrTools=(()=>{var e=Object.defineProperty,t=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i=(t,n)=>{for(var a in n)e(t,a,{get:n[a],enumerable:!0})},o={};function r(e){if(!Number.isSafeInteger(e)||e<0)throw new Error(`Wrong positive integer: ${e}`)}function s(e,...t){if(!(e instanceof Uint8Array))throw new Error("Expected Uint8Array");if(t.length>0&&!t.includes(e.length))throw new Error(`Expected Uint8Array of length ${t}, not of length=${e.length}`)}function l(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}i(o,{Relay:()=>Ba,SimplePool:()=>$a,finalizeEvent:()=>Ft,fj:()=>Sa,generateSecretKey:()=>jt,getEventHash:()=>qt,getFilterLimit:()=>xa,getPublicKey:()=>Bt,kinds:()=>Vt,matchFilter:()=>ya,matchFilters:()=>wa,mergeFilters:()=>ka,nip04:()=>Ni,nip05:()=>Wo,nip10:()=>er,nip11:()=>nr,nip13:()=>or,nip17:()=>ur,nip18:()=>ls,nip19:()=>Va,nip21:()=>hs,nip25:()=>gs,nip27:()=>bs,nip28:()=>Ss,nip30:()=>Ms,nip39:()=>Is,nip42:()=>La,nip44:()=>dr,nip47:()=>js,nip54:()=>$s,nip57:()=>Hs,nip59:()=>cr,nip77:()=>Js,nip98:()=>pl,parseReferences:()=>zi,serializeEvent:()=>It,sortEvents:()=>ft,utils:()=>Pt,validateEvent:()=>pt,verifiedSymbol:()=>dt,verifyEvent:()=>$t});var u="object"==typeof globalThis&&"crypto"in globalThis?globalThis.crypto:void 0,c=e=>e instanceof Uint8Array,d=e=>new DataView(e.buffer,e.byteOffset,e.byteLength),h=(e,t)=>e<<32-t|e>>>t;if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");function p(e){if("string"==typeof e&&(e=function(e){if("string"!=typeof e)throw new Error("utf8ToBytes expected string, got "+typeof e);return new Uint8Array((new TextEncoder).encode(e))}(e)),!c(e))throw new Error("expected Uint8Array, got "+typeof e);return e}var f=class{clone(){return this._cloneInto()}};function m(e){const t=t=>e().update(p(t)).digest(),n=e();return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=()=>e(),t}function g(e=32){if(u&&"function"==typeof u.getRandomValues)return u.getRandomValues(new Uint8Array(e));throw new Error("crypto.getRandomValues must be defined")}var _=class extends f{constructor(e,t,n,a){super(),this.blockLen=e,this.outputLen=t,this.padOffset=n,this.isLE=a,this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.buffer=new Uint8Array(e),this.view=d(this.buffer)}update(e){l(this);const{view:t,buffer:n,blockLen:a}=this,i=(e=p(e)).length;for(let o=0;oa-o&&(this.process(n,0),o=0);for(let e=o;e>i&o),s=Number(n&o),l=a?4:0,u=a?0:4;e.setUint32(t+l,r,a),e.setUint32(t+u,s,a)}(n,a-8,BigInt(8*this.length),i),this.process(n,0);const r=d(e),u=this.outputLen;if(u%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const c=u/4,h=this.get();if(c>h.length)throw new Error("_sha2: outputLen bigger than state");for(let e=0;ee&t^~e&n,b=(e,t,n)=>e&t^e&n^t&n,y=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),w=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),k=new Uint32Array(64),x=class extends _{constructor(){super(64,32,8,!1),this.A=0|w[0],this.B=0|w[1],this.C=0|w[2],this.D=0|w[3],this.E=0|w[4],this.F=0|w[5],this.G=0|w[6],this.H=0|w[7]}get(){const{A:e,B:t,C:n,D:a,E:i,F:o,G:r,H:s}=this;return[e,t,n,a,i,o,r,s]}set(e,t,n,a,i,o,r,s){this.A=0|e,this.B=0|t,this.C=0|n,this.D=0|a,this.E=0|i,this.F=0|o,this.G=0|r,this.H=0|s}process(e,t){for(let n=0;n<16;n++,t+=4)k[n]=e.getUint32(t,!1);for(let e=16;e<64;e++){const t=k[e-15],n=k[e-2],a=h(t,7)^h(t,18)^t>>>3,i=h(n,17)^h(n,19)^n>>>10;k[e]=i+k[e-7]+a+k[e-16]|0}let{A:n,B:a,C:i,D:o,E:r,F:s,G:l,H:u}=this;for(let e=0;e<64;e++){const t=u+(h(r,6)^h(r,11)^h(r,25))+v(r,s,l)+y[e]+k[e]|0,c=(h(n,2)^h(n,13)^h(n,22))+b(n,a,i)|0;u=l,l=s,s=r,r=o+t|0,o=i,i=a,a=n,n=t+c|0}n=n+this.A|0,a=a+this.B|0,i=i+this.C|0,o=o+this.D|0,r=r+this.E|0,s=s+this.F|0,l=l+this.G|0,u=u+this.H|0,this.set(n,a,i,o,r,s,l,u)}roundClean(){k.fill(0)}destroy(){this.set(0,0,0,0,0,0,0,0),this.buffer.fill(0)}},S=m(()=>new x),C={};i(C,{bitGet:()=>H,bitLen:()=>U,bitMask:()=>G,bitSet:()=>W,bytesToHex:()=>L,bytesToNumberBE:()=>O,bytesToNumberLE:()=>I,concatBytes:()=>F,createHmacDrbg:()=>Q,ensureBytes:()=>B,equalBytes:()=>$,hexToBytes:()=>N,hexToNumber:()=>z,numberToBytesBE:()=>q,numberToBytesLE:()=>D,numberToHexUnpadded:()=>R,numberToVarBytesBE:()=>j,utf8ToBytes:()=>V,validateObject:()=>J});var T=BigInt(0),P=BigInt(1),E=BigInt(2),A=e=>e instanceof Uint8Array,M=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function L(e){if(!A(e))throw new Error("Uint8Array expected");let t="";for(let n=0;ne+t.length,0));let n=0;return e.forEach(e=>{if(!A(e))throw new Error("Uint8Array expected");t.set(e,n),n+=e.length}),t}function $(e,t){if(e.length!==t.length)return!1;for(let n=0;nT;e>>=P,t+=1);return t}function H(e,t){return e>>BigInt(t)&P}var W=(e,t,n)=>e|(n?P:T)<(E<new Uint8Array(e),Y=e=>Uint8Array.from(e);function Q(e,t,n){if("number"!=typeof e||e<2)throw new Error("hashLen must be a number");if("number"!=typeof t||t<2)throw new Error("qByteLen must be a number");if("function"!=typeof n)throw new Error("hmacFn must be a function");let a=K(e),i=K(e),o=0;const r=()=>{a.fill(1),i.fill(0),o=0},s=(...e)=>n(i,a,...e),l=(e=K())=>{i=s(Y([0]),e),a=s(),0!==e.length&&(i=s(Y([1]),e),a=s())},u=()=>{if(o++>=1e3)throw new Error("drbg: tried 1000 values");let e=0;const n=[];for(;e{let n;for(r(),l(e);!(n=t(u()));)l();return r(),n}}var Z={bigint:e=>"bigint"==typeof e,function:e=>"function"==typeof e,boolean:e=>"boolean"==typeof e,string:e=>"string"==typeof e,stringOrUint8Array:e=>"string"==typeof e||e instanceof Uint8Array,isSafeInteger:e=>Number.isSafeInteger(e),array:e=>Array.isArray(e),field:(e,t)=>t.Fp.isValid(e),hash:e=>"function"==typeof e&&Number.isSafeInteger(e.outputLen)};function J(e,t,n={}){const a=(t,n,a)=>{const i=Z[n];if("function"!=typeof i)throw new Error(`Invalid validator "${n}", expected function`);const o=e[t];if(!(a&&void 0===o||i(o,e)))throw new Error(`Invalid param ${String(t)}=${o} (${typeof o}), expected ${n}`)};for(const[e,n]of Object.entries(t))a(e,n,!1);for(const[e,t]of Object.entries(n))a(e,t,!0);return e}var X=BigInt(0),ee=BigInt(1),te=BigInt(2),ne=BigInt(3),ae=BigInt(4),ie=BigInt(5),oe=BigInt(8);BigInt(9),BigInt(16);function re(e,t){const n=e%t;return n>=X?n:t+n}function se(e,t,n){if(n<=X||t 0");if(n===ee)return X;let a=ee;for(;t>X;)t&ee&&(a=a*e%n),e=e*e%n,t>>=ee;return a}function le(e,t,n){let a=e;for(;t-- >X;)a*=a,a%=n;return a}function ue(e,t){if(e===X||t<=X)throw new Error(`invert: expected positive integers, got n=${e} mod=${t}`);let n=re(e,t),a=t,i=X,o=ee,r=ee,s=X;for(;n!==X;){const e=a/n,t=a%n,l=i-r*e,u=o-s*e;a=n,n=t,i=r,o=s,r=l,s=u}if(a!==ee)throw new Error("invert: does not exist");return re(i,t)}function ce(e){if(e%ae===ne){const t=(e+ee)/ae;return function(e,n){const a=e.pow(n,t);if(!e.eql(e.sqr(a),n))throw new Error("Cannot find square root");return a}}if(e%oe===ie){const t=(e-ie)/oe;return function(e,n){const a=e.mul(n,te),i=e.pow(a,t),o=e.mul(n,i),r=e.mul(e.mul(o,te),i),s=e.mul(o,e.sub(r,e.ONE));if(!e.eql(e.sqr(s),n))throw new Error("Cannot find square root");return s}}return function(e){const t=(e-ee)/te;let n,a,i;for(n=e-ee,a=0;n%te===X;n/=te,a++);for(i=te;i(e[t]="function",e),{ORDER:"bigint",MASK:"bigint",BYTES:"isSafeInteger",BITS:"isSafeInteger"})),J(e,{n:"bigint",h:"bigint",Gx:"field",Gy:"field"},{nBitLength:"isSafeInteger",nByteLength:"isSafeInteger"}),Object.freeze({...he(e.n,e.nBitLength),...e,p:e.Fp.ORDER})}var{bytesToNumberBE:ve,hexToBytes:be}=C,ye={Err:class extends Error{constructor(e=""){super(e)}},_parseInt(e){const{Err:t}=ye;if(e.length<2||2!==e[0])throw new t("Invalid signature integer tag");const n=e[1],a=e.subarray(2,n+2);if(!n||a.length!==n)throw new t("Invalid signature integer: wrong length");if(128&a[0])throw new t("Invalid signature integer: negative");if(0===a[0]&&!(128&a[1]))throw new t("Invalid signature integer: unnecessary leading zero");return{d:ve(a),l:e.subarray(n+2)}},toSig(e){const{Err:t}=ye,n="string"==typeof e?be(e):e;if(!(n instanceof Uint8Array))throw new Error("ui8a expected");let a=n.length;if(a<2||48!=n[0])throw new t("Invalid signature tag");if(n[1]!==a-2)throw new t("Invalid signature: incorrect length");const{d:i,l:o}=ye._parseInt(n.subarray(2)),{d:r,l:s}=ye._parseInt(o);if(s.length)throw new t("Invalid signature: left bytes after parsing");return{r:i,s:r}},hexFromSig(e){const t=e=>8&Number.parseInt(e[0],16)?"00"+e:e,n=e=>{const t=e.toString(16);return 1&t.length?`0${t}`:t},a=t(n(e.s)),i=t(n(e.r)),o=a.length/2,r=i.length/2,s=n(o),l=n(r);return`30${n(r+o+4)}02${l}${i}02${s}${a}`}},we=BigInt(0),ke=BigInt(1),xe=(BigInt(2),BigInt(3));BigInt(4);function Se(e){const t=function(e){const t=_e(e);J(t,{a:"field",b:"field"},{allowedPrivateKeyLengths:"array",wrapPrivateKey:"boolean",isTorsionFree:"function",clearCofactor:"function",allowInfinityPoint:"boolean",fromBytes:"function",toBytes:"function"});const{endo:n,Fp:a,a:i}=t;if(n){if(!a.eql(i,a.ZERO))throw new Error("Endomorphism can only be defined for Koblitz curves that have a=0");if("object"!=typeof n||"bigint"!=typeof n.beta||"function"!=typeof n.splitScalar)throw new Error("Expected endomorphism with beta: bigint and splitScalar: function")}return Object.freeze({...t})}(e),{Fp:n}=t,a=t.toBytes||((e,t,a)=>{const i=t.toAffine();return F(Uint8Array.from([4]),n.toBytes(i.x),n.toBytes(i.y))}),i=t.fromBytes||(e=>{const t=e.subarray(1);return{x:n.fromBytes(t.subarray(0,n.BYTES)),y:n.fromBytes(t.subarray(n.BYTES,2*n.BYTES))}});function o(e){const{a:a,b:i}=t,o=n.sqr(e),r=n.mul(o,e);return n.add(n.add(r,n.mul(e,a)),i)}if(!n.eql(n.sqr(t.Gy),o(t.Gx)))throw new Error("bad generator point: equation left != right");function r(e){return"bigint"==typeof e&&wen.eql(e,n.ZERO);return i(t)&&i(a)?d.ZERO:new d(t,a,n.ONE)}get x(){return this.toAffine().x}get y(){return this.toAffine().y}static normalizeZ(e){const t=n.invertBatch(e.map(e=>e.pz));return e.map((e,n)=>e.toAffine(t[n])).map(d.fromAffine)}static fromHex(e){const t=d.fromAffine(i(B("pointHex",e)));return t.assertValidity(),t}static fromPrivateKey(e){return d.BASE.multiply(l(e))}_setWindowSize(e){this._WINDOW_SIZE=e,u.delete(this)}assertValidity(){if(this.is0()){if(t.allowInfinityPoint&&!n.is0(this.py))return;throw new Error("bad point: ZERO")}const{x:e,y:a}=this.toAffine();if(!n.isValid(e)||!n.isValid(a))throw new Error("bad point: x or y not FE");const i=n.sqr(a),r=o(e);if(!n.eql(i,r))throw new Error("bad point: equation left != right");if(!this.isTorsionFree())throw new Error("bad point: not in prime-order subgroup")}hasEvenY(){const{y:e}=this.toAffine();if(n.isOdd)return!n.isOdd(e);throw new Error("Field doesn't support isOdd")}equals(e){c(e);const{px:t,py:a,pz:i}=this,{px:o,py:r,pz:s}=e,l=n.eql(n.mul(t,s),n.mul(o,i)),u=n.eql(n.mul(a,s),n.mul(r,i));return l&&u}negate(){return new d(this.px,n.neg(this.py),this.pz)}double(){const{a:e,b:a}=t,i=n.mul(a,xe),{px:o,py:r,pz:s}=this;let l=n.ZERO,u=n.ZERO,c=n.ZERO,h=n.mul(o,o),p=n.mul(r,r),f=n.mul(s,s),m=n.mul(o,r);return m=n.add(m,m),c=n.mul(o,s),c=n.add(c,c),l=n.mul(e,c),u=n.mul(i,f),u=n.add(l,u),l=n.sub(p,u),u=n.add(p,u),u=n.mul(l,u),l=n.mul(m,l),c=n.mul(i,c),f=n.mul(e,f),m=n.sub(h,f),m=n.mul(e,m),m=n.add(m,c),c=n.add(h,h),h=n.add(c,h),h=n.add(h,f),h=n.mul(h,m),u=n.add(u,h),f=n.mul(r,s),f=n.add(f,f),h=n.mul(f,m),l=n.sub(l,h),c=n.mul(f,p),c=n.add(c,c),c=n.add(c,c),new d(l,u,c)}add(e){c(e);const{px:a,py:i,pz:o}=this,{px:r,py:s,pz:l}=e;let u=n.ZERO,h=n.ZERO,p=n.ZERO;const f=t.a,m=n.mul(t.b,xe);let g=n.mul(a,r),_=n.mul(i,s),v=n.mul(o,l),b=n.add(a,i),y=n.add(r,s);b=n.mul(b,y),y=n.add(g,_),b=n.sub(b,y),y=n.add(a,o);let w=n.add(r,l);return y=n.mul(y,w),w=n.add(g,v),y=n.sub(y,w),w=n.add(i,o),u=n.add(s,l),w=n.mul(w,u),u=n.add(_,v),w=n.sub(w,u),p=n.mul(f,y),u=n.mul(m,v),p=n.add(u,p),u=n.sub(_,p),p=n.add(_,p),h=n.mul(u,p),_=n.add(g,g),_=n.add(_,g),v=n.mul(f,v),y=n.mul(m,y),_=n.add(_,v),v=n.sub(g,v),v=n.mul(f,v),y=n.add(y,v),g=n.mul(_,y),h=n.add(h,g),g=n.mul(w,y),u=n.mul(b,u),u=n.sub(u,g),g=n.mul(b,_),p=n.mul(w,p),p=n.add(p,g),new d(u,h,p)}subtract(e){return this.add(e.negate())}is0(){return this.equals(d.ZERO)}wNAF(e){return p.wNAFCached(this,u,e,e=>{const t=n.invertBatch(e.map(e=>e.pz));return e.map((e,n)=>e.toAffine(t[n])).map(d.fromAffine)})}multiplyUnsafe(e){const a=d.ZERO;if(e===we)return a;if(s(e),e===ke)return this;const{endo:i}=t;if(!i)return p.unsafeLadder(this,e);let{k1neg:o,k1:r,k2neg:l,k2:u}=i.splitScalar(e),c=a,h=a,f=this;for(;r>we||u>we;)r&ke&&(c=c.add(f)),u&ke&&(h=h.add(f)),f=f.double(),r>>=ke,u>>=ke;return o&&(c=c.negate()),l&&(h=h.negate()),h=new d(n.mul(h.px,i.beta),h.py,h.pz),c.add(h)}multiply(e){s(e);let a,i,o=e;const{endo:r}=t;if(r){const{k1neg:e,k1:t,k2neg:s,k2:l}=r.splitScalar(o);let{p:u,f:c}=this.wNAF(t),{p:h,f:f}=this.wNAF(l);u=p.constTimeNegate(e,u),h=p.constTimeNegate(s,h),h=new d(n.mul(h.px,r.beta),h.py,h.pz),a=u.add(h),i=c.add(f)}else{const{p:e,f:t}=this.wNAF(o);a=e,i=t}return d.normalizeZ([a,i])[0]}multiplyAndAddUnsafe(e,t,n){const a=d.BASE,i=(e,t)=>t!==we&&t!==ke&&e.equals(a)?e.multiply(t):e.multiplyUnsafe(t),o=i(this,t).add(i(e,n));return o.is0()?void 0:o}toAffine(e){const{px:t,py:a,pz:i}=this,o=this.is0();null==e&&(e=o?n.ONE:n.inv(i));const r=n.mul(t,e),s=n.mul(a,e),l=n.mul(i,e);if(o)return{x:n.ZERO,y:n.ZERO};if(!n.eql(l,n.ONE))throw new Error("invZ was invalid");return{x:r,y:s}}isTorsionFree(){const{h:e,isTorsionFree:n}=t;if(e===ke)return!0;if(n)return n(d,this);throw new Error("isTorsionFree() has not been declared for the elliptic curve")}clearCofactor(){const{h:e,clearCofactor:n}=t;return e===ke?this:n?n(d,this):this.multiplyUnsafe(t.h)}toRawBytes(e=!0){return this.assertValidity(),a(d,this,e)}toHex(e=!0){return L(this.toRawBytes(e))}}d.BASE=new d(t.Gx,t.Gy,n.ONE),d.ZERO=new d(n.ZERO,n.ONE,n.ZERO);const h=t.nBitLength,p=function(e,t){const n=(e,t)=>{const n=t.negate();return e?n:t},a=e=>({windows:Math.ceil(t/e)+1,windowSize:2**(e-1)});return{constTimeNegate:n,unsafeLadder(t,n){let a=e.ZERO,i=t;for(;n>me;)n&ge&&(a=a.add(i)),i=i.double(),n>>=ge;return a},precomputeWindow(e,t){const{windows:n,windowSize:i}=a(t),o=[];let r=e,s=r;for(let e=0;e>=h,a>s&&(a-=d,o+=ge);const r=t,p=t+Math.abs(a)-1,f=e%2!=0,m=a<0;0===a?u=u.add(n(f,i[r])):l=l.add(n(m,i[p]))}return{p:l,f:u}},wNAFCached(e,t,n,a){const i=e._WINDOW_SIZE||1;let o=t.get(e);return o||(o=this.precomputeWindow(e,i),1!==i&&t.set(e,a(o))),this.wNAF(i,o,n)}}}(d,t.endo?Math.ceil(h/2):h);return{CURVE:t,ProjectivePoint:d,normPrivateKeyToScalar:l,weierstrassEquation:o,isWithinCurveOrder:r}}function Ce(e){const t=function(e){const t=_e(e);return J(t,{hash:"hash",hmac:"function",randomBytes:"function"},{bits2int:"function",bits2int_modN:"function",lowS:"boolean"}),Object.freeze({lowS:!0,...t})}(e),{Fp:n,n:a}=t,i=n.BYTES+1,o=2*n.BYTES+1;function r(e){return re(e,a)}function s(e){return ue(e,a)}const{ProjectivePoint:l,normPrivateKeyToScalar:u,weierstrassEquation:c,isWithinCurveOrder:d}=Se({...t,toBytes(e,t,a){const i=t.toAffine(),o=n.toBytes(i.x),r=F;return a?r(Uint8Array.from([t.hasEvenY()?2:3]),o):r(Uint8Array.from([4]),o,n.toBytes(i.y))},fromBytes(e){const t=e.length,a=e[0],r=e.subarray(1);if(t!==i||2!==a&&3!==a){if(t===o&&4===a){return{x:n.fromBytes(r.subarray(0,n.BYTES)),y:n.fromBytes(r.subarray(n.BYTES,2*n.BYTES))}}throw new Error(`Point of length ${t} was invalid. Expected ${i} compressed bytes or ${o} uncompressed bytes`)}{const e=O(r);if(!(we<(s=e)&&sL(q(e,t.nByteLength));function p(e){return e>a>>ke}const f=(e,t,n)=>O(e.slice(t,n));class m{constructor(e,t,n){this.r=e,this.s=t,this.recovery=n,this.assertValidity()}static fromCompact(e){const n=t.nByteLength;return e=B("compactSignature",e,2*n),new m(f(e,0,n),f(e,n,2*n))}static fromDER(e){const{r:t,s:n}=ye.toSig(B("DER",e));return new m(t,n)}assertValidity(){if(!d(this.r))throw new Error("r must be 0 < r < CURVE.n");if(!d(this.s))throw new Error("s must be 0 < s < CURVE.n")}addRecoveryBit(e){return new m(this.r,this.s,e)}recoverPublicKey(e){const{r:a,s:i,recovery:o}=this,u=b(B("msgHash",e));if(null==o||![0,1,2,3].includes(o))throw new Error("recovery id invalid");const c=2===o||3===o?a+t.n:a;if(c>=n.ORDER)throw new Error("recovery id 2 or 3 invalid");const d=1&o?"03":"02",p=l.fromHex(d+h(c)),f=s(c),m=r(-u*f),g=r(i*f),_=l.BASE.multiplyAndAddUnsafe(p,m,g);if(!_)throw new Error("point at infinify");return _.assertValidity(),_}hasHighS(){return p(this.s)}normalizeS(){return this.hasHighS()?new m(this.r,r(-this.s),this.recovery):this}toDERRawBytes(){return N(this.toDERHex())}toDERHex(){return ye.hexFromSig({r:this.r,s:this.s})}toCompactRawBytes(){return N(this.toCompactHex())}toCompactHex(){return h(this.r)+h(this.s)}}const g={isValidPrivateKey(e){try{return u(e),!0}catch(e){return!1}},normPrivateKeyToScalar:u,randomPrivateKey:()=>{const e=fe(t.n);return function(e,t,n=!1){const a=e.length,i=pe(t),o=fe(t);if(a<16||a1024)throw new Error(`expected ${o}-1024 bytes of input, got ${a}`);const r=re(n?O(e):I(e),t-ee)+ee;return n?D(r,i):q(r,i)}(t.randomBytes(e),t.n)},precompute:(e=8,t=l.BASE)=>(t._setWindowSize(e),t.multiply(BigInt(3)),t)};function _(e){const t=e instanceof Uint8Array,n="string"==typeof e,a=(t||n)&&e.length;return t?a===i||a===o:n?a===2*i||a===2*o:e instanceof l}const v=t.bits2int||function(e){const n=O(e),a=8*e.length-t.nBitLength;return a>0?n>>BigInt(a):n},b=t.bits2int_modN||function(e){return r(v(e))},y=G(t.nBitLength);function w(e){if("bigint"!=typeof e)throw new Error("bigint expected");if(!(we<=e&&ee in i))throw new Error("sign() legacy options not supported");const{hash:o,randomBytes:c}=t;let{lowS:h,prehash:f,extraEntropy:g}=i;null==h&&(h=!0),e=B("msgHash",e),f&&(e=B("prehashed msgHash",o(e)));const _=b(e),y=u(a),k=[w(y),w(_)];if(null!=g){const e=!0===g?c(n.BYTES):g;k.push(B("extraEntropy",e))}const S=F(...k),C=_;return{seed:S,k2sig:function(e){const t=v(e);if(!d(t))return;const n=s(t),a=l.BASE.multiply(t).toAffine(),i=r(a.x);if(i===we)return;const o=r(n*r(C+i*y));if(o===we)return;let u=(a.x===i?0:2)|Number(a.y&ke),c=o;return h&&p(o)&&(c=function(e){return p(e)?r(-e):e}(o),u^=1),new m(i,c,u)}}}const x={lowS:t.lowS,prehash:!1},S={lowS:t.lowS,prehash:!1};return l.BASE._setWindowSize(8),{CURVE:t,getPublicKey:function(e,t=!0){return l.fromPrivateKey(e).toRawBytes(t)},getSharedSecret:function(e,t,n=!0){if(_(e))throw new Error("first arg must be private key");if(!_(t))throw new Error("second arg must be public key");return l.fromHex(t).multiply(u(e)).toRawBytes(n)},sign:function(e,n,a=x){const{seed:i,k2sig:o}=k(e,n,a),r=t;return Q(r.hash.outputLen,r.nByteLength,r.hmac)(i,o)},verify:function(e,n,a,i=S){const o=e;if(n=B("msgHash",n),a=B("publicKey",a),"strict"in i)throw new Error("options.strict was renamed to lowS");const{lowS:u,prehash:c}=i;let d,h;try{if("string"==typeof o||o instanceof Uint8Array)try{d=m.fromDER(o)}catch(e){if(!(e instanceof ye.Err))throw e;d=m.fromCompact(o)}else{if("object"!=typeof o||"bigint"!=typeof o.r||"bigint"!=typeof o.s)throw new Error("PARSE");{const{r:e,s:t}=o;d=new m(e,t)}}h=l.fromHex(a)}catch(e){if("PARSE"===e.message)throw new Error("signature must be Signature instance, Uint8Array or hex string");return!1}if(u&&d.hasHighS())return!1;c&&(n=t.hash(n));const{r:p,s:f}=d,g=b(n),_=s(f),v=r(g*_),y=r(p*_),w=l.BASE.multiplyAndAddUnsafe(h,v,y)?.toAffine();return!!w&&r(w.x)===p},ProjectivePoint:l,Signature:m,utils:g}}var Te=class extends f{constructor(e,t){super(),this.finished=!1,this.destroyed=!1,function(e){if("function"!=typeof e||"function"!=typeof e.create)throw new Error("Hash should be wrapped by utils.wrapConstructor");r(e.outputLen),r(e.blockLen)}(e);const n=p(t);if(this.iHash=e.create(),"function"!=typeof this.iHash.update)throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;const a=this.blockLen,i=new Uint8Array(a);i.set(n.length>a?e.create().update(n).digest():n);for(let e=0;enew Te(e,t).update(n).digest();function Ee(e){return{hash:e,hmac:(t,...n)=>Pe(e,t,function(...e){const t=new Uint8Array(e.reduce((e,t)=>e+t.length,0));let n=0;return e.forEach(e=>{if(!c(e))throw new Error("Uint8Array expected");t.set(e,n),n+=e.length}),t}(...n)),randomBytes:g}}Pe.create=(e,t)=>new Te(e,t);var Ae=BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),Me=BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),Le=BigInt(1),Re=BigInt(2),ze=(e,t)=>(e+t/Re)/t;function Ne(e){const t=Ae,n=BigInt(3),a=BigInt(6),i=BigInt(11),o=BigInt(22),r=BigInt(23),s=BigInt(44),l=BigInt(88),u=e*e*e%t,c=u*u*e%t,d=le(c,n,t)*c%t,h=le(d,n,t)*c%t,p=le(h,Re,t)*u%t,f=le(p,i,t)*p%t,m=le(f,o,t)*f%t,g=le(m,s,t)*m%t,_=le(g,l,t)*g%t,v=le(_,s,t)*m%t,b=le(v,n,t)*c%t,y=le(b,r,t)*f%t,w=le(y,a,t)*u%t,k=le(w,Re,t);if(!Oe.eql(Oe.sqr(k),e))throw new Error("Cannot find square root");return k}var Oe=function(e,t,n=!1,a={}){if(e<=X)throw new Error(`Expected Field ORDER > 0, got ${e}`);const{nBitLength:i,nByteLength:o}=he(e,t);if(o>2048)throw new Error("Field lengths over 2048 bytes are not supported");const r=ce(e),s=Object.freeze({ORDER:e,BITS:i,BYTES:o,MASK:G(i),ZERO:X,ONE:ee,create:t=>re(t,e),isValid:t=>{if("bigint"!=typeof t)throw new Error("Invalid field element: expected bigint, got "+typeof t);return X<=t&&te===X,isOdd:e=>(e&ee)===ee,neg:t=>re(-t,e),eql:(e,t)=>e===t,sqr:t=>re(t*t,e),add:(t,n)=>re(t+n,e),sub:(t,n)=>re(t-n,e),mul:(t,n)=>re(t*n,e),pow:(e,t)=>function(e,t,n){if(n 0");if(n===X)return e.ONE;if(n===ee)return t;let a=e.ONE,i=t;for(;n>X;)n&ee&&(a=e.mul(a,i)),i=e.sqr(i),n>>=ee;return a}(s,e,t),div:(t,n)=>re(t*ue(n,e),e),sqrN:e=>e*e,addN:(e,t)=>e+t,subN:(e,t)=>e-t,mulN:(e,t)=>e*t,inv:t=>ue(t,e),sqrt:a.sqrt||(e=>r(s,e)),invertBatch:e=>function(e,t){const n=new Array(t.length),a=t.reduce((t,a,i)=>e.is0(a)?t:(n[i]=t,e.mul(t,a)),e.ONE),i=e.inv(a);return t.reduceRight((t,a,i)=>e.is0(a)?t:(n[i]=e.mul(t,n[i]),e.mul(t,a)),i),n}(s,e),cmov:(e,t,n)=>n?t:e,toBytes:e=>n?D(e,o):q(e,o),fromBytes:e=>{if(e.length!==o)throw new Error(`Fp.fromBytes: expected ${o}, got ${e.length}`);return n?I(e):O(e)}});return Object.freeze(s)}(Ae,void 0,void 0,{sqrt:Ne}),Ie=function(e,t){const n=t=>Ce({...e,...Ee(t)});return Object.freeze({...n(t),create:n})}({a:BigInt(0),b:BigInt(7),Fp:Oe,n:Me,Gx:BigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240"),Gy:BigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424"),h:BigInt(1),lowS:!0,endo:{beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),splitScalar:e=>{const t=Me,n=BigInt("0x3086d221a7d46bcde86c90e49284eb15"),a=-Le*BigInt("0xe4437ed6010e88286f547fa90abfe4c3"),i=BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),o=n,r=BigInt("0x100000000000000000000000000000000"),s=ze(o*e,t),l=ze(-a*e,t);let u=re(e-s*n-l*i,t),c=re(-s*a-l*o,t);const d=u>r,h=c>r;if(d&&(u=t-u),h&&(c=t-c),u>r||c>r)throw new Error("splitScalar: Endomorphism failed, k="+e);return{k1neg:d,k1:u,k2neg:h,k2:c}}}},S),qe=BigInt(0),De=e=>"bigint"==typeof e&&qee.charCodeAt(0)));n=F(t,t),je[e]=n}return S(F(n,...t))}var Fe=e=>e.toRawBytes(!0).slice(1),$e=e=>q(e,32),Ve=e=>re(e,Ae),Ue=e=>re(e,Me),He=Ie.ProjectivePoint;function We(e){let t=Ie.utils.normPrivateKeyToScalar(e),n=He.fromPrivateKey(t);return{scalar:n.hasEvenY()?t:Ue(-t),bytes:Fe(n)}}function Ge(e){if(!De(e))throw new Error("bad x: need 0 < x < p");const t=Ve(e*e);let n=Ne(Ve(t*e+BigInt(7)));n%Re!==qe&&(n=Ve(-n));const a=new He(e,n,Le);return a.assertValidity(),a}function Ke(...e){return Ue(O(Be("BIP0340/challenge",...e)))}function Ye(e){return We(e).bytes}function Qe(e,t,n=g(32)){const a=B("message",e),{bytes:i,scalar:o}=We(t),r=B("auxRand",n,32),s=$e(o^O(Be("BIP0340/aux",r))),l=Be("BIP0340/nonce",s,i,a),u=Ue(O(l));if(u===qe)throw new Error("sign failed: k is zero");const{bytes:c,scalar:d}=We(u),h=Ke(c,i,a),p=new Uint8Array(64);if(p.set(c,0),p.set($e(Ue(d+h*o)),32),!Ze(p,a,i))throw new Error("sign: Invalid signature produced");return p}function Ze(e,t,n){const a=B("signature",e,64),i=B("message",t),o=B("publicKey",n,32);try{const e=Ge(O(o)),t=O(a.subarray(0,32));if(!De(t))return!1;const n=O(a.subarray(32,64));if(!("bigint"==typeof(u=n)&&qe({getPublicKey:Ye,sign:Qe,verify:Ze,utils:{randomPrivateKey:Ie.utils.randomPrivateKey,lift_x:Ge,pointToBytes:Fe,numberToBytesBE:q,bytesToNumberBE:O,taggedHash:Be,mod:re}}))(),Xe="object"==typeof globalThis&&"crypto"in globalThis?globalThis.crypto:void 0,et=e=>e instanceof Uint8Array,tt=e=>new DataView(e.buffer,e.byteOffset,e.byteLength),nt=(e,t)=>e<<32-t|e>>>t;if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");var at=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function it(e){if(!et(e))throw new Error("Uint8Array expected");let t="";for(let n=0;ne+t.length,0));let n=0;return e.forEach(e=>{if(!et(e))throw new Error("Uint8Array expected");t.set(e,n),n+=e.length}),t}var lt=class{clone(){return this._cloneInto()}};function ut(e){const t=t=>e().update(rt(t)).digest(),n=e();return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=()=>e(),t}function ct(e=32){if(Xe&&"function"==typeof Xe.getRandomValues)return Xe.getRandomValues(new Uint8Array(e));throw new Error("crypto.getRandomValues must be defined")}var dt=Symbol("verified"),ht=e=>e instanceof Object;function pt(e){if(!ht(e))return!1;if("number"!=typeof e.kind)return!1;if("string"!=typeof e.content)return!1;if("number"!=typeof e.created_at)return!1;if("string"!=typeof e.pubkey)return!1;if(!e.pubkey.match(/^[a-f0-9]{64}$/))return!1;if(!Array.isArray(e.tags))return!1;for(let t=0;te.created_at!==t.created_at?t.created_at-e.created_at:e.id.localeCompare(t.id))}function mt(e){if(!Number.isSafeInteger(e)||e<0)throw new Error(`Wrong positive integer: ${e}`)}function gt(e,...t){if(!(e instanceof Uint8Array))throw new Error("Expected Uint8Array");if(t.length>0&&!t.includes(e.length))throw new Error(`Expected Uint8Array of length ${t}, not of length=${e.length}`)}var _t={number:mt,bool:function(e){if("boolean"!=typeof e)throw new Error(`Expected boolean, not ${e}`)},bytes:gt,hash:function(e){if("function"!=typeof e||"function"!=typeof e.create)throw new Error("Hash should be wrapped by utils.wrapConstructor");mt(e.outputLen),mt(e.blockLen)},exists:function(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")},output:function(e,t){gt(e);const n=t.outputLen;if(e.lengtha-o&&(this.process(n,0),o=0);for(let e=o;e>i&o),s=Number(n&o),l=a?4:0,u=a?0:4;e.setUint32(t+l,r,a),e.setUint32(t+u,s,a)}(n,a-8,BigInt(8*this.length),i),this.process(n,0);const r=tt(e),s=this.outputLen;if(s%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const l=s/4,u=this.get();if(l>u.length)throw new Error("_sha2: outputLen bigger than state");for(let e=0;ee&t^~e&n,yt=(e,t,n)=>e&t^e&n^t&n,wt=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),kt=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),xt=new Uint32Array(64),St=class extends vt{constructor(){super(64,32,8,!1),this.A=0|kt[0],this.B=0|kt[1],this.C=0|kt[2],this.D=0|kt[3],this.E=0|kt[4],this.F=0|kt[5],this.G=0|kt[6],this.H=0|kt[7]}get(){const{A:e,B:t,C:n,D:a,E:i,F:o,G:r,H:s}=this;return[e,t,n,a,i,o,r,s]}set(e,t,n,a,i,o,r,s){this.A=0|e,this.B=0|t,this.C=0|n,this.D=0|a,this.E=0|i,this.F=0|o,this.G=0|r,this.H=0|s}process(e,t){for(let n=0;n<16;n++,t+=4)xt[n]=e.getUint32(t,!1);for(let e=16;e<64;e++){const t=xt[e-15],n=xt[e-2],a=nt(t,7)^nt(t,18)^t>>>3,i=nt(n,17)^nt(n,19)^n>>>10;xt[e]=i+xt[e-7]+a+xt[e-16]|0}let{A:n,B:a,C:i,D:o,E:r,F:s,G:l,H:u}=this;for(let e=0;e<64;e++){const t=u+(nt(r,6)^nt(r,11)^nt(r,25))+bt(r,s,l)+wt[e]+xt[e]|0,c=(nt(n,2)^nt(n,13)^nt(n,22))+yt(n,a,i)|0;u=l,l=s,s=r,r=o+t|0,o=i,i=a,a=n,n=t+c|0}n=n+this.A|0,a=a+this.B|0,i=i+this.C|0,o=o+this.D|0,r=r+this.E|0,s=s+this.F|0,l=l+this.G|0,u=u+this.H|0,this.set(n,a,i,o,r,s,l,u)}roundClean(){xt.fill(0)}destroy(){this.set(0,0,0,0,0,0,0,0),this.buffer.fill(0)}},Ct=class extends St{constructor(){super(),this.A=-1056596264,this.B=914150663,this.C=812702999,this.D=-150054599,this.E=-4191439,this.F=1750603025,this.G=1694076839,this.H=-1090891868,this.outputLen=28}},Tt=ut(()=>new St),Pt=(ut(()=>new Ct),{});i(Pt,{Queue:()=>Ot,QueueNode:()=>Nt,binarySearch:()=>zt,bytesToHex:()=>it,hexToBytes:()=>ot,insertEventIntoAscendingList:()=>Rt,insertEventIntoDescendingList:()=>Lt,normalizeURL:()=>Mt,utf8Decoder:()=>Et,utf8Encoder:()=>At});var Et=new TextDecoder("utf-8"),At=new TextEncoder;function Mt(e){try{-1===e.indexOf("://")&&(e="wss://"+e);let t=new URL(e);return"http:"===t.protocol?t.protocol="ws:":"https:"===t.protocol&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),("80"===t.port&&"ws:"===t.protocol||"443"===t.port&&"wss:"===t.protocol)&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch(t){throw new Error(`Invalid URL: ${e}`)}}function Lt(e,t){const[n,a]=zt(e,e=>t.id===e.id?0:t.created_at===e.created_at?-1:e.created_at-t.created_at);return a||e.splice(n,0,t),e}function Rt(e,t){const[n,a]=zt(e,e=>t.id===e.id?0:t.created_at===e.created_at?-1:t.created_at-e.created_at);return a||e.splice(n,0,t),e}function zt(e,t){let n=0,a=e.length-1;for(;n<=a;){const i=Math.floor((n+a)/2),o=t(e[i]);if(0===o)return[i,!0];o<0?a=i-1:n=i+1}return[n,!1]}var Nt=class{value;next=null;prev=null;constructor(e){this.value=e}},Ot=class{first;last;constructor(){this.first=null,this.last=null}enqueue(e){const t=new Nt(e);return this.last?this.last===this.first?(this.last=t,this.last.prev=this.first,this.first.next=t):(t.prev=this.last,this.last.next=t,this.last=t):(this.first=t,this.last=t),!0}dequeue(){if(!this.first)return null;if(this.first===this.last){const e=this.first;return this.first=null,this.last=null,e.value}const e=this.first;return this.first=e.next,this.first&&(this.first.prev=null),e.value}};function It(e){if(!pt(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function qt(e){return it(Tt(At.encode(It(e))))}var Dt=new class{generateSecretKey(){return Je.utils.randomPrivateKey()}getPublicKey(e){return it(Je.getPublicKey(e))}finalizeEvent(e,t){const n=e;return n.pubkey=it(Je.getPublicKey(t)),n.id=qt(n),n.sig=it(Je.sign(qt(n),t)),n[dt]=!0,n}verifyEvent(e){if("boolean"==typeof e[dt])return e[dt];const t=qt(e);if(t!==e.id)return e[dt]=!1,!1;try{const n=Je.verify(e.sig,t,e.pubkey);return e[dt]=n,n}catch(t){return e[dt]=!1,!1}}},jt=Dt.generateSecretKey,Bt=Dt.getPublicKey,Ft=Dt.finalizeEvent,$t=Dt.verifyEvent,Vt={};function Ut(e){return e<1e4&&0!==e&&3!==e}function Ht(e){return 0===e||3===e||1e4<=e&&e<2e4}function Wt(e){return 2e4<=e&&e<3e4}function Gt(e){return 3e4<=e&&e<4e4}function Kt(e){return Ut(e)?"regular":Ht(e)?"replaceable":Wt(e)?"ephemeral":Gt(e)?"parameterized":"unknown"}function Yt(e,t){const n=t instanceof Array?t:[t];return pt(e)&&n.includes(e.kind)||!1}i(Vt,{Application:()=>la,BadgeAward:()=>on,BadgeDefinition:()=>ta,BlockedRelaysList:()=>In,BookmarkList:()=>zn,Bookmarksets:()=>Jn,Calendar:()=>ma,CalendarEventRSVP:()=>ga,ChannelCreation:()=>un,ChannelHideMessage:()=>hn,ChannelMessage:()=>dn,ChannelMetadata:()=>cn,ChannelMuteUser:()=>pn,ClassifiedListing:()=>da,ClientAuth:()=>Un,CommunitiesList:()=>Nn,CommunityDefinition:()=>ba,CommunityPostApproval:()=>kn,Contacts:()=>Xt,CreateOrUpdateProduct:()=>ia,CreateOrUpdateStall:()=>aa,Curationsets:()=>Xn,Date:()=>pa,DirectMessageRelaysList:()=>Bn,DraftClassifiedListing:()=>ha,DraftLong:()=>ra,Emojisets:()=>sa,EncryptedDirectMessage:()=>en,EventDeletion:()=>tn,FileMetadata:()=>gn,FileServerPreference:()=>Fn,Followsets:()=>Yn,GenericRepost:()=>ln,Genericlists:()=>Qn,GiftWrap:()=>mn,HTTPAuth:()=>Kn,Handlerinformation:()=>va,Handlerrecommendation:()=>_a,Highlights:()=>An,InterestsList:()=>Dn,Interestsets:()=>na,JobFeedback:()=>Cn,JobRequest:()=>xn,JobResult:()=>Sn,Label:()=>wn,LightningPubRPC:()=>Vn,LiveChatMessage:()=>_n,LiveEvent:()=>ua,LongFormArticle:()=>oa,Metadata:()=>Qt,Mutelist:()=>Mn,NWCWalletInfo:()=>$n,NWCWalletRequest:()=>Hn,NWCWalletResponse:()=>Wn,NostrConnect:()=>Gn,OpenTimestamps:()=>fn,Pinlist:()=>Ln,PrivateDirectMessage:()=>sn,ProblemTracker:()=>vn,ProfileBadges:()=>ea,PublicChatsList:()=>On,Reaction:()=>an,RecommendRelay:()=>Jt,RelayList:()=>Rn,Relaysets:()=>Zn,Report:()=>bn,Reporting:()=>yn,Repost:()=>nn,Seal:()=>rn,SearchRelaysList:()=>qn,ShortTextNote:()=>Zt,Time:()=>fa,UserEmojiList:()=>jn,UserStatuses:()=>ca,Zap:()=>En,ZapGoal:()=>Tn,ZapRequest:()=>Pn,classifyKind:()=>Kt,isAddressableKind:()=>Gt,isEphemeralKind:()=>Wt,isKind:()=>Yt,isRegularKind:()=>Ut,isReplaceableKind:()=>Ht});var Qt=0,Zt=1,Jt=2,Xt=3,en=4,tn=5,nn=6,an=7,on=8,rn=13,sn=14,ln=16,un=40,cn=41,dn=42,hn=43,pn=44,fn=1040,mn=1059,gn=1063,_n=1311,vn=1971,bn=1984,yn=1984,wn=1985,kn=4550,xn=5999,Sn=6999,Cn=7e3,Tn=9041,Pn=9734,En=9735,An=9802,Mn=1e4,Ln=10001,Rn=10002,zn=10003,Nn=10004,On=10005,In=10006,qn=10007,Dn=10015,jn=10030,Bn=10050,Fn=10096,$n=13194,Vn=21e3,Un=22242,Hn=23194,Wn=23195,Gn=24133,Kn=27235,Yn=3e4,Qn=30001,Zn=30002,Jn=30003,Xn=30004,ea=30008,ta=30009,na=30015,aa=30017,ia=30018,oa=30023,ra=30024,sa=30030,la=30078,ua=30311,ca=30315,da=30402,ha=30403,pa=31922,fa=31923,ma=31924,ga=31925,_a=31989,va=31990,ba=34550;function ya(e,t){if(e.ids&&-1===e.ids.indexOf(t.id))return!1;if(e.kinds&&-1===e.kinds.indexOf(t.kind))return!1;if(e.authors&&-1===e.authors.indexOf(t.pubkey))return!1;for(let n in e)if("#"===n[0]){let a=e[`#${n.slice(1)}`];if(a&&!t.tags.find(([e,t])=>e===n.slice(1)&&-1!==a.indexOf(t)))return!1}return!(e.since&&t.created_ate.until)}function wa(e,t){for(let n=0;n{if("kinds"===e||"ids"===e||"authors"===e||"#"===e[0]){t[e]=t[e]||[];for(let a=0;at.limit)&&(t.limit=a.limit),a.until&&(!t.until||a.until>t.until)&&(t.until=a.until),a.since&&(!t.since||a.sinceHt(e))?e.authors.length*e.kinds.length:1/0,e.authors?.length&&e.kinds?.every(e=>Gt(e))&&e["#d"]?.length?e.authors.length*e.kinds.length*e["#d"].length:1/0)}var Sa={};function Ca(e,t){let n=t.length+3,a=e.indexOf(`"${t}":`)+n,i=e.slice(a).indexOf('"')+a+1;return e.slice(i,i+64)}function Ta(e,t){let n=t.length,a=e.indexOf(`"${t}":`)+n+3,i=e.slice(a),o=Math.min(i.indexOf(","),i.indexOf("}"));return parseInt(i.slice(0,o),10)}function Pa(e){let t=e.slice(0,22).indexOf('"EVENT"');if(-1===t)return null;let n=e.slice(t+7+1).indexOf('"');if(-1===n)return null;let a=t+7+1+n,i=e.slice(a+1,80).indexOf('"');if(-1===i)return null;let o=a+1+i;return e.slice(a+1,o)}function Ea(e,t){return t===Ca(e,"id")}function Aa(e,t){return t===Ca(e,"pubkey")}function Ma(e,t){return t===Ta(e,"kind")}i(Sa,{getHex64:()=>Ca,getInt:()=>Ta,getSubscriptionId:()=>Pa,matchEventId:()=>Ea,matchEventKind:()=>Ma,matchEventPubkey:()=>Aa});var La={};function Ra(e,t){return{kind:Un,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}async function za(){return new Promise((e,t)=>{try{if("undefined"!=typeof MessageChannel){const t=new MessageChannel,n=()=>{t.port1.removeEventListener("message",n),e()};t.port1.addEventListener("message",n),t.port2.postMessage(0),t.port1.start()}else"undefined"!=typeof setImmediate?setImmediate(e):"undefined"!=typeof setTimeout?setTimeout(e,0):e()}catch(e){console.error("during yield: ",e),t(e)}})}i(La,{makeAuthEvent:()=>Ra});var Na,Oa=e=>(e[dt]=!0,!0),Ia=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},qa=class{url;_connected=!1;onclose=null;onnotice=e=>console.debug(`NOTICE from ${this.url}: ${e}`);baseEoseTimeout=4400;connectionTimeout=4400;publishTimeout=4400;pingFrequency=2e4;pingTimeout=2e4;resubscribeBackoff=[1e4,1e4,1e4,2e4,2e4,3e4,6e4];openSubs=new Map;enablePing;enableReconnect;connectionTimeoutHandle;reconnectTimeoutHandle;pingTimeoutHandle;reconnectAttempts=0;closedIntentionally=!1;connectionPromise;openCountRequests=new Map;openEventPublishes=new Map;ws;incomingMessageQueue=new Ot;queueRunning=!1;challenge;authPromise;serial=0;verifyEvent;_WebSocket;constructor(e,t){this.url=Mt(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1}static async connect(e,t){const n=new qa(e,t);return await n.connect(),n}closeAllSubscriptions(e){for(let[t,n]of this.openSubs)n.close(e);this.openSubs.clear();for(let[t,n]of this.openEventPublishes)n.reject(new Error(e));this.openEventPublishes.clear();for(let[t,n]of this.openCountRequests)n.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}async reconnect(){const e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch(e){}},e)}handleHardClose(e){this.pingTimeoutHandle&&(clearTimeout(this.pingTimeoutHandle),this.pingTimeoutHandle=void 0),this._connected=!1,this.connectionPromise=void 0;const t=this.closedIntentionally;this.closedIntentionally=!1,this.onclose?.(),this.enableReconnect&&!t?this.reconnect():this.closeAllSubscriptions(e)}async connect(){return this.connectionPromise||(this.challenge=void 0,this.authPromise=void 0,this.connectionPromise=new Promise((e,t)=>{this.connectionTimeoutHandle=setTimeout(()=>{t("connection timed out"),this.connectionPromise=void 0,this.onclose?.(),this.closeAllSubscriptions("relay connection timed out")},this.connectionTimeout);try{this.ws=new this._WebSocket(this.url)}catch(e){return clearTimeout(this.connectionTimeoutHandle),void t(e)}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(this.connectionTimeoutHandle),this._connected=!0,this.reconnectAttempts=0;for(const e of this.openSubs.values())e.eosed=!1,"function"==typeof this.enableReconnect&&(e.filters=this.enableReconnect(e.filters)),e.fire();this.enablePing&&this.pingpong(),e()},this.ws.onerror=e=>{clearTimeout(this.connectionTimeoutHandle),t(e.message||"websocket error"),this.handleHardClose("relay connection errored")},this.ws.onclose=e=>{clearTimeout(this.connectionTimeoutHandle),t(e.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)})),this.connectionPromise}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}async waitForDummyReq(){return new Promise((e,t)=>{const n=this.subscribe([{ids:["a".repeat(64)]}],{oneose:()=>{n.close(),e(!0)},eoseTimeout:this.pingTimeout+1e3})})}async pingpong(){if(1===this.ws?.readyState){await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(e=>setTimeout(()=>e(!1),this.pingTimeout))])?this.pingTimeoutHandle=setTimeout(()=>this.pingpong(),this.pingFrequency):this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}}async runQueue(){for(this.queueRunning=!0;!1!==this.handleNext();)await za();this.queueRunning=!1}handleNext(){const e=this.incomingMessageQueue.dequeue();if(!e)return!1;const t=Pa(e);if(t){const n=this.openSubs.get(t);if(!n)return;const a=Ca(e,"id"),i=n.alreadyHaveEvent?.(a);if(n.receivedEvent?.(this,a),i)return}try{let t=JSON.parse(e);switch(t[0]){case"EVENT":{const e=this.openSubs.get(t[1]),n=t[2];return void(this.verifyEvent(n)&&wa(e.filters,n)&&e.onevent(n))}case"COUNT":{const e=t[1],n=t[2],a=this.openCountRequests.get(e);return void(a&&(a.resolve(n.count),this.openCountRequests.delete(e)))}case"EOSE":{const e=this.openSubs.get(t[1]);if(!e)return;return void e.receivedEose()}case"OK":{const e=t[1],n=t[2],a=t[3],i=this.openEventPublishes.get(e);return void(i&&(clearTimeout(i.timeout),n?i.resolve(a):i.reject(new Error(a)),this.openEventPublishes.delete(e)))}case"CLOSED":{const e=t[1],n=this.openSubs.get(e);if(!n)return;return n.closed=!0,void n.close(t[2])}case"NOTICE":return void this.onnotice(t[1]);case"AUTH":return void(this.challenge=t[1]);default:{const e=this.openSubs.get(t[1]);return void e?.oncustom?.(t)}}}catch(e){return}}async send(e){if(!this.connectionPromise)throw new Ia(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){const t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise||(this.authPromise=new Promise(async(n,a)=>{try{let i=await e(Ra(this.url,t)),o=setTimeout(()=>{let e=this.openEventPublishes.get(i.id);e&&(e.reject(new Error("auth timed out")),this.openEventPublishes.delete(i.id))},this.publishTimeout);this.openEventPublishes.set(i.id,{resolve:n,reject:a,timeout:o}),this.send('["AUTH",'+JSON.stringify(i)+"]")}catch(e){console.warn("subscribe auth function failed:",e)}})),this.authPromise}async publish(e){const t=new Promise((t,n)=>{const a=setTimeout(()=>{const t=this.openEventPublishes.get(e.id);t&&(t.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:t,reject:n,timeout:a})});return this.send('["EVENT",'+JSON.stringify(e)+"]"),t}async count(e,t){this.serial++;const n=t?.id||"count:"+this.serial,a=new Promise((e,t)=>{this.openCountRequests.set(n,{resolve:e,reject:t})});return this.send('["COUNT","'+n+'",'+JSON.stringify(e).substring(1)),a}subscribe(e,t){const n=this.prepareSubscription(e,t);return n.fire(),n}prepareSubscription(e,t){this.serial++;const n=t.id||(t.label?t.label+":":"sub:")+this.serial,a=new Da(this,n,e,t);return this.openSubs.set(n,a),a}close(){this.closedIntentionally=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingTimeoutHandle&&(clearTimeout(this.pingTimeoutHandle),this.pingTimeoutHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.onclose?.(),this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}_onmessage(e){this.incomingMessageQueue.enqueue(e.data),this.queueRunning||this.runQueue()}},Da=class{relay;id;closed=!1;eosed=!1;filters;alreadyHaveEvent;receivedEvent;onevent;oneose;onclose;oncustom;eoseTimeout;eoseTimeoutHandle;constructor(e,t,n,a){if(0===n.length)throw new Error("subscription can't be created with zero filters");this.relay=e,this.filters=n,this.id=t,this.alreadyHaveEvent=a.alreadyHaveEvent,this.receivedEvent=a.receivedEvent,this.eoseTimeout=a.eoseTimeout||e.baseEoseTimeout,this.oneose=a.oneose,this.onclose=a.onclose,this.onevent=a.onevent||(e=>{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,e)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(e){if(!(e instanceof Ia))throw e}this.closed=!0}this.relay.openSubs.delete(this.id),this.onclose?.(e)}};try{Na=WebSocket}catch{}var ja,Ba=class extends qa{constructor(e,t){super(e,{verifyEvent:$t,websocketImplementation:Na,...t})}static async connect(e,t){const n=new Ba(e,t);return await n.connect(),n}},Fa=class{relays=new Map;seenOn=new Map;trackRelays=!1;verifyEvent;enablePing;enableReconnect;trustedRelayURLs=new Set;_WebSocket;constructor(e){this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect}async ensureRelay(e,t){e=Mt(e);let n=this.relays.get(e);return n||(n=new qa(e,{verifyEvent:this.trustedRelayURLs.has(e)?Oa:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect}),n.onclose=()=>{n&&!n.enableReconnect&&this.relays.delete(e)},t?.connectionTimeout&&(n.connectionTimeout=t.connectionTimeout),this.relays.set(e,n)),await n.connect(),n}close(e){e.map(Mt).forEach(e=>{this.relays.get(e)?.close(),this.relays.delete(e)})}subscribe(e,t,n){n.onauth=n.onauth||n.doauth;const a=[];for(let n=0;ne.url===i)||a.push({url:i,filter:t})}return this.subscribeMap(a,n)}subscribeMany(e,t,n){n.onauth=n.onauth||n.doauth;const a=[],i=[];for(let n=0;n({url:e,filters:t}));this.trackRelays&&(t.receivedEvent=(e,t)=>{let n=this.seenOn.get(t);n||(n=new Set,this.seenOn.set(t,n)),n.add(e)});const i=new Set,o=[],r=[];let s=e=>{r[e]||(r[e]=!0,r.filter(e=>e).length===a.length&&(t.oneose?.(),s=()=>{}))};const l=[];let u=(e,n)=>{l[e]||(s(e),l[e]=n,l.filter(e=>e).length===a.length&&(t.onclose?.(l),u=()=>{}))};const c=e=>{if(t.alreadyHaveEvent?.(e))return!0;const n=i.has(e);return i.add(e),n},d=Promise.all(a.map(async({url:e,filters:n},a)=>{let i;try{i=await this.ensureRelay(e,{connectionTimeout:t.maxWait?Math.max(.8*t.maxWait,t.maxWait-1e3):void 0})}catch(e){return void u(a,e?.message||String(e))}let r=i.subscribe(n,{...t,oneose:()=>s(a),onclose:e=>{e.startsWith("auth-required: ")&&t.onauth?i.auth(t.onauth).then(()=>{i.subscribe(n,{...t,oneose:()=>s(a),onclose:e=>{u(a,e)},alreadyHaveEvent:c,eoseTimeout:t.maxWait})}).catch(e=>{u(a,`auth was required and attempted, but failed with: ${e}`)}):u(a,e)},alreadyHaveEvent:c,eoseTimeout:t.maxWait});o.push(r)}));return{async close(e){await d,o.forEach(t=>{t.close(e)})}}}subscribeEose(e,t,n){n.onauth=n.onauth||n.doauth;const a=this.subscribe(e,t,{...n,oneose(){a.close("closed automatically on eose")}});return a}subscribeManyEose(e,t,n){n.onauth=n.onauth||n.doauth;const a=this.subscribeMany(e,t,{...n,oneose(){a.close("closed automatically on eose")}});return a}async querySync(e,t,n){return new Promise(async a=>{const i=[];this.subscribeEose(e,t,{...n,onevent(e){i.push(e)},onclose(e){a(i)}})})}async get(e,t,n){t.limit=1;const a=await this.querySync(e,t,n);return a.sort((e,t)=>t.created_at-e.created_at),a[0]||null}publish(e,t,n){return e.map(Mt).map(async(e,a,i)=>{if(i.indexOf(e)!==a)return Promise.reject("duplicate url");let o=await this.ensureRelay(e);return o.publish(t).catch(async e=>{if(e instanceof Error&&e.message.startsWith("auth-required: ")&&n?.onauth)return await o.auth(n.onauth),o.publish(t);throw e}).then(e=>{if(this.trackRelays){let e=this.seenOn.get(t.id);e||(e=new Set,this.seenOn.set(t.id,e)),e.add(o)}return e})})}listConnectionStatus(){const e=new Map;return this.relays.forEach((t,n)=>e.set(n,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}};try{ja=WebSocket}catch{}var $a=class extends Fa{constructor(e){super({verifyEvent:$t,websocketImplementation:ja,...e})}},Va={};function Ua(e){if(!Number.isSafeInteger(e))throw new Error(`Wrong integer: ${e}`)}function Ha(...e){const t=(e,t)=>n=>e(t(n));return{encode:Array.from(e).reverse().reduce((e,n)=>e?t(e,n.encode):n.encode,void 0),decode:e.reduce((e,n)=>e?t(e,n.decode):n.decode,void 0)}}function Wa(e){return{encode:t=>{if(!Array.isArray(t)||t.length&&"number"!=typeof t[0])throw new Error("alphabet.encode input should be an array of numbers");return t.map(t=>{if(Ua(t),t<0||t>=e.length)throw new Error(`Digit index outside alphabet: ${t} (alphabet: ${e.length})`);return e[t]})},decode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("alphabet.decode input should be array of strings");return t.map(t=>{if("string"!=typeof t)throw new Error(`alphabet.decode: not string element=${t}`);const n=e.indexOf(t);if(-1===n)throw new Error(`Unknown letter: "${t}". Allowed: ${e}`);return n})}}}function Ga(e=""){if("string"!=typeof e)throw new Error("join separator should be string");return{encode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("join.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`join.encode: non-string input=${e}`);return t.join(e)},decode:t=>{if("string"!=typeof t)throw new Error("join.decode input should be string");return t.split(e)}}}function Ka(e,t="="){if(Ua(e),"string"!=typeof t)throw new Error("padding chr should be string");return{encode(n){if(!Array.isArray(n)||n.length&&"string"!=typeof n[0])throw new Error("padding.encode input should be array of strings");for(let e of n)if("string"!=typeof e)throw new Error(`padding.encode: non-string input=${e}`);for(;n.length*e%8;)n.push(t);return n},decode(n){if(!Array.isArray(n)||n.length&&"string"!=typeof n[0])throw new Error("padding.encode input should be array of strings");for(let e of n)if("string"!=typeof e)throw new Error(`padding.decode: non-string input=${e}`);let a=n.length;if(a*e%8)throw new Error("Invalid padding: string should have whole number of bytes");for(;a>0&&n[a-1]===t;a--)if(!((a-1)*e%8))throw new Error("Invalid padding: string has too much padding");return n.slice(0,a)}}}function Ya(e){if("function"!=typeof e)throw new Error("normalize fn should be function");return{encode:e=>e,decode:t=>e(t)}}function Qa(e,t,n){if(t<2)throw new Error(`convertRadix: wrong from=${t}, base cannot be less than 2`);if(n<2)throw new Error(`convertRadix: wrong to=${n}, base cannot be less than 2`);if(!Array.isArray(e))throw new Error("convertRadix: data should be array");if(!e.length)return[];let a=0;const i=[],o=Array.from(e);for(o.forEach(e=>{if(Ua(e),e<0||e>=t)throw new Error(`Wrong integer: ${e}`)});;){let e=0,r=!0;for(let i=a;ibi,Bech32MaxSize:()=>vi,NostrTypeGuard:()=>_i,decode:()=>wi,decodeNostrURI:()=>yi,encodeBytes:()=>Pi,naddrEncode:()=>Mi,neventEncode:()=>Ai,noteEncode:()=>Ci,nprofileEncode:()=>Ei,npubEncode:()=>Si,nsecEncode:()=>xi});var Za=(e,t)=>t?Za(t,e%t):e,Ja=(e,t)=>e+(t-Za(e,t));function Xa(e,t,n,a){if(!Array.isArray(e))throw new Error("convertRadix2: data should be array");if(t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(n<=0||n>32)throw new Error(`convertRadix2: wrong to=${n}`);if(Ja(t,n)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${n} carryBits=${Ja(t,n)}`);let i=0,o=0;const r=2**n-1,s=[];for(const a of e){if(Ua(a),a>=2**t)throw new Error(`convertRadix2: invalid data word=${a} from=${t}`);if(i=i<32)throw new Error(`convertRadix2: carry overflow pos=${o} from=${t}`);for(o+=t;o>=n;o-=n)s.push((i>>o-n&r)>>>0);i&=2**o-1}if(i=i<=t)throw new Error("Excess padding");if(!a&&i)throw new Error(`Non-zero padding: ${i}`);return a&&o>0&&s.push(i>>>0),s}function ei(e,t=!1){if(Ua(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(Ja(8,e)>32||Ja(e,8)>32)throw new Error("radix2: carry overflow");return{encode:n=>{if(!(n instanceof Uint8Array))throw new Error("radix2.encode input should be Uint8Array");return Xa(Array.from(n),8,e,!t)},decode:n=>{if(!Array.isArray(n)||n.length&&"number"!=typeof n[0])throw new Error("radix2.decode input should be array of strings");return Uint8Array.from(Xa(n,e,8,t))}}}function ti(e){if("function"!=typeof e)throw new Error("unsafeWrapper fn should be function");return function(...t){try{return e.apply(null,t)}catch(e){}}}var ni=Ha(ei(4),Wa("0123456789ABCDEF"),Ga("")),ai=Ha(ei(5),Wa("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),Ka(5),Ga("")),ii=(Ha(ei(5),Wa("0123456789ABCDEFGHIJKLMNOPQRSTUV"),Ka(5),Ga("")),Ha(ei(5),Wa("0123456789ABCDEFGHJKMNPQRSTVWXYZ"),Ga(""),Ya(e=>e.toUpperCase().replace(/O/g,"0").replace(/[IL]/g,"1"))),Ha(ei(6),Wa("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),Ka(6),Ga(""))),oi=Ha(ei(6),Wa("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),Ka(6),Ga("")),ri=e=>{return Ha((Ua(t=58),{encode:e=>{if(!(e instanceof Uint8Array))throw new Error("radix.encode input should be Uint8Array");return Qa(Array.from(e),256,t)},decode:e=>{if(!Array.isArray(e)||e.length&&"number"!=typeof e[0])throw new Error("radix.decode input should be array of strings");return Uint8Array.from(Qa(e,t,256))}}),Wa(e),Ga(""));var t},si=ri("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),li=(ri("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"),ri("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"),[0,2,3,5,6,7,9,10,11]),ui={encode(e){let t="";for(let n=0;n>25;let n=(33554431&e)<<5;for(let e=0;e>e&1)&&(n^=di[e]);return n}function pi(e,t,n=1){const a=e.length;let i=1;for(let t=0;t126)throw new Error(`Invalid prefix (${e})`);i=hi(i)^n>>5}i=hi(i);for(let t=0;tn)throw new TypeError(`Wrong string length: ${e.length} (${e}). Expected (8..${n})`);const a=e.toLowerCase();if(e!==a&&e!==e.toUpperCase())throw new Error("String must be lowercase or uppercase");const i=(e=a).lastIndexOf("1");if(0===i||-1===i)throw new Error('Letter "1" must be present between prefix and data only');const o=e.slice(0,i),r=e.slice(i+1);if(r.length<6)throw new Error("Data must be at least 6 characters long");const s=ci.decode(r).slice(0,-6),l=pi(o,s,t);if(!r.endsWith(l))throw new Error(`Invalid checksum in ${e}: expected "${l}"`);return{prefix:o,words:s}}return{encode:function(e,n,a=90){if("string"!=typeof e)throw new Error("bech32.encode prefix should be string, not "+typeof e);if(!Array.isArray(n)||n.length&&"number"!=typeof n[0])throw new Error("bech32.encode words should be array of numbers, not "+typeof n);const i=e.length+7+n.length;if(!1!==a&&i>a)throw new TypeError(`Length ${i} exceeds limit ${a}`);return`${e=e.toLowerCase()}1${ci.encode(n)}${pi(e,n,t)}`},decode:r,decodeToBytes:function(e){const{prefix:t,words:n}=r(e,!1);return{prefix:t,words:n,bytes:a(n)}},decodeUnsafe:ti(r),fromWords:a,fromWordsUnsafe:o,toWords:i}}var mi=fi("bech32"),gi=(fi("bech32m"),{utf8:{encode:e=>(new TextDecoder).decode(e),decode:e=>(new TextEncoder).encode(e)},hex:Ha(ei(4),Wa("0123456789abcdef"),Ga(""),Ya(e=>{if("string"!=typeof e||e.length%2)throw new TypeError(`hex.decode: expected string, got ${typeof e} with length ${e.length}`);return e.toLowerCase()})),base16:ni,base32:ai,base64:ii,base64url:oi,base58:si,base58xmr:ui}),_i=(Object.keys(gi).join(", "),{isNProfile:e=>/^nprofile1[a-z\d]+$/.test(e||""),isNEvent:e=>/^nevent1[a-z\d]+$/.test(e||""),isNAddr:e=>/^naddr1[a-z\d]+$/.test(e||""),isNSec:e=>/^nsec1[a-z\d]{58}$/.test(e||""),isNPub:e=>/^npub1[a-z\d]{58}$/.test(e||""),isNote:e=>/^note1[a-z\d]+$/.test(e||""),isNcryptsec:e=>/^ncryptsec1[a-z\d]+$/.test(e||"")}),vi=5e3,bi=/[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;function yi(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),wi(e)}catch(e){return{type:"invalid",data:null}}}function wi(e){let{prefix:t,words:n}=mi.decode(e,vi),a=new Uint8Array(mi.fromWords(n));switch(t){case"nprofile":{let e=ki(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for nprofile");if(32!==e[0][0].length)throw new Error("TLV 0 should be 32 bytes");return{type:"nprofile",data:{pubkey:it(e[0][0]),relays:e[1]?e[1].map(e=>Et.decode(e)):[]}}}case"nevent":{let e=ki(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for nevent");if(32!==e[0][0].length)throw new Error("TLV 0 should be 32 bytes");if(e[2]&&32!==e[2][0].length)throw new Error("TLV 2 should be 32 bytes");if(e[3]&&4!==e[3][0].length)throw new Error("TLV 3 should be 4 bytes");return{type:"nevent",data:{id:it(e[0][0]),relays:e[1]?e[1].map(e=>Et.decode(e)):[],author:e[2]?.[0]?it(e[2][0]):void 0,kind:e[3]?.[0]?parseInt(it(e[3][0]),16):void 0}}}case"naddr":{let e=ki(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for naddr");if(!e[2]?.[0])throw new Error("missing TLV 2 for naddr");if(32!==e[2][0].length)throw new Error("TLV 2 should be 32 bytes");if(!e[3]?.[0])throw new Error("missing TLV 3 for naddr");if(4!==e[3][0].length)throw new Error("TLV 3 should be 4 bytes");return{type:"naddr",data:{identifier:Et.decode(e[0][0]),pubkey:it(e[2][0]),kind:parseInt(it(e[3][0]),16),relays:e[1]?e[1].map(e=>Et.decode(e)):[]}}}case"nsec":return{type:t,data:a};case"npub":case"note":return{type:t,data:it(a)};default:throw new Error(`unknown prefix ${t}`)}}function ki(e){let t={},n=e;for(;n.length>0;){let e=n[0],a=n[1],i=n.slice(2,2+a);if(n=n.slice(2+a),i.lengthAt.encode(e))}))}function Ai(e){let t;return void 0!==e.kind&&(t=function(e){const t=new Uint8Array(4);return t[0]=e>>24&255,t[1]=e>>16&255,t[2]=e>>8&255,t[3]=255&e,t}(e.kind)),Ti("nevent",Li({0:[ot(e.id)],1:(e.relays||[]).map(e=>At.encode(e)),2:e.author?[ot(e.author)]:[],3:t?[new Uint8Array(t)]:[]}))}function Mi(e){let t=new ArrayBuffer(4);return new DataView(t).setUint32(0,e.kind,!1),Ti("naddr",Li({0:[At.encode(e.identifier)],1:(e.relays||[]).map(e=>At.encode(e)),2:[ot(e.pubkey)],3:[new Uint8Array(t)]}))}function Li(e){let t=[];return Object.entries(e).reverse().forEach(([e,n])=>{n.forEach(n=>{let a=new Uint8Array(n.length+2);a.set([parseInt(e)],0),a.set([n.length],1),a.set(n,2),t.push(a)})}),st(...t)}var Ri=/\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g;function zi(e){let t=[];for(let n of e.content.matchAll(Ri))if(n[2])try{let{type:e,data:a}=wi(n[1]);switch(e){case"npub":t.push({text:n[0],profile:{pubkey:a,relays:[]}});break;case"nprofile":t.push({text:n[0],profile:a});break;case"note":t.push({text:n[0],event:{id:a,relays:[]}});break;case"nevent":t.push({text:n[0],event:a});break;case"naddr":t.push({text:n[0],address:a})}}catch(e){}else if(n[3]){let a=parseInt(n[3],10),i=e.tags[a];if(!i)continue;switch(i[0]){case"p":t.push({text:n[0],profile:{pubkey:i[1],relays:i[2]?[i[2]]:[]}});break;case"e":t.push({text:n[0],event:{id:i[1],relays:i[2]?[i[2]]:[]}});break;case"a":try{let[e,a,o]=i[1].split(":");t.push({text:n[0],address:{identifier:o,pubkey:a,kind:parseInt(e,10),relays:i[2]?[i[2]]:[]}})}catch(e){}}}return t}var Ni={};function Oi(e){if(!Number.isSafeInteger(e)||e<0)throw new Error(`positive integer expected, not ${e}`)}function Ii(e){if("boolean"!=typeof e)throw new Error(`boolean expected, not ${e}`)}function qi(e){return e instanceof Uint8Array||null!=e&&"object"==typeof e&&"Uint8Array"===e.constructor.name}function Di(e,...t){if(!qi(e))throw new Error("Uint8Array expected");if(t.length>0&&!t.includes(e.length))throw new Error(`Uint8Array expected of length ${t}, not of length=${e.length}`)}function ji(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Bi(e,t){Di(e);const n=t.outputLen;if(e.lengthUo,encrypt:()=>Vo});var Fi=e=>new Uint8Array(e.buffer,e.byteOffset,e.byteLength),$i=e=>new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4)),Vi=e=>new DataView(e.buffer,e.byteOffset,e.byteLength);if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");var Ui=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function Hi(e){Di(e);let t="";for(let n=0;n=Wi&&e<=Gi?e-Wi:e>=Ki&&e<=Yi?e-(Ki-10):e>=Qi&&e<=Zi?e-(Qi-10):void 0}function Xi(e){if("string"!=typeof e)throw new Error("hex string expected, got "+typeof e);const t=e.length,n=t/2;if(t%2)throw new Error("padded hex string expected, got unpadded hex of length "+t);const a=new Uint8Array(n);for(let t=0,i=0;t(Object.assign(t,e),t);function io(e,t,n,a){if("function"==typeof e.setBigUint64)return e.setBigUint64(t,n,a);const i=BigInt(32),o=BigInt(4294967295),r=Number(n>>i&o),s=Number(n&o),l=a?4:0,u=a?0:4;e.setUint32(t+l,r,a),e.setUint32(t+u,s,a)}var oo=16,ro=new Uint8Array(16),so=$i(ro),lo=(e,t,n,a)=>({s3:n<<31|a>>>1,s2:t<<31|n>>>1,s1:e<<31|t>>>1,s0:e>>>1^225<<24&-(1&(1&a))}),uo=e=>(e>>>0&255)<<24|(e>>>8&255)<<16|(e>>>16&255)<<8|e>>>24&255;var co=class{constructor(e,t){this.blockLen=oo,this.outputLen=oo,this.s0=0,this.s1=0,this.s2=0,this.s3=0,this.finished=!1,Di(e=to(e),16);const n=Vi(e);let a=n.getUint32(0,!1),i=n.getUint32(4,!1),o=n.getUint32(8,!1),r=n.getUint32(12,!1);const s=[];for(let e=0;e<128;e++)s.push({s0:uo(a),s1:uo(i),s2:uo(o),s3:uo(r)}),({s0:a,s1:i,s2:o,s3:r}=lo(a,i,o,r));const l=(u=t||1024)>65536?8:u>1024?4:2;var u;if(![1,2,4,8].includes(l))throw new Error(`ghash: wrong window size=${l}, should be 2, 4 or 8`);this.W=l;const c=128/l,d=this.windowSize=2**l,h=[];for(let e=0;e>>l-r-1&1))continue;const{s0:u,s1:c,s2:d,s3:h}=s[l*e+r];n^=u,a^=c,i^=d,o^=h}h.push({s0:n,s1:a,s2:i,s3:o})}this.t=h}_updateBlock(e,t,n,a){e^=this.s0,t^=this.s1,n^=this.s2,a^=this.s3;const{W:i,t:o,windowSize:r}=this;let s=0,l=0,u=0,c=0;const d=(1<>>8*e&255;for(let e=8/i-1;e>=0;e--){const n=t>>>i*e&d,{s0:a,s1:p,s2:f,s3:m}=o[h*r+n];s^=a,l^=p,u^=f,c^=m,h+=1}}this.s0=s,this.s1=l,this.s2=u,this.s3=c}update(e){e=to(e),ji(this);const t=$i(e),n=Math.floor(e.length/oo),a=e.length%oo;for(let e=0;e>>1|n,n=(1&a)<<7}return e[0]^=225&-t,e}((e=to(e)).slice());super(n,t),n.fill(0)}update(e){e=to(e),ji(this);const t=$i(e),n=e.length%oo,a=Math.floor(e.length/oo);for(let e=0;ee(n,t.length).update(to(t)).digest(),n=e(new Uint8Array(16),0);return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=(t,n)=>e(t,n),t}var fo=po((e,t)=>new co(e,t)),mo=po((e,t)=>new ho(e,t)),go=16,_o=new Uint8Array(go);function vo(e){return e<<1^283&-(e>>7)}function bo(e,t){let n=0;for(;t>0;t>>=1)n^=e&-(1&t),e=vo(e);return n}var yo=(()=>{let e=new Uint8Array(256);for(let t=0,n=1;t<256;t++,n^=vo(n))e[t]=n;const t=new Uint8Array(256);t[0]=99;for(let n=0;n<255;n++){let a=e[255-n];a|=a<<8,t[e[n]]=255&(a^a>>4^a>>5^a>>6^a>>7^99)}return t})(),wo=yo.map((e,t)=>yo.indexOf(t)),ko=e=>e<<24|e>>>8,xo=e=>e<<8|e>>>24;function So(e,t){if(256!==e.length)throw new Error("Wrong sbox length");const n=new Uint32Array(256).map((n,a)=>t(e[a])),a=n.map(xo),i=a.map(xo),o=i.map(xo),r=new Uint32Array(65536),s=new Uint32Array(65536),l=new Uint16Array(65536);for(let t=0;t<256;t++)for(let u=0;u<256;u++){const c=256*t+u;r[c]=n[t]^a[u],s[c]=i[t]^o[u],l[c]=e[t]<<8|e[u]}return{sbox:e,sbox2:l,T0:n,T1:a,T2:i,T3:o,T01:r,T23:s}}var Co=So(yo,e=>bo(e,3)<<24|e<<16|e<<8|bo(e,2)),To=So(wo,e=>bo(e,11)<<24|bo(e,13)<<16|bo(e,9)<<8|bo(e,14)),Po=(()=>{const e=new Uint8Array(16);for(let t=0,n=1;t<16;t++,n=vo(n))e[t]=n;return e})();function Eo(e){Di(e);const t=e.length;if(![16,24,32].includes(t))throw new Error(`aes: wrong key size: should be 16, 24 or 32, got: ${t}`);const{sbox2:n}=Co,a=$i(e),i=a.length,o=e=>Lo(n,e,e,e,e),r=new Uint32Array(t+28);r.set(a);for(let e=i;e6&&e%i===4&&(t=o(t)),r[e]=r[e-i]^t}return r}function Ao(e){const t=Eo(e),n=t.slice(),a=t.length,{sbox2:i}=Co,{T0:o,T1:r,T2:s,T3:l}=To;for(let e=0;e>>8&255]^s[a>>>16&255]^l[a>>>24]}return n}function Mo(e,t,n,a,i,o){return e[n<<8&65280|a>>>8&255]^t[i>>>8&65280|o>>>24&255]}function Lo(e,t,n,a,i){return e[255&t|65280&n]|e[a>>>16&255|i>>>16&65280]<<16}function Ro(e,t,n,a,i){const{sbox2:o,T01:r,T23:s}=Co;let l=0;t^=e[l++],n^=e[l++],a^=e[l++],i^=e[l++];const u=e.length/4-2;for(let o=0;o>>0,s.setUint32(c,h,t),({s0:p,s1:f,s2:m,s3:g}=Ro(e,r[0],r[1],r[2],r[3]));const _=go*Math.floor(l.length/4);if(_=0;e--)n=n+(255&o[e])|0,o[e]=255&n,n>>>=8;({s0:s,s1:l,s2:u,s3:c}=Ro(e,r[0],r[1],r[2],r[3]))}const p=go*Math.floor(d.length/4);if(pn(e,t),decrypt:(e,t)=>n(e,t)}});function Io(e){if(Di(e),e.length%go!==0)throw new Error("aes/(cbc-ecb).decrypt ciphertext should consist of blocks with size 16")}function qo(e,t,n){let a=e.length;const i=a%go;if(!t&&0!==i)throw new Error("aec/(cbc-ecb): unpadded plaintext with disabled padding");const o=$i(e);if(t){let e=go-i;e||(e=go),a+=e}const r=No(a,n);return{b:o,o:$i(r),out:r}}function Do(e,t){if(!t)return e;const n=e.length;if(!n)throw new Error("aes/pcks5: empty ciphertext not allowed");const a=e[n-1];if(a<=0||a>16)throw new Error(`aes/pcks5: wrong padding byte: ${a}`);const i=e.subarray(0,-a);for(let t=0;t{Di(t);const{b:i,o:o,out:r}=qo(t,n,a),s=Eo(e);let l=0;for(;l+4<=i.length;){const{s0:e,s1:t,s2:n,s3:a}=Ro(s,i[l+0],i[l+1],i[l+2],i[l+3]);o[l++]=e,o[l++]=t,o[l++]=n,o[l++]=a}if(n){const e=jo(t.subarray(4*l)),{s0:n,s1:a,s2:i,s3:r}=Ro(s,e[0],e[1],e[2],e[3]);o[l++]=n,o[l++]=a,o[l++]=i,o[l++]=r}return s.fill(0),r},decrypt:(t,a)=>{Io(t);const i=Ao(e),o=No(t.length,a),r=$i(t),s=$i(o);for(let e=0;e+4<=r.length;){const{s0:t,s1:n,s2:a,s3:o}=zo(i,r[e+0],r[e+1],r[e+2],r[e+3]);s[e++]=t,s[e++]=n,s[e++]=a,s[e++]=o}return i.fill(0),Do(o,n)}}});var Bo=ao({blockSize:16,nonceLength:16},function(e,t,n={}){Di(e),Di(t,16);const a=!n.disablePadding;return{encrypt:(n,i)=>{const o=Eo(e),{b:r,o:s,out:l}=qo(n,a,i),u=$i(t);let c=u[0],d=u[1],h=u[2],p=u[3],f=0;for(;f+4<=r.length;)c^=r[f+0],d^=r[f+1],h^=r[f+2],p^=r[f+3],({s0:c,s1:d,s2:h,s3:p}=Ro(o,c,d,h,p)),s[f++]=c,s[f++]=d,s[f++]=h,s[f++]=p;if(a){const e=jo(n.subarray(4*f));c^=e[0],d^=e[1],h^=e[2],p^=e[3],({s0:c,s1:d,s2:h,s3:p}=Ro(o,c,d,h,p)),s[f++]=c,s[f++]=d,s[f++]=h,s[f++]=p}return o.fill(0),l},decrypt:(n,i)=>{Io(n);const o=Ao(e),r=$i(t),s=No(n.length,i),l=$i(n),u=$i(s);let c=r[0],d=r[1],h=r[2],p=r[3];for(let e=0;e+4<=l.length;){const t=c,n=d,a=h,i=p;c=l[e+0],d=l[e+1],h=l[e+2],p=l[e+3];const{s0:r,s1:s,s2:f,s3:m}=zo(o,c,d,h,p);u[e++]=r^t,u[e++]=s^n,u[e++]=f^a,u[e++]=m^i}return o.fill(0),Do(s,a)}}});function Fo(e,t,n,a,i){const o=e.create(n,a.length+(i?.length||0));i&&o.update(i),o.update(a);const r=new Uint8Array(16),s=Vi(r);return i&&io(s,0,BigInt(8*i.length),t),io(s,8,BigInt(8*a.length),t),o.update(r),o.digest()}ao({blockSize:16,nonceLength:12,tagLength:16},function(e,t,n){if(Di(t),0===t.length)throw new Error("aes/gcm: empty nonce");const a=16;function i(e,t,a){const i=Fo(fo,!1,e,a,n);for(let e=0;e{Di(e);const{xk:t,authKey:n,counter:r,tagMask:s}=o(),l=new Uint8Array(e.length+a);Oo(t,!1,r,e,l);const u=i(n,s,l.subarray(0,l.length-a));return l.set(u,e.length),t.fill(0),l},decrypt:e=>{if(Di(e),e.lengtha=>{if(!Number.isSafeInteger(a)||t>a||a>n)throw new Error(`${e}: invalid value=${a}, must be [${t}..${n}]`)};ao({blockSize:16,nonceLength:12,tagLength:16},function(e,t,n){const a=$o("AAD",0,2**36),i=$o("plaintext",0,2**36),o=$o("nonce",12,12),r=$o("ciphertext",16,2**36+16);function s(){const n=e.length;if(16!==n&&24!==n&&32!==n)throw new Error(`key length must be 16, 24 or 32 bytes, got: ${n} bytes`);const a=Eo(e),i=new Uint8Array(n),o=new Uint8Array(16),r=$i(t);let s=0,l=r[0],u=r[1],c=r[2],d=0;for(const e of[o,i].map($i)){const t=$i(e);for(let e=0;e{Di(e),i(e.length);const{encKey:t,authKey:n}=s(),a=l(t,n,e),o=new Uint8Array(e.length+16);return o.set(a,e.length),o.set(u(t,a,e)),t.fill(0),n.fill(0),o},decrypt:e=>{Di(e),r(e.length);const t=e.subarray(-16),{encKey:n,authKey:a}=s(),i=u(n,t,e.subarray(0,-16)),o=l(n,a,i);if(n.fill(0),a.fill(0),!no(t,o))throw new Error("invalid polyval tag");return i}}});function Vo(e,t,n){const a=e instanceof Uint8Array?it(e):e,i=Ho(Ie.getSharedSecret(a,"02"+t));let o=Uint8Array.from(ct(16)),r=At.encode(n),s=Bo(i,o).encrypt(r);return`${ii.encode(new Uint8Array(s))}?iv=${ii.encode(new Uint8Array(o.buffer))}`}function Uo(e,t,n){const a=e instanceof Uint8Array?it(e):e;let[i,o]=n.split("?iv="),r=Ho(Ie.getSharedSecret(a,"02"+t)),s=ii.decode(o),l=ii.decode(i),u=Bo(r,s).decrypt(l);return Et.decode(u)}function Ho(e){return e.slice(1,33)}var Wo={};i(Wo,{NIP05_REGEX:()=>Ko,isNip05:()=>Yo,isValid:()=>Xo,queryProfile:()=>Jo,searchDomain:()=>Zo,useFetchImplementation:()=>Qo});var Go,Ko=/^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/,Yo=e=>Ko.test(e||"");try{Go=fetch}catch(e){}function Qo(e){Go=e}async function Zo(e,t=""){try{const n=`https://${e}/.well-known/nostr.json?name=${t}`,a=await Go(n,{redirect:"manual"});if(200!==a.status)throw Error("Wrong response code");return(await a.json()).names}catch(e){return{}}}async function Jo(e){const t=e.match(Ko);if(!t)return null;const[,n="_",a]=t;try{const e=`https://${a}/.well-known/nostr.json?name=${n}`,t=await Go(e,{redirect:"manual"});if(200!==t.status)throw Error("Wrong response code");const i=await t.json(),o=i.names[n];return o?{pubkey:o,relays:i.relays?.[o]}:null}catch(e){return null}}async function Xo(e,t){const n=await Jo(t);return!!n&&n.pubkey===e}var er={};function tr(e){const t={reply:void 0,root:void 0,mentions:[],profiles:[],quotes:[]};let n,a;for(let i=e.tags.length-1;i>=0;i--){const o=e.tags[i];if("e"===o[0]&&o[1]){const[e,i,r,s,l]=o,u={id:i,relays:r?[r]:[],author:l};if("root"===s){t.root=u;continue}if("reply"===s){t.reply=u;continue}if("mention"===s){t.mentions.push(u);continue}n?a=u:n=u,t.mentions.push(u);continue}if("q"===o[0]&&o[1]){const[e,n,a]=o;t.quotes.push({id:n,relays:a?[a]:[]})}"p"===o[0]&&o[1]&&t.profiles.push({pubkey:o[1],relays:o[2]?[o[2]]:[]})}return t.root||(t.root=a||n||t.reply),t.reply||(t.reply=n||t.root),[t.reply,t.root].forEach(e=>{if(!e)return;let n=t.mentions.indexOf(e);if(-1!==n&&t.mentions.splice(n,1),e.author){let n=t.profiles.find(t=>t.pubkey===e.author);n&&n.relays&&(e.relays||(e.relays=[]),n.relays.forEach(t=>{-1===e.relays?.indexOf(t)&&e.relays.push(t)}),n.relays=e.relays)}}),t.mentions.forEach(e=>{if(e.author){let n=t.profiles.find(t=>t.pubkey===e.author);n&&n.relays&&(e.relays||(e.relays=[]),n.relays.forEach(t=>{-1===e.relays.indexOf(t)&&e.relays.push(t)}),n.relays=e.relays)}}),t}i(er,{parse:()=>tr});var nr={};i(nr,{fetchRelayInformation:()=>ir,useFetchImplementation:()=>ar});try{fetch}catch{}function ar(e){0}async function ir(e){return await(await fetch(e.replace("ws://","http://").replace("wss://","https://"),{headers:{Accept:"application/nostr+json"}})).json()}var or={};function rr(e){let t=0;for(let n=0;n<64;n+=8){const a=parseInt(e.substring(n,n+8),16);if(0!==a){t+=Math.clz32(a);break}t+=32}return t}function sr(e,t){let n=0;const a=e,i=["nonce",n.toString(),t.toString()];for(a.tags.push(i);;){const e=Math.floor((new Date).getTime()/1e3);if(e!==a.created_at&&(n=0,a.created_at=e),i[1]=(++n).toString(),a.id=lr(a),rr(a.id)>=t)break}return a}function lr(e){return it(Tt(At.encode(JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content]))))}i(or,{fastEventHash:()=>lr,getPow:()=>rr,minePow:()=>sr});var ur={};i(ur,{unwrapEvent:()=>rs,unwrapManyEvents:()=>ss,wrapEvent:()=>is,wrapManyEvents:()=>os});var cr={};i(cr,{createRumor:()=>Zr,createSeal:()=>Jr,createWrap:()=>Xr,unwrapEvent:()=>ns,unwrapManyEvents:()=>as,wrapEvent:()=>es,wrapManyEvents:()=>ts});var dr={};i(dr,{decrypt:()=>Ur,encrypt:()=>Vr,getConversationKey:()=>Dr,v2:()=>Hr});var hr=(e,t)=>255&e[t++]|(255&e[t++])<<8,pr=class{constructor(e){this.blockLen=16,this.outputLen=16,this.buffer=new Uint8Array(16),this.r=new Uint16Array(10),this.h=new Uint16Array(10),this.pad=new Uint16Array(8),this.pos=0,this.finished=!1,Di(e=to(e),32);const t=hr(e,0),n=hr(e,2),a=hr(e,4),i=hr(e,6),o=hr(e,8),r=hr(e,10),s=hr(e,12),l=hr(e,14);this.r[0]=8191&t,this.r[1]=8191&(t>>>13|n<<3),this.r[2]=7939&(n>>>10|a<<6),this.r[3]=8191&(a>>>7|i<<9),this.r[4]=255&(i>>>4|o<<12),this.r[5]=o>>>1&8190,this.r[6]=8191&(o>>>14|r<<2),this.r[7]=8065&(r>>>11|s<<5),this.r[8]=8191&(s>>>8|l<<8),this.r[9]=l>>>5&127;for(let t=0;t<8;t++)this.pad[t]=hr(e,16+2*t)}process(e,t,n=!1){const a=n?0:2048,{h:i,r:o}=this,r=o[0],s=o[1],l=o[2],u=o[3],c=o[4],d=o[5],h=o[6],p=o[7],f=o[8],m=o[9],g=hr(e,t+0),_=hr(e,t+2),v=hr(e,t+4),b=hr(e,t+6),y=hr(e,t+8),w=hr(e,t+10),k=hr(e,t+12),x=hr(e,t+14);let S=i[0]+(8191&g),C=i[1]+(8191&(g>>>13|_<<3)),T=i[2]+(8191&(_>>>10|v<<6)),P=i[3]+(8191&(v>>>7|b<<9)),E=i[4]+(8191&(b>>>4|y<<12)),A=i[5]+(y>>>1&8191),M=i[6]+(8191&(y>>>14|w<<2)),L=i[7]+(8191&(w>>>11|k<<5)),R=i[8]+(8191&(k>>>8|x<<8)),z=i[9]+(x>>>5|a),N=0,O=N+S*r+C*(5*m)+T*(5*f)+P*(5*p)+E*(5*h);N=O>>>13,O&=8191,O+=A*(5*d)+M*(5*c)+L*(5*u)+R*(5*l)+z*(5*s),N+=O>>>13,O&=8191;let I=N+S*s+C*r+T*(5*m)+P*(5*f)+E*(5*p);N=I>>>13,I&=8191,I+=A*(5*h)+M*(5*d)+L*(5*c)+R*(5*u)+z*(5*l),N+=I>>>13,I&=8191;let q=N+S*l+C*s+T*r+P*(5*m)+E*(5*f);N=q>>>13,q&=8191,q+=A*(5*p)+M*(5*h)+L*(5*d)+R*(5*c)+z*(5*u),N+=q>>>13,q&=8191;let D=N+S*u+C*l+T*s+P*r+E*(5*m);N=D>>>13,D&=8191,D+=A*(5*f)+M*(5*p)+L*(5*h)+R*(5*d)+z*(5*c),N+=D>>>13,D&=8191;let j=N+S*c+C*u+T*l+P*s+E*r;N=j>>>13,j&=8191,j+=A*(5*m)+M*(5*f)+L*(5*p)+R*(5*h)+z*(5*d),N+=j>>>13,j&=8191;let B=N+S*d+C*c+T*u+P*l+E*s;N=B>>>13,B&=8191,B+=A*r+M*(5*m)+L*(5*f)+R*(5*p)+z*(5*h),N+=B>>>13,B&=8191;let F=N+S*h+C*d+T*c+P*u+E*l;N=F>>>13,F&=8191,F+=A*s+M*r+L*(5*m)+R*(5*f)+z*(5*p),N+=F>>>13,F&=8191;let $=N+S*p+C*h+T*d+P*c+E*u;N=$>>>13,$&=8191,$+=A*l+M*s+L*r+R*(5*m)+z*(5*f),N+=$>>>13,$&=8191;let V=N+S*f+C*p+T*h+P*d+E*c;N=V>>>13,V&=8191,V+=A*u+M*l+L*s+R*r+z*(5*m),N+=V>>>13,V&=8191;let U=N+S*m+C*f+T*p+P*h+E*d;N=U>>>13,U&=8191,U+=A*c+M*u+L*l+R*s+z*r,N+=U>>>13,U&=8191,N=(N<<2)+N|0,N=N+O|0,O=8191&N,N>>>=13,I+=N,i[0]=O,i[1]=I,i[2]=q,i[3]=D,i[4]=j,i[5]=B,i[6]=F,i[7]=$,i[8]=V,i[9]=U}finalize(){const{h:e,pad:t}=this,n=new Uint16Array(10);let a=e[1]>>>13;e[1]&=8191;for(let t=2;t<10;t++)e[t]+=a,a=e[t]>>>13,e[t]&=8191;e[0]+=5*a,a=e[0]>>>13,e[0]&=8191,e[1]+=a,a=e[1]>>>13,e[1]&=8191,e[2]+=a,n[0]=e[0]+5,a=n[0]>>>13,n[0]&=8191;for(let t=1;t<10;t++)n[t]=e[t]+a,a=n[t]>>>13,n[t]&=8191;n[9]-=8192;let i=(1^a)-1;for(let e=0;e<10;e++)n[e]&=i;i=~i;for(let t=0;t<10;t++)e[t]=e[t]&i|n[t];e[0]=65535&(e[0]|e[1]<<13),e[1]=65535&(e[1]>>>3|e[2]<<10),e[2]=65535&(e[2]>>>6|e[3]<<7),e[3]=65535&(e[3]>>>9|e[4]<<4),e[4]=65535&(e[4]>>>12|e[5]<<1|e[6]<<14),e[5]=65535&(e[6]>>>2|e[7]<<11),e[6]=65535&(e[7]>>>5|e[8]<<8),e[7]=65535&(e[8]>>>8|e[9]<<5);let o=e[0]+t[0];e[0]=65535&o;for(let n=1;n<8;n++)o=(e[n]+t[n]|0)+(o>>>16)|0,e[n]=65535&o}update(e){ji(this);const{buffer:t,blockLen:n}=this,a=(e=to(e)).length;for(let i=0;i>>0,e[i++]=n[t]>>>8;return e}digest(){const{buffer:e,outputLen:t}=this;this.digestInto(e);const n=e.slice(0,t);return this.destroy(),n}};var fr=function(e){const t=(t,n)=>e(n).update(to(t)).digest(),n=e(new Uint8Array(32));return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=t=>e(t),t}(e=>new pr(e)),mr=eo("expand 16-byte k"),gr=eo("expand 32-byte k"),_r=$i(mr),vr=$i(gr);function br(e,t){return e<>>32-t}function yr(e){return e.byteOffset%4==0}var wr=2**32-1,kr=new Uint32Array;function xr(e,t){const{allowShortKeys:n,extendNonceFn:a,counterLength:i,counterRight:o,rounds:r}=function(e,t){if(null==t||"object"!=typeof t)throw new Error("options must be defined");return Object.assign(e,t)}({allowShortKeys:!1,counterLength:8,counterRight:!1,rounds:20},t);if("function"!=typeof e)throw new Error("core must be a function");return Oi(i),Oi(r),Ii(o),Ii(n),(t,s,l,u,c=0)=>{Di(t),Di(s),Di(l);const d=l.length;if(u||(u=new Uint8Array(d)),Di(u),Oi(c),c<0||c>=wr)throw new Error("arx: counter overflow");if(u.length=wr)throw new Error("arx: counter overflow");const m=Math.min(64,l-f);if(d&&64===m){const e=f/4;if(f%4!=0)throw new Error("arx: invalid block position");for(let t,n=0;n<16;n++)t=e+n,p[t]=h[t]^c[n];f+=64;continue}for(let e,t=0;t0;)h.pop().fill(0);return u}}function Sr(e,t,n,a,i,o=20){let r=e[0],s=e[1],l=e[2],u=e[3],c=t[0],d=t[1],h=t[2],p=t[3],f=t[4],m=t[5],g=t[6],_=t[7],v=i,b=n[0],y=n[1],w=n[2],k=r,x=s,S=l,C=u,T=c,P=d,E=h,A=p,M=f,L=m,R=g,z=_,N=v,O=b,I=y,q=w;for(let e=0;e{e.update(t);const n=t.length%16;n&&e.update(Pr.subarray(n))},Ar=new Uint8Array(32);function Mr(e,t,n,a,i){const o=e(t,n,Ar),r=fr.create(o);i&&Er(r,i),Er(r,a);const s=new Uint8Array(16),l=Vi(s);io(l,0,BigInt(i?i.length:0),!0),io(l,8,BigInt(a.length),!0),r.update(s);const u=r.digest();return o.fill(0),u}var Lr=e=>(t,n,a)=>{const i=16;return Di(t,32),Di(n),{encrypt:(o,r)=>{const s=o.length,l=s+i;r?Di(r,l):r=new Uint8Array(l),e(t,n,o,r,1);const u=Mr(e,t,n,r.subarray(0,-16),a);return r.set(u,s),r},decrypt:(o,r)=>{const s=o.length,l=s-i;if(sa?e.create().update(n).digest():n);for(let e=0;enew Rr(e,t).update(n).digest();zr.create=(e,t)=>new Rr(e,t);var Nr=new Uint8Array([0]),Or=new Uint8Array;var Ir=1,qr=65535;function Dr(e,t){const n=Ie.getSharedSecret(e,"02"+t).subarray(1,33);return a=Tt,i=n,o="nip44-v2",_t.hash(a),void 0===o&&(o=new Uint8Array(a.outputLen)),zr(a,rt(o),rt(i));var a,i,o}function jr(e,t){const n=function(e,t,n,a=32){if(_t.hash(e),_t.number(a),a>255*e.outputLen)throw new Error("Length should be <= 255*HashLen");const i=Math.ceil(a/e.outputLen);void 0===n&&(n=Or);const o=new Uint8Array(i*e.outputLen),r=zr.create(e,t),s=r._cloneInto(),l=new Uint8Array(r.outputLen);for(let t=0;tqr)throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");const t=new Uint8Array(2);return new DataView(t.buffer).setUint16(0,e,!1),t}(n),t,new Uint8Array(Br(n)-n))}function $r(e,t,n){if(32!==n.length)throw new Error("AAD associated data must be 32 bytes");const a=st(n,t);return zr(Tt,e,a)}function Vr(e,t,n=ct(32)){const{chacha_key:a,chacha_nonce:i,hmac_key:o}=jr(t,n),r=Fr(e),s=Cr(a,i,r),l=$r(o,s,n);return ii.encode(st(new Uint8Array([2]),n,s,l))}function Ur(e,t){const{nonce:n,ciphertext:a,mac:i}=function(e){if("string"!=typeof e)throw new Error("payload must be a valid string");const t=e.length;if(t<132||t>87472)throw new Error("invalid payload length: "+t);if("#"===e[0])throw new Error("unknown encryption version");let n;try{n=ii.decode(e)}catch(e){throw new Error("invalid base64: "+e.message)}const a=n.length;if(a<99||a>65603)throw new Error("invalid data length: "+a);const i=n[0];if(2!==i)throw new Error("unknown encryption version "+i);return{nonce:n.subarray(1,33),ciphertext:n.subarray(33,-32),mac:n.subarray(-32)}}(e),{chacha_key:o,chacha_nonce:r,hmac_key:s}=jr(t,n);if(!no($r(s,a,n),i))throw new Error("invalid MAC");return function(e){const t=new DataView(e.buffer).getUint16(0),n=e.subarray(2,2+t);if(tqr||n.length!==t||e.length!==2+Br(t))throw new Error("invalid padding");return Et.decode(n)}(Cr(o,r,a))}var Hr={utils:{getConversationKey:Dr,calcPaddedLen:Br},encrypt:Vr,decrypt:Ur},Wr=()=>Math.round(Date.now()/1e3),Gr=()=>Math.round(Wr()-172800*Math.random()),Kr=(e,t)=>Dr(e,t),Yr=(e,t,n)=>Vr(JSON.stringify(e),Kr(t,n)),Qr=(e,t)=>JSON.parse(Ur(e.content,Kr(t,e.pubkey)));function Zr(e,t){const n={created_at:Wr(),content:"",tags:[],...e,pubkey:Bt(t)};return n.id=qt(n),n}function Jr(e,t,n){return Ft({kind:rn,content:Yr(e,t,n),created_at:Gr(),tags:[]},t)}function Xr(e,t){const n=jt();return Ft({kind:mn,content:Yr(e,n,t),created_at:Gr(),tags:[["p",t]]},n)}function es(e,t,n){return Xr(Jr(Zr(e,t),t,n),n)}function ts(e,t,n){if(!n||0===n.length)throw new Error("At least one recipient is required.");const a=Bt(t),i=[es(e,t,a)];return n.forEach(n=>{i.push(es(e,t,n))}),i}function ns(e,t){const n=Qr(e,t);return Qr(n,t)}function as(e,t){let n=[];return e.forEach(e=>{n.push(ns(e,t))}),n.sort((e,t)=>e.created_at-t.created_at),n}function is(e,t,n,a,i){const o=function(e,t,n,a){const i={created_at:Math.ceil(Date.now()/1e3),kind:sn,tags:[],content:t};return(Array.isArray(e)?e:[e]).forEach(({publicKey:e,relayUrl:t})=>{i.tags.push(t?["p",e,t]:["p",e])}),a&&i.tags.push(["e",a.eventId,a.relayUrl||"","reply"]),n&&i.tags.push(["subject",n]),i}(t,n,a,i);return es(o,e,t.publicKey)}function os(e,t,n,a,i){if(!t||0===t.length)throw new Error("At least one recipient is required.");return[{publicKey:Bt(e)},...t].map(t=>is(e,t,n,a,i))}var rs=ns,ss=as,ls={};function us(e,t,n,a){let i;const o=[...e.tags??[],["e",t.id,n],["p",t.pubkey]];return t.kind===Zt?i=nn:(i=ln,o.push(["k",String(t.kind)])),Ft({kind:i,tags:o,content:""===e.content||t.tags?.find(e=>"-"===e[0])?"":JSON.stringify(t),created_at:e.created_at},a)}function cs(e){if(![nn,ln].includes(e.kind))return;let t,n;for(let a=e.tags.length-1;a>=0&&(void 0===t||void 0===n);a--){const i=e.tags[a];i.length>=2&&("e"===i[0]&&void 0===t?t=i:"p"===i[0]&&void 0===n&&(n=i))}return void 0!==t?{id:t[1],relays:[t[2],n?.[2]].filter(e=>"string"==typeof e),author:n?.[1]}:void 0}function ds(e,{skipVerification:t}={}){const n=cs(e);if(void 0===n||""===e.content)return;let a;try{a=JSON.parse(e.content)}catch(e){return}return a.id===n.id&&(t||$t(a))?a:void 0}i(ls,{finishRepostEvent:()=>us,getRepostedEvent:()=>ds,getRepostedEventPointer:()=>cs});var hs={};i(hs,{NOSTR_URI_REGEX:()=>ps,parse:()=>ms,test:()=>fs});var ps=new RegExp(`nostr:(${bi.source})`);function fs(e){return"string"==typeof e&&new RegExp(`^${ps.source}$`).test(e)}function ms(e){const t=e.match(new RegExp(`^${ps.source}$`));if(!t)throw new Error(`Invalid Nostr URI: ${e}`);return{uri:t[0],value:t[1],decoded:wi(t[1])}}var gs={};function _s(e,t,n){const a=t.tags.filter(e=>e.length>=2&&("e"===e[0]||"p"===e[0]));return Ft({...e,kind:an,tags:[...e.tags??[],...a,["e",t.id],["p",t.pubkey]],content:e.content??"+"},n)}function vs(e){if(e.kind!==an)return;let t,n;for(let a=e.tags.length-1;a>=0&&(void 0===t||void 0===n);a--){const i=e.tags[a];i.length>=2&&("e"===i[0]&&void 0===t?t=i:"p"===i[0]&&void 0===n&&(n=i))}return void 0!==t&&void 0!==n?{id:t[1],relays:[t[2],n[2]].filter(e=>void 0!==e),author:n[1]}:void 0}i(gs,{finishReactionEvent:()=>_s,getReactedEventPointer:()=>vs});var bs={};i(bs,{parse:()=>xs});var ys=/\W/m,ws=/\W |\W$|$|,| /m,ks=42;function*xs(e){let t=[];if("string"!=typeof e){for(let n=0;n=3&&t.push({type:"emoji",shortcode:a[1],url:a[2]})}e=e.content}const n=e.length;let a=0,i=0;e:for(;i=0&&rCs,channelHideMessageEvent:()=>Es,channelMessageEvent:()=>Ps,channelMetadataEvent:()=>Ts,channelMuteUserEvent:()=>As});var Cs=(e,t)=>{let n;if("object"==typeof e.content)n=JSON.stringify(e.content);else{if("string"!=typeof e.content)return;n=e.content}return Ft({kind:un,tags:[...e.tags??[]],content:n,created_at:e.created_at},t)},Ts=(e,t)=>{let n;if("object"==typeof e.content)n=JSON.stringify(e.content);else{if("string"!=typeof e.content)return;n=e.content}return Ft({kind:cn,tags:[["e",e.channel_create_event_id],...e.tags??[]],content:n,created_at:e.created_at},t)},Ps=(e,t)=>{const n=[["e",e.channel_create_event_id,e.relay_url,"root"]];return e.reply_to_channel_message_event_id&&n.push(["e",e.reply_to_channel_message_event_id,e.relay_url,"reply"]),Ft({kind:dn,tags:[...n,...e.tags??[]],content:e.content,created_at:e.created_at},t)},Es=(e,t)=>{let n;if("object"==typeof e.content)n=JSON.stringify(e.content);else{if("string"!=typeof e.content)return;n=e.content}return Ft({kind:hn,tags:[["e",e.channel_message_event_id],...e.tags??[]],content:n,created_at:e.created_at},t)},As=(e,t)=>{let n;if("object"==typeof e.content)n=JSON.stringify(e.content);else{if("string"!=typeof e.content)return;n=e.content}return Ft({kind:pn,tags:[["p",e.pubkey_to_mute],...e.tags??[]],content:n,created_at:e.created_at},t)},Ms={};i(Ms,{EMOJI_SHORTCODE_REGEX:()=>Ls,matchAll:()=>zs,regex:()=>Rs,replaceAll:()=>Ns});var Ls=/:(\w+):/,Rs=()=>new RegExp(`\\B${Ls.source}\\B`,"g");function*zs(e){const t=e.matchAll(Rs());for(const e of t)try{const[t,n]=e;yield{shortcode:t,name:n,start:e.index,end:e.index+t.length}}catch(e){}}function Ns(e,t){return e.replaceAll(Rs(),(e,n)=>t({shortcode:e,name:n}))}var Os,Is={};i(Is,{useFetchImplementation:()=>qs,validateGithub:()=>Ds});try{Os=fetch}catch{}function qs(e){Os=e}async function Ds(e,t,n){try{return await(await Os(`https://gist.github.com/${t}/${n}/raw`)).text()===`Verifying that I control the following Nostr public key: ${e}`}catch(e){return!1}}var js={};function Bs(e){const{host:t,pathname:n,searchParams:a}=new URL(e),i=n||t,o=a.get("relay"),r=a.get("secret");if(!i||!o||!r)throw new Error("invalid connection string");return{pubkey:i,relay:o,secret:r}}async function Fs(e,t,n){const a={method:"pay_invoice",params:{invoice:n}},i=Vo(t,e,JSON.stringify(a)),o={kind:Hn,created_at:Math.round(Date.now()/1e3),content:i,tags:[["p",e]]};return Ft(o,t)}i(js,{makeNwcRequestEvent:()=>Fs,parseConnectionString:()=>Bs});var $s={};function Vs(e){return e=(e=e.trim().toLowerCase()).normalize("NFKC"),Array.from(e).map(e=>/\p{Letter}/u.test(e)||/\p{Number}/u.test(e)?e:"-").join("")}i($s,{normalizeIdentifier:()=>Vs});var Us,Hs={};i(Hs,{getSatoshisAmountFromBolt11:()=>Zs,getZapEndpoint:()=>Gs,makeZapReceipt:()=>Qs,makeZapRequest:()=>Ks,useFetchImplementation:()=>Ws,validateZapRequest:()=>Ys});try{Us=fetch}catch{}function Ws(e){Us=e}async function Gs(e){try{let t="",{lud06:n,lud16:a}=JSON.parse(e.content);if(a){let[e,n]=a.split("@");t=new URL(`/.well-known/lnurlp/${e}`,`https://${n}`).toString()}else{if(!n)return null;{let{words:e}=mi.decode(n,1e3),a=mi.fromWords(e);t=Et.decode(a)}}let i=await Us(t),o=await i.json();if(o.allowsNostr&&o.nostrPubkey)return o.callback}catch(e){}return null}function Ks(e){let t={kind:9734,created_at:Math.round(Date.now()/1e3),content:e.comment||"",tags:[["p","pubkey"in e?e.pubkey:e.event.pubkey],["amount",e.amount.toString()],["relays",...e.relays]]};if("event"in e){if(t.tags.push(["e",e.event.id]),Ht(e.event.kind)){const n=["a",`${e.event.kind}:${e.event.pubkey}:`];t.tags.push(n)}else if(Gt(e.event.kind)){let n=e.event.tags.find(([e,t])=>"d"===e&&t);if(!n)throw new Error("d tag not found or is empty");const a=["a",`${e.event.kind}:${e.event.pubkey}:${n[1]}`];t.tags.push(a)}t.tags.push(["k",e.event.kind.toString()])}return t}function Ys(e){let t;try{t=JSON.parse(e)}catch(e){return"Invalid zap request JSON."}if(!pt(t))return"Zap request is not a valid Nostr event.";if(!$t(t))return"Invalid signature on zap request.";let n=t.tags.find(([e,t])=>"p"===e&&t);if(!n)return"Zap request doesn't have a 'p' tag.";if(!n[1].match(/^[a-f0-9]{64}$/))return"Zap request 'p' tag is not valid hex.";let a=t.tags.find(([e,t])=>"e"===e&&t);return a&&!a[1].match(/^[a-f0-9]{64}$/)?"Zap request 'e' tag is not valid hex.":t.tags.find(([e,t])=>"relays"===e&&t)?null:"Zap request doesn't have a 'relays' tag."}function Qs({zapRequest:e,preimage:t,bolt11:n,paidAt:a}){let i=JSON.parse(e),o=i.tags.filter(([e])=>"e"===e||"p"===e||"a"===e),r={kind:9735,created_at:Math.round(a.getTime()/1e3),content:"",tags:[...o,["P",i.pubkey],["bolt11",n],["description",e]]};return t&&r.tags.push(["preimage",t]),r}function Zs(e){if(e.length<50)return 0;const t=(e=e.substring(0,50)).lastIndexOf("1");if(-1===t)return 0;const n=e.substring(0,t);if(!n.startsWith("lnbc"))return 0;const a=n.substring(4);if(a.length<1)return 0;const i=a[a.length-1],o=i.charCodeAt(0)-"0".charCodeAt(0),r=o>=0&&o<=9;let s=a.length-1;if(r&&s++,s<1)return 0;const l=parseInt(a.substring(0,s));switch(i){case"m":return 1e5*l;case"u":return 100*l;case"n":return l/10;case"p":return l/1e4;default:return 1e8*l}}var Js={};i(Js,{Negentropy:()=>ul,NegentropyStorageVector:()=>ll,NegentropySync:()=>hl});var Xs=32,el=0,tl=1,nl=2,al=class{_raw;length;constructor(e){"number"==typeof e?(this._raw=new Uint8Array(e),this.length=0):e instanceof Uint8Array?(this._raw=new Uint8Array(e),this.length=e.length):(this._raw=new Uint8Array(512),this.length=0)}unwrap(){return this._raw.subarray(0,this.length)}get capacity(){return this._raw.byteLength}extend(e){if(e instanceof al&&(e=e.unwrap()),"number"!=typeof e.length)throw Error("bad length");const t=e.length+this.length;if(this.capacity>>=7;t.reverse();for(let e=0;e4294967295&&(n=1),a.setUint32(o,4294967295&r,!0),t=n,n=0}}negate(){let e=new DataView(this.buf.buffer);for(let t=0;t<8;t++){let n=4*t;e.setUint32(n,~e.getUint32(n,!0))}let t=new Uint8Array(Xs);t[0]=1,this.add(t)}getFingerprint(e){let t=new al;return t.extend(this.buf),t.extend(ol(e)),Tt(t.unwrap()).subarray(0,16)}},ll=class{items;sealed;constructor(){this.items=[],this.sealed=!1}insert(e,t){if(this.sealed)throw Error("already sealed");const n=Xi(t);if(n.byteLength!==Xs)throw Error("bad id size for added item");this.items.push({timestamp:e,id:n})}seal(){if(this.sealed)throw Error("already sealed");this.sealed=!0,this.items.sort(dl);for(let e=1;e=this.items.length)throw Error("out of range");return this.items[e]}iterate(e,t,n){this._checkSealed(),this._checkBounds(e,t);for(let a=e;adl(e,n)<0)}fingerprint(e,t){let n=new sl;return n.setToZero(),this.iterate(e,t,e=>(n.add(e.id),!0)),n.getFingerprint(t-e)}_checkSealed(){if(!this.sealed)throw Error("not sealed")}_checkBounds(e,t){if(e>t||t>this.items.length)throw Error("bad range")}_binarySearch(e,t,n,a){let i=n-t;for(;i>0;){let n=t,o=Math.floor(i/2);n+=o,a(e[n])?(t=++n,i-=o+1):i=o}return t}},ul=class{storage;frameSizeLimit;lastTimestampIn;lastTimestampOut;constructor(e,t=6e4){if(t<4096)throw Error("frameSizeLimit too small");this.storage=e,this.frameSizeLimit=t,this.lastTimestampIn=0,this.lastTimestampOut=0}_bound(e,t){return{timestamp:e,id:t||new Uint8Array(0)}}initiate(){let e=new al;return e.extend(new Uint8Array([97])),this.splitRange(0,this.storage.size(),this._bound(Number.MAX_VALUE),e),Hi(e.unwrap())}reconcile(e,t,n){const a=new al(Xi(e));this.lastTimestampIn=this.lastTimestampOut=0;let i=new al;i.extend(new Uint8Array([97]));let o=rl(a,1)[0];if(o<96||o>111)throw Error("invalid negentropy protocol version byte");if(97!==o)throw Error("unsupported negentropy protocol version requested: "+(o-96));let r=this.storage.size(),s=this._bound(0),l=0,u=!1;for(;0!==a.length;){let e=new al,o=()=>{u&&(u=!1,e.extend(this.encodeBound(s)),e.extend(ol(el)))},c=this.decodeBound(a),d=il(a),h=l,p=this.storage.findLowerBound(l,r,c);if(d===el)u=!0;else if(d===tl){0!==cl(rl(a,16),this.storage.fingerprint(h,p))?(o(),this.splitRange(h,p,c,e)):u=!0}else{if(d!==nl)throw Error("unexpected mode");{let e=il(a),i={};for(let t=0;t{let n=e.id;const a=Hi(n);return i[a]?delete i[Hi(n)]:t?.(a),!0}),n)for(let e of Object.values(i))n(Hi(e))}}if(this.exceededFrameSizeLimit(i.length+e.length)){let e=this.storage.fingerprint(p,r);i.extend(this.encodeBound(this._bound(Number.MAX_VALUE))),i.extend(ol(tl)),i.extend(e);break}i.extend(e),l=p,s=c}return 1===i.length?null:Hi(i.unwrap())}splitRange(e,t,n,a){let i=t-e;if(i<32)a.extend(this.encodeBound(n)),a.extend(ol(nl)),a.extend(ol(i)),this.storage.iterate(e,t,e=>(a.extend(e.id),!0));else{let o=Math.floor(i/16),r=i%16,s=e;for(let e=0;e<16;e++){let i,l=o+(e(a===s-1?e=n:t=n,!0)),i=this.getMinimalBound(e,t)}a.extend(this.encodeBound(i)),a.extend(ol(tl)),a.extend(u)}}}exceededFrameSizeLimit(e){return e>this.frameSizeLimit-200}decodeTimestampIn(e){let t=il(e);return t=0===t?Number.MAX_VALUE:t-1,this.lastTimestampIn===Number.MAX_VALUE||t===Number.MAX_VALUE?(this.lastTimestampIn=Number.MAX_VALUE,Number.MAX_VALUE):(t+=this.lastTimestampIn,this.lastTimestampIn=t,t)}decodeBound(e){let t=this.decodeTimestampIn(e),n=il(e);if(n>Xs)throw Error("bound key too long");return{timestamp:t,id:rl(e,n)}}encodeTimestampOut(e){if(e===Number.MAX_VALUE)return this.lastTimestampOut=Number.MAX_VALUE,ol(0);let t=e;return e-=this.lastTimestampOut,this.lastTimestampOut=t,ol(e+1)}encodeBound(e){let t=new al;return t.extend(this.encodeTimestampOut(e.timestamp)),t.extend(ol(e.id.length)),t.extend(e.id),t}getMinimalBound(e,t){if(t.timestamp!==e.timestamp)return this._bound(t.timestamp);{let n=0,a=t.id,i=e.id;for(let e=0;et[n])return 1}return e.byteLength>t.byteLength?1:e.byteLength{switch(e[0]){case"NEG-MSG":e.length<3&&console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${e}`);try{const t=this.neg.reconcile(e[2],this.onhave,this.onneed);t?this.relay.send(`["NEG-MSG", "${this.subscription.id}", "${t}"]`):(this.close(),a.onclose?.())}catch(e){console.error("negentropy reconcile error:",e),a?.onclose?.(`reconcile error: ${e}`)}break;case"NEG-CLOSE":{const t=e[2];console.warn("negentropy error:",t),a.onclose?.(t);break}case"NEG-ERR":a.onclose?.()}}}async start(){const e=this.neg.initiate();this.relay.send(`["NEG-OPEN","${this.subscription.id}",${JSON.stringify(this.filter)},"${e}"]`)}close(){this.relay.send(`["NEG-CLOSE","${this.subscription.id}"]`),this.subscription.close()}},pl={};i(pl,{getToken:()=>gl,hashPayload:()=>xl,unpackEventFromToken:()=>vl,validateEvent:()=>Cl,validateEventKind:()=>yl,validateEventMethodTag:()=>kl,validateEventPayloadTag:()=>Sl,validateEventTimestamp:()=>bl,validateEventUrlTag:()=>wl,validateToken:()=>_l});var fl,ml="Nostr ";async function gl(e,t,n,a=!1,i){const o={kind:Kn,tags:[["u",e],["method",t]],created_at:Math.round((new Date).getTime()/1e3),content:""};i&&o.tags.push(["payload",xl(i)]);const r=await n(o);return(a?ml:"")+ii.encode(At.encode(JSON.stringify(r)))}async function _l(e,t,n){const a=await vl(e).catch(e=>{throw e});return await Cl(a,t,n).catch(e=>{throw e})}async function vl(e){if(!e)throw new Error("Missing token");e=e.replace(ml,"");const t=Et.decode(ii.decode(e));if(!t||0===t.length||!t.startsWith("{"))throw new Error("Invalid token");return JSON.parse(t)}function bl(e){return!!e.created_at&&Math.round((new Date).getTime()/1e3)-e.created_at<60}function yl(e){return e.kind===Kn}function wl(e,t){const n=e.tags.find(e=>"u"===e[0]);return!!n&&(n.length>0&&n[1]===t)}function kl(e,t){const n=e.tags.find(e=>"method"===e[0]);return!!n&&(n.length>0&&n[1].toLowerCase()===t.toLowerCase())}function xl(e){return it(Tt(At.encode(JSON.stringify(e))))}function Sl(e,t){const n=e.tags.find(e=>"payload"===e[0]);if(!n)return!1;const a=xl(t);return n.length>0&&n[1]===a}async function Cl(e,t,n,a){if(!$t(e))throw new Error("Invalid nostr event, signature invalid");if(!yl(e))throw new Error("Invalid nostr event, kind invalid");if(!bl(e))throw new Error("Invalid nostr event, created_at timestamp invalid");if(!wl(e,t))throw new Error("Invalid nostr event, url tag invalid");if(!kl(e,n))throw new Error("Invalid nostr event, method tag invalid");if(Boolean(a)&&"object"==typeof a&&Object.keys(a).length>0&&!Sl(e,a))throw new Error("Invalid nostr event, payload tag does not match request body hash");return!0}return fl=o,((i,o,r,s)=>{if(o&&"object"==typeof o||"function"==typeof o)for(let l of n(o))a.call(i,l)||l===r||e(i,l,{get:()=>o[l],enumerable:!(s=t(o,l))||s.enumerable});return i})(e({},"__esModule",{value:!0}),fl)})();window.localisation={},window.localisation.de={confirm:"Ja",server:"Server",theme:"Theme",site_customisation:"Website-Anpassung",funding:"Funding",users:"Benutzer",audit:"Prüfung",apps:"Apps",channels:"Kanäle",transactions:"Transaktionen",dashboard:"Armaturenbrett",node:"Knoten",export_users:"Benutzer exportieren",no_users:"Keine Benutzer gefunden",total_capacity:"Gesamtkapazität",avg_channel_size:"Durchschn. Kanalgröße",biggest_channel_size:"Größte Kanalgröße",smallest_channel_size:"Kleinste Kanalgröße",number_of_channels:"Anzahl der Kanäle",active_channels:"Aktive Kanäle",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Offener Kanal",open:"Öffnen",close_channel:"Kanal schließen",close:"Schließen",restart:"Server neu starten",save:"Speichern",save_tooltip:"Änderungen speichern",credit_debit:"Kredit / Debit",credit_hint:"Klicke Enter, um das Konto zu belasten",credit_label:"{denomination} zu belasten",credit_ok:"Erfolgreiches Gutschreiben/Abziehen von virtuellen Geldern ({amount} Sats). Zahlungen hängen von den tatsächlichen Mitteln der Finanzierungsquelle ab.",restart_tooltip:"Starte den Server neu, um die Änderungen zu übernehmen",add_funds_tooltip:"Füge Geld zu einer Wallet hinzu.",reset_defaults:"Zurücksetzen",reset_defaults_tooltip:"Alle Einstellungen auf die Standardeinstellungen zurücksetzen.",download_backup:"Datenbank-Backup herunterladen",name_your_wallet:"Vergib deiner {name} Wallet einen Namen",paste_invoice_label:"Füge eine Rechnung, Zahlungsanforderung oder LNURL ein *",lnbits_description:"Einfach zu installieren und kompakt, LNbits kann auf jeder Funding-Quelle im Lightning Netzwerk aufsetzen und sogar LNbits selbst! Du kannst LNbits für dich selbst betreiben oder anderen die Verwaltung durch dich anbieten. Jede Wallet hat ihre eigenen API-Schlüssel und die Anzahl der Wallets ist unbegrenzt. Die Möglichkeit, Gelder auf verschiedene Accounts mit unterschiedlicher Logik aufteilen zu können macht LNbits zu einem nützlichen Werkzeug für deine Buchhaltung - aber auch als Entwicklungswerkzeug. Erweiterungen bereichern LNbits Accounts um zusätzliche Funktionalität, so dass du mit einer Reihe von neuartigen Technologien auf dem Lightning-Netzwerk experimentieren kannst. Wir haben es so einfach wie möglich gemacht, Erweiterungen zu entwickeln, und als freies und Open-Source-Projekt möchten wir Menschen ermutigen, sich selbst hieran zu versuchen und gemeinsam mit uns neue Funktionalitäten zu entwickeln.",export_to_phone:"Auf dem Telefon öffnen",export_to_phone_desc:"Dieser QR-Code beinhaltet vollständige Rechte auf deine Wallet. Du kannst den QR-Code mit Deinem Telefon scannen, um deine Wallet dort zu öffnen.",wallet:"Brieftasche:",wallets:"Wallets",add_wallet:"Wallet hinzufügen",delete_wallet:"Wallet löschen",delete_wallet_desc:"Die Wallet wird gelöscht, die hierin beinhalteten Daten hierin oder innerhalb einer Erweiterung sind UNWIEDERBRINGLICH.",rename_wallet:"Wallet umbenennen",update_name:"Namen aktualisieren",fiat_tracking:"Fiat-Tracking",currency:"Währung",update_currency:"Währung aktualisieren",press_to_claim:"Klicken, um Bitcoin einzufordern.",donate:"Spenden",view_github:"Auf GitHub anzeigen",voidwallet_active:"VoidWallet ist aktiv! Zahlungen deaktiviert",use_with_caution:"BITTE MIT VORSICHT BENUTZEN - {name} Wallet ist noch BETA",service_fee:"Dienstleistungsgebühr: {amount} % pro Transaktion",service_fee_max:"Servicegebühr: {amount} % pro Transaktion (max {max} Sats)",service_fee_tooltip:"Bearbeitungsgebühr, die vom LNbits Server-Administrator pro ausgehender Transaktion berechnet wird",toggle_darkmode:"Auf Dark Mode umschalten",payment_reactions:"Zahlungsreaktionen",view_swagger_docs:"LNbits Swagger API-Dokumentation",api_docs:"API-Dokumentation",api_keys_api_docs:"Knoten-URL, API-Schlüssel und API-Dokumentation",lnbits_version:"LNbits-Version",runs_on:"Läuft auf",paste:"Einfügen",paste_from_clipboard:"Einfügen aus der Zwischenablage",paste_request:"Anfrage einfügen",create_invoice:"Rechnung erstellen",camera_tooltip:"Verwende die Kamera, um eine Rechnung oder einen QR-Code zu scannen",export_csv:"Exportieren als CSV",chart_tooltip:"Diagramm anzeigen",pending:"Ausstehend",copy_invoice:"Rechnung kopieren",withdraw_from:"Abheben von",cancel:"Stornieren",scan:"Scannen",read:"Lesen",pay:"Zahlen",memo:"Memo",date:"Datum",payment_processing:"Zahlung wird verarbeitet ...",not_enough_funds:"Geldmittel sind erschöpft!",search_by_tag_memo_amount:"Suche nach Tag, Memo, Betrag",invoice_waiting:"Rechnung wartend auf Zahlung",payment_received:"Zahlung erhalten",payment_sent:"Zahlung gesendet",receive:"erhalten",send:"schicken",outgoing_payment_pending:"Ausgehende Zahlung wartend",drain_funds:"Sats abziehen",drain_funds_desc:"LNURL-withdraw QR-Code, der das Abziehen aller Geldmittel aus dieser Wallet erlaubt. Teile ihn mit niemandem! Kompatibel mit balanceCheck und balanceNotify, so dass dein Wallet die Sats nach dem ersten Abzug kontinuierlich von hier abziehen kann.",i_understand:"Ich verstehe",copy_wallet_url:"Wallet-URL kopieren",disclaimer_dialog_title:"Wichtig!",disclaimer_dialog:"Login-Funktionalität wird in einem zukünftigen Update veröffentlicht. Bis dahin ist die Speicherung der Wallet-URL als Lesezeichen absolut notwendig, um Zugriff auf die Wallet zu erhalten! Dieser Service ist in BETA und wir übernehmen keine Verantwortung für Verluste durch verlorene Zugriffe.",no_transactions:"Keine Transaktionen",manage:"Verwalten",exchanges:"Börsenplätze",extensions:"Erweiterungen",no_extensions:"Du hast noch keine Erweiterungen installiert :(",created:"Erstellt",search_extensions:"Sucherweiterungen",extension_sources:"Erweiterungsquellen",ext_sources_hint:"Repositorys, von denen die Erweiterungen heruntergeladen werden können.",ext_sources_label:"Quell-URL (verwenden Sie nur die offizielle LNbits-Erweiterungsquelle und vertrauenswürdige Quellen)",warning:"Warnung",repository:"Repository",confirm_continue:"Bist du sicher, dass du fortfahren möchtest?",manage_extension_details:"Erweiterung installieren/deinstallieren",install:"Installieren",uninstall:"Deinstallieren",drop_db:"Daten löschen",enable:"Aktivieren",pay_to_enable:"Zahlen Sie zum Aktivieren",enable_extension_details:"Erweiterung für aktuellen Benutzer aktivieren",disable:"Deaktivieren",delete:"Löschen",installed:"Installiert",activated:"Aktiviert",deactivated:"Deaktiviert",release_notes:"Versionshinweise",activate_extension_details:"Erweiterung für Benutzer verfügbar/nicht verfügbar machen",featured:"Vorgestellt",all:"Alle",only_admins_can_install:"(Nur Administratorkonten können Erweiterungen installieren)",admin_only:"Nur für Admins",new_version:"Neue Version",extension_depends_on:"Hängt ab von:",extension_rating_soon:"Bewertungen sind bald verfügbar",extension_installed_version:"Installierte Version",extension_uninstall_warning:"Sie sind dabei, die Erweiterung für alle Benutzer zu entfernen.",uninstall_confirm:"Ja, deinstallieren",extension_db_drop_info:"Alle Daten für die Erweiterung werden dauerhaft gelöscht. Es gibt keine Möglichkeit, diesen Vorgang rückgängig zu machen!",extension_db_drop_warning:"Sie sind dabei, alle Daten für die Erweiterung zu entfernen. Bitte geben Sie den Namen der Erweiterung ein, um fortzufahren:",extension_required_lnbits_version:"Diese Version erfordert mindestens die LNbits-Version",min_version:"Mindestwert (inklusive)",max_version:"Maximalwert (ausgeschlossen)",payment_hash:"Zahlungs-Hash",fee:"Gebühr",amount:"Menge",amount_sats:"Betrag (sats)",tag:"Tag",unit:"Einheit",description:"Beschreibung",expiry:"Ablauf",webhook:"Webhook",payment_proof:"Beleg",update:"Aktualisieren",update_available:"Aktualisierung {version} verfügbar!",latest_update:"Sie sind auf der neuesten Version {version}.",notifications:"Benachrichtigungen",no_notifications:"Keine Benachrichtigungen",notifications_disabled:"LNbits Statusbenachrichtigungen sind deaktiviert.",enable_notifications:"Aktiviere Benachrichtigungen",enable_notifications_desc:"Wenn aktiviert, werden die neuesten LNbits-Statusaktualisierungen, wie Sicherheitsvorfälle und Updates, abgerufen.",enable_watchdog:"Aktiviere Watchdog",enable_watchdog_desc:"Wenn aktiviert, wird Ihre Zahlungsquelle automatisch auf VoidWallet umgestellt, wenn Ihr Guthaben niedriger als das LNbits-Guthaben ist. Nach einem Update müssen Sie dies manuell aktivieren.",watchdog_interval:"Überwachungszeitintervall",watchdog_interval_desc:"Wie oft die Hintergrundaufgabe nach einem Abschaltsignal im Wachhund-Delta [node_balance - lnbits_balance] suchen soll (in Minuten).",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Limit, bevor der Notausschalter die Finanzierungsquelle auf VoidWallet ändert [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Benachrichtigungsquelle",notification_source_label:"Quell-URL (verwenden Sie nur die offizielle LNbits-Statusquelle und Quellen, denen Sie vertrauen können)",more:"mehr",less:"weniger",releases:"Veröffentlichungen",watchdog:"Wachhund",server_logs:"Serverprotokolle",ip_blocker:"IP-Sperre",security:"Sicherheit",security_tools:"Sicherheitstools",block_access_hint:"Zugriff per IP sperren",allow_access_hint:"Zugriff durch IP erlauben (überschreibt blockierte IPs)",enter_ip:"Geben Sie die IP ein und drücken Sie die Eingabetaste",rate_limiter:"Ratenbegrenzer",wallet_limiter:"Geldbeutel-Limiter",wallet_limit_max_withdraw_per_day:"Maximales tägliches Wallet-Auszahlungslimit in Sats (0 zum Deaktivieren)",wallet_max_ballance:"Maximales Guthaben der Wallet in Sats (0 zum Deaktivieren)",wallet_limit_secs_between_trans:"Mindestsekunden zwischen Transaktionen pro Wallet (0 zum Deaktivieren)",number_of_requests:"Anzahl der Anfragen",time_unit:"Zeiteinheit",minute:"Minute",second:"Sekunde",hour:"Stunde",disable_server_log:"Server-Log deaktivieren",enable_server_log:"Serverprotokollierung aktivieren",coming_soon:"Funktion demnächst verfügbar",session_has_expired:"Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",instant_access_question:"Möchten Sie sofortigen Zugang?",login_with_user_id:"Mit Benutzer-ID anmelden",or:"oder",create_new_wallet:"Neue Geldbörse erstellen",login_to_account:"Melden Sie sich bei Ihrem Konto an",create_account:"Konto erstellen",account_settings:"Kontoeinstellungen",signin_with_nostr:"Mit Nostr fortfahren",signin_with_google:"Mit Google anmelden",signin_with_github:"Anmelden mit GitHub",signin_with_keycloak:"Mit Keycloak anmelden",username_or_email:"Benutzername oder E-Mail",password:"Passwort",password_config:"Passwortkonfiguration",password_repeat:"Passwortwiederholung",change_password:"Passwort ändern",update_credentials:"Anmeldeinformationen aktualisieren",update_pubkey:"Öffentlichen Schlüssel aktualisieren",set_password:"Passwort festlegen",invalid_password:"Das Passwort muss mindestens 8 Zeichen haben.",login:"Anmelden",register:"Registrieren",username:"Benutzername",pubkey:"Öffentlicher Schlüssel",user_id:"Benutzer-ID",email:"E-Mail",first_name:"Vorname",last_name:"Nachname",picture:"Bild",verify_email:"E-Mail verifizieren mit",account:"Konto",update_account:"Konto aktualisieren",invalid_username:"Ungültiger Benutzername",auth_provider:"Anbieter für Authentifizierung",my_account:"Mein Konto",back:"Zurück",logout:"Abmelden",look_and_feel:"Aussehen und Verhalten",toggle_gradient:"Verlauf umschalten",gradient_background:"Verlaufs-Hintergrund",language:"Sprache",color_scheme:"Farbschema",admin_settings:"Admin-Einstellungen",extension_cost:"Diese Version erfordert eine Zahlung von mindestens {cost} Sats.",extension_paid_sats:"Sie haben bereits {paid_sats} Sats bezahlt.",release_details_error:"Kann die Details zur Veröffentlichung nicht abrufen.",pay_from_wallet:"Zahlen aus dem Geldbeutel",wallet_required:"Wallet *",show_qr:"QR anzeigen",retry_install:"Installieren erneut versuchen",new_payment:"Neue Zahlung vornehmen",update_payment:"Zahlung aktualisieren",already_paid_question:"Haben Sie schon bezahlt?",sell:"Verkaufen",sell_require:"Zahlung anfordern, um die Erweiterung zu aktivieren",sell_info:"Die {name}-Erweiterung erfordert eine Zahlung von mindestens {amount} Satoshis, um aktiviert zu werden.",hide_empty_wallets:"Leere Geldbörsen verbergen",recheck:"Erneut überprüfen",contributors:"Mitwirkende",license:"Lizenz",reset_key:"Zurücksetzen-Schlüssel",reset_password:"Passwort zurücksetzen",border_choices:"Randoptionen",select_all:"Alles auswählen",nfc_supported:"NFC unterstützt",nfc_not_supported:"NFC wird nicht unterstützt",expire_date:"Ablaufdatum:",hash:"Hash:",welcome_lnbits:"Willkommen bei LNbits",setup_su_account:"Richten Sie das Superuser-Konto unten ein.",create_ticker_converter:"Währungsticker-Konverter erstellen",enable_audit:"Audit aktivieren",recommended:"Empfohlen",audit_desc:"HTTP-Anfragen entsprechend den angegebenen Filtern aufzeichnen",audit_record_req:"Anfragekörper aufzeichnen",audit_record_warning:"Warnung:",audit_record_req_warning_1:"Vertrauliche Daten (wie Passwörter) werden protokolliert.",audit_record_req_warning_2:"Der Anfragetext kann groß sein.",audit_record_use:"Verwenden Sie es mit Vorsicht.",audit_ip:"IP-Adresse aufzeichnen",audit_ip_desc:"Speichern Sie die IP-Adresse des Clients",audit_path_params:"Pfadparameter aufzeichnen",audit_query_params:"Abfrageparameter aufzeichnen",audit_http_methods:"HTTP-Methoden einschließen",audit_http_methods_hint:"Liste der HTTP-Methoden, die einbezogen werden sollen. Leere Listen bedeuten alle.",audit_http_methods_label:"HTTP-Methoden",audit_resp_codes:"HTTP-Antwortcodes einbeziehen",audit_resp_codes_hint:"Liste der einzuschließenden HTTP-Codes (regex-Match). Leere Liste bedeutet alle. Z.B.: 4.*, 5.*",audit_resp_codes_label:"HTTP-Antwortcode (Regex)",audit_paths:"Einfügepfade",audit_paths_hint:"Liste der aufzunehmenden Pfade (Regex-Übereinstimmung). Leere Liste bedeutet alle.",audit_paths_label:"HTTP-Pfad (Regex)",audit_paths_exclude:"Pfade ausschließen",audit_paths_exclude_hint:"Liste der auszuschließenden Pfade (regex-Match). Leere Liste bedeutet keine.",audit_paths_exclude_label:"HTTP-Pfad (Regex)",exchange_providers:"Austauschdienste",admin_extensions:"Admin-Erweiterungen",admin_extensions_label:"Admin-Erweiterungen",admin_extensions_hint:"Nur Benutzer mit Admin-Rechten können Erweiterungen verwenden.",user_default_extensions:"Standarderweiterungen des Benutzers",user_default_extensions_label:"Benutzererweiterungen",user_default_extensions_hint:"Erweiterungen, die standardmäßig für die Benutzer aktiviert werden.",miscellanous:"Verschiedenes",misc_disable_extensions:"Erweiterungen deaktivieren",misc_disable_extensions_label:"Alle Erweiterungen deaktivieren",misc_hide_api:"API ausblenden",misc_hide_api_label:"Verbirgt Wallet-API, Erweiterungen können es ehren",wallets_management:"Verwaltung von Geldbörsen",funding_source_info:"Finanzierungsquelleninformationen",funding_source:"Finanzierungsquelle: {wallet_class}",node_balance:"Kontostand: {balance} Sats",lnbits_balance:"LNbits-Guthaben: {balance} Sats",funding_reserve_percent:"Reservieren Prozent: {percent} %",node_management:"Knotenverwaltung",node_management_not_supported:"Knotenverwaltung wird von der aktiven Finanzierungsquelle nicht unterstützt",toggle_node_ui:"Node-Benutzeroberfläche",toggle_public_node_ui:"Öffentliche Knoten-Benutzeroberfläche",toggle_transactions_node_ui:"Transaktionen-Tab (Bei großen CLN-Knoten deaktivieren)",invoice_expiry:"Rechnungsablauf",invoice_expiry_label:"Rechnungsablauf (Sekunden)",fee_reserve:"Gebührenreserve",fee_reserve_msats:"Reservierungsgebühr in msats",fee_reserve_percent:"Reservierungsgebühr in Prozent",server_management:"Serververwaltung",base_url:"Basis-URL",base_url_label:"Statische/Basis-URL für den Server",authentication:"Authentifizierung",auth_token_expiry_label:"Token-Ablaufminuten",auth_token_expiry_hint:"Zeit in Minuten bis der Token abläuft",auth_allowed_methods_label:"Erlaubte Autorisierungsmethoden",auth_allowed_methods_hint:"Wählen Sie Autorisierungsmethoden aus",auth_nostr_label:"Nostr-Anforderungs-URL",auth_nostr_hint:"Absolute URL, die die Clients für die Anmeldung verwenden.",auth_google_ci_label:"Google-Client-ID",auth_google_ci_hint:"Stellen Sie sicher, dass die autorisierten Umleitungs-URIs https://{domain}/api/v1/auth/google/token enthalten",auth_google_cs_label:"Google-Client-Geheimnis",auth_gh_client_id_label:"GitHub-Client-ID",auth_gh_client_id_hint:"Stellen Sie sicher, dass die URL für den Autorisierungsrückruf auf https://{domain}/api/v1/auth/github/token gesetzt ist.",auth_gh_client_secret_label:"GitHub-Client-Geheimnis",auth_keycloak_label:"Keycloak Discovery-URL",auth_keycloak_ci_label:"Keycloak-Client-ID",auth_keycloak_ci_hint:"Stellen Sie sicher, dass die Autorisierungs-Callback-URL auf https://{domain}/api/v1/auth/keycloak/token eingestellt ist.",auth_keycloak_cs_label:"Keycloak-Client-Geheimnis",currency_settings:"Währungseinstellungen",allowed_currencies:"Erlaubte Währungen",allowed_currencies_hint:"Begrenzen Sie die Anzahl der verfügbaren Fiat-Währungen",default_account_currency:"Standardkontowährung",default_account_currency_hint:"Standardwährung für Buchhaltung",service_fee_label:"Servicegebühr (%)",service_fee_hint:"Gebühr pro Transaktion (%)",service_fee_max_label:"Servicegebühr max. (sats)",service_fee_max_hint:"Maximale Servicegebühr in (sats) berechnen.",fee_wallet:"Gebühren-Wallet",fee_wallet_label:"Gebühren-Wallet (Wallet-ID)",fee_wallet_hint:"Wallet-ID, an die Gelder gesendet werden sollen",disable_fee:"Gebühr deaktivieren",disable_fee_internal:"Dienstleistungsgebühr für interne Zahlungen deaktivieren",disable_fee_internal_desc:"Dienstleistungsgebühr für interne Lightning-Zahlungen deaktivieren",ui_management:"UI-Verwaltung",ui_site_title:"Seitentitel",ui_site_tagline:"Seitenslogan",ui_elements_enable:"Elemente auf der Startseite aktivieren",ui_elements_disable:"Elemente auf der Startseite deaktivieren",ui_toggle_elements_tip:"Entfernen Sie Homepage-Elemente wie 'läuft auf' usw.",ui_site_description:"Seitenbeschreibung",ui_site_description_hint:"Verwenden Sie einfachen Text, Markdown oder rohes HTML",ui_default_wallet_name:"Standard-Walletname",lnbits_wallet:"LNbits-Wallet",denomination:"Nomination",denomination_hint:"Der Name für das FakeWallet-Token",ui_qr_code_logo:"QR-Code-Logo",ui_qr_code_logo_hint:"URL zum Logo-Bild im QR-Code",ui_custom_badge:"Benutzerdefiniertes Abzeichen",ui_custom_badge_label:"Benutzerdefiniertes Abzeichen 'MIT VORSICHT VERWENDEN - LNbits-Wallet ist noch in der BETA-Phase'",ui_custom_badge_color_label:"Benutzerdefinierte Abzeichenfarbe",themes:"Themen",themes_hint:"Wählen Sie Themen, die für Benutzer verfügbar sind",custom_logo:"Benutzerdefiniertes Logo",custom_logo_hint:"URL zum Logobild",ad_space_title:"Anzeigentitel",ad_space_title_label:"Unterstützt von",ad_slots:"Werbeplätze",ad_slots_hint:"URL-Adressen und Bilddateipfade im CSV-Format, Erweiterungen können darauf achten",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anzeigen aktiviert",ads_disabled:"Anzeigen deaktiviert",user_management:"Benutzerverwaltung",admin_users:"Admin-Benutzer",admin_users_hint:"Benutzer mit Administratorrechten",admin_users_label:"Benutzer-ID",allowed_users:"Zugelassene Benutzer",allowed_users_hint:"Nur diese Benutzer können LNbits verwenden.",allowed_users_label:"Benutzer-ID",allow_creation_user:"Erlauben Sie die Erstellung neuer Benutzer",allow_creation_user_desc:"Erlauben Sie das Erstellen neuer Benutzer auf der Indexseite",components:"Komponenten",long_running_endpoints:"Top 5 lang laufende Endpunkte",http_request_methods:"HTTP-Anfragemethoden",http_response_codes:"HTTP-Antwortcodes",request_details:"Anfragedetails",http_request_details:"HTTP-Anfragedetails"},window.localisation.en={confirm:"Yes",server:"Server",theme:"Theme",site_customisation:"Site Customisation",funding:"Funding",users:"Users",audit:"Audit",api_watch:"API Watch",apps:"Apps",channels:"Channels",transactions:"Transactions",dashboard:"Dashboard",node:"Node",export_users:"Export Users",no_users:"No users found",total_capacity:"Total Capacity",avg_channel_size:"Avg. Channel Size",biggest_channel_size:"Biggest Channel Size",smallest_channel_size:"Smallest Channel Size",number_of_channels:"Number of Channels",active_channels:"Active Channels",connect_peer:"Connect Peer",connect:"Connect",reconnect:"Reconnect",open_channel:"Open Channel",open:"Open",clear:"Clear",close_channel:"Close Channel",close:"Close",restart:"Restart server",image_library:"Image Library",save:"Save",save_tooltip:"Save your changes",must_save:"You have unsaved changes",credit_debit:"Credit / Debit",credit_hint:"Press Enter to credit/debit wallet (negative values allowed)",credit_label:"{denomination} to credit/debit",credit_ok:"Success crediting/debiting virtual funds ({amount} sats). Payments depend on actual funds on funding source.",restart_tooltip:"Restart the server for changes to take effect",add_funds_tooltip:"Add funds to a wallet.",reset_defaults:"Reset to defaults",reset_defaults_tooltip:"Delete all settings and reset to defaults.",download_backup:"Download database backup",name_your_wallet:"Name your {name} wallet",paste_invoice_label:"Paste an invoice, payment request or lnurl code *",lnbits_description:"Easy to set up and lightweight, LNbits can run on any Lightning Network funding source and even LNbits itself! You can run LNbits for yourself, or easily offer a custodian solution for others. Each wallet has its own API keys and there is no limit to the number of wallets you can make. Being able to partition funds makes LNbits a useful tool for money management and as a development tool. Extensions add extra functionality to LNbits so you can experiment with a range of cutting-edge technologies on the lightning network. We have made developing extensions as easy as possible, and as a free and open-source project, we encourage people to develop and submit their own.",export_to_phone:"Export to Phone with QR Code",export_to_phone_desc:"This QR code contains your wallet URL with full access. You can scan it from your phone to open your wallet from there.",access_wallet_on_mobile:"Mobile Access",stored_paylinks:"Stored LNURL pay links",wallet:"Wallet: ",wallet_name:"Wallet name",wallet_type:"Wallet type",shared_wallet:"Shared Wallet",share_wallet:"Share Wallet",update_permissions:"Update Permissions",shared_wallet_id:"Shared Wallet ID",shared_wallet_desc:"You have been invited to have access to someone else's wallet.",wallets:"Wallets",exclude_wallets:"Exclude Wallets",add_wallet:"Add wallet",reject_wallet:"Reject wallet",add_new_wallet:"Add a new wallet",pin_wallet:"Pin wallet",delete_wallet:"Delete wallet",delete_wallet_desc:"This whole wallet will be deleted, the funds will be UNRECOVERABLE.",rename_wallet:"Rename wallet",update_name:"Update name",fiat_tracking:"Fiat tracking",fiat_providers:"Fiat providers",fiat_warning_bitcoin:'Fiat providers can get twitchy about anything bitcoin, so avoid using word "bitcoin" in your memos!',currency:"Currency",update_currency:"Update currency",press_to_claim:"Press to claim bitcoin",claim_desc:"It seems you have a claimable amount of bitcoin but you don’t have a wallet yet. Press the button below to claim it. This will create a new wallet for you.",donate:"Donate",view_github:"View on GitHub",voidwallet_active:"VoidWallet is active! Payments disabled",voidwallet_active_user:"Funding source unavailable. Please contact your admin to configure.",voidwallet_active_admin:"Funding source unavailable. Click here to configure.",service_fee_badge:"Service fee: {amount} % per transaction",service_fee_max_badge:"Service fee: {amount} % per transaction (max {max} {denom})",service_fee_tooltip:"Service fee charged by the LNbits server admin per outgoing transaction",toggle_darkmode:"Toggle Dark Mode",payment_reactions:"Payment Reactions",view_swagger_docs:"View LNbits Swagger API docs",api_docs:"API docs",api_keys_api_docs:"Node URL, API keys and API docs",lnbits_version:"LNbits version",runs_on:"Runs on",paste:"Paste",paste_from_clipboard:"Paste from clipboard",paste_request:"Paste Request",create_invoice:"Create Invoice",camera_tooltip:"Use camera to scan an invoice/QR",export_csv:"Export to CSV",export_csv_details:"Export to CSV with details",chart_tooltip:"Show chart",pending:"Pending",copy_invoice:"Copy invoice",withdraw_from:"Withdraw from",cancel:"Cancel",scan:"Scan",read:"Read",write:"Write",pay:"Pay",memo:"Memo",date:"Date",path:"Path",internal_memo:"Internal memo (optional)",internal_memo_hint_receive:"This memo is not shown to the payer but it's stored in the invoice for your reference.",internal_memo_hint_pay:"This memo is not shown to the payee but it's stored in the payment for your reference.",payment_processing:"Processing payment...",payment_processing:"Processing payment...",payment_successful:"Payment successful!",payment_pending:"Payment pending...",payment_check:"Check payment",not_enough_funds:"Not enough funds!",search_by_tag_memo_amount:"Search by tag, memo, amount",search:"Search",invoice_waiting:"Invoice waiting to be paid",payment_received:"Payment Received",payment_sent:"Payment Sent",payment_failed:"Payment Failed",receive:"receive",send:"send",outgoing_payment_pending:"Outgoing payment pending",drain_funds:"Drain Funds",drain_funds_desc:"This is an LNURL-withdraw QR code for slurping everything from this wallet. Do not share with anyone. It is compatible with balanceCheck and balanceNotify so your wallet may keep pulling the funds continuously from here after the first withdraw.",i_understand:"I understand",copy_wallet_url:"Copy wallet URL",disclaimer_dialog_title:"Important!",disclaimer_dialog:"You *must* save your login credentials to be able to access your wallet again. If you lose them, you will lose access to your wallet and funds.\n\nFind your login credentials on your account settings page.\n\nLNbits holds no responsibility for loss of access to funds.",no_transactions:"No transactions made yet",manage:"Manage",exchanges:"Exchanges",extensions:"Extensions",no_extensions:"You don't have any extensions installed :(",created:"Created",created_at:"Created At",updated_at:"Updated At",search_extensions:"Search extensions",search_wallets:"Search wallets",extension_sources:"Extension Sources",ext_sources_hint:"Repositories from where the extensions can be downloaded",ext_sources_label:"Source URL (only use the official LNbits extension source, and sources you can trust)",warning:"Warning",repository:"Repository",confirm_continue:"Are you sure you want to continue?",manage_extension_details:"Install/uninstall extension",upload:"Upload",install:"Install",uninstall:"Uninstall",drop_db:"Remove Data",enable:"Enable",enabled:"Enabled",disabled:"Disabled",pay_to_enable:"Pay To Enable",enable_extension_details:"Enable extension for current user",disable:"Disable",delete:"Delete",installed:"Installed",activated:"Activated",deactivated:"Deactivated",activate:"Activate",deactivate:"Deactivate",release_notes:"Release Notes",activate_extension_details:"Make extension available/unavailable for users",featured:"Featured",all:"All",only_admins_can_install:"(Only admin accounts can install extensions)",only_admins_can_create_extensions:"Only admin accounts can create extensions",admin_only:"Admin Only",make_user_admin:"Make User Admin",revoke_admin:"Revoke Admin",new_version:"New Version",reviews_url:"Reviews URL",reviews_url_label:"Reviews server URL",reviews_url_hint:"Full PaidReviews URL including the settings id (e.g. https://example.com/paidreviews/SETTINGS_ID)",reviews_open:"View reviews",reviews_leave:"Leave a review",reviews_name:"Your name",reviews_comment:"Your review",reviews_rating:"Rating",reviews_submit:"Submit review",reviews_loading:"Loading reviews...",reviews_refresh:"Refresh reviews",reviews_error_load:"Could not load reviews",reviews_url_not_configured:"Reviews URL not configured",reviews_pay_invoice:"Pay invoice",reviews_invoice_paid:"Invoice paid",reviews_invoice_title:"Pay this invoice to submit your review",reviews_count:"Reviews",no_reviews:"No reviews yet",extension_has_free_release:"Has free releases",extension_has_paid_release:"Has paid releases",extension_depends_on:"Depends on:",extension_rating_soon:"Ratings coming soon",extension_installed_version:"Installed version",extension_uninstall_warning:"You are about to remove the extension for all users.",uninstall_confirm:"Yes, Uninstall",extension_db_drop_info:"All data for the extension will be permanently deleted. There is no way to undo this operation!",extension_db_drop_warning:"You are about to remove all data for the extension. Please type the extension name to continue:",extension_required_lnbits_version:"This release requires LNbits version",min_version:"Minimum (included)",max_version:"Maximum (excluded)",preimage:"Preimage",preimage_hint:"Preimage to settle the hold invoice",hold_invoice:"Hold Invoice",hold_invoice_description:"This invoice is on hold and requires a preimage to settle.",payment_hash:"Payment Hash",invoice_cancelled:"Invoice Cancelled",invoice_settled:"Invoice Settled",hold_invoice_payment_hash:"Payment hash for hold invoice (optional)",settle_invoice:"Settle Invoice",cancel_invoice:"Cancel Invoice",fee:"Fee",amount:"Amount",amount_limits:"Amount Limits",amount_sats:"Amount (sats)",faucest_wallet:"Faucet Wallet",faucest_wallet_desc_1:"Each time a payment is confirmed by the {provider} provider funds will be subtracted from this wallet.",faucest_wallet_desc_2:"This helps monitor all {provider} payments and their status.",faucest_wallet_desc_3:"This wallet must be topped up with the amount of sats that the admin is willing to offer in exchange for the fiat currency.",faucest_wallet_desc_4:"If this wallet is configured, but is empty, the {provider} payments will not be processed.",faucest_wallet_desc_5:"This wallet can eventually get to a negative balance if parallel fiat payments are made.",faucest_wallet_id:"Faucet Wallet ID (optional)",faucest_wallet_id_hint:"Wallet ID to use for the faucet. It will be used to send the funds to the user.",tag:"Tag",unit:"Unit",description:"Description",expiry:"Expiry",webhook:"Webhook",webhook_url:"Webhook URL",webhook_url_hint:"Webhook URL to send the payment details to. It will be called when the payment is completed.",copy_webhook_url:"Copy webhook URL",webhook_events_list:"The following events must be supported by the webhook:",webhook_stripe_description:"One the stripe side you must configure a webhook with a URL that points to your LNbits server.",payment_proof:"Payment Proof",update:"Update",update_available:"Update {version} available!",funding_sources:"Funding Sources",funding_source:"Funding Source",requires_server_restart:"Changing these settings requires a server restart to take effect.",funding_source_info:"Select the active funding wallet",latest_update:"You are on the latest version {version}.",notifications:"Notifications",notifications_configure:"Configure Notifications",notifications_nostr_config:"Nostr Configuration",notifications_enable_nostr:"Enable Nostr",notifications_enable_nostr_desc:"Send notifications over Nostr",notifications_nostr_private_key:"Nostr Private Key",notifications_nostr_private_key_desc:"Private key (hex or nsec) to sign the messages sent to Nostr",notifications_nostr_identifier:"Nostr Identifier",notifications_nostr_identifier_desc:"Nip5 identifier to send notifications to",notifications_nostr_identifiers:"Nostr Identifiers",notifications_nostr_identifiers_desc:"List of identifiers to send notifications to.",notifications_telegram_config:"Telegram Configuration",notifications_enable_telegram:"Enable Telegram",notifications_enable_telegram_desc:"Send notifications over Telegram",notifications_telegram_access_token:"Access Token",notifications_telegram_access_token_desc:"Access token for the bot",notifications_chat_id:"Telegram Chat ID",notifications_chat_id_desc:"Telegram Chat ID to send the notifications to",notifications_excluded_wallets_desc:"Do not send notifications for these wallets",notifications_email_config:"Email Configuration",notifications_enable_email:"Enable Email",notifications_enable_email_desc:"Send notifications over email",notifications_send_test_email:"Send test email",notifications_send_email:"Send email",notifications_send_email_desc:"Email you will send from",notifications_send_email_username:"Username",notifications_send_email_username_desc:"Username, will use the email if not set",notifications_send_email_password:"Send email password",notifications_send_email_password_desc:"Password for the email you will send from",notifications_send_email_server_port:"Send email SMTP port",notifications_send_email_server_port_desc:"Port for the SMTP server",notifications_send_email_server:"Send email SMTP server",notifications_send_email_server_desc:"SMTP server for the email you will send from",notifications_send_to_emails:"Emails to send to",notifications_send_to_emails_desc:"Emails notifications will be sent to",notification_settings_update:"Settings updated",notification_settings_update_desc:"Send a notification when server settings have been updated",notification_server_start_stop:"Server Start/Stop",notification_server_start_stop_desc:"Send a notification when the server has been started/stopped",notification_watchdog_limit:"Watchdog Limit Notification",notification_watchdog_limit_desc:"Send a notification when the watchdog limit has been reached (does not affect the funding source)",notification_server_status:"Server Status",notification_server_status_desc:"Send regular notifications about the server status (interval value in hours)",notification_incoming_payment:"Incoming Payments",notification_incoming_payment_desc:"Send a notification when a wallet has received a payment above the specified amount (sats)",notification_outgoing_payment:"Outgoing Payments",notification_outgoing_payment_desc:"Send a notification when a wallet has sent a payment above the specified amount (sats)",notification_credit_debit:"Credit / Debit",notification_credit_debit_desc:"Send a notification when a wallet has been credited/debited by the superuser",notification_balance_delta_changed:"Balance Delta Changed",notification_balance_delta_changed_desc:"Send a notification when the difference between the node balance and the LNbits balance has changed by more than the specified amount (in sats). Set to 0 to disable. This runs every minute.",watchdog_introduction:"Watchdog is a feature that allows you to automatically switch the LNbits funding source to VoidWallet if your node balance is lower than the LNbits balance by a certain threshold. This can help prevent overspending and keep your node's funds safe.",enable_watchdog:"Enable Watchdog",enable_watchdog_desc:"You will need to re-enable this manually after an update.",watchdog_interval:"Watchdog Check Interval",watchdog_interval_desc:"How often LNbits should check for a killswitch signal in the watchdog threshold delta value [node_balance - lnbits_balance] (in minutes).",watchdog_delta:"Watchdog Threshold Delta",watchdog_delta_desc:"The LNbit's > Node balance delta threshold. If this threshold is exceeded, the funding source is changed to VoidWallet.",status:"Status",notification_source:"Notification Source",notification_source_label:"Source URL (only use the official LNbits status source, and sources you can trust)",more:"more",more_count:"{count} more",less:"less",releases:"Releases",watchdog:"Watchdog",server_logs:"Server Logs",ip_blocker:"IP Blacklist/Whitelist",security:"Security",security_tools:"Security Tools",block_access_hint:"Block access by IP",allow_access_hint:"Allow access by IP (will override blocked IPs)",enter_ip:"Enter an IP address and press enter",rate_limiter:"Rate Limiter",callback_url_rules:"Callback URL Rules",enter_callback_url_rule:"Enter URL rule as regex and hit enter",callback_url_rule_hint:"Callback URLs (like LNURL one) will be validated against these rules. At leat one rule must match. No rule means all URLs are allowed.",wallet_limiter:"Wallet Limiter",wallet_config:"Wallet Config",wallet_charts:"Wallet Charts",wallet_limit_max_withdraw_per_day:"Max daily wallet withdrawal in sats (0 for no limit, -1 to block withdrawal)",wallet_max_ballance:"Wallet max balance in sats (0 to disable)",wallet_limit_secs_between_trans:"Min secs between transactions per wallet (0 to disable)",only_incoming_payments_allowed:"Allow incoming payments only",disable_outgoing_payments:"Disable outgoing payments",number_of_requests:"Number of requests to allow",number_of_requests_hint:'Number of requests to allow per "time unit" for the rate limiter. Set to 0 to disable.',time_unit:"Time unit",minute:"Minute",settings:"Settings",second:"Second",hour:"Hour",disable_server_log:"Disable Server Log",enable_server_log:"Enable Server Log",coming_soon:"Feature coming soon",session_has_expired:"Your session has expired. Please login again.",instant_access_question:"or instant access",login_with_user_id:"Login with user ID",or:"or",create_new_wallet:"Create New Wallet",delete_all_wallets:"Delete All Wallets",confirm_delete_all_wallets:"Are you sure you want to delete ALL wallets for this user?",login_to_account:"Login to your account",create_account:"Create account",account_settings:"Account Settings",signin_with_oauth:"Login with",signin_with_oauth_or:"or Login with",signin_with_nostr:"Continue with Nostr",signin_with_google:"Sign in with Google",signin_with_github:"Sign in with GitHub",signin_with_custom_org:"Sign in with {custom_org}",username_or_email:"Username or Email",password:"Password",password_config:"Password Config",password_repeat:"Password repeat",update_password:"Update Password",change_password:"Change Password",update_credentials:"Update Credentials",update_pubkey:"Update Public Key",nostr_pubkey_tooltip:"Enter this user's Nostr public key (hex value)",set_password:"Set Password",set_password_tooltip:"Set a password for this user",invalid_password:"Password must have at least 8 characters",invalid_password_repeat:"Passwords do not match",reset_key_generated:"A reset key has been generated.",reset_key_copy:"Click OK to copy the reset URL to your clipboard.",login:"Login",register:"Register",username:"Username",pubkey:"Public Key",user_id:"User ID",id:"ID",email:"Email",first_name:"First Name",last_name:"Last Name",picture:"Picture",user_picture_desc:"URL to an image to use as profile picture. You can upload it as an asset.",verify_email:"Verify email with",account:"Account",update_account:"Update Account",invalid_username:"Invalid Username",auth_provider:"Auth Provider",external_id:"External ID",my_account:"My Account",existing_account_question:"Already have an account?",background_image:"Background Image",back:"Back",logout:"Logout",look_and_feel:"Look and Feel",endpoint:"Endpoint",api:"API",api_stripe:"API",api_token:"API Token",api_tokens:"API Tokens",access_control_list:"Access Control List",access_control_list_admin_warning:"This is an admin account. The generated tokens will have admin privileges.",new_api_acl:"New Access Control List",api_token_id:"Token Id",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",rounded_ui:"Rounded Cards & Buttons",toggle_rounded_ui:"Toggle rounded corners for cards and buttons",card_gradient:"Card Gradient",toggle_card_gradient:"Toggle gradient on cards",card_shadow:"Card Shadow",toggle_card_shadow:"Toggle shadow on cards",language:"Language",assets:"Assets",max_asset_size_mb:"Max Asset Size (MB)",max_asset_size_mb_desc:"The maximum allowed size for asset uploads in megabytes (can use decimal values).",assets_allowed_mime_types:"Allowed MIME Types",assets_allowed_mime_types_desc:"The MIME types that are allowed for asset uploads. No value means all uploads are allowed.",thumbnail_width:"Thumbnail Width",thumbnail_width_desc:"Width of the generated thumbnail in pixels.",thumbnail_height:"Thumbnail Height",thumbnail_height_desc:"Height of the generated thumbnail in pixels.",thumbnail_format:"Thumbnail Format",thumbnail_format_desc:"Image format of the generated thumbnail (PNG, JPEG, etc.).",max_assets_per_user:"Max Assets Per User",max_assets_per_user_desc:"The maximum number of assets a user can upload. Zero means upload forbidden.",assets_no_limit_users:"Users Without Asset Limits",assets_no_limit_users_desc:"These users can upload an unlimited number of assets (user id based).",color_scheme:"Color Scheme",visible_wallet_count:"Visible Wallet Count",admin_settings:"Admin Settings",extension_cost:"This release requires a payment of minimum {cost} sats.",extension_paid_sats:"You have already paid {paid_sats} sats.",create_extension:"Create Extension",release_details_error:"Cannot get the release details.",pay_from_wallet:"Pay from Wallet",pay_with:"Pay with {provider}",select_payment_provider:"Select payment provider",wallet_required:"Wallet *",show_qr:"Show QR",retry_install:"Retry Install",new_payment:"Make New Payment",update_payment:"Update Payment",already_paid_question:"Have you already paid?",sell:"Sell",sell_require:"Ask payment to enable extension",sell_info:"The {name} extension requires a payment of minimum {amount} sats to enable.",hide_empty_wallets:"Hide empty wallets",recheck:"Recheck",check:"Check",check_connection:"Check Connection",check_webhook:"Check Webhook",contributors:"Contributors",license:"License",reset_key:"Reset Key",reset_password:"Reset Password",border_choices:"Border Choices",select_all:"Select All",nfc_supported:"NFC Supported",nfc_not_supported:"NFC not Supported",expire_date:"Expire Date: ",hash:"Hash: ",welcome_lnbits:"Welcome to LNbits",setup_su_account:"Set up the Superuser account below.",first_install_token:"First Install Token",create_ticker_converter:"Create Currency Ticker Converter",enable_audit:"Enable Audit",recommended:"Recommended",audit_desc:"Log HTTP requests according to the filters specified below.",audit_record_req:"Log Request Body",audit_record_warning:"Warning!",audit_record_req_warning_1:"Sensitive data (like passwords) will be logged.",audit_record_req_warning_2:"The request body can be large. This can fill up your logs quickly.",audit_record_use:"Use this with caution!",audit_ip:"Log IP Address",audit_ip_desc:"Log the IP address of users making requests to LNbits.",audit_path_params:"Log Path Parameters",audit_query_params:"Log Query Parameters",audit_http_methods:"Include HTTP Methods",audit_http_methods_hint:"List of HTTP methods to be logged. No value means all methods will be logged.",audit_http_methods_label:"HTTP Methods to Log",audit_resp_codes_hint:"List of HTTP codes to be included (regex match). Empty lists means all. Eg: 4.*, 5.*",audit_resp_codes_label:"HTTP Response Codes to Log (regex)",audit_paths_hint:"List of paths to be included (regex match). Empty list means all.",audit_paths_label:"HTTP Paths to Log (regex)",audit_paths_exclude_hint:"List of paths to be excluded (regex match). Empty list means none.",audit_paths_exclude_label:"HTTP Paths to Exclude from Logging (regex)",exchange_providers:"Exchange Providers",admin_extensions:"Admin Extensions",admin_extensions_label:"Admin extensions",admin_extensions_hint:"Extensions only user with admin privileges can use",user_default_extensions:"User Default Extensions",user_default_extensions_label:"User extensions",user_default_extensions_hint:"Extensions that will be enabled by default for the users.",extension_builder:"Extension Builder",extension_builder_manifest_url:"Extension Builder Manifest URL",extension_builder_manifest_url_hint:"URL to a JSON manifest file with extension builder details",miscellanous:"Miscellanous",misc_disable_extensions:"Disable Extensions",misc_disable_extensions_label:"Disable all extensions",misc_disable_extensions_builder:"Enable Extensions Builder",misc_disable_extensions_builder_label:"Enable Extensions Builder for non admin users.",misc_hide_api:"Hide API",misc_hide_api_label:"Hides wallet API, extensions can choose to honor",wallets_management:"Wallets Management",funding_source_info:"Funding Source Information",funding_source:"Funding source: {wallet_class}",node_balance:"Node balance: {balance} sats",lnbits_balance:"LNbits balance: {balance} sats",funding_reserve_percent:"Funding reserve percentage: {percent} %",node_management:"Node Management",node_management_not_supported:"Node management is not supported by the active funding source",toggle_node_ui:"Node UI",toggle_public_node_ui:"Public Node UI",toggle_transactions_node_ui:"Transactions Tab (Disable on large CLN nodes)",invoice_expiry:"Invoice Expiry",routing_fee_reserve_calculations:"Routing Fee Reserve Calculations",routing_fee_reserve_calculations_desc:"LNbits sets aside a “reserve amount” for each payment to cover routing fees. The maximum routing fee passed to the funding source is whichever is higher: the minimum routing fee reserve or the routing fee reserve percentage.",millisats:"millisats",fee_reserve:"Minimum Routing Fee Reserve",fee_reserve_percent:"Routing Fee Reserve Percentage",fee_reserve_min_hint:"The minimum fee reserved per payment.
This acts as a floor - the maximum allowed routing fee will never be lower than this value regardless of payment size.",fee_reserve_percent_hint:"The percentage of the payment amount to reserve for routing fees.",payment_timeouts:"Payment Timeouts",payment_wait_time:"Payment Wait Time",seconds:"seconds",payment_wait_time_desc:"Wait time before marking an outgoing payment as pending. Default: 5s; raise for slow-settling invoices.",payment_wait_time_tooltip:"Controls how long LNbits waits for an outgoing payment attempt to confirm before marking it as pending. Higher values help when paying slow-settling invoices (e.g., HODL invoices, Boltz). The payment will be rechecked later and updated automatically or manually.",server_management:"Server Management",base_url_label:"Base URL of the server",authentication:"Authentication",auth_token_expiry_label:"Token expiry (minutes)",auth_token_expiry_hint:"Time in minutes until the token expires",auth_authentication_cache_label:"Cache time (minutes)",auth_authentication_cache_hint:"Time in minutes to cache successful authentication (0 to disable)",auth_allowed_methods_label:"Allowed authorization methods",auth_allowed_methods_hint:"Select allowed authorization methods",auth_nostr_label:"Nostr Request URL",auth_nostr_hint:"Absolute URL that the clients will use to login.",auth_google_ci_label:"Google Client ID",auth_google_ci_hint:"Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub Client ID",auth_gh_client_id_hint:"Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Keycloak Discovery URL",auth_keycloak_ci_label:"Keycloak Client ID",auth_keycloak_ci_hint:"Make sure thant the authorization callback URL is set to https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",auth_keycloak_custom_org_label:"Keycloak Custom Organization",auth_keycloak_custom_icon_label:"Keycloak Custom Icon (URL)",currency_settings:"Currency Settings",allowed_currencies:"Allowed Currencies",allowed_currencies_hint:"Set the allowed fiat currencies for the exchange features",default_account_currency:"Default Accounting Currency",default_account_currency_hint:"The default currency to use for accounting features.",min_incoming_payment_amount:"Min Incoming Payment Amount",min_incoming_payment_amount_desc:"Minimum amount allowed for generating an invoice",max_incoming_payment_amount:"Maximum Incoming Payment Amount",max_incoming_payment_amount_desc:"Maximum amount allowed when generating an invoice",max_outgoing_payment_amount:"Maximum Outgoing Payment Amount",max_outgoing_payment_amount_desc:"Maximum amount allowed when making a payment",service_fees:"Service Fees",service_fee:"Service Fee",service_fee_label:"Service Fee Charged Per Transaction",service_fee_max_label:"Maximum Service Fee Limit",fee_wallet_label:"Service Fee Wallet ID",fee_wallet_hint:"The ID of the wallet to which to send service funds",disable_fee:"Disable Service Fees for Internal Payments",ui_management:"UI Management",ui_site_title:"Site Title",ui_changing_remove_lnbits_elements:" (changing will remove LNbits elements on the homepage and footer)",ui_site_tagline:"Site Tagline",ui_elements_enable:"Enable elements on homepage/footer",ui_elements_disable:"Disable elements on homepage/footer",ui_toggle_elements_tip:"Remove homepage elements like 'runs on' etc",ui_site_description:"Site Description",ui_site_description_hint:"Use plain text, Markdown, or raw HTML",ui_default_wallet_name:"Default Wallet Name",ui_default_theme:"Default Theme",wallet_featured_button_title:"Wallet - Featured Button",wallet_featured_button_label:"Wallet Featured Button Label",wallet_featured_button_label_hint:"Show featured button on the wallet homepage",wallet_featured_button_url:"Featured Button URL",wallet_featured_button_url_hint:"On click the button will open this URL. Leave empty to hide the button.",wallet_featured_button_icon:"Featured Button Icon",wallet_featured_button_icon_hint:'Icon shown on the featured button (Quasar icon name e.g. "bolt")',lnbits_wallet:"LNbits wallet",denomination:"Denomination",denomination_hint:"The name for the FakeWallet token",denomination_error:"Denomination must be 3 characters, or `sats`",ui_qr_code_logo:"QR Code/Favicon Logo",ui_qr_code_logo_hint:"QR code icon and favicon logo URL",ui_apple_touch_icon:"Apple Touch Icon",ui_apple_touch_icon_hint:"Apple touch icon URL",ui_custom_image:"Custom Image",ui_custom_image_label:"URL to custom image",ui_custom_image_hint:"This image is shown on the LNbits homepage and login screen.",ui_custom_badge_title:"Custom Badge Settings",ui_custom_badge_desc:"Show a custom badge in the header of LNbits",ui_custom_badge:"Custom Badge Text",ui_custom_badge_label:"Custom Badge 'USE WITH CAUTION'",ui_custom_badge_color_label:"Custom Badge Color",themes:"Themes",themes_hint:"Choose themes available for users",custom_logo:"Custom Logo",custom_logo_hint:"URL to logo image",ad_space_section_title:"Advertisement Space",ad_space_section_desc:"Configure the advertisement space on the wallet sidebar.",ad_space_title:"Advertisement Space Title",ad_space_title_hint:"Title shown above the advertisement space",ad_slots:"Advertisement Slots",ad_slots_hint:"Advertisement image filepaths in CSV format, extensions can choose to honor. Format: url;img_light_url;img_dark_url, url..",ads_enabled:"Enable Advertisement",ads_disabled:"Disabled Advertisement",user_management:"User Management",admin_users:"Admin Users",admin_users_hint:"Users with admin privileges",admin_users_label:"User ID",allowed_users:"Allowed Users",allowed_users_hint:"Only these users can use LNbits",allowed_users_hint_feature:"Only these users can use {feature}",allowed_users_label:"User ID",allow_creation_user:"Allow creation of new users",allow_creation_user_desc:"Allow creation of new users on the index page",require_user_activation:"Require user activation",require_user_activation_desc:"New users will be activated only after they pass one of the confirmation methods. Admins can activate users manually from the admin panel.",reusable_activation_code:"Reusable activation code",reusable_activation_code_label:"Reusable activation code",reusable_activation_code_hint:"This activation code can be used multiple times by different users.",one_time_activation_code:"One-time activation codes",one_time_activation_code_label:"Add activation code",one_time_activation_code_hint:"List of one-time activation codes. Each code can be used only once, then will be reomved from the list.",invitation_code:"Invitation Code",invitation_code_hint:"The invitation code that you have received.",email:"Email",email_confirmation_hint:"Email address to send the confirmation code to.",nostr_identifier:"Nostr Identifier",nostr_identifier_hint:"Nostr nip5 identifier or to send the confirmation code to.",new_user_not_allowed:"Registration is disabled.",start_user_impersonation:"Impersonate this user",stop_user_impersonation:"Stop User Impersonation",components:"Components",long_running_endpoints:"Top 5 Long Running Endpoints",http_request_methods:"HTTP Request Methods",http_response_codes:"HTTP Response Codes",request_details:"Request Details",http_request_details:"HTTP Request Details",payment_details:"Payment Details",payment_details_desc:"Detailed information about the payment",payments:"Payments",payment_show_internal:"Show Internal Payments",payment_chart_flow:"Monthly Payment Flow",payment_chart_status:"Payment Status",payment_chart_tx_per_wallet:"Transactions per Wallet (balance/count)",payment_details_back:"Back to Payments",payment_chart_tags:"Payments by Tags",payments_balance_in_out:"Balance In/Out",payments_count_in_out:"Count In/Out",payments_status_chart:"Status Chart",payments_tag_chart:"Tag Chart",payments_balance_chart:"Balance Chart",payments_wallets_chart:"Wallets Chart",payments_balance_in_out_chart:"Balance In/Out Chart",payments_count_in_out_chart:"Count In/Out Chart",reset_wallet_keys:"Reset Keys",reset_wallet_keys_desc:"Reset the API keys for this wallet. This will invalidate the current keys and generate new ones.",view_list:"View wallets as list",view_column:"View wallets as rows",filter_payments:"Filter payments",filter_labels:"Filter labels",filter_date:"Filter by date",websocket_example:"Websocket example",client_id:"Client ID",secret_key:"Secret Key",signing_secret:"Signing Secret",signing_secret_hint:"Signing secret for the webhook. Messages will be signed with this secret.",webhook_id:"Webhook ID",webhook_id_hint:"PayPal webhook ID used to verify incoming events.",webhook_paypal_description:"On the PayPal side configure a webhook pointing to your LNbits server.",callback_success_url:"Callback Success URL",callback_success_url_hint:"The user will be redirected to this URL after the payment is successful",connected:"Connected",not_connected:"Not Connected",free:"Free",paid:"Paid",funding_source_retries:"Max Retries",funding_source_retries_desc:"Maximum number of retries for funding sources, before it falls back to VoidWallet.",add_label:"Add Label",label:"Label",labels:"Labels",label_filter:"Label Filter",no_labels_defined:"No labels defined yet",manage_labels:"Manage Labels",update_label:"Update Label",delete_label:"Delete Label",add_remove_labels:"Add or Remove Labels",payment_labels_updated:"Payment labels updated",color:"Color",sort:"Sort",sort_by:"Sort by"},window.localisation.es={confirm:"Sí",server:"Servidor",theme:"Tema",site_customisation:"Personalización del sitio",funding:"Financiación",users:"Usuarios",audit:"Auditoría",apps:"Aplicaciones",channels:"Canales",transactions:"Transacciones",dashboard:"Tablero de instrumentos",node:"Nodo",export_users:"Exportar Usuarios",no_users:"No se encontraron usuarios",total_capacity:"Capacidad Total",avg_channel_size:"Tamaño Medio del Canal",biggest_channel_size:"Tamaño del Canal Más Grande",smallest_channel_size:"Tamaño de canal más pequeño",number_of_channels:"Número de canales",active_channels:"Canales activos",connect_peer:"Conectar Par",connect:"Conectar",open_channel:"Canal Abierto",open:"Abrir",close_channel:"Cerrar canal",close:"Cerrar",restart:"Reiniciar el servidor",save:"Guardar",save_tooltip:"Guardar cambios",credit_debit:"Crédito / Débito",credit_hint:"Presione Enter para cargar la cuenta",credit_label:"Cargar {denomination}",credit_ok:"Éxito al acreditar/debitar fondos virtuales ({amount} sats). Los pagos dependen de los fondos reales en la fuente de financiación.",restart_tooltip:"Reinicie el servidor para aplicar los cambios",add_funds_tooltip:"Agregue fondos a una billetera.",reset_defaults:"Restablecer",reset_defaults_tooltip:"Borrar todas las configuraciones y restablecer a los valores predeterminados.",download_backup:"Descargar copia de seguridad de la base de datos",name_your_wallet:"Nombre de su billetera {name}",paste_invoice_label:"Pegue la factura aquí",lnbits_description:"Fácil de instalar y liviano, LNbits puede ejecutarse en cualquier fuente de financiación de la red Lightning y hasta LNbits mismo! Puede ejecutar LNbits para usted mismo o ofrecer una solución competente a otros. Cada billetera tiene su propia clave API y no hay límite para la cantidad de billeteras que puede crear. La capacidad de particionar fondos hace de LNbits una herramienta útil para la administración de fondos y como herramienta de desarrollo. Las extensiones agregan funcionalidad adicional a LNbits, por lo que puede experimentar con una variedad de tecnologías de vanguardia en la red Lightning. Lo hemos hecho lo más simple posible para desarrollar extensiones y, como un proyecto gratuito y de código abierto, animamos a las personas a que se desarrollen a sí mismas y envíen sus propios contribuciones.",export_to_phone:"Exportar a teléfono con código QR",export_to_phone_desc:"Este código QR contiene su URL de billetera con acceso completo. Puede escanearlo desde su teléfono para abrir su billetera allí.",wallet:"Billetera:",wallets:"Billeteras",add_wallet:"Agregar nueva billetera",delete_wallet:"Eliminar billetera",delete_wallet_desc:"Esta billetera completa se eliminará, los fondos son IRREVERSIBLES.",rename_wallet:"Cambiar el nombre de la billetera",update_name:"Actualizar nombre",fiat_tracking:"Seguimiento Fiat",currency:"Moneda",update_currency:"Actualizar moneda",press_to_claim:"Presione para reclamar Bitcoin",donate:"Donar",view_github:"Ver en GitHub",voidwallet_active:"¡VoidWallet está activo! Pagos desactivados",use_with_caution:"USAR CON CUIDADO - {name} Wallet aún está en BETA",service_fee:"Tarifa de servicio: {amount} % por transacción",service_fee_max:"Tarifa de servicio: {amount} % por transacción (máx {max} sats)",service_fee_tooltip:"Comisión de servicio cobrada por el administrador del servidor LNbits por cada transacción saliente",toggle_darkmode:"Cambiar modo oscuro",payment_reactions:"Reacciones de Pago",view_swagger_docs:"Ver documentación de API de LNbits Swagger",api_docs:"Documentación de API",api_keys_api_docs:"URL del nodo, claves de API y documentación de API",lnbits_version:"Versión de LNbits",runs_on:"Corre en",paste:"Pegar",paste_from_clipboard:"Pegar desde el portapapeles",paste_request:"Pegar solicitud",create_invoice:"Crear factura",camera_tooltip:"Utilice la cámara para escanear una factura / código QR",export_csv:"Exportar a CSV",chart_tooltip:"Mostrar gráfico",pending:"Pendiente",copy_invoice:"Copiar factura",withdraw_from:"Retirar de",cancel:"Cancelar",scan:"Escanear",read:"Leer",pay:"Pagar",memo:"Memo",date:"Fecha",payment_processing:"Procesando pago ...",not_enough_funds:"¡No hay suficientes fondos!",search_by_tag_memo_amount:"Buscar por etiqueta, memo, cantidad",invoice_waiting:"Factura esperando pago",payment_received:"Pago recibido",payment_sent:"Pago enviado",receive:"recibir",send:"enviar",outgoing_payment_pending:"Pago saliente pendiente",drain_funds:"Drenar fondos",drain_funds_desc:"Este es un código QR LNURL-withdraw para drenar todos los fondos de esta billetera. No lo comparta con nadie. Es compatible con balanceCheck y balanceNotify, por lo que su billetera puede continuar drenando los fondos de aquí después del primer drenaje.",i_understand:"Lo entiendo",copy_wallet_url:"Copiar URL de billetera",disclaimer_dialog_title:"¡Importante!",disclaimer_dialog:"La funcionalidad de inicio de sesión se lanzará en una actualización futura, por ahora, asegúrese de guardar esta página como marcador para acceder a su billetera en el futuro. Este servicio está en BETA y no asumimos ninguna responsabilidad por personas que pierdan el acceso a sus fondos.",no_transactions:"No hay transacciones todavía",manage:"Administrar",exchanges:"Intercambios",extensions:"Extensiones",no_extensions:"No tienes extensiones instaladas :(",created:"Creado",search_extensions:"Extensiones de búsqueda",extension_sources:"Fuentes de extensión",ext_sources_hint:"Repositorios desde donde se pueden descargar las extensiones",ext_sources_label:"URL de origen (utilice solo la fuente oficial de la extensión LNbits y fuentes en las que pueda confiar)",warning:"Advertencia",repository:"Repositorio",confirm_continue:"¿Está seguro de que desea continuar?",manage_extension_details:"Instalar/desinstalar extensión",install:"Instalar",uninstall:"Desinstalar",drop_db:"Eliminar datos",enable:"Habilitar",pay_to_enable:"Pagar para habilitar",enable_extension_details:"Habilitar extensión para el usuario actual",disable:"Deshabilitar",delete:"Eliminar",installed:"Instalado",activated:"Activado",deactivated:"Desactivado",release_notes:"Notas de la versión",activate_extension_details:"Hacer que la extensión esté disponible/no disponible para los usuarios",featured:"Destacado",all:"Todos",only_admins_can_install:"(Solo las cuentas de administrador pueden instalar extensiones)",admin_only:"Solo administradores",new_version:"Nueva Versión",extension_depends_on:"Depende de:",extension_rating_soon:"Calificaciones próximamente",extension_installed_version:"Versión instalada",extension_uninstall_warning:"Está a punto de eliminar la extensión para todos los usuarios.",uninstall_confirm:"Sí, desinstalar",extension_db_drop_info:"Todos los datos para la extensión se eliminarán permanentemente. ¡No hay manera de deshacer esta operación!",extension_db_drop_warning:"Está a punto de eliminar todos los datos para la extensión. Por favor, escriba el nombre de la extensión para continuar:",extension_required_lnbits_version:"Esta versión requiere al menos una versión de LNbits",min_version:"Mínimo (incluido)",max_version:"Máximo (excluido)",payment_hash:"Hash de pago",fee:"Cuota",amount:"Cantidad",amount_sats:"Cantidad (sats)",tag:"Etiqueta",unit:"Unidad",description:"Descripción",expiry:"Expiración",webhook:"Webhook",payment_proof:"Prueba de pago",update:"Actualizar",update_available:"¡Actualización {version} disponible!",latest_update:"Usted está en la última versión {version}.",notifications:"Notificaciones",no_notifications:"No hay notificaciones",notifications_disabled:"Las notificaciones de estado de LNbits están desactivadas.",enable_notifications:"Activar notificaciones",enable_notifications_desc:"Si está activado, buscará las últimas actualizaciones del estado de LNbits, como incidentes de seguridad y actualizaciones.",enable_watchdog_desc:"Si está activado, cambiará automáticamente su fuente de financiamiento a VoidWallet si su saldo es inferior al saldo de LNbits. Tendrá que activarlo manualmente después de una actualización.",watchdog_interval:"Intervalo de vigilancia",watchdog_interval_desc:"Con qué frecuencia la tarea de fondo debe verificar la señal de killswitch en el delta del watchdog [node_balance - lnbits_balance] (en minutos).",watchdog_delta:"Vigilante Delta",watchdog_delta_desc:"Límite antes de que el interruptor de apagado cambie la fuente de financiamiento a VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fuente de notificación",notification_source_label:"URL de origen (solo use la fuente oficial de estado de LNbits y fuentes en las que confíe)",more:"más",less:"menos",releases:"Lanzamientos",watchdog:"Perro guardián",server_logs:"Registros del Servidor",ip_blocker:"Bloqueador de IP",security:"Seguridad",security_tools:"Herramientas de seguridad",block_access_hint:"Bloquear acceso por IP",allow_access_hint:"Permitir acceso por IP (anulará las IPs bloqueadas)",enter_ip:"Ingrese la IP y presione enter",rate_limiter:"Limitador de tasa",wallet_limiter:"Limitador de Cartera",wallet_limit_max_withdraw_per_day:"Límite diario de retiro de la cartera en sats (0 para deshabilitar)",wallet_max_ballance:"Saldo máximo de la billetera en sats (0 para desactivar)",wallet_limit_secs_between_trans:"Mín. segs entre transacciones por cartera (0 para desactivar)",number_of_requests:"Número de solicitudes",time_unit:"Unidad de tiempo",minute:"minuto",second:"segundo",hour:"hora",disable_server_log:"Desactivar registro del servidor",enable_server_log:"Activar registro del servidor",coming_soon:"Función próximamente disponible",session_has_expired:"Tu sesión ha expirado. Por favor, inicia sesión de nuevo.",instant_access_question:"¿Quieres acceso instantáneo?",login_with_user_id:"Iniciar sesión con ID de usuario",or:"o",create_new_wallet:"Crear Nueva Cartera",login_to_account:"Inicie sesión en su cuenta",create_account:"Crear cuenta",account_settings:"Configuración de la cuenta",signin_with_nostr:"Continuar con Nostr",signin_with_google:"Inicia sesión con Google",signin_with_github:"Inicia sesión con GitHub",signin_with_keycloak:"Iniciar sesión con Keycloak",username_or_email:"Nombre de usuario o correo electrónico",password:"Contraseña",password_config:"Configuración de Contraseña",password_repeat:"Repetición de contraseña",change_password:"Cambiar contraseña",update_credentials:"Actualizar credenciales",update_pubkey:"Actualizar clave pública",set_password:"Establecer contraseña",invalid_password:"La contraseña debe tener al menos 8 caracteres.",login:"Iniciar sesión",register:"Registrarse",username:"Nombre de usuario",pubkey:"Clave pública",user_id:"Identificación de usuario",email:"Correo electrónico",first_name:"Nombre de pila",last_name:"Apellido",picture:"Imagen",verify_email:"Verifique el correo electrónico con",account:"Cuenta",update_account:"Actualizar cuenta",invalid_username:"Nombre de usuario inválido",auth_provider:"Proveedor de Autenticación",my_account:"Mi cuenta",back:"Atrás",logout:"Cerrar sesión",look_and_feel:"Apariencia",toggle_gradient:"Alternar degradado",gradient_background:"Fondo de gradiente",language:"Idioma",color_scheme:"Esquema de colores",admin_settings:"Configuración del administrador",extension_cost:"Esta versión requiere un pago mínimo de {cost} sats.",extension_paid_sats:"Ya has pagado {paid_sats} sats.",release_details_error:"No se pueden obtener los detalles de la versión.",pay_from_wallet:"Pagar desde la billetera",wallet_required:"Billetera *",show_qr:"Mostrar QR",retry_install:"Reintentar Instalación",new_payment:"Realizar nuevo pago",update_payment:"Actualizar Pago",already_paid_question:"¿Ya has pagado?",sell:"Vender",sell_require:"Solicitar pago para habilitar la extensión",sell_info:"La extensión {name} requiere un pago mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar billeteras vacías",recheck:"Revisar de nuevo",contributors:"Colaboradores",license:"Licencia",reset_key:"Restablecer clave",reset_password:"Restablecer contraseña",border_choices:"Opciones de Borde",select_all:"Seleccionar todo",nfc_supported:"Compatible con NFC",nfc_not_supported:"NFC no compatible",expire_date:"Fecha de vencimiento:",hash:"Hash:",welcome_lnbits:"Bienvenido a LNbits",setup_su_account:"Configura la cuenta de Superusuario a continuación.",create_ticker_converter:"Crear Convertidor de Ticker de Moneda",enable_audit:"Habilitar auditoría",recommended:"Recomendado",audit_desc:"Registrar solicitudes HTTP de acuerdo con los filtros especificados",audit_record_req:"Registrar cuerpo de solicitud",audit_record_warning:"Advertencia:",audit_record_req_warning_1:"los datos confidenciales (como las contraseñas) serán registrados.",audit_record_req_warning_2:"el cuerpo de la solicitud puede tener un tamaño grande.",audit_record_use:"Úsalo con precaución.",audit_ip:"Registrar Dirección IP",audit_ip_desc:"Registra la dirección IP del cliente",audit_path_params:"Registrar parámetros de ruta",audit_query_params:"Registrar parámetros de consulta",audit_http_methods:"Incluye métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a incluir. Las listas vacías significan todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Respuesta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a incluir (coincidencia regex). Listas vacías significan todos. Ej: 4.*, 5.*",audit_resp_codes_label:"Código de respuesta HTTP (regex)",audit_paths:"Incluir rutas",audit_paths_hint:"Lista de rutas a incluir (coincidencia de expresión regular). Lista vacía significa todas.",audit_paths_label:"Ruta HTTP (regex)",audit_paths_exclude:"Excluir rutas",audit_paths_exclude_hint:"Lista de rutas a excluir (coincidencia de expresiones regulares). Lista vacía significa ninguna.",audit_paths_exclude_label:"Ruta HTTP (regex)",exchange_providers:"Proveedores de intercambio",admin_extensions:"Extensiones de Administración",admin_extensions_label:"Extensiones de administración",admin_extensions_hint:"Solo los usuarios con privilegios de administrador pueden usar extensiones.",user_default_extensions:"Extensiones predeterminadas del usuario",user_default_extensions_label:"Extensiones de usuario",user_default_extensions_hint:"Extensiones que estarán habilitadas de forma predeterminada para los usuarios.",miscellanous:"Misceláneo",misc_disable_extensions:"Desactivar extensiones",misc_disable_extensions_label:"Desactivar todas las extensiones",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta la API de la billetera, las extensiones pueden optar por respetar",wallets_management:"Gestión de Carteras",funding_source_info:"Información sobre la Fuente de Financiamiento",funding_source:"Fuente de financiamiento: {wallet_class}",node_balance:"Balance de Nodo: {balance} sats",lnbits_balance:"Saldo de LNbits: {balance} sats",funding_reserve_percent:"Reserve Porcentaje: {percent} %",node_management:"Gestión de nodos",node_management_not_supported:"La gestión de nodos no es compatible con la fuente de financiación activa",toggle_node_ui:"Interfaz de usuario de nodo",toggle_public_node_ui:"Interfaz Pública de Nodo",toggle_transactions_node_ui:"Pestaña de transacciones (desactivar en nodos CLN grandes)",invoice_expiry:"Vencimiento de la Factura",invoice_expiry_label:"Expiración de la factura (segundos)",fee_reserve:"Reserva de tarifa",fee_reserve_msats:"Cuota de reserva en msats",fee_reserve_percent:"Tasa de reserva en porcentaje",server_management:"Gestión del Servidor",base_url:"URL base",base_url_label:"URL base estática para el servidor",authentication:"Autenticación",auth_token_expiry_label:"Minutos de vencimiento del token",auth_token_expiry_hint:"Tiempo en minutos hasta que el token expire",auth_allowed_methods_label:"Métodos de autorización permitidos",auth_allowed_methods_hint:"Seleccione métodos de autorización",auth_nostr_label:"URL de solicitud Nostr",auth_nostr_hint:"URL absoluto que los clientes utilizarán para iniciar sesión.",auth_google_ci_label:"ID de cliente de Google",auth_google_ci_hint:"Asegúrate de que los URIs de redirección autorizados contengan https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secreto del Cliente de Google",auth_gh_client_id_label:"ID de cliente de GitHub",auth_gh_client_id_hint:"Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secreto del cliente de GitHub",auth_keycloak_label:"URL de descubrimiento de Keycloak",auth_keycloak_ci_label:"ID de cliente de Keycloak",auth_keycloak_ci_hint:"Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secreto del Cliente de Keycloak",currency_settings:"Configuración de moneda",allowed_currencies:"Monedas permitidas",allowed_currencies_hint:"Limite el número de monedas fiduciarias disponibles",default_account_currency:"Moneda predeterminada de la cuenta",default_account_currency_hint:"Moneda predeterminada para contabilidad",service_fee_label:"Tarifa de servicio (%)",service_fee_hint:"Tarifa cobrada por tx (%)",service_fee_max_label:"Tarifa de servicio máx (sats)",service_fee_max_hint:"Tarifa máxima por servicio a cobrar en (sats)",fee_wallet:"Billetera de Tarifas",fee_wallet_label:"Billetera de tarifas (ID de billetera)",fee_wallet_hint:"ID de la billetera a la que enviar fondos",disable_fee:"Desactivar tarifa",disable_fee_internal:"Desactivar tarifa de servicio para pagos internos",disable_fee_internal_desc:"Desactivar tarifa de servicio para pagos internos Lightning",ui_management:"Gestión de la interfaz de usuario",ui_site_title:"Título del Sitio",ui_site_tagline:"Lema del sitio",ui_elements_enable:"Habilitar elementos en la página de inicio",ui_elements_disable:"Desactivar elementos en la página de inicio",ui_toggle_elements_tip:"Eliminar elementos de la página de inicio como 'funciona en', etc.",ui_site_description:"Descripción del sitio",ui_site_description_hint:"Usa texto sin formato, Markdown o HTML sin procesar",ui_default_wallet_name:"Nombre predeterminado de la billetera",lnbits_wallet:"Cartera LNbits",denomination:"Denominación",denomination_hint:"El nombre para el token FakeWallet",ui_qr_code_logo:"Logo de código QR",ui_qr_code_logo_hint:"URL a la imagen del logo en el código QR",ui_custom_badge:"Insignia personalizada",ui_custom_badge_label:"Insignia personalizada 'USAR CON PRECAUCIÓN - La billetera LNbits aún está en BETA'",ui_custom_badge_color_label:"Color personalizado de insignia",themes:"Temas",themes_hint:"Elige los temas disponibles para los usuarios",custom_logo:"Logotipo personalizado",custom_logo_hint:"URL a la imagen del logo",ad_space_title:"Título del Espacio Publicitario",ad_space_title_label:"Respaldado por",ad_slots:"Espacios publicitarios",ad_slots_hint:"URL de anuncio y rutas de archivo de imagen en formato CSV, las extensiones pueden optar por respetar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anuncios habilitados",ads_disabled:"Anuncios desactivados",user_management:"Gestión de Usuarios",admin_users:"Usuarios Administradores",admin_users_hint:"Usuarios con privilegios de administrador",admin_users_label:"ID de usuario",allowed_users:"Usuarios Permitidos",allowed_users_hint:"Solo estos usuarios pueden usar LNbits",allowed_users_label:"ID de usuario",allow_creation_user:"Permitir la creación de nuevos usuarios",allow_creation_user_desc:"Permitir la creación de nuevos usuarios en la página de índice",components:"Componentes",long_running_endpoints:"Principales 5 puntos de conexión de larga duración",http_request_methods:"Métodos de solicitud HTTP",http_response_codes:"Códigos de Respuesta HTTP",request_details:"Detalles de la solicitud",http_request_details:"Detalles de la Solicitud HTTP"},window.localisation.fr={confirm:"Oui",server:"Serveur",theme:"Thème",site_customisation:"Personnalisation du site",funding:"Financement",users:"Utilisateurs",audit:"Audit",apps:"Applications",channels:"Canaux",transactions:"Transactions",dashboard:"Tableau de bord",node:"Noeud",export_users:"Exporter les utilisateurs",no_users:"Aucun utilisateur trouvé",total_capacity:"Capacité totale",avg_channel_size:"Taille moyenne du canal",biggest_channel_size:"Taille de canal maximale",smallest_channel_size:"Taille de canal la plus petite",number_of_channels:"Nombre de canaux",active_channels:"Canaux actifs",connect_peer:"Connecter un pair",connect:"Connecter",open_channel:"Ouvrir le canal",open:"Ouvrir",close_channel:"Fermer le canal",close:"Fermer",restart:"Redémarrer le serveur",save:"Enregistrer",save_tooltip:"Enregistrer vos modifications",credit_debit:"Crédit / Débit",credit_hint:"Appuyez sur Entrée pour créditer le compte",credit_label:"{denomination} à créditer",credit_ok:"Succès du crédit/débit des fonds virtuels ({amount} sats). Les paiements dépendent des fonds réels sur la source de financement.",restart_tooltip:"Redémarrez le serveur pour que les changements prennent effet",add_funds_tooltip:"Ajouter des fonds à un portefeuille.",reset_defaults:"Réinitialiser aux valeurs par défaut",reset_defaults_tooltip:"Supprimer tous les paramètres et les réinitialiser aux valeurs par défaut.",download_backup:"Télécharger la sauvegarde de la base de données",name_your_wallet:"Nommez votre portefeuille {name}",paste_invoice_label:"Coller une facture, une demande de paiement ou un code lnurl *",lnbits_description:"Facile à installer et léger, LNbits peut fonctionner sur n'importe quelle source de financement du réseau Lightning et même LNbits lui-même! Vous pouvez exécuter LNbits pour vous-même ou offrir facilement une solution de gardien pour les autres. Chaque portefeuille a ses propres clés API et il n'y a pas de limite au nombre de portefeuilles que vous pouvez créer. La capacité de partitionner les fonds rend LNbits un outil utile pour la gestion de l'argent et comme outil de développement. Les extensions ajoutent une fonctionnalité supplémentaire à LNbits afin que vous puissiez expérimenter une gamme de technologies de pointe sur le réseau Lightning. Nous avons rendu le développement d'extensions aussi simple que possible et, en tant que projet gratuit et open source, nous encourageons les gens à développer et à soumettre les leurs.",export_to_phone:"Exporter vers le téléphone avec un code QR",export_to_phone_desc:"Ce code QR contient l'URL de votre portefeuille avec un accès complet. Vous pouvez le scanner depuis votre téléphone pour ouvrir votre portefeuille depuis là-bas.",wallet:"Portefeuille :",wallets:"Portefeuilles",add_wallet:"Ajouter un nouveau portefeuille",delete_wallet:"Supprimer le portefeuille",delete_wallet_desc:"Ce portefeuille entier sera supprimé et les fonds seront IRRECUPERABLES.",rename_wallet:"Renommer le portefeuille",update_name:"Mettre à jour le nom",fiat_tracking:"Suivi Fiat",currency:"Devise",update_currency:"Mettre à jour la devise",press_to_claim:"Appuyez pour demander du Bitcoin",donate:"Donner",view_github:"Voir sur GitHub",voidwallet_active:"VoidWallet est actif! Paiements désactivés",use_with_caution:"UTILISER AVEC PRUDENCE - Le portefeuille {name} est toujours en version BETA",service_fee:"Frais de service : {amount} % par transaction",service_fee_max:"Frais de service : {amount} % par transaction (max {max} sats)",service_fee_tooltip:"Frais de service facturés par l'administrateur du serveur LNbits pour chaque transaction sortante",toggle_darkmode:"Basculer le mode sombre",payment_reactions:"Réactions de paiement",view_swagger_docs:"Voir les documentation de l'API Swagger de LNbits",api_docs:"Documentation de l'API",api_keys_api_docs:"URL du nœud, clés API et documentation API",lnbits_version:"Version de LNbits",runs_on:"Fonctionne sur",paste:"Coller",paste_from_clipboard:"Coller depuis le presse-papiers",paste_request:"Coller la requête",create_invoice:"Créer une facture",camera_tooltip:"Utiliser la caméra pour scanner une facture / un code QR",export_csv:"Exporter vers CSV",chart_tooltip:"Afficher le graphique",pending:"En attente",copy_invoice:"Copier la facture",withdraw_from:"Retirer de",cancel:"Annuler",scan:"Scanner",read:"Lire",pay:"Payer",memo:"Mémo",date:"Date",payment_processing:"Traitement du paiement...",not_enough_funds:"Fonds insuffisants !",search_by_tag_memo_amount:"Rechercher par tag, mémo, montant",invoice_waiting:"Facture en attente de paiement",payment_received:"Paiement reçu",payment_sent:"Paiement envoyé",receive:"recevoir",send:"envoyer",outgoing_payment_pending:"Paiement sortant en attente",drain_funds:"Vider les fonds",drain_funds_desc:"Il s'agit d'un code QR LNURL-withdraw pour tout aspirer de ce portefeuille. Ne le partagez avec personne. Il est compatible avec balanceCheck et balanceNotify, de sorte que votre portefeuille peut continuer à retirer les fonds continuellement à partir d'ici après le premier retrait.",i_understand:"J'ai compris",copy_wallet_url:"Copier l'URL du portefeuille",disclaimer_dialog_title:"Important !",disclaimer_dialog:"La fonctionnalité de connexion sera publiée dans une future mise à jour, pour l'instant, assurez-vous de mettre cette page en favori pour accéder à votre portefeuille ultérieurement ! Ce service est en BETA, et nous ne sommes pas responsables des personnes qui perdent l'accès à leurs fonds.",no_transactions:"Aucune transaction effectuée pour le moment",manage:"Gérer",exchanges:"Échanges",extensions:"Extensions",no_extensions:"Vous n'avez installé aucune extension :(",created:"Créé",search_extensions:"Rechercher des extensions",extension_sources:"Sources d'extension",ext_sources_hint:"Dépôts à partir desquels les extensions peuvent être téléchargées",ext_sources_label:"URL source (utilisez uniquement la source officielle de l'extension LNbits et des sources fiables)",warning:"Avertissement",repository:"Référentiel",confirm_continue:"Êtes-vous sûr de vouloir continuer ?",manage_extension_details:"Installer/désinstaller l'extension",install:"Installer",uninstall:"Désinstaller",drop_db:"Supprimer les données",enable:"Activer",pay_to_enable:"Payer pour activer",enable_extension_details:"Activer l'extension pour l'utilisateur actuel",disable:"Désactiver",delete:"Supprimer",installed:"Installé",activated:"Activé",deactivated:"Désactivé",release_notes:"Notes de version",activate_extension_details:"Rendre l'extension disponible/indisponible pour les utilisateurs",featured:"Mis en avant",all:"Tout",only_admins_can_install:"Seuls les comptes administrateurs peuvent installer des extensions",admin_only:"Réservé aux administrateurs",new_version:"Nouvelle version",extension_depends_on:"Dépend de :",extension_rating_soon:"Notes des utilisateurs à venir bientôt",extension_installed_version:"Version installée",extension_uninstall_warning:"Vous êtes sur le point de supprimer l'extension pour tous les utilisateurs.",uninstall_confirm:"Oui, Désinstaller",extension_db_drop_info:"Toutes les données pour l'extension seront supprimées de manière permanente. Il n'est pas possible d'annuler cette opération !",extension_db_drop_warning:"Vous êtes sur le point de supprimer toutes les données de l'extension. Veuillez taper le nom de l'extension pour continuer :",extension_required_lnbits_version:"Cette version nécessite au moins LNbits version",min_version:"Minimum (inclus)",max_version:"Maximum (exclu)",payment_hash:"Hash de paiement",fee:"Frais",amount:"Montant",amount_sats:"Montant (sats)",tag:"Étiqueter",unit:"Unité",description:"Description",expiry:"Expiration",webhook:"Webhook",payment_proof:"Preuve de paiement",update:"Mettre à jour",update_available:"Mise à jour {version} disponible !",latest_update:"Vous êtes sur la dernière version {version}.",notifications:"Notifications",no_notifications:"Aucune notification",notifications_disabled:"Les notifications de statut LNbits sont désactivées.",enable_notifications:"Activer les notifications",enable_notifications_desc:"Si activé, il récupérera les dernières mises à jour du statut LNbits, telles que les incidents de sécurité et les mises à jour.",enable_watchdog:"Activer le Watchdog",enable_watchdog_desc:"Si elle est activée, elle changera automatiquement votre source de financement en VoidWallet si votre solde est inférieur au solde LNbits. Vous devrez activer manuellement après une mise à jour.",watchdog_interval:"Intervalle du gardien",watchdog_interval_desc:"À quelle fréquence la tâche en arrière-plan doit-elle vérifier la présence d'un signal d'arrêt d'urgence dans le delta du gardien [node_balance - lnbits_balance] (en minutes).",watchdog_delta:"Chien de garde Delta",watchdog_delta_desc:"Limite avant que l'interrupteur d'arrêt ne change la source de financement pour VoidWallet [lnbits_balance - node_balance > delta]",status:"Statut",notification_source:"Source de notification",notification_source_label:"URL source (utilisez uniquement la source officielle de statut LNbits et des sources de confiance)",more:"plus",less:"moins",releases:"Versions",watchdog:"Chien de garde",server_logs:"Journaux du serveur",ip_blocker:"Bloqueur d'IP",security:"Sécurité",security_tools:"Outils de sécurité",block_access_hint:"Bloquer l'accès par IP",allow_access_hint:"Autoriser l'accès par IP (cela passera outre les IP bloquées)",enter_ip:"Entrez l'adresse IP et appuyez sur Entrée",rate_limiter:"Limiteur de débit",wallet_limiter:"Limiteur de portefeuille",wallet_limit_max_withdraw_per_day:"Retrait quotidien maximum du portefeuille en sats (0 pour désactiver)",wallet_max_ballance:"Solde maximum du portefeuille en sats (0 pour désactiver)",wallet_limit_secs_between_trans:"Minutes et secondes entre les transactions par portefeuille (0 pour désactiver)",number_of_requests:"Nombre de requêtes",time_unit:"Unité de temps",minute:"minute",second:"seconde",hour:"heure",disable_server_log:"Désactiver le journal du serveur",enable_server_log:"Activer le journal du serveur",coming_soon:"Fonctionnalité à venir bientôt",session_has_expired:"Votre session a expiré. Veuillez vous reconnecter.",instant_access_question:"Voulez-vous un accès instantané ?",login_with_user_id:"Connexion avec l'identifiant utilisateur",or:"ou",create_new_wallet:"Créer un nouveau portefeuille",login_to_account:"Connectez-vous à votre compte",create_account:"Créer un compte",account_settings:"Paramètres du compte",signin_with_nostr:"Continuer avec Nostr",signin_with_google:"Connectez-vous avec Google",signin_with_github:"Connectez-vous avec GitHub",signin_with_keycloak:"Connectez-vous avec Keycloak",username_or_email:"Nom d'utilisateur ou e-mail",password:"Mot de passe",password_config:"Configuration du mot de passe",password_repeat:"Répétition du mot de passe",change_password:"Changer le mot de passe",update_credentials:"Mettre à jour les informations d'identification",update_pubkey:"Mettre à jour la clé publique",set_password:"Définir le mot de passe",invalid_password:"Le mot de passe doit comporter au moins 8 caractères",login:"Connexion",register:"Inscrire",username:"Nom d'utilisateur",pubkey:"Clé publique",user_id:"Identifiant utilisateur",email:"E-mail",first_name:"Prénom",last_name:"Nom de famille",picture:"Image",verify_email:"Vérifiez l'e-mail avec",account:"Compte",update_account:"Mettre à jour le compte",invalid_username:"Nom d'utilisateur invalide",auth_provider:"Fournisseur d'authentification",my_account:"Mon compte",back:"Retour",logout:"Déconnexion",look_and_feel:"Apparence",toggle_gradient:"Basculer le dégradé",gradient_background:"Fond en dégradé",language:"Langue",color_scheme:"Schéma de couleurs",admin_settings:"Paramètres administrateur",extension_cost:"Cette version nécessite un paiement minimum de {cost} sats.",extension_paid_sats:"Vous avez déjà payé {paid_sats} sats.",release_details_error:"Impossible d'obtenir les détails de la version.",pay_from_wallet:"Payer depuis le portefeuille",wallet_required:"Portefeuille *",show_qr:"Afficher le QR",retry_install:"Réessayer l'installation",new_payment:"Effectuer un nouveau paiement",update_payment:"Mettre à jour le paiement",already_paid_question:"Avez-vous déjà payé ?",sell:"Vendre",sell_require:"Demander un paiement pour activer l'extension",sell_info:"L'extension {name} nécessite un paiement minimum de {amount} sats pour être activée.",hide_empty_wallets:"Masquer les portefeuilles vides",recheck:"Revérifier",contributors:"Contributeurs",license:"Licence",reset_key:"Réinitialiser la clé",reset_password:"Réinitialiser le mot de passe",border_choices:"Choix de bordure",select_all:"Sélectionner tout",nfc_supported:"NFC pris en charge",nfc_not_supported:"NFC non pris en charge",expire_date:"Date d'expiration :",hash:"Hash :",welcome_lnbits:"Bienvenue à LNbits",setup_su_account:"Configurez le compte Superuser ci-dessous.",create_ticker_converter:"Créer un convertisseur de code de devise",enable_audit:"Activer l'audit",recommended:"Recommandé",audit_desc:"Enregistrer les requêtes HTTP selon les filtres spécifiés",audit_record_req:"Enregistrer le corps de la demande",audit_record_warning:"Avertissement :",audit_record_req_warning_1:"les données confidentielles (comme les mots de passe) seront enregistrées.",audit_record_req_warning_2:"le corps de la requête peut être de grande taille.",audit_record_use:"Utilisez-le avec précaution.",audit_ip:"Enregistrer l'adresse IP",audit_ip_desc:"Enregistrer l'adresse IP du client",audit_path_params:"Enregistrer les paramètres de chemin",audit_query_params:"Enregistrer les paramètres de la requête",audit_http_methods:"Inclure les méthodes HTTP",audit_http_methods_hint:"Liste des méthodes HTTP à inclure. Listes vides signifie toutes.",audit_http_methods_label:"Méthodes HTTP",audit_resp_codes:"Inclure les codes de réponse HTTP",audit_resp_codes_hint:"Liste des codes HTTP à inclure (correspondance regex). Les listes vides signifient tout. Ex : 4.*, 5.*",audit_resp_codes_label:"Code de réponse HTTP (regex)",audit_paths:"Inclure des chemins",audit_paths_hint:"Liste des chemins à inclure (correspondance regex). Liste vide signifie tout.",audit_paths_label:"Chemin HTTP (regex)",audit_paths_exclude:"Exclure les chemins",audit_paths_exclude_hint:"Liste des chemins à exclure (correspondance regex). Liste vide signifie aucun.",audit_paths_exclude_label:"Chemin HTTP (regex)",exchange_providers:"Fournisseurs d'échange",admin_extensions:"Extensions d'administration",admin_extensions_label:"Extensions d'administration",admin_extensions_hint:"Seuls les utilisateurs avec des privilèges d'administrateur peuvent utiliser les extensions.",user_default_extensions:"Extensions par défaut de l'utilisateur",user_default_extensions_label:"Extensions utilisateur",user_default_extensions_hint:"Extensions qui seront activées par défaut pour les utilisateurs.",miscellanous:"Divers",misc_disable_extensions:"Désactiver les extensions",misc_disable_extensions_label:"Désactiver toutes les extensions",misc_hide_api:"Masquer l'API",misc_hide_api_label:"Masque l'API du portefeuille, les extensions peuvent choisir de respecter",wallets_management:"Gestion des portefeuilles",funding_source_info:"Informations sur la source de financement",funding_source:"Source de financement : {wallet_class}",node_balance:"Solde du nœud : {balance} sats",lnbits_balance:"Solde LNbits : {balance} sats",funding_reserve_percent:"Pourcentage de Réserve : {percent} %",node_management:"Gestion des nœuds",node_management_not_supported:"La gestion des nœuds n'est pas prise en charge par la source de financement active",toggle_node_ui:"Interface utilisateur de nœud",toggle_public_node_ui:"Interface utilisateur du nœud public",toggle_transactions_node_ui:"Onglet des transactions (Désactiver sur les grands nœuds CLN)",invoice_expiry:"Expiration de la facture",invoice_expiry_label:"Expiration de la facture (secondes)",fee_reserve:"Réserve de frais",fee_reserve_msats:"Frais de réservation en msats",fee_reserve_percent:"Frais de réservation en pourcentage",server_management:"Gestion de serveur",base_url:"URL de base",base_url_label:"URL statique/de base pour le serveur",authentication:"Authentification",auth_token_expiry_label:"Durée d'expiration du jeton (en minutes)",auth_token_expiry_hint:"Durée en minutes avant l'expiration du jeton",auth_allowed_methods_label:"Méthodes d'autorisation autorisées",auth_allowed_methods_hint:"Sélectionnez les méthodes d'autorisation",auth_nostr_label:"URL de requête Nostr",auth_nostr_hint:"URL absolue que les clients utiliseront pour se connecter.",auth_google_ci_label:"ID Client Google",auth_google_ci_hint:"Assurez-vous que les URIs de redirection autorisées contiennent https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secret client Google",auth_gh_client_id_label:"Identifiant client GitHub",auth_gh_client_id_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secret Client GitHub",auth_keycloak_label:"URL de découverte Keycloak",auth_keycloak_ci_label:"ID Client Keycloak",auth_keycloak_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secret client Keycloak",currency_settings:"Paramètres de devise",allowed_currencies:"Devises autorisées",allowed_currencies_hint:"Limiter le nombre de devises fiduciaires disponibles",default_account_currency:"Devise par défaut du compte",default_account_currency_hint:"Devise par défaut pour la comptabilité",service_fee_label:"Frais de service (%)",service_fee_hint:"Frais facturés par tx (%)",service_fee_max_label:"Frais de service max (sats)",service_fee_max_hint:"Frais de service maximum à facturer en (sats)",fee_wallet:"Portefeuille de frais",fee_wallet_label:"Portefeuille de frais (ID de portefeuille)",fee_wallet_hint:"Identifiant de portefeuille pour envoyer des fonds à",disable_fee:"Désactiver les frais",disable_fee_internal:"Désactiver les frais de service pour les paiements internes",disable_fee_internal_desc:"Désactiver les frais de service pour les paiements Lightning internes",ui_management:"Gestion de l'interface utilisateur",ui_site_title:"Titre du site",ui_site_tagline:"Slogan du site",ui_elements_enable:"Activer les éléments sur la page d'accueil",ui_elements_disable:"Désactiver les éléments sur la page d'accueil",ui_toggle_elements_tip:"Supprimer les éléments de la page d'accueil comme 'fonctionne avec', etc.",ui_site_description:"Description du site",ui_site_description_hint:"Utilisez du texte brut, du Markdown ou du HTML brut",ui_default_wallet_name:"Nom par Défaut du Portefeuille",lnbits_wallet:"Portefeuille LNbits",denomination:"Dénomination",denomination_hint:"Le nom du jeton FakeWallet",ui_qr_code_logo:"Logo de code QR",ui_qr_code_logo_hint:"URL de l'image du logo dans le code QR",ui_custom_badge:"Badge personnalisé",ui_custom_badge_label:"Badge personnalisé 'À UTILISER AVEC PRÉCAUTION - Le portefeuille LNbits est encore en BÊTA'",ui_custom_badge_color_label:"Couleur de badge personnalisée",themes:"Thèmes",themes_hint:"Choisissez des thèmes disponibles pour les utilisateurs",custom_logo:"Logo personnalisé",custom_logo_hint:"URL de l'image du logo",ad_space_title:"Titre de l'espace publicitaire",ad_space_title_label:"Soutenu par",ad_slots:"Emplacements publicitaires",ad_slots_hint:"URL de l'annonce et chemins des fichiers image au format CSV, les extensions peuvent choisir de respecter",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annonces activées",ads_disabled:"Publicités désactivées",user_management:"Gestion des utilisateurs",admin_users:"Utilisateurs administrateurs",admin_users_hint:"Utilisateurs avec des privilèges d'administration",admin_users_label:"Identifiant utilisateur",allowed_users:"Utilisateurs autorisés",allowed_users_hint:"Seuls ces utilisateurs peuvent utiliser LNbits",allowed_users_label:"ID utilisateur",allow_creation_user:"Autoriser la création de nouveaux utilisateurs",allow_creation_user_desc:"Permettre la création de nouveaux utilisateurs sur la page d’index",components:"Composants",long_running_endpoints:"Top 5 points de terminaison longue durée",http_request_methods:"Méthodes de requête HTTP",http_response_codes:"Codes de réponse HTTP",request_details:"Détails de la demande",http_request_details:"Détails de la requête HTTP"},window.localisation.it={confirm:"Sì",server:"Server",theme:"Tema",site_customisation:"Personalizzazione del sito",funding:"Funding",users:"Utenti",audit:"Verifica",apps:"Applicazioni",channels:"Canali",transactions:"Transazioni",dashboard:"Pannello di controllo",node:"Interruttore",export_users:"Esporta utenti",no_users:"Nessun utente trovato",total_capacity:"Capacità Totale",avg_channel_size:"Dimensione media del canale",biggest_channel_size:"Dimensione del canale più grande",smallest_channel_size:"Dimensione Più Piccola del Canale",number_of_channels:"Numero di Canali",active_channels:"Canali Attivi",connect_peer:"Connetti Peer",connect:"Connetti",open_channel:"Canale aperto",open:"Apri",close_channel:"Chiudi Canale",close:"Chiudi",restart:"Riavvia il server",save:"Salva",save_tooltip:"Salva le modifiche",credit_debit:"Credito / Debito",credit_hint:"Premere Invio per accreditare i fondi",credit_label:"{denomination} da accreditare",credit_ok:"Credito/addebito riuscito di fondi virtuali ({amount} sats). I pagamenti dipendono dai fondi effettivi sulla fonte di finanziamento.",restart_tooltip:"Riavvia il server affinché le modifiche abbiano effetto",add_funds_tooltip:"Aggiungere fondi a un portafoglio",reset_defaults:"Ripristina le impostazioni predefinite",reset_defaults_tooltip:"Cancella tutte le impostazioni e ripristina i valori predefiniti",download_backup:"Scarica il backup del database",name_your_wallet:"Dai un nome al tuo portafoglio {name}",paste_invoice_label:"Incolla una fattura, una richiesta di pagamento o un codice lnurl *",lnbits_description:"Leggero e facile da configurare, LNbits può funzionare su qualsiasi fonte di finanziamento Lightning Network e persino LNbits stesso! Potete gestire LNbits per conto vostro o offrire facilmente una soluzione di custodia per altri. Ogni portafoglio ha le proprie chiavi API e non c'è limite al numero di portafogli che si possono creare. La possibilità di suddividere i fondi rende LNbits uno strumento utile per la gestione del denaro e come strumento di sviluppo. Le estensioni aggiungono ulteriori funzionalità a LNbits, consentendo di sperimentare una serie di tecnologie all'avanguardia sulla rete Lightning. Abbiamo reso lo sviluppo delle estensioni il più semplice possibile e, in quanto progetto libero e open-source, incoraggiamo le persone a sviluppare e inviare le proprie",export_to_phone:"Esportazione su telefono con codice QR",export_to_phone_desc:"Questo codice QR contiene l'URL del portafoglio con accesso da amministratore. È possibile scansionarlo dal telefono per aprire il portafoglio da lì.",wallet:"Portafoglio:",wallets:"Portafogli",add_wallet:"Aggiungi un nuovo portafoglio",delete_wallet:"Elimina il portafoglio",delete_wallet_desc:"L'intero portafoglio sarà cancellato, i fondi saranno irrecuperabili",rename_wallet:"Rinomina il portafoglio",update_name:"Aggiorna il nome",fiat_tracking:"Tracciamento Fiat",currency:"Valuta",update_currency:"Aggiorna valuta",press_to_claim:"Premi per richiedere bitcoin",donate:"Donazioni",view_github:"Visualizza su GitHub",voidwallet_active:"VoidWallet è attivo! Pagamenti disabilitati",use_with_caution:"USARE CON CAUTELA - {name} portafoglio è ancora in BETA",service_fee:"Commissione di servizio: {amount} % per transazione",service_fee_max:"Commissione di servizio: {amount} % per transazione (max {max} sats)",service_fee_tooltip:"Commissione di servizio addebitata dall'amministratore del server LNbits per ogni transazione in uscita",toggle_darkmode:"Attiva la modalità notturna",payment_reactions:"Reazioni al Pagamento",view_swagger_docs:"Visualizza i documentazione dell'API Swagger di LNbits",api_docs:"Documentazione dell'API",api_keys_api_docs:"URL del nodo, chiavi API e documentazione API",lnbits_version:"Versione di LNbits",runs_on:"Esegue su",paste:"Incolla",paste_from_clipboard:"Incolla dagli appunti",paste_request:"Richiesta di pagamento",create_invoice:"Crea fattura",camera_tooltip:"Usa la fotocamera per scansionare la fattura/QR",export_csv:"Esporta CSV",chart_tooltip:"Mostra grafico",pending:"In attesa",copy_invoice:"Copia fattura",withdraw_from:"Prelevare da",cancel:"Annulla",scan:"Scansiona",read:"Leggi",pay:"Paga",memo:"Memo",date:"Dati",payment_processing:"Elaborazione pagamento...",not_enough_funds:"Non ci sono abbastanza fondi!",search_by_tag_memo_amount:"Cerca per tag, memo, importo...",invoice_waiting:"Fattura in attesa di pagamento",payment_received:"Pagamento ricevuto",payment_sent:"Pagamento inviato",receive:"ricevere",send:"inviare",outgoing_payment_pending:"Pagamento in uscita in attesa",drain_funds:"Fondi di drenaggio",drain_funds_desc:"Questo è un codice QR LNURL-withdraw per prelevare tutti i fondi da questo portafoglio. Non condividerlo con nessuno. È compatibile con balanceCheck e balanceNotify, di conseguenza il vostro portafoglio può continuare a prelevare continuamente i fondi da qui dopo il primo prelievo",i_understand:"Ho capito",copy_wallet_url:"Copia URL portafoglio",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"La funzionalità di login sarà rilasciata in un futuro aggiornamento; per ora, assicuratevi di salvare tra i preferiti questa pagina per accedere nuovamente in futuro a questo portafoglio! Questo servizio è in fase BETA e non ci assumiamo alcuna responsabilità per la perdita all'accesso dei fondi",no_transactions:"Nessuna transazione effettuata",manage:"Gestisci",exchanges:"Scambi",extensions:"Estensioni",no_extensions:"Non ci sono estensioni installate :(",created:"Creato",search_extensions:"Estensioni di ricerca",extension_sources:"Fonti di estensione",ext_sources_hint:"Repository da cui è possibile scaricare le estensioni",ext_sources_label:"URL di origine (utilizzare solo la fonte ufficiale dell'estensione LNbits e fonti affidabili)",warning:"Attenzione",repository:"Deposito",confirm_continue:"Sei sicuro di voler continuare?",manage_extension_details:"Installa/disinstalla estensione",install:"Installare",uninstall:"Disinstalla",drop_db:"Rimuovi Dati",enable:"Abilita",pay_to_enable:"Paga per abilitare",enable_extension_details:"Attiva l'estensione per l'utente corrente",disable:"Disabilita",delete:"Elimina",installed:"Installato",activated:"Attivato",deactivated:"Disattivato",release_notes:"Note di Rilascio",activate_extension_details:"Rendi l'estensione disponibile/non disponibile per gli utenti",featured:"In primo piano",all:"Tutto",only_admins_can_install:"Solo gli account amministratore possono installare estensioni.",admin_only:"Solo amministratore",new_version:"Nuova Versione",extension_depends_on:"Dipende da:",extension_rating_soon:"Valutazioni in arrivo",extension_installed_version:"Versione installata",extension_uninstall_warning:"Stai per rimuovere l'estensione per tutti gli utenti.",uninstall_confirm:"Sì, Disinstalla",extension_db_drop_info:"Tutti i dati relativi all'estensione saranno cancellati permanentemente. Non c'è modo di annullare questa operazione!",extension_db_drop_warning:"Stai per rimuovere tutti i dati per l'estensione. Digita il nome dell'estensione per continuare:",extension_required_lnbits_version:"Questa versione richiede almeno la versione LNbits",min_version:"Minimo (incluso)",max_version:"Massimo (escluso)",payment_hash:"Hash del pagamento",fee:"Tariffa",amount:"Importo",amount_sats:"Importo (sats)",tag:"Etichetta",unit:"Unità",description:"Descrizione",expiry:"Scadenza",webhook:"Webhook",payment_proof:"Prova di pagamento",update:"Aggiorna",update_available:"Aggiornamento {version} disponibile!",latest_update:"Sei sulla versione più recente {version}.",notifications:"Notifiche",no_notifications:"Nessuna notifica",notifications_disabled:"Le notifiche di stato di LNbits sono disattivate.",enable_notifications:"Attiva le notifiche",enable_notifications_desc:"Se attivato, recupererà gli ultimi aggiornamenti sullo stato di LNbits, come incidenti di sicurezza e aggiornamenti.",enable_watchdog:"Attiva Watchdog",enable_watchdog_desc:"Se abilitato, cambierà automaticamente la tua fonte di finanziamento in VoidWallet se il tuo saldo è inferiore al saldo LNbits. Dovrai abilitarlo manualmente dopo un aggiornamento.",watchdog_interval:"Intervallo Watchdog",watchdog_interval_desc:"Quanto spesso il task in background dovrebbe controllare un segnale di killswitch nel delta del watchdog [node_balance - lnbits_balance] (in minuti).",watchdog_delta:"Guardiano Delta",watchdog_delta_desc:"Limite prima che l'interruttore di sicurezza modifichi la fonte di finanziamento in VoidWallet [lnbits_balance - node_balance > delta]",status:"Stato",notification_source:"Sorgente di notifica",notification_source_label:"URL sorgente (utilizzare solo la fonte ufficiale di stato LNbits e fonti di cui ti puoi fidare)",more:"più",less:"meno",releases:"Pubblicazioni",watchdog:"Cane da guardia",server_logs:"Registri del server",ip_blocker:"Blocco IP",security:"Sicurezza",security_tools:"Strumenti di sicurezza",block_access_hint:"Blocca l'accesso per IP",allow_access_hint:"Consenti l'accesso per IP (sovrascriverà gli IP bloccati)",enter_ip:"Inserisci l'IP e premi invio",rate_limiter:"Limitatore di frequenza",wallet_limiter:"Limitatore del Portafoglio",wallet_limit_max_withdraw_per_day:"Prelievo massimo giornaliero dal portafoglio in sats (0 per disabilitare)",wallet_max_ballance:"Saldo massimo del portafoglio in sats (0 per disabilitare)",wallet_limit_secs_between_trans:"Minuti e secondi tra transazioni per portafoglio (0 per disabilitare)",number_of_requests:"Numero di richieste",time_unit:"Unità di tempo",minute:"minuto",second:"secondo",hour:"ora",disable_server_log:"Disabilita Registro Server",enable_server_log:"Attiva Registro Server",coming_soon:"Caratteristica in arrivo prossimamente",session_has_expired:"La tua sessione è scaduta. Per favore, effettua nuovamente il login.",instant_access_question:"Vuoi accesso immediato?",login_with_user_id:"Accedi con ID utente",or:"oppure",create_new_wallet:"Crea nuovo portafoglio",login_to_account:"Accedi al tuo account",create_account:"Crea un account",account_settings:"Impostazioni dell'account",signin_with_nostr:"Continua con Nostr",signin_with_google:"Accedi con Google",signin_with_github:"Accedi con GitHub",signin_with_keycloak:"Accedi con Keycloak",username_or_email:"Nome utente o Email",password:"Password",password_config:"Configurazione della password",password_repeat:"Ripeti la password",change_password:"Cambia Password",update_credentials:"Aggiorna credenziali",update_pubkey:"Aggiorna chiave pubblica",set_password:"Imposta password",invalid_password:"La password deve contenere almeno 8 caratteri",login:"Accesso",register:"Registrati",username:"Nome utente",pubkey:"Chiave pubblica",user_id:"ID utente",email:"Email",first_name:"Nome",last_name:"Cognome",picture:"Immagine",verify_email:"Verifica email con",account:"Conto",update_account:"Aggiorna Account",invalid_username:"Nome utente non valido",auth_provider:"Provider di Autenticazione",my_account:"Il mio account",back:"Indietro",logout:"Esci",look_and_feel:"Aspetto e Comportamento",toggle_gradient:"Attiva/disattiva gradiente",gradient_background:"Sfondo sfumato",language:"Lingua",color_scheme:"Schema dei colori",admin_settings:"Impostazioni di amministrazione",extension_cost:"Questa versione richiede un pagamento minimo di {cost} satoshi.",extension_paid_sats:"Hai già pagato {paid_sats} sats.",release_details_error:"Impossibile ottenere i dettagli della versione.",pay_from_wallet:"Paga dal Portafoglio",wallet_required:"Portafoglio *",show_qr:"Mostra QR",retry_install:"Riprova Installazione",new_payment:"Effettua Nuovo Pagamento",update_payment:"Aggiorna Pagamento",already_paid_question:"Hai già pagato?",sell:"Vendi",sell_require:"Chiedi il pagamento per abilitare l'estensione",sell_info:"L'estensione {name} richiede un pagamento minimo di {amount} sats per essere abilitata.",hide_empty_wallets:"Nascondi portafogli vuoti",recheck:"Ricontrolla",contributors:"Contributori",license:"Licenza",reset_key:"Reimposta Chiave",reset_password:"Reimposta password",border_choices:"Scelte del bordo",select_all:"Seleziona tutto",nfc_supported:"Supportato NFC",nfc_not_supported:"NFC non supportato",expire_date:"Data di scadenza:",hash:"Hash:",welcome_lnbits:"Benvenuto in LNbits",setup_su_account:"Configura l'account Superuser qui sotto.",create_ticker_converter:"Crea Convertitore di Simboli di Valuta",enable_audit:"Abilita controllo",recommended:"Consigliato",audit_desc:"Registrare le richieste HTTP secondo i filtri specificati",audit_record_req:"Registra il corpo della richiesta",audit_record_warning:"Avvertimento:",audit_record_req_warning_1:"I dati riservati (come le password) verranno registrati.",audit_record_req_warning_2:"il corpo della richiesta può avere grandi dimensioni.",audit_record_use:"Usalo con cautela.",audit_ip:"Registrare l'indirizzo IP",audit_ip_desc:"Registra l'indirizzo IP del cliente",audit_path_params:"Registra i parametri del percorso",audit_query_params:"Registrare i parametri di query",audit_http_methods:"Includi i metodi HTTP",audit_http_methods_hint:"Elenco di metodi HTTP da includere. Liste vuote significano tutti.",audit_http_methods_label:"Metodi HTTP",audit_resp_codes:"Includere codici di risposta HTTP",audit_resp_codes_hint:"Elenco dei codici HTTP da includere (corrispondenza regex). Liste vuote significano tutto. Ad esempio: 4.*, 5.*",audit_resp_codes_label:"Codice di risposta HTTP (regex)",audit_paths:"Includi percorsi",audit_paths_hint:"Elenco dei percorsi da includere (corrispondenza regex). Elenco vuoto significa tutto.",audit_paths_label:"Percorso HTTP (regex)",audit_paths_exclude:"Escludi percorsi",audit_paths_exclude_hint:"Elenco dei percorsi da escludere (corrispondenza regex). Un elenco vuoto significa nessuno.",audit_paths_exclude_label:"Percorso HTTP (regex)",exchange_providers:"Fornitori di scambio",admin_extensions:"Estensioni Admin",admin_extensions_label:"Estensioni amministrative",admin_extensions_hint:"Solo un utente con privilegi di amministratore può utilizzare le estensioni.",user_default_extensions:"Estensioni predefinite dell'utente",user_default_extensions_label:"Estensioni utente",user_default_extensions_hint:"Estensioni che saranno abilitate di default per gli utenti.",miscellanous:"Varie",misc_disable_extensions:"Disabilita estensioni",misc_disable_extensions_label:"Disabilita tutte le estensioni",misc_hide_api:"Nascondi API",misc_hide_api_label:"Nasconde l'api del portafoglio, le estensioni possono scegliere di onorare",wallets_management:"Gestione dei portafogli",funding_source_info:"Informazioni sulla fonte di finanziamento",funding_source:"Fonte di finanziamento: {wallet_class}",node_balance:"Saldo Nodo: {balance} sats",lnbits_balance:"Saldo LNbits: {balance} sats",funding_reserve_percent:"Riserva Percentuale: {percent} %",node_management:"Gestione dei nodi",node_management_not_supported:"La gestione dei nodi non è supportata dalla fonte di finanziamento attiva.",toggle_node_ui:"Interfaccia utente del nodo",toggle_public_node_ui:"Interfaccia Utente Nodo Pubblico",toggle_transactions_node_ui:"Scheda Transazioni (Disabilita su nodi CLN grandi)",invoice_expiry:"Scadenza fattura",invoice_expiry_label:"Scadenza fattura (secondi)",fee_reserve:"Riserva delle commissioni",fee_reserve_msats:"Tariffa di prenotazione in msats",fee_reserve_percent:"Commissione di riserva in percentuale",server_management:"Gestione server",base_url:"URL di base",base_url_label:"URL statica/base per il server",authentication:"Autenticazione",auth_token_expiry_label:"Minuti di scadenza del token",auth_token_expiry_hint:"Tempo in minuti fino alla scadenza del token",auth_allowed_methods_label:"Metodi di autorizzazione consentiti",auth_allowed_methods_hint:"Seleziona i metodi di autorizzazione",auth_nostr_label:"URL richiesta Nostr",auth_nostr_hint:"URL assoluto che i clienti utilizzeranno per accedere.",auth_google_ci_label:"ID client di Google",auth_google_ci_hint:"Assicurati che gli URI di reindirizzamento autorizzati contengano https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"ID client di GitHub",auth_gh_client_id_hint:"Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Segreto Client GitHub",auth_keycloak_label:"URL di individuazione di Keycloak",auth_keycloak_ci_label:"ID client di Keycloak",auth_keycloak_ci_hint:"Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",currency_settings:"Impostazioni valuta",allowed_currencies:"Valute consentite",allowed_currencies_hint:"Limita il numero di valute fiat disponibili",default_account_currency:"Valuta predefinita del conto",default_account_currency_hint:"Valuta predefinita per la contabilità",service_fee_label:"Tassa di servizio (%)",service_fee_hint:"Tariffa addebitata per transazione (%)",service_fee_max_label:"Commissione di servizio max (sats)",service_fee_max_hint:"Commissione massima da addebitare in (sats)",fee_wallet:"Portafoglio delle commissioni",fee_wallet_label:"Portafoglio delle commissioni (ID portafoglio)",fee_wallet_hint:"ID portafoglio a cui inviare fondi",disable_fee:"Disabilita Commissione",disable_fee_internal:"Disabilita la commissione di servizio per i pagamenti interni",disable_fee_internal_desc:"Disabilita la commissione di servizio per i pagamenti Lightning interni",ui_management:"Gestione dell'interfaccia utente",ui_site_title:"Titolo del sito",ui_site_tagline:"Slogan del sito",ui_elements_enable:"Abilita elementi sulla homepage",ui_elements_disable:"Disabilita elementi sulla homepage",ui_toggle_elements_tip:"Rimuovi elementi della homepage come 'runs on' ecc.",ui_site_description:"Descrizione del sito",ui_site_description_hint:"Usa testo normale, Markdown o HTML grezzo",ui_default_wallet_name:"Nome predefinito del portafoglio",lnbits_wallet:"Portafoglio LNbits",denomination:"Denominazione",denomination_hint:"Il nome per il token FakeWallet",ui_qr_code_logo:"Logo del codice QR",ui_qr_code_logo_hint:"URL all'immagine del logo nel codice QR",ui_custom_badge:"Badge personalizzato",ui_custom_badge_label:"Badge personalizzato 'USARE CON CAUTELA - Il portafoglio LNbits è ancora in BETA'",ui_custom_badge_color_label:"Colore distintivo personalizzato",themes:"Temi",themes_hint:"Scegli i temi disponibili per gli utenti",custom_logo:"Logo personalizzato",custom_logo_hint:"URL all'immagine del logo",ad_space_title:"Titolo Spazio Pubblicitario",ad_space_title_label:"Supportato da",ad_slots:"Spazi pubblicitari",ad_slots_hint:"Percorso dell'URL e dell'immagine in formato CSV, le estensioni possono scegliere di rispettare",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annunci abilitati",ads_disabled:"Annunci disabilitati",user_management:"Gestione utenti",admin_users:"Utenti amministratori",admin_users_hint:"Utenti con privilegi di amministratore",admin_users_label:"ID utente",allowed_users:"Utenti consentiti",allowed_users_hint:"Solo questi utenti possono usare LNbits",allowed_users_label:"ID utente",allow_creation_user:"Consenti la creazione di nuovi utenti",allow_creation_user_desc:"Consenti la creazione di nuovi utenti nella pagina indice",components:"Componenti",long_running_endpoints:"I primi 5 endpoint a lunga esecuzione",http_request_methods:"Metodi di richiesta HTTP",http_response_codes:"Codici di risposta HTTP",request_details:"Dettagli della richiesta",http_request_details:"Dettagli della richiesta HTTP"},window.localisation.jp={confirm:"はい",server:"サーバー",theme:"テーマ",site_customisation:"サイトカスタマイズ",funding:"資金調達",users:"ユーザー",audit:"監査",apps:"アプリ",channels:"チャンネル",transactions:"トランザクション",dashboard:"ダッシュボード",node:"ノード",export_users:"ユーザーのエクスポート",no_users:"ユーザーが見つかりません",total_capacity:"合計容量",avg_channel_size:"平均チャンネルサイズ",biggest_channel_size:"最大チャネルサイズ",smallest_channel_size:"最小チャンネルサイズ",number_of_channels:"チャンネル数",active_channels:"アクティブチャンネル",connect_peer:"ピアを接続",connect:"接続",open_channel:"オープンチャンネル",open:"開く",close_channel:"チャンネルを閉じる",close:"閉じる",restart:"サーバーを再起動する",save:"保存",save_tooltip:"変更を保存する",credit_debit:"クレジット / デビット",credit_hint:"クレジットカードを使用して資金を追加するには、LNbitsを使用してください。",credit_label:"{denomination} をクレジットに",restart_tooltip:"サーバーを再起動して変更を適用します",add_funds_tooltip:"ウォレットに資金を追加します。",reset_defaults:"リセット",reset_defaults_tooltip:"すべての設定を削除してデフォルトに戻します。",download_backup:"データベースのバックアップをダウンロードする",name_your_wallet:"あなたのウォレットの名前 {name}",paste_invoice_label:"請求書を貼り付けてください",lnbits_description:"簡単にインストールでき、軽量なLNbitsは、あらゆるライトニングネットワークの資金源と、LNbits自身でさえも実行できます!LNbitsを個人で実行することも、他人に対してカストディアンソリューションをで実行できます! LNbitsを自分で実行することも、他の人に優れたソリューションを提供することもできます。各ウォレットには独自のAPIキーがあり、作成できるウォレットの数に制限はありません。資金を分割する機能は、LNbitsを資金管理ツールとして使用したり、開発ツールとして使用したりするための便利なツールです。拡張機能は、LNbitsに追加の機能を追加します。そのため、LNbitsは最先端の技術をネットワークLightningで試すことができます。拡張機能を開発するのは簡単で、無料でオープンソースのプロジェクトであるため、人々が自分で開発し、自分の貢献を送信することを奨励しています。",export_to_phone:"電話にエクスポート",export_to_phone_desc:"ウォレットを電話にエクスポートすると、ウォレットを削除する前にウォレットを復元できます。ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。",wallet:"ウォレット:",wallets:"ウォレット",add_wallet:"ウォレットを追加",delete_wallet:"ウォレットを削除",delete_wallet_desc:"ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。",rename_wallet:"ウォレットの名前を変更",update_name:"名前を更新",fiat_tracking:"フィアット追跡",currency:"通貨",update_currency:"通貨を更新する",press_to_claim:"クレームするには押してください",donate:"寄付",view_github:"GitHubで表示",voidwallet_active:"Voidwalletアクティブ",use_with_caution:"注意して使用してください - {name} ウォレットはまだベータ版です",service_fee:"取引ごとのサービス手数料: {amount} %",service_fee_max:"取引手数料:{amount}%(最大{max}サトシ)",service_fee_tooltip:"LNbitsサーバー管理者が発生する送金ごとの手数料",toggle_darkmode:"ダークモードを切り替える",payment_reactions:"支払いの反応",view_swagger_docs:"Swaggerドキュメントを表示",api_docs:"APIドキュメント",api_keys_api_docs:"ノードURL、APIキー、APIドキュメント",lnbits_version:"LNbits バージョン",runs_on:"で実行",paste:"貼り付け",paste_from_clipboard:"クリップボードから貼り付け",paste_request:"リクエストを貼り付ける",create_invoice:"請求書を作成する",camera_tooltip:"QRコードを読み取る",export_csv:"CSVでエクスポート",chart_tooltip:"チャートを表示するには、グラフの上にカーソルを合わせます",pending:"保留中",copy_invoice:"請求書をコピー",withdraw_from:"出金",cancel:"キャンセル",scan:"スキャン",read:"読む",pay:"支払う",memo:"メモ",date:"日付",payment_processing:"支払い処理中",not_enough_funds:"資金が不足しています",search_by_tag_memo_amount:"タグ、メモ、金額で検索",invoice_waiting:"請求書を待っています",payment_received:"お支払いありがとうございます",payment_sent:"支払いが完了しました",receive:"受け取る",send:"送信",outgoing_payment_pending:"支払い保留中",drain_funds:"資金を排出する",drain_funds_desc:"ウォレットの残高をすべて他のウォレットに送金します",i_understand:"理解した",copy_wallet_url:"ウォレットURLをコピー",disclaimer_dialog_title:"重要!",disclaimer_dialog:"ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。ウォレットを削除する前に、ウォレットをエクスポートしてください。",no_transactions:"トランザクションはありません",manage:"管理",exchanges:"取引所",extensions:"拡張機能",no_extensions:"拡張機能はありません",created:"作成済み",search_extensions:"検索拡張機能",extension_sources:"拡張ソース",ext_sources_hint:"拡張機能をダウンロードできるリポジトリ",ext_sources_label:"ソースURL(公式のLNbits拡張ソースおよび信頼できるソースのみを使用してください)",warning:"警告",repository:"リポジトリ",confirm_continue:"続行してもよろしいですか?",manage_extension_details:"拡張機能のインストール/アンインストール",install:"インストール",uninstall:"アンインストール",drop_db:"データを削除",enable:"有効",pay_to_enable:"有効にするために支払う",enable_extension_details:"現在のユーザーの拡張機能を有効にする",disable:"無効",delete:"削除",installed:"インストール済み",activated:"有効化",deactivated:"無効化",release_notes:"リリースノート",activate_extension_details:"拡張機能をユーザーが利用できるようにする/利用できないようにする",featured:"特集",all:"すべて",only_admins_can_install:"(管理者アカウントのみが拡張機能をインストールできます)",admin_only:"管理者のみ",new_version:"新しいバージョン",extension_depends_on:"依存先:",extension_rating_soon:"評価は近日公開",extension_installed_version:"インストール済みバージョン",extension_uninstall_warning:"すべてのユーザーの拡張機能を削除しようとしています.",uninstall_confirm:"はい、アンインストールします",extension_db_drop_info:"エクステンションのすべてのデータが完全に削除されます。この操作を元に戻す方法はありません!",extension_db_drop_warning:"エクステンションのすべてのデータを削除しようとしています。続行するには、エクステンションの名前を入力してください:",extension_required_lnbits_version:"このリリースには少なくとも LNbits バージョンが必要です",min_version:"最小値(含む)",max_version:"最大(除外)",payment_hash:"支払いハッシュ",fee:"料金",amount:"量",amount_sats:"金額 (サッツ)",tag:"タグ",unit:"単位",description:"説明",expiry:"有効期限",webhook:"ウェブフック",payment_proof:"支払い証明",update:"更新",update_available:"アップデート{version}が利用可能です!",latest_update:"あなたは最新バージョン{version}を使用しています。",notifications:"通知",no_notifications:"通知はありません",notifications_disabled:"LNbitsステータス通知は無効です。",enable_notifications:"通知を有効にする",enable_notifications_desc:"有効にすると、セキュリティインシデントやアップデートのような最新のLNbitsステータス更新を取得します。",enable_watchdog:"ウォッチドッグを有効にする",enable_watchdog_desc:"有効にすると、残高がLNbitsの残高より少ない場合に、資金源を自動的にVoidWalletに変更します。アップデート後は手動で有効にする必要があります。",watchdog_interval:"ウォッチドッグ・インターバル",watchdog_interval_desc:"バックグラウンドタスクがウォッチドッグデルタ[node_balance - lnbits_balance]でキルスイッチシグナルを確認する頻度(分単位)。",watchdog_delta:"ウォッチドッグデルタ",watchdog_delta_desc:"キルスイッチが資金源をVoidWalletに変更する前の限界 [lnbits_balance - node_balance > delta]",status:"ステータス",notification_source:"通知ソース",notification_source_label:"ソースURL(公式のLNbitsステータスソースのみを使用し、信頼できるソースのみを利用してください)",more:"より多くの",less:"少ない",releases:"リリース",watchdog:"ウォッチドッグ",server_logs:"サーバーログ",ip_blocker:"IPブロッカー",security:"セキュリティ",security_tools:"セキュリティツール",block_access_hint:"IPによるアクセスをブロック",allow_access_hint:"IPによるアクセスを許可する(ブロックされたIPを上書きします)",enter_ip:"IPを入力してエンターキーを押してください",rate_limiter:"レートリミッター",wallet_limiter:"ウォレットリミッター",wallet_limit_max_withdraw_per_day:"1日あたりの最大ウォレット出金額をsatsで入力してください(0 で無効)。",wallet_max_ballance:"ウォレットの最大残高(sats)(0は無効)",wallet_limit_secs_between_trans:"トランザクション間の最小秒数(ウォレットごと)(0は無効)",number_of_requests:"リクエストの数",time_unit:"時間単位",minute:"分",second:"秒",hour:"時間",disable_server_log:"サーバーログを無効にする",enable_server_log:"サーバーログを有効にする",coming_soon:"機能は間もなく登場します",session_has_expired:"あなたのセッションは期限切れです。もう一度ログインしてください。",instant_access_question:"即時アクセスをご希望ですか?",login_with_user_id:"ユーザーIDでログイン",or:"または",create_new_wallet:"新しいウォレットを作成",login_to_account:"アカウントにログインしてください",create_account:"アカウントを作成",account_settings:"アカウント設定",signin_with_nostr:"Nostrで続行",signin_with_google:"Googleでサインイン",signin_with_github:"GitHubでサインイン",signin_with_keycloak:"Keycloakでサインイン",username_or_email:"ユーザー名またはメールアドレス",password:"パスワード",password_config:"パスワード設定",password_repeat:"パスワードの再入力",change_password:"パスワードを変更",update_credentials:"資格情報を更新する",update_pubkey:"公開鍵を更新",set_password:"パスワードを設定",invalid_password:"パスワードは少なくとも8文字必要です",login:"ログイン",register:"登録",username:"ユーザー名",pubkey:"公開鍵",user_id:"ユーザーID",email:"メール",first_name:"名",last_name:"姓",picture:"写真",verify_email:"メールアドレスの確認を行ってください",account:"アカウント",update_account:"アカウントを更新",invalid_username:"無効なユーザー名",auth_provider:"認証プロバイダ",my_account:"マイアカウント",back:"戻る",logout:"ログアウト",look_and_feel:"ルック・アンド・フィール",toggle_gradient:"グラデーションを切り替える",gradient_background:"グラデーション背景",language:"言語",color_scheme:"カラースキーム",admin_settings:"管理設定",extension_cost:"このリリースには最低 {cost} サトシの支払いが必要です。",extension_paid_sats:"すでに{paid_sats} satsを支払いました。",release_details_error:"リリースの詳細を取得できません。",pay_from_wallet:"ウォレットから支払う",wallet_required:"ウォレット *",show_qr:"QRを表示",retry_install:"再試行インストール",new_payment:"新しい支払いを作成する",update_payment:"支払いを更新する",already_paid_question:"すでに支払いましたか?",sell:"販売する",sell_require:"拡張を有効にするために支払いを求める",sell_info:"{name}拡張機能を有効にするには、最小{amount}サツの支払いが必要です。",hide_empty_wallets:"空のウォレットを非表示にする",recheck:"再確認",contributors:"貢献者",license:"ライセンス",reset_key:"リセットキー",reset_password:"パスワードをリセットする",border_choices:"境界の選択肢",select_all:"すべて選択",nfc_supported:"NFC対応",nfc_not_supported:"NFCがサポートされていません",expire_date:"有効期限日:",hash:"ハッシュ:",welcome_lnbits:"LNbitsへようこそ",setup_su_account:"スーパーアカウントを以下に設定してください。",create_ticker_converter:"通貨ティッカーコンバーターを作成",enable_audit:"監査を有効にする",recommended:"推奨",audit_desc:"指定されたフィルターに従ってHTTPリクエストを記録する",audit_record_req:"リクエストボディの記録",audit_record_warning:"警告:",audit_record_req_warning_1:"パスワードなどの機密データが記録されます。",audit_record_req_warning_2:"リクエストボディは大きなサイズになる可能性があります。",audit_record_use:"注意して使用してください。",audit_ip:"IPアドレスを記録する",audit_ip_desc:"クライアントのIPアドレスを記録する",audit_path_params:"パスパラメータを記録",audit_query_params:"クエリパラメータを記録する",audit_http_methods:"HTTPメソッドを含める",audit_http_methods_hint:"含めるHTTPメソッドのリスト。空のリストはすべてを意味します。",audit_http_methods_label:"HTTPメソッド",audit_resp_codes:"HTTPレスポンスコードを含める",audit_resp_codes_hint:"含めるHTTPコードの一覧(正規表現で一致)。空のリストはすべてを意味します。例: 4.*, 5.*",audit_resp_codes_label:"HTTPレスポンスコード(正規表現)",audit_paths:"パスを含める",audit_paths_hint:"含めるパスのリスト(正規表現マッチ)。空のリストはすべてを意味します。",audit_paths_label:"HTTP パス (正規表現)",audit_paths_exclude:"パスを除外",audit_paths_exclude_hint:"除外するパスの一覧(正規表現の一致)。空のリストは対象がないことを意味します。",audit_paths_exclude_label:"HTTP パス (正規表現)",exchange_providers:"取引所プロバイダー",admin_extensions:"管理拡張機能",admin_extensions_label:"管理者拡張機能",admin_extensions_hint:"拡張機能は管理者権限を持つユーザーのみが使用できます",user_default_extensions:"ユーザーデフォルト拡張機能",user_default_extensions_label:"ユーザー拡張機能",user_default_extensions_hint:"ユーザーに対してデフォルトで有効化される拡張機能。",miscellanous:"その他",misc_disable_extensions:"拡張機能を無効にする",misc_disable_extensions_label:"すべての拡張機能を無効にする",misc_hide_api:"APIを非表示",misc_hide_api_label:"ウォレットAPIを隠すことができ、拡張機能は尊重することを選ぶことができます。",wallets_management:"ウォレット管理",funding_source_info:"資金源情報",funding_source:"資金源: {wallet_class}",node_balance:"ノード残高: {balance} サッツ",lnbits_balance:"LNbits残高: {balance} sats",funding_reserve_percent:"予約パーセント: {percent} %",node_management:"ノード管理",node_management_not_supported:"アクティブな資金源ではノード管理がサポートされていません",toggle_node_ui:"ノードUI",toggle_public_node_ui:"パブリックノードUI",toggle_transactions_node_ui:"トランザクションタブ(大規模なCLNノードで無効化)",invoice_expiry:"インボイスの有効期限",invoice_expiry_label:"インボイスの有効期限(秒)",fee_reserve:"料金予約",fee_reserve_msats:"ミリサトシでの予約手数料",fee_reserve_percent:"パーセンテージの予約料",server_management:"サーバー管理",base_url:"ベースURL",base_url_label:"サーバーの静的/基本URL",authentication:"認証",auth_token_expiry_label:"トークン有効期限(分)",auth_token_expiry_hint:"トークンが失効するまでの時間(分)",auth_allowed_methods_label:"許可された認証方法",auth_allowed_methods_hint:"認証方法を選択",auth_nostr_label:"Nostr リクエスト URL",auth_nostr_hint:"クライアントがログインするために使用する絶対URL。",auth_google_ci_label:"Google クライアントID",auth_google_ci_hint:"認可されたリダイレクトURIにhttps://{domain}/api/v1/auth/google/tokenが含まれていることを確認してください",auth_google_cs_label:"Google クライアントシークレット",auth_gh_client_id_label:"GitHub クライアントID",auth_gh_client_id_hint:"認証コールバックURLがhttps://{domain}/api/v1/auth/github/tokenに設定されていることを確認してください。",auth_gh_client_secret_label:"GitHub クライアントシークレット",auth_keycloak_label:"キーコーク ディスカバリー URL",auth_keycloak_ci_label:"Keycloak クライアント ID",auth_keycloak_ci_hint:"認証コールバックURLが https://{domain}/api/v1/auth/keycloak/token に設定されていることを確認してください。",auth_keycloak_cs_label:"キークローククライアントシークレット",currency_settings:"通貨設定",allowed_currencies:"許可されている通貨",allowed_currencies_hint:"利用可能な法定通貨の数を制限する",default_account_currency:"デフォルト口座通貨",default_account_currency_hint:"会計のデフォルト通貨",service_fee_label:"サービス料 (%)",service_fee_hint:"1 取引あたりの手数料 (%)",service_fee_max_label:"サービス料最大 (sats)",service_fee_max_hint:"(サット)での最大サービス料金",fee_wallet:"手数料ウォレット",fee_wallet_label:"手数料ウォレット (ウォレットID)",fee_wallet_hint:"送金先のウォレットID",disable_fee:"手数料を無効にする",disable_fee_internal:"内部支払に対するサービス手数料を無効にする",disable_fee_internal_desc:"内部のライトニングペイメントのサービス料金を無効にする",ui_management:"UI管理",ui_site_title:"サイトのタイトル",ui_site_tagline:"サイトのタグライン",ui_elements_enable:"ホームページの要素を有効にする",ui_elements_disable:"ホームページの要素を無効にする",ui_toggle_elements_tip:"「runs on」などのホームページ要素を削除します。",ui_site_description:"サイトの説明",ui_site_description_hint:"プレーンテキスト、Markdown、または生のHTMLを使用してください。",ui_default_wallet_name:"デフォルトウォレット名",lnbits_wallet:"LNbitsウォレット",denomination:"額面",denomination_hint:"FakeWalletトークンの名前",ui_qr_code_logo:"QRコードロゴ",ui_qr_code_logo_hint:"QRコードのロゴ画像のURL",ui_custom_badge:"カスタムバッジ",ui_custom_badge_label:"カスタムバッジ「使用に注意 - LNbitsウォレットはまだベータ版です」",ui_custom_badge_color_label:"カスタムバッジカラー",themes:"テーマ",themes_hint:"ユーザーが利用可能なテーマを選択してください",custom_logo:"カスタムロゴ",custom_logo_hint:"ロゴ画像へのURL",ad_space_title:"広告スペースのタイトル",ad_space_title_label:"サポートされています",ad_slots:"広告スロット",ad_slots_hint:"CSV形式の広告URLと画像ファイルパス、拡張機能は遵守することを選択できます",ad_slots_label:"URL;img_light_url;img_dark_url、URL...",ads_enabled:"広告が有効になっています",ads_disabled:"広告が無効になっています",user_management:"ユーザー管理",admin_users:"管理者ユーザー",admin_users_hint:"管理者権限を持つユーザー",admin_users_label:"ユーザーID",allowed_users:"許可されたユーザー",allowed_users_hint:"これらのユーザーのみがLNbitsを使用できます。",allowed_users_label:"ユーザーID",allow_creation_user:"新しいユーザーの作成を許可",allow_creation_user_desc:"インデックスページで新しいユーザーの作成を許可する",components:"コンポーネント",long_running_endpoints:"トップ5の長時間実行エンドポイント",http_request_methods:"HTTPリクエストメソッド",http_response_codes:"HTTPレスポンスコード",request_details:"リクエストの詳細",http_request_details:"HTTPリクエストの詳細"},window.localisation.cn={confirm:"确定",server:"服务器",theme:"主题",site_customisation:"网站定制",funding:"资金",users:"用户",audit:"审计",apps:"应用程序",channels:"频道",transactions:"交易记录",dashboard:"控制面板",node:"节点",export_users:"导出用户",no_users:"未找到用户",total_capacity:"总容量",avg_channel_size:"平均频道大小",biggest_channel_size:"最大通道大小",smallest_channel_size:"最小频道尺寸",number_of_channels:"频道数量",active_channels:"活跃频道",connect_peer:"连接对等",connect:"连接",open_channel:"打开频道",open:"打开",close_channel:"关闭频道",close:"关闭",restart:"重新启动服务器",save:"保存",save_tooltip:"保存更改",credit_debit:"信用卡 / 借记卡",credit_hint:"按 Enter 键充值账户",credit_label:"{denomination} 充值",credit_ok:"成功记入/扣除虚拟资金 ({amount} sats)。付款取决于资金来源的实际资金。",restart_tooltip:"重新启动服务器以使更改生效",add_funds_tooltip:"为钱包添加资金",reset_defaults:"重置为默认设置",reset_defaults_tooltip:"删除所有设置并重置为默认设置",download_backup:"下载数据库备份",name_your_wallet:"给你的 {name}钱包起个名字",paste_invoice_label:"粘贴发票,付款请求或lnurl*",lnbits_description:"LNbits 设置简单、轻量级,可以在任何闪电网络的资金来源上运行,甚至可以在LNbits自身上运行!您可以为自己运行LNbits,或者轻松为他人提供托管解决方案。每个钱包都有自己的 API 密钥,你可以创建的钱包数量没有限制。能够把资金分开管理使 LNbits 成为一款有用的资金管理和开发工具。扩展程序增加了 LNbits 的额外功能,所以你可以在闪电网络上尝试各种尖端技术。我们已经尽可能简化了开发扩展程序的过程,作为一个免费和开源的项目,我们鼓励人们开发并提交自己的扩展程序。",export_to_phone:"通过二维码导出到手机",export_to_phone_desc:"这个二维码包含您钱包的URL。您可以使用手机扫描的方式打开您的钱包。",wallet:"钱包:",wallets:"钱包",add_wallet:"添加新钱包",delete_wallet:"删除钱包",delete_wallet_desc:"整个钱包将被删除,资金将无法恢复",rename_wallet:"重命名钱包",update_name:"更新名称",fiat_tracking:"菲亚特追踪",currency:"货币",update_currency:"更新货币",press_to_claim:"点击领取比特币",donate:"捐献",view_github:"在GitHub上查看",voidwallet_active:"VoidWallet 已激活!付款功能已禁用。",use_with_caution:"请谨慎使用 - {name}钱包还处于测试版阶段",service_fee:"服务费:{amount}% 每笔交易",service_fee_max:"服务费:{amount}% 每笔交易(最高 {max} sats)",service_fee_tooltip:"LNbits服务器管理员每笔外发交易收取的服务费",toggle_darkmode:"切换暗黑模式",payment_reactions:"支付反应",view_swagger_docs:"查看 LNbits Swagger API 文档",api_docs:"API文档",api_keys_api_docs:"节点URL、API密钥和API文档",lnbits_version:"LNbits版本",runs_on:"可运行在",paste:"粘贴",paste_from_clipboard:"从剪贴板粘贴",paste_request:"粘贴请求",create_invoice:"创建发票",camera_tooltip:"用相机扫描发票/二维码",export_csv:"导出为CSV",chart_tooltip:"显示图表",pending:"待处理",copy_invoice:"复制发票",withdraw_from:"从",cancel:"取消",scan:"扫描",read:"读取",pay:"付款",memo:"备注",date:"日期",payment_processing:"正在处理支付...",not_enough_funds:"资金不足!",search_by_tag_memo_amount:"按标签、备注、金额搜索",invoice_waiting:"待支付的发票",payment_received:"收到付款",payment_sent:"付款已发送",receive:"收款",send:"付款",outgoing_payment_pending:"付款正在等待处理",drain_funds:"清空资金",drain_funds_desc:"这是一个 LNURL-取款的二维码,用于从该钱包中提取全部资金。请不要与他人分享。它与 balanceCheck 和 balanceNotify 兼容,因此在第一次取款后,您的钱包还可能会持续从这里提取资金",i_understand:"我明白",copy_wallet_url:"复制钱包URL",disclaimer_dialog_title:"重要!",disclaimer_dialog:"登录功能将在以后的更新中发布,请将此页面加为书签,以便将来访问您的钱包!此服务处于测试阶段,我们不对资金的丢失承担任何责任。",no_transactions:"尚未进行任何交易",manage:"管理",exchanges:"交易所",extensions:"扩展程序",no_extensions:"你没有安装任何扩展程序 :(",created:"已创建",search_extensions:"搜索扩展程序",extension_sources:"扩展源",ext_sources_hint:"可以下载扩展的存储库",ext_sources_label:"来源网址(仅使用官方LNbits扩展程序来源和您可以信任的来源)",warning:"警告",repository:"代码库",confirm_continue:"你确定要继续吗?",manage_extension_details:"安装/卸载扩展程序",install:"安装",uninstall:"卸载",drop_db:"删除数据",enable:"启用",pay_to_enable:"支付以启用",enable_extension_details:"为当前用户启用扩展程序",disable:"禁用",delete:"删除",installed:"已安装",activated:"已激活",deactivated:"已停用",release_notes:"发布说明",activate_extension_details:"对用户开放或禁用扩展程序",featured:"精选",all:"全部",only_admins_can_install:"(只有管理员账户可以安装扩展)",admin_only:"仅限管理员",new_version:"新版本",extension_depends_on:"依赖于:",extension_rating_soon:"即将推出评分",extension_installed_version:"已安装的版本",extension_uninstall_warning:"您即将对所有用户删除该扩展程序。",uninstall_confirm:"是的,卸载",extension_db_drop_info:"该扩展程序的所有数据将被永久删除。此操作无法撤销!",extension_db_drop_warning:"您即将删除该扩展的所有数据。请继续输入扩展程序名称以确认操作:",extension_required_lnbits_version:"此版本要求最低的 LNbits 版本为",min_version:"最小值(包含)",max_version:"最大值(不含)",payment_hash:"付款哈希",fee:"费",amount:"金额",amount_sats:"金额(聪)",tag:"标签",unit:"单位",description:"详情",expiry:"过期时间",webhook:"Webhook",payment_proof:"付款证明",update:"更新",update_available:"更新{version}可用!",latest_update:"您当前使用的是最新版本{version}。",notifications:"通知",no_notifications:"没有通知",notifications_disabled:"LNbits状态通知已禁用。",enable_notifications:"启用通知",enable_notifications_desc:"如果启用,它将获取最新的LNbits状态更新,如安全事件和更新。",enable_watchdog:"启用看门狗",enable_watchdog_desc:"如果启用,当您的余额低于LNbits余额时,系统将自动将您的资金来源更改为VoidWallet。更新后您将需要手动启用。",watchdog_interval:"看门狗间隔",watchdog_interval_desc:"后台任务应该多久检查一次看门狗增量中的 killswitch 信号 [node_balance - lnbits_balance](以分钟计)。",watchdog_delta:"看门狗德尔塔",watchdog_delta_desc:"在触发紧急停止前切换资金来源至VoidWallet的限制 [lnbits_balance - node_balance > delta]",status:"状态",notification_source:"通知来源",notification_source_label:"来源 URL(仅使用官方LNbits状态源和您信任的源)",more:"更多",less:"少",releases:"版本",watchdog:"监控程序",server_logs:"服务器日志",ip_blocker:"IP 阻止器",security:"安全",security_tools:"安全工具",block_access_hint:"屏蔽IP访问",allow_access_hint:"允许通过IP访问(将覆盖被屏蔽的IP)",enter_ip:"输入IP地址并按回车键",rate_limiter:"速率限制器",wallet_limiter:"钱包限制器",wallet_limit_max_withdraw_per_day:"每日钱包最大提现额度(单位:sats)(设为0则禁用)",wallet_max_ballance:"钱包最大余额(以sats计)(设为0则禁用)",wallet_limit_secs_between_trans:"每个钱包交易间最少秒数(设为0则禁用)",number_of_requests:"请求次数",time_unit:"时间单位",minute:"分钟",second:"秒",hour:"小时",disable_server_log:"禁用服务器日志",enable_server_log:"启用服务器日志",coming_soon:"功能即将推出",session_has_expired:"您的会话已过期。请重新登录。",instant_access_question:"想要即时访问吗?",login_with_user_id:"使用用户ID登录",or:"或",create_new_wallet:"创建新钱包",login_to_account:"登录您的账户",create_account:"创建账户",account_settings:"账户设置",signin_with_nostr:"继续使用 Nostr",signin_with_google:"使用谷歌账号登录",signin_with_github:"使用GitHub登录",signin_with_keycloak:"使用Keycloak登录",username_or_email:"用户名或电子邮箱",password:"密码",password_config:"密码配置",password_repeat:"密码重复",change_password:"修改密码",update_credentials:"更新凭证",update_pubkey:"更新公钥",set_password:"设置密码",invalid_password:"密码至少需要有8个字符",login:"登录",register:"注册",username:"用户名",pubkey:"公钥",user_id:"用户ID",email:"电子邮件",first_name:"名字",last_name:"姓氏",picture:"图片",verify_email:"验证电子邮件与",account:"账户",update_account:"更新帐户",invalid_username:"无效用户名",auth_provider:"认证提供者",my_account:"我的账户",back:"返回",logout:"注销",look_and_feel:"外观和感觉",toggle_gradient:"切换渐变",gradient_background:"渐变背景",language:"语言",color_scheme:"配色方案",admin_settings:"管理员设置",extension_cost:"此版本需要支付最低 {cost} sats。",extension_paid_sats:"您已经支付了{paid_sats} sats。",release_details_error:"无法获取发布详情。",pay_from_wallet:"从钱包支付",wallet_required:"钱包 *",show_qr:"显示QR码",retry_install:"重试安装",new_payment:"创建新支付",update_payment:"更新付款",already_paid_question:"你已经付款了吗?",sell:"出售",sell_require:"请求付款以启用扩展",sell_info:"{name} 扩展需要支付至少 {amount} sat 才能启用。",hide_empty_wallets:"隐藏空钱包",recheck:"重新检查",contributors:"贡献者们",license:"许可证",reset_key:"重置密钥",reset_password:"重置密码",border_choices:"边框选项",select_all:"全选",nfc_supported:"支持NFC",nfc_not_supported:"不支持NFC",expire_date:"有效期:",hash:"哈希:",welcome_lnbits:"欢迎来到LNbits",setup_su_account:"设置超级用户账户如下。",create_ticker_converter:"创建货币代码转换器",enable_audit:"启用审核",recommended:"推荐",audit_desc:"根据指定的过滤器记录HTTP请求",audit_record_req:"记录请求主体",audit_record_warning:"警告:",audit_record_req_warning_1:"机密数据(如密码)将被记录。",audit_record_req_warning_2:"请求主体可能会有较大尺寸。",audit_record_use:"请谨慎使用。",audit_ip:"记录 IP 地址",audit_ip_desc:"记录客户端的IP地址",audit_path_params:"记录路径参数",audit_query_params:"记录查询参数",audit_http_methods:"包括 HTTP 方法",audit_http_methods_hint:"要包含的 HTTP 方法列表。空列表表示全部。",audit_http_methods_label:"HTTP 方法",audit_resp_codes:"包括 HTTP 响应代码",audit_resp_codes_hint:"要包含的 HTTP 代码列表(正则表达式匹配)。空列表表示全部。例如:4.*,5.*",audit_resp_codes_label:"HTTP响应代码(正则表达式)",audit_paths:"包含路径",audit_paths_hint:"要包含的路径列表(正则表达式匹配)。空列表意味着全部。",audit_paths_label:"HTTP 路径(正则表达式)",audit_paths_exclude:"排除路径",audit_paths_exclude_hint:"要排除的路径列表(正则表达式匹配)。空列表表示没有。",audit_paths_exclude_label:"HTTP 路径(正则表达式)",exchange_providers:"兑换提供商",admin_extensions:"管理员扩展",admin_extensions_label:"管理员扩展件",admin_extensions_hint:"只有具有管理员权限的用户才能使用扩展程序",user_default_extensions:"用户默认扩展",user_default_extensions_label:"用户扩展",user_default_extensions_hint:"对用户默认启用的扩展。",miscellanous:"杂项",misc_disable_extensions:"禁用扩展程序",misc_disable_extensions_label:"禁用所有扩展程序",misc_hide_api:"隐藏 API",misc_hide_api_label:"隐藏钱包 api,扩展程序可以选择遵守",wallets_management:"钱包管理",funding_source_info:"资金来源信息",funding_source:"资金来源:{wallet_class}",node_balance:"节点余额:{balance} sats",lnbits_balance:"LNbits 余额:{balance} sats",funding_reserve_percent:"保留百分比: {percent} %",node_management:"节点管理",node_management_not_supported:"活动资金来源不支持节点管理",toggle_node_ui:"节点用户界面",toggle_public_node_ui:"公共节点用户界面",toggle_transactions_node_ui:"交易选项卡(在大型 CLN 节点上禁用)",invoice_expiry:"发票到期",invoice_expiry_label:"发票到期(秒)",fee_reserve:"费用储备",fee_reserve_msats:"以msats计的保留费",fee_reserve_percent:"以百分比计的保留费用",server_management:"服务器管理",base_url:"基本URL",base_url_label:"服务器的静态/基本网址",authentication:"认证",auth_token_expiry_label:"令牌过期分钟数",auth_token_expiry_hint:"令牌过期的剩余时间(分钟)",auth_allowed_methods_label:"允许的授权方法",auth_allowed_methods_hint:"选择授权方法",auth_nostr_label:"Nostr请求URL",auth_nostr_hint:"客户端将用于登录的绝对URL。",auth_google_ci_label:"谷歌客户ID",auth_google_ci_hint:"确保授权重定向URI包含https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google客户端密钥",auth_gh_client_id_label:"GitHub 客户端 ID",auth_gh_client_id_hint:"确保授权回调 URL 设置为 https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub客户端密码",auth_keycloak_label:"Keycloak 发现 URL",auth_keycloak_ci_label:"Keycloak 客户端 ID",auth_keycloak_ci_hint:"确保授权回调URL设置为https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak客户端密钥",currency_settings:"货币设置",allowed_currencies:"允许的货币",allowed_currencies_hint:"限制可用法定货币的数量",default_account_currency:"默认账户货币",default_account_currency_hint:"默认的会计货币",service_fee_label:"服务费 (%)",service_fee_hint:"每笔交易收取的费用 (%)",service_fee_max_label:"服务费最大值(聪)",service_fee_max_hint:"最大服务费以 (sats) 收取",fee_wallet:"费用钱包",fee_wallet_label:"费用钱包(钱包 ID)",fee_wallet_hint:"用于接收资金的钱包 ID",disable_fee:"禁用费用",disable_fee_internal:"禁用内部付款服务费",disable_fee_internal_desc:"禁用内部闪电支付的服务费",ui_management:"用户界面管理",ui_site_title:"网站标题",ui_site_tagline:"网站标语",ui_elements_enable:"在主页上启用元素",ui_elements_disable:"禁用主页上的元素",ui_toggle_elements_tip:"移除主页元素,例如“运行于”等。",ui_site_description:"网站描述",ui_site_description_hint:"使用纯文本、Markdown或原始HTML",ui_default_wallet_name:"默认钱包名称",lnbits_wallet:"LNbits 钱包",denomination:"面额",denomination_hint:"FakeWallet 代币的名称",ui_qr_code_logo:"二维码标志",ui_qr_code_logo_hint:"二维码中标志图像的 URL",ui_custom_badge:"自定义徽章",ui_custom_badge_label:"自定义徽章“慎用 - LNbits 钱包仍在测试阶段”",ui_custom_badge_color_label:"自定义徽章颜色",themes:"主题",themes_hint:"选择可供用户使用的主题",custom_logo:"自定义徽标",custom_logo_hint:"徽标图像的URL",ad_space_title:"广告位标题",ad_space_title_label:"由...支持",ad_slots:"广告位",ad_slots_hint:"广告网址和图像文件路径以CSV格式存储,扩展可以选择遵循。",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"启用广告",ads_disabled:"广告已禁用",user_management:"用户管理",admin_users:"管理员用户",admin_users_hint:"具有管理员权限的用户",admin_users_label:"用户ID",allowed_users:"允许的用户",allowed_users_hint:"仅这些用户可以使用LNbits",allowed_users_label:"用户 ID",allow_creation_user:"允许创建新用户",allow_creation_user_desc:"允许在索引页面上创建新用户",components:"组件",long_running_endpoints:"前五个长时间运行的端点",http_request_methods:"HTTP请求方法",http_response_codes:"HTTP响应代码",request_details:"请求详情",http_request_details:"HTTP请求详细信息"},window.localisation.nl={confirm:"Ja",server:"Server",theme:"Thema",site_customisation:"Site-aanpassing",funding:"Financiering",users:"Gebruikers",audit:"Controle",apps:"Apps",channels:"Kanalen",transactions:"Transacties",dashboard:"Dashboard",node:"Knooppunt",export_users:"Gebruikers exporteren",no_users:"Geen gebruikers gevonden",total_capacity:"Totale capaciteit",avg_channel_size:"Gem. Kanaalgrootte",biggest_channel_size:"Grootste Kanaalgrootte",smallest_channel_size:"Kleinste Kanaalgrootte",number_of_channels:"Aantal kanalen",active_channels:"Actieve Kanalen",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Open Kanaal",open:"Open",close_channel:"Kanaal Sluiten",close:"Sluiten",restart:"Server opnieuw opstarten",save:"Opslaan",save_tooltip:"Sla uw wijzigingen op",credit_debit:"Credit / Debet",credit_hint:"Druk op Enter om de rekening te crediteren",credit_label:"{denomination} te crediteren",credit_ok:"Succesvol crediteren/debiteren van virtuele gelden ({amount} sats). Betalingen zijn afhankelijk van de werkelijke fondsen op de financieringsbron.",restart_tooltip:"Start de server opnieuw op zodat wijzigingen van kracht worden",add_funds_tooltip:"Voeg geld toe aan een portemonnee.",reset_defaults:"Standaardinstellingen herstellen",reset_defaults_tooltip:"Wis alle instellingen en herstel de standaardinstellingen.",download_backup:"Databaseback-up downloaden",name_your_wallet:"Geef je {name} portemonnee een naam",paste_invoice_label:"Plak een factuur, betalingsverzoek of lnurl-code*",lnbits_description:"Gemakkelijk in te stellen en lichtgewicht, LNbits kan op elke lightning-netwerkfinancieringsbron draaien en zelfs LNbits zelf! U kunt LNbits voor uzelf laten draaien of gemakkelijk een bewaardersoplossing voor anderen bieden. Elke portemonnee heeft zijn eigen API-sleutels en er is geen limiet aan het aantal portemonnees dat u kunt maken. Het kunnen partitioneren van fondsen maakt LNbits een nuttige tool voor geldbeheer en als ontwikkelingstool. Extensies voegen extra functionaliteit toe aan LNbits, zodat u kunt experimenteren met een reeks toonaangevende technologieën op het bliksemschichtnetwerk. We hebben het ontwikkelen van extensies zo eenvoudig mogelijk gemaakt en als een gratis en opensource-project moedigen we mensen aan om hun eigen ontwikkelingen in te dienen.",export_to_phone:"Exporteren naar telefoon met QR-code",export_to_phone_desc:"Deze QR-code bevat uw portemonnee-URL met volledige toegang. U kunt het vanaf uw telefoon scannen om uw portemonnee van daaruit te openen.",wallet:"Wallet:",wallets:"Portemonnees",add_wallet:"Een nieuwe portemonnee toevoegen",delete_wallet:"Portemonnee verwijderen",delete_wallet_desc:"Deze hele portemonnee wordt verwijderd, de fondsen worden NIET TERUGGEVONDEN.",rename_wallet:"Portemonnee hernoemen",update_name:"Naam bijwerken",fiat_tracking:"Volgfunctie voor fiat-valuata",currency:"Valuta",update_currency:"Valuta bijwerken",press_to_claim:"Druk om bitcoin te claimen",donate:"Doneren",view_github:"Bekijken op GitHub",voidwallet_active:"VoidWallet is actief! Betalingen uitgeschakeld",use_with_caution:"GEBRUIK MET VOORZICHTIGHEID - {name} portemonnee is nog in BETA",service_fee:"Servicekosten: {amount} % per transactie",service_fee_max:"Servicekosten: {amount} % per transactie (max {max} sats)",service_fee_tooltip:"Transactiekosten in rekening gebracht door de LNbits serverbeheerder per uitgaande transactie",toggle_darkmode:"Donkere modus aan/uit",payment_reactions:"Betalingsreacties",view_swagger_docs:"Bekijk LNbits Swagger API-documentatie",api_docs:"API-documentatie",api_keys_api_docs:"Node URL, API-sleutels en API-documentatie",lnbits_version:"LNbits-versie",runs_on:"Draait op",paste:"Plakken",paste_from_clipboard:"Plakken van klembord",paste_request:"Verzoek plakken",create_invoice:"Factuur aanmaken",camera_tooltip:"Gebruik de camera om een factuur/QR-code te scannen",export_csv:"Exporteer naar CSV",chart_tooltip:"Toon grafiek",pending:"In behandeling",copy_invoice:"Kopieer factuur",withdraw_from:"Opnemen van",cancel:"Annuleren",scan:"Scannen",read:"Lezen",pay:"Betalen",memo:"Memo",date:"Datum",payment_processing:"Verwerking betaling...",not_enough_funds:"Onvoldoende saldo!",search_by_tag_memo_amount:"Zoeken op tag, memo, bedrag",invoice_waiting:"Factuur wachtend op betaling",payment_received:"Betaling ontvangen",payment_sent:"Betaling verzonden",receive:"ontvangen",send:"versturen",outgoing_payment_pending:"Uitgaande betaling in behandeling",drain_funds:"Geld opnemen",drain_funds_desc:"Dit is een LNURL-withdraw QR-code om alles uit deze portemonnee te halen. Deel deze code niet met anderen. Het is compatibel met balanceCheck en balanceNotify zodat jouw portemonnee continu geld kan blijven opnemen vanaf hier na de eerste opname.",i_understand:"Ik begrijp het",copy_wallet_url:"Kopieer portemonnee-URL",disclaimer_dialog_title:"Belangrijk!",disclaimer_dialog:"Inlogfunctionaliteit wordt uitgebracht in een toekomstige update. Zorg er nu voor dat je deze pagina als favoriet markeert om in de toekomst toegang te krijgen tot je portemonnee! Deze service is in BETA en we zijn niet verantwoordelijk voor mensen die de toegang tot hun fondsen verliezen.",no_transactions:"Er zijn nog geen transacties gedaan",manage:"Beheer",exchanges:"Beurzen",extensions:"Extensies",no_extensions:"Je hebt geen extensies geïnstalleerd :(",created:"Aangemaakt",search_extensions:"Zoekextensies",extension_sources:"Extensiebronnen",ext_sources_hint:"Repositories van waar de extensies kunnen worden gedownload",ext_sources_label:"Bron-URL (gebruik alleen de officiële LNbits-extensiebron en bronnen die je kunt vertrouwen)",warning:"Waarschuwing",repository:"Repository",confirm_continue:"Weet je zeker dat je wilt doorgaan?",manage_extension_details:"Installeren/verwijderen van extensie",install:"Installeren",uninstall:"Deïnstalleren",drop_db:"Gegevens verwijderen",enable:"Inschakelen",pay_to_enable:"Betalen om te activeren",enable_extension_details:"Schakel extensie in voor huidige gebruiker",disable:"Uitschakelen",delete:"Verwijderen",installed:"Geïnstalleerd",activated:"Geactiveerd",deactivated:"Gedeactiveerd",release_notes:"Release-opmerkingen",activate_extension_details:"Maak extensie beschikbaar/niet beschikbaar voor gebruikers",featured:"Uitgelicht",all:"Alles",only_admins_can_install:"Alleen beheerdersaccounts kunnen extensies installeren",admin_only:"Alleen beheerder",new_version:"Nieuwe Versie",extension_depends_on:"Afhankelijk van:",extension_rating_soon:"Beoordelingen binnenkort beschikbaar",extension_installed_version:"Geïnstalleerde versie",extension_uninstall_warning:"U staat op het punt de extensie voor alle gebruikers te verwijderen.",uninstall_confirm:"Ja, de-installeren",extension_db_drop_info:"Alle gegevens voor de extensie zullen permanent worden verwijderd. Er is geen manier om deze bewerking ongedaan te maken!",extension_db_drop_warning:"U staat op het punt alle gegevens voor de extensie te verwijderen. Typ de naam van de extensie om door te gaan:",extension_required_lnbits_version:"Deze release vereist ten minste LNbits-versie",min_version:"Minimum (inbegrepen)",max_version:"Maximum (uitgesloten)",payment_hash:"Betalings-hash",fee:"Kosten",amount:"Bedrag",amount_sats:"Bedrag (sats)",tag:"Label",unit:"Eenheid",description:"Beschrijving",expiry:"Vervaldatum",webhook:"Webhook",payment_proof:"Betalingsbewijs",update:"Bijwerken",update_available:"Update {version} beschikbaar!",latest_update:"U bent op de nieuwste versie {version}.",notifications:"Meldingen",no_notifications:"Geen meldingen",notifications_disabled:"LNbits-statusmeldingen zijn uitgeschakeld.",enable_notifications:"Schakel meldingen in",enable_notifications_desc:"Indien ingeschakeld zal het de laatste LNbits Status updates ophalen, zoals veiligheidsincidenten en updates.",enable_watchdog:"Inschakelen Watchdog",enable_watchdog_desc:"Indien ingeschakeld, wordt uw betaalbron automatisch gewijzigd naar VoidWallet als uw saldo lager is dan het saldo van LNbits. U zult dit na een update handmatig moeten inschakelen.",watchdog_interval:"Watchdog-interval",watchdog_interval_desc:"Hoe vaak de achtergrondtaak moet controleren op een killswitch signaal in het watchdog verschil [node_balance - lnbits_balance] (in minuten).",watchdog_delta:"Waakhond Delta",watchdog_delta_desc:"Limiet voordat de killswitch de financieringsbron verandert naar VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notificatiebron",notification_source_label:"Bron-URL (gebruik alleen de officiële LNbits-statusbron en bronnen die u vertrouwt)",more:"meer",less:"minder",releases:"Uitgaven",watchdog:"Waakhond",server_logs:"Serverlogboeken",ip_blocker:"IP-blokkering",security:"Beveiliging",security_tools:"Beveiligingstools",block_access_hint:"Toegang blokkeren per IP",allow_access_hint:"Toegang verlenen op basis van IP (zal geblokkeerde IP's overschrijven)",enter_ip:"Voer IP in en druk op enter",rate_limiter:"Snelheidsbegrenzer",wallet_limiter:"Portemonnee Limietsteller",wallet_limit_max_withdraw_per_day:"Maximale dagelijkse opname van wallet in sats (0 om uit te schakelen)",wallet_max_ballance:"Maximale portefeuillesaldo in sats (0 om uit te schakelen)",wallet_limit_secs_between_trans:"Min seconden tussen transacties per portemonnee (0 om uit te schakelen)",number_of_requests:"Aantal verzoeken",time_unit:"Tijdeenheid",minute:"minuut",second:"seconde",hour:"uur",disable_server_log:"Serverlog uitschakelen",enable_server_log:"Activeer Serverlog",coming_soon:"Functie binnenkort beschikbaar",session_has_expired:"Uw sessie is verlopen. Log alstublieft opnieuw in.",instant_access_question:"Wil je directe toegang?",login_with_user_id:"Inloggen met gebruikers-ID",or:"of",create_new_wallet:"Nieuwe portemonnee aanmaken",login_to_account:"Log in op je account",create_account:"Account aanmaken",account_settings:"Accountinstellingen",signin_with_nostr:"Doorgaan met Nostr",signin_with_google:"Inloggen met Google",signin_with_github:"Inloggen met GitHub",signin_with_keycloak:"Inloggen met Keycloak",username_or_email:"Gebruikersnaam of e-mail",password:"Wachtwoord",password_config:"Wachtwoordconfiguratie",password_repeat:"Wachtwoord herhalen",change_password:"Wachtwoord wijzigen",update_credentials:"Referenties bijwerken",update_pubkey:"Openbare Sleutel Bijwerken",set_password:"Wachtwoord instellen",invalid_password:"Wachtwoord moet ten minste 8 tekens bevatten",login:"Inloggen",register:"Registreren",username:"Gebruikersnaam",pubkey:"Publieke Sleutel",user_id:"Gebruikers-ID",email:"E-mail",first_name:"Voornaam",last_name:"Achternaam",picture:"Foto",verify_email:"E-mail verifiëren met",account:"Account",update_account:"Account bijwerken",invalid_username:"Ongeldige gebruikersnaam",auth_provider:"Auth Provider",my_account:"Mijn Account",back:"Terug",logout:"Afmelden",look_and_feel:"Uiterlijk en gedrag",toggle_gradient:"Gradiënt Schakelen",gradient_background:"Verloopachtergrond",language:"Taal",color_scheme:"Kleurenschema",admin_settings:"Beheerdersinstellingen",extension_cost:"Deze release vereist een betaling van minimaal {cost} sats.",extension_paid_sats:"U heeft al {paid_sats} sats betaald.",release_details_error:"Kan de gegevens van de release niet ophalen.",pay_from_wallet:"Betalen vanuit Portemonnee",wallet_required:"Wallet *",show_qr:"Toon QR",retry_install:"Opnieuw installeren",new_payment:"Nieuwe betaling maken",update_payment:"Betaling bijwerken",already_paid_question:"Heb je al betaald?",sell:"Verkopen",sell_require:"Vraag betaling om de extensie te activeren.",sell_info:"De {name} extensie vereist een betaling van minimaal {amount} sats om in te schakelen.",hide_empty_wallets:"Verberg lege portemonnees",recheck:"Opnieuw controleren",contributors:"Bijdragers",license:"Licentie",reset_key:"Hersteltoets",reset_password:"Wachtwoord Resetten",border_choices:"Randkeuzes",select_all:"Alles selecteren",nfc_supported:"NFC Ondersteund",nfc_not_supported:"NFC niet ondersteund",expire_date:"Vervaldatum:",hash:"Hash:",welcome_lnbits:"Welkom bij LNbits",setup_su_account:"Stel het Superuser-account hieronder in.",create_ticker_converter:"Maak Valuta Ticker Converter",enable_audit:"Audit inschakelen",recommended:"Aanbevolen",audit_desc:"HTTP-verzoeken vastleggen volgens de opgegeven filters",audit_record_req:"Verzoeklichaam registreren",audit_record_warning:"Waarschuwing:",audit_record_req_warning_1:"vertrouwelijke gegevens (zoals wachtwoorden) worden gelogd.",audit_record_req_warning_2:"de aanvraagbody kan een grote omvang hebben.",audit_record_use:"Gebruik het met voorzichtigheid.",audit_ip:"IP-adres vastleggen",audit_ip_desc:"Leg het IP-adres van de klant vast",audit_path_params:"Parameters van het pad opnemen",audit_query_params:"Queryparameters vastleggen",audit_http_methods:"Inclusief HTTP-methoden",audit_http_methods_hint:"Lijst van HTTP-methoden die moeten worden opgenomen. Lege lijsten betekenen alles.",audit_http_methods_label:"HTTP-methoden",audit_resp_codes:"Inclusief HTTP-responscodes",audit_resp_codes_hint:"Lijst van op te nemen HTTP-codes (regex-overeenkomst). Lege lijst betekent alles. Bijvoorbeeld: 4.*, 5.*",audit_resp_codes_label:"HTTP-responscode (regex)",audit_paths:"Inclusiepad",audit_paths_hint:"Lijst met paden die moeten worden opgenomen (regex match). Lege lijst betekent alles.",audit_paths_label:"HTTP-pad (regex)",audit_paths_exclude:"Paden uitsluiten",audit_paths_exclude_hint:"Lijst met paden die moeten worden uitgesloten (regex-overeenkomst). Een lege lijst betekent geen.",audit_paths_exclude_label:"HTTP-pad (regex)",exchange_providers:"Wisselaanbieders",admin_extensions:"Beheeruitbreidingen",admin_extensions_label:"Beheerdersuitbreidingen",admin_extensions_hint:"Alleen gebruikers met beheerdersrechten kunnen extensies gebruiken.",user_default_extensions:"Standaardextensies voor gebruikers",user_default_extensions_label:"Gebruikersuitbreidingen",user_default_extensions_hint:"Extensies die standaard voor de gebruikers worden ingeschakeld.",miscellanous:"Diversen",misc_disable_extensions:"Extensies uitschakelen",misc_disable_extensions_label:"Alle extensies uitschakelen",misc_hide_api:"API verbergen",misc_hide_api_label:"Verbergt de wallet-API, extensies kunnen ervoor kiezen dit te respecteren",wallets_management:"Beheer van portemonnees",funding_source_info:"Financieringsbroninfo",funding_source:"Financieringsbron: {wallet_class}",node_balance:"Node Balans: {balance} sats",lnbits_balance:"LNbits Saldo: {balance} sats",funding_reserve_percent:"Reservepercentage: {percent} %",node_management:"Nodebeheer",node_management_not_supported:"Nodebeheer wordt niet ondersteund door de actieve financieringsbron",toggle_node_ui:"Node UI",toggle_public_node_ui:"Openbare Node UI",toggle_transactions_node_ui:"Transacties Tabblad (Uitschakelen op grote CLN-nodes)",invoice_expiry:"Factuurvervaldatum",invoice_expiry_label:"Factuurverloop (seconden)",fee_reserve:"Toegangsvergoeding Reserve",fee_reserve_msats:"Reserveringskosten in msats",fee_reserve_percent:"Reserveringskosten in procent",server_management:"Serverbeheer",base_url:"Basis-URL",base_url_label:"Statisch/Basis-URL voor de server",authentication:"Authenticatie",auth_token_expiry_label:"Token vervalt over minuten",auth_token_expiry_hint:"Tijd in minuten totdat de token verloopt",auth_allowed_methods_label:"Toegestane autorisatiemethoden",auth_allowed_methods_hint:"Selecteer autorisatiemethoden",auth_nostr_label:"Nostr Aanvraag-URL",auth_nostr_hint:"Absolute URL die de klanten zullen gebruiken om in te loggen.",auth_google_ci_label:"Google Client-ID",auth_google_ci_hint:"Zorg ervoor dat de geautoriseerde omleidings-URL's https://{domain}/api/v1/auth/google/token bevatten.",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub client-ID",auth_gh_client_id_hint:"Zorg ervoor dat de autorisatie-callback-URL is ingesteld op https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Clientgeheim",auth_keycloak_label:"Keycloak Ontdekking URL",auth_keycloak_ci_label:"Keycloak-client-ID",auth_keycloak_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Clientgeheim",currency_settings:"Valuta-instellingen",allowed_currencies:"Toegestane valuta's",allowed_currencies_hint:"Beperk het aantal beschikbare fiatvaluta's",default_account_currency:"Standaardrekeningvaluta",default_account_currency_hint:"Standaardvaluta voor boekhouding",service_fee_label:"Servicekosten (%)",service_fee_hint:"Toeslag per transactie (%)",service_fee_max_label:"Servicekosten max (sats)",service_fee_max_hint:"Maximale servicekosten om in rekening te brengen in (sats)",fee_wallet:"Kosten Portemonnee",fee_wallet_label:"Kosten portemonnee (wallet ID)",fee_wallet_hint:"Wallet-ID om geld naar over te maken",disable_fee:"Kosten uitschakelen",disable_fee_internal:"Servicekosten uitschakelen voor interne betalingen",disable_fee_internal_desc:"Dienstenkosten uitschakelen voor interne Lightning-betalingen",ui_management:"UI-beheer",ui_site_title:"Site titel",ui_site_tagline:"Site-slogan",ui_elements_enable:"Elementen op de homepage inschakelen",ui_elements_disable:"Elementen op de homepage uitschakelen",ui_toggle_elements_tip:"Verwijder startpagina-elementen zoals 'werkt op' enz.",ui_site_description:"Sitebeschrijving",ui_site_description_hint:"Gebruik platte tekst, Markdown, of ruwe HTML",ui_default_wallet_name:"Standaard Wallet Naam",lnbits_wallet:"LNbits-portemonnee",denomination:"Denominatie",denomination_hint:"De naam voor de FakeWallet token",ui_qr_code_logo:"QR-code-logo",ui_qr_code_logo_hint:"URL naar logo-afbeelding in QR-code",ui_custom_badge:"Aangepaste badge",ui_custom_badge_label:"Aangepaste Badge 'GEBRUIK MET VOORZICHTIGHEID - LNbits-portemonnee is nog in BÈTA'",ui_custom_badge_color_label:"Aangepaste Badge Kleur",themes:"Thema's",themes_hint:"Kies thema's beschikbaar voor gebruikers",custom_logo:"Aangepast logo",custom_logo_hint:"URL naar logo-afbeelding",ad_space_title:"Advertentieruimte Titel",ad_space_title_label:"Ondersteund door",ad_slots:"Advertentieblokken",ad_slots_hint:"Ad URL en afbeeldingspad in CSV-formaat, extensies kunnen ervoor kiezen te honoreren",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Advertenties ingeschakeld",ads_disabled:"Advertenties uitgeschakeld",user_management:"Gebruikersbeheer",admin_users:"Beheerdersgebruikers",admin_users_hint:"Gebruikers met beheerdersrechten",admin_users_label:"Gebruikers-ID",allowed_users:"Toegestane gebruikers",allowed_users_hint:"Alleen deze gebruikers kunnen LNbits gebruiken",allowed_users_label:"Gebruikers-ID",allow_creation_user:"Sta het aanmaken van nieuwe gebruikers toe",allow_creation_user_desc:"Sta de aanmaak van nieuwe gebruikers op de indexpagina toe",components:"Componenten",long_running_endpoints:"Top 5 langlopende eindpunten",http_request_methods:"HTTP-aanvraagmethoden",http_response_codes:"HTTP-responscodes",request_details:"Aanvraagdetails",http_request_details:"HTTP-verzoekdetails"},window.localisation.pi={confirm:"Aye",server:"Cap`n",theme:"Theme",site_customisation:"Site Customisation",funding:"Funding",users:"Buccaneers",audit:"Arrr-dit",apps:"Arrrrplications",channels:"Channels",transactions:"Pirate Transactions and loot",dashboard:"Arrr-board",node:"Node",export_users:"Export Mateys",no_users:"No swabbies found",total_capacity:"Total Capacity",avg_channel_size:"Avg. Channel Size",biggest_channel_size:"Largest Bilge Size",smallest_channel_size:"Smallest Channel Size",number_of_channels:"Nummer o' Channels",active_channels:"Active Channels",connect_peer:"Connect Peer",connect:"Connect",open_channel:"Open Channel",open:"Open yer hatches",close_channel:"Shut Yer Gob Channel",close:"Batten down the hatches, we be closin",restart:"Arr, restart Cap`n",save:"Bury Treasure",save_tooltip:"Bury yer changes, matey",credit_debit:"Credit / Debit",credit_hint:"Press Enter to credit account and make it richer",credit_label:"{denomination} to credit, arr!",credit_ok:"Success creditin'/debitin' virtual funds ({amount} sats). Payments depend on actual funds on fundin' source.",restart_tooltip:"Restart the Cap`n for changes to take effect, arr!",add_funds_tooltip:"Add doubloons to a chest and make it heavier",reset_defaults:"Reset to Davy Jones Locker",reset_defaults_tooltip:"Scuttle all settings and reset to Davy Jones Locker. Aye, start anew!",download_backup:"Download database booty",name_your_wallet:"Name yer {name} treasure chest",paste_invoice_label:"Paste a booty, payment request or lnurl code, matey!",lnbits_description:"Arr, easy to set up and lightweight, LNbits can run on any Lightning Network funding source and even LNbits itself! Ye can run LNbits for yourself, or easily offer a custodian solution for others. Each chest has its own API keys and there be no limit to the number of chests ye can make. Being able to partition booty makes LNbits a useful tool for money management and as a development tool. Arr, extensions add extra functionality to LNbits so ye can experiment with a range of cutting-edge technologies on the lightning network. We have made developing extensions as easy as possible, and as a free and open-source project, we encourage scallywags to develop and submit their own.",export_to_phone:"Export to Phone with QR Code, me hearties",export_to_phone_desc:"This QR code contains yer chest URL with full access. Ye can scan it from yer phone to open yer chest from there, arr!",wallet:"Booty Chest:",wallets:"Treasure Chests",add_wallet:"Add a new chest and fill it with doubloons!",delete_wallet:"Scuttle the Chest",delete_wallet_desc:"This whole chest will be scuttled, the booty will be UNRECOVERABLE. Aye, be warned!",rename_wallet:"Rename the Chest, me hearty",update_name:"Update name like a captain",fiat_tracking:"Trackin' o' the treasure",currency:"Curr'nsey",update_currency:"Update doubloons",press_to_claim:"Press to claim gold doubloons, matey!",donate:"Donate like a true pirate!",view_github:"View on GitHub and find treasures",voidwallet_active:"VoidWallet be active! Payments disabled",use_with_caution:"USE WITH CAUTION - {name} chest be still in BETA. Aye, be careful!",service_fee:"Service fee: {amount} % per transaction",service_fee_max:"Service fee: {amount} % per transaction (max {max} sats)",service_fee_tooltip:"Service fee charged by the LNbits server admin per goin' transaction",toggle_darkmode:"Toggle Dark Mode, arr!",payment_reactions:"Payment Reactions",view_swagger_docs:"View LNbits Swagger API docs and learn the secrets",api_docs:"API docs for the scallywags",api_keys_api_docs:"Node URL, API keys and API docs",lnbits_version:"LNbits version, arr!",runs_on:"Runs on, matey",paste:"Stow",paste_from_clipboard:"Paste from clipboard",paste_request:"Paste Request and find treasures",create_invoice:"Create Booty Request and get rich, me hearties!",camera_tooltip:"Use spyglass to scan a booty/QR, arr!",export_csv:"Export to CSV and keep track of the booty",chart_tooltip:"Show ye chart, me hearty",pending:"Pendin like a ship at anchor",copy_invoice:"Copy booty request, arrr",withdraw_from:"Withdraw from",cancel:"Abandon ship! We be retreatin",scan:"Avast! Scan me beauty, arrr",read:"Read it, if ye dare",pay:"Pay up or walk the plank, ye scallywag",memo:"Message in a bottle, argh",date:"Date of the map, me matey",payment_processing:"Processing yer payment... don´t make me say it again",not_enough_funds:"Arrr, ye don´t have enough doubloons! Walk the plank!",search_by_tag_memo_amount:"Search by tag, message, or booty amount, savvy",invoice_waiting:"Invoice waiting to be plundered, arrr",payment_received:"Payment Received like a treasure, argh",payment_sent:"Payment Sent, hoist the colors! We´ve got some doubloons!",receive:"booty",send:"hoist",outgoing_payment_pending:"Outgoing payment pending in the port, ye scurvy dog",drain_funds:"Plunder all the doubloons, ye buccaneer",drain_funds_desc:"This be an LNURL-withdraw QR code for slurpin everything from this wallet. Don`t share with anyone. It be compatible with balanceCheck and balanceNotify so yer wallet may keep pullin` the funds continuously from here after the first withdraw.",i_understand:"I understand, yo ho ho and a bottle of rum!",copy_wallet_url:"Copy wallet URL like a map, savvy",disclaimer_dialog_title:"Avast!",disclaimer_dialog:"Login functionality to be released in a future update, for now, make sure ye bookmark this page for future access to your booty! This service be in BETA, and we hold no responsibility for people losing access to doubloons.",no_transactions:"No transactions made yet, me hearties. Belay that!",manage:"Manage, me hearty",exchanges:"Exchanges",extensions:"Yer Extensions, ye scurvy dog",no_extensions:"Ye don't have any extensions installed, ye scallywag :(. Where be yer loot?",created:"Created like a legend, savvy",search_extensions:"Search fer extensions",extension_sources:"Extension Sources",ext_sources_hint:"Repositories from wharrr the extensions can be downloaded",ext_sources_label:"Source URL (only use th' official LNbits extension source, and sources ye can trust)",warning:"Avast",repository:"Repository",confirm_continue:"Be ye sure ye want t' proceed?",manage_extension_details:"Install/uninstall extension",install:"Set sail",uninstall:"Avaast",drop_db:"Scuttle Data",enable:"Enable",pay_to_enable:"Pay To Hoist",enable_extension_details:"Enable extension fer th' current user",disable:"Disablin'",delete:"Blow down",installed:"Installed",activated:"Activated",deactivated:"Deactivated",release_notes:"Release Notes",activate_extension_details:"Make extension available/unavailable fer users",featured:"Featured",all:"Arr",only_admins_can_install:"(Only admin accounts can install extensions)",admin_only:"Cap'n Only",new_version:"New Version",extension_depends_on:"Depends on:",extension_rating_soon:"Ratings a'comin' soon",extension_installed_version:"Installed version",extension_uninstall_warning:"Ye be about t' remove th' extension fer all hands.",uninstall_confirm:"Aye, Uninstall",extension_db_drop_info:"All data fer th' extension will be permanently deleted. There be no way to undo this operation!",extension_db_drop_warning:"Ye be about to scuttle all data fer th' extension. Please scribble th' extension name to continue:",extension_required_lnbits_version:"This release be needin' at least LNbits version",min_version:"Minimum (inclooded)",max_version:"Maximum (excluded)",payment_hash:"Payment Hash like a treasure map, arrr",fee:"Fee like a toll to cross a strait, matey",amount:"Amount of doubloons, arrr",amount_sats:"Amount (sats)",tag:"Tag",unit:"Unit of measurement like a fathom, ye buccaneer",description:"Description like a tale of adventure, arrr",expiry:"Expiry like the food on a ship, ye landlubber",webhook:"Webhook like a fishing line, arrr",payment_proof:"Payment Proof like a seal of authenticity, argh",update:"Updatin'",update_available:"Update {version} available, me matey!",latest_update:"Ye be on th' latest version {version}.",notifications:"Notificashuns",no_notifications:"No noticin's",notifications_disabled:"LNbits status notifications be disabled, arr!",enable_notifications:"Enable Notifications",enable_notifications_desc:"If ye be allowin' it, it'll be fetchin' the latest LNbits Status updates, like security incidents and updates.",enable_watchdog:"Enable Seadog",enable_watchdog_desc:"If enabled, it will swap yer treasure source t' VoidWallet on its own if yer balance be lower than th' LNbits balance. Ye'll need t' enable by hand after an update.",watchdog_interval:"Seadog Interval",watchdog_interval_desc:"How oft th' background task should be checkin' fer a killswitch signal in th' seadog delta [node_balance - lnbits_balance] (in minutes), arr.",watchdog_delta:"Seadog Delta",watchdog_delta_desc:"Limit afore killswitch changes fundin' source to VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notification Source",notification_source_label:"Source URL (only use th' official LNbits status source, and sources ye can trust)",more:"Arr, 'tis more.",less:"Arr, 'tis more fewer.",releases:"Releases",watchdog:"Seadog",server_logs:"Server Logs",ip_blocker:"IP Blockar",security:"Securrrity",security_tools:"Securrrity tools",block_access_hint:"Block access by IP",allow_access_hint:"Grant permission by IP (will override barred IPs)",enter_ip:"Enter IP and hit enter",rate_limiter:"Rate Limiter",wallet_limiter:"Pouch Limitar",wallet_limit_max_withdraw_per_day:"Max daily wallet withdrawal in sats (0 for no limit, -1 to block withdrawal)",wallet_max_ballance:"Purse max heaviness in sats (0 fer scuttle)",wallet_limit_secs_between_trans:"Min secs 'tween transactions per wallet (0 to disable)",number_of_requests:"Number o' requests",time_unit:"time bein'",minute:"minnit",second:"second",hour:"hour",disable_server_log:"Disabl' {Server} Log",enable_server_log:"Enable Server Log",coming_soon:"Feature comin' soon",session_has_expired:"Yer session has expired. Please login again.",instant_access_question:"Be wantin' quick entry, aye?",login_with_user_id:"Login with user ID",or:"arr",create_new_wallet:"Create New Wallet",login_to_account:"Log in to yer account",create_account:"Create account",account_settings:"Account Settin's",signin_with_nostr:"Continue with Nostr",signin_with_google:"Sign in wit' Google",signin_with_github:"Sign in wit' GitHub",signin_with_keycloak:"Sign in wit' Keycloak",username_or_email:"Usarrrname or Email",password:"Passwarrd",password_config:"Passwarrd Config",password_repeat:"Passwarrd repeat",change_password:"Change Passwarrd",update_credentials:"Hoist New Credentials",update_pubkey:"Swab Public Key",set_password:"Set yer Secret Code",invalid_password:"Passwarrd must be havin' at leest 8 charrracters",login:"Log in",register:"Sign on",username:"Username",pubkey:"Public Key",user_id:"User ID",email:"Email",first_name:"Firrrst Name",last_name:"Surname",picture:"pictur'",verify_email:"Verify email with",account:"Arrrccount",update_account:"Updatin' Arrrccount",invalid_username:"Username be not valid, matey!",auth_provider:"Auth Provider becometh Auth Provider, ye see?",my_account:"Me Arrrccount",back:"Return",logout:"Log out yer session",look_and_feel:"Look and Feel",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",language:"Langwidge",color_scheme:"Colour Scheme",admin_settings:"Admin Settin's",extension_cost:"This release be needin' a payment o' minimum {cost} sats, arr.",extension_paid_sats:"Ye have already paid {paid_sats} sats.",release_details_error:"Cannot get th' release details.",pay_from_wallet:"Pay from ye Wallet",wallet_required:"Doubloon Locker *",show_qr:"Show QR",retry_install:"Try 'nstallin' Again",new_payment:"Make New Payment",update_payment:"Be Updatin' Payment",already_paid_question:"Have ye already paid?",sell:"Sell",sell_require:"Ask fer payment to enable extension",sell_info:"The {name} extension requires a payment of minimum {amount} sats to enable.",hide_empty_wallets:"Stow empty wallets",recheck:"Recheck",contributors:"Contributors",license:"License",reset_key:"Reset Key",reset_password:"Reset Password",border_choices:"Border Choices",select_all:"Select All",nfc_supported:"NFC Supported",nfc_not_supported:"NFC not Supported",expire_date:"Expire Date:",hash:"Mizzenmast:",welcome_lnbits:"Welcome t' LNbits",setup_su_account:"Set up the Superuser account below.",create_ticker_converter:"Create Currency Ticker Converter",enable_audit:"Set Sail Fer Auditin'",recommended:"Recommended",audit_desc:"Record HTTP requests accordin' with the specified filters",audit_record_req:"Record Request Body",audit_record_warning:"Arrrning:",audit_record_req_warning_1:"confidential data (like passwords) will be logged.",audit_record_req_warning_2:"th' request body can have large size.",audit_record_use:"Use it with caution.",audit_ip:"Log IP Address",audit_ip_desc:"Record the IP address o' the client",audit_path_params:"Record Path Parameters",audit_query_params:"Rransack th' Query Parameters",audit_http_methods:"Include HTTP Methods",audit_http_methods_hint:"List o' HTTP methods to be included. Empty lists means all.",audit_http_methods_label:"HTTP Methods",audit_resp_codes:"Include HTTP Response Codes",audit_resp_codes_hint:"List o' HTTP codes t' be included (regex match). Empty lists means all. Eg: 4.*, 5.*",audit_resp_codes_label:"HTTP Response code (regex)",audit_paths:"Include Paths",audit_paths_hint:"List o' paths t' be included (regex match). Empty list means all.",audit_paths_label:"HTTP Path (regex)",audit_paths_exclude:"Exclude Paths",audit_paths_exclude_hint:"List o' paths t' be excluded (regex match). Empty list means none.",audit_paths_exclude_label:"HTTP Path (regex)",exchange_providers:"Trade Buccaneers",admin_extensions:"Admin Extensions",admin_extensions_label:"Admin extensions",admin_extensions_hint:"Extensions only user with admin privileges can use",user_default_extensions:"Crew Mate Default Extensions",user_default_extensions_label:"User extensions",user_default_extensions_hint:"Extensions that will be enabled by default fer the users.",miscellanous:"Miscelaneous",misc_disable_extensions:"Belay Extensions",misc_disable_extensions_label:"Disable all extensions",misc_hide_api:"Stow API",misc_hide_api_label:"Burieds wallet api, extensions be able t' choose t' honor",wallets_management:"Wallets Management",funding_source_info:"Loot Source Info",funding_source:"Loot Source: {wallet_class}",node_balance:"Node Balance: {balance} doubloons",lnbits_balance:"LNbits Balance: {balance} pieces o' eight",funding_reserve_percent:"Reserve Percent: {percent} %",node_management:"Node Management",node_management_not_supported:"Node Management not be supported by active funding source",toggle_node_ui:"Node Main Deck",toggle_public_node_ui:"Public Node UI",toggle_transactions_node_ui:"Transactions Tab (Disable on large CLN nodes)",invoice_expiry:"Invoice Expiry",invoice_expiry_label:"Invoice expiry (seconds)",fee_reserve:"Plunder Reserve",fee_reserve_msats:"Reserve fee in msats",fee_reserve_percent:"Reserve fee in percent",server_management:"Server Management",base_url:"Base URL",base_url_label:"Static/Base url fer the server",authentication:"Authent Mateys!",auth_token_expiry_label:"Token expire minutes",auth_token_expiry_hint:"Time in minutes until th' token expires",auth_allowed_methods_label:"Allowed authorizashun methods",auth_allowed_methods_hint:"Select arrrrthorization methods",auth_nostr_label:"Nostr Request URL",auth_nostr_hint:"Absolute URL that th' clients will use t' login.",auth_google_ci_label:"Google Client ID",auth_google_ci_hint:"Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub Client ID",auth_gh_client_id_hint:"Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Keycloak Discovery URL",auth_keycloak_ci_label:"Keycloak Client ID",auth_keycloak_ci_hint:"Make sure thant th' authorization callback URL be set t' https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",currency_settings:"Doubloon Settin's",allowed_currencies:"Allo'ed Doubloons",allowed_currencies_hint:"Limit the number of available fiat doubloons",default_account_currency:"Default Account Currency",default_account_currency_hint:"Default dubloon fer accountin'",service_fee_label:"Service fee (%).",service_fee_hint:"Fee charged per tx (%)",service_fee_max_label:"Service fee max (sats)",service_fee_max_hint:"Max service fee to charge in (sats)",fee_wallet:"Fee Wallet",fee_wallet_label:"Tariff wallet (wallet ID)",fee_wallet_hint:"Wallett ID t' send funds t'",disable_fee:"Disable Fee",disable_fee_internal:"Disable Service Fee for Internal Payments",disable_fee_internal_desc:"Disable Service Fee fer Internal Lightning Payments",ui_management:"UI Management",ui_site_title:"Site Title",ui_site_tagline:"Site Tagline",ui_elements_enable:"Set course for the homepage elements!",ui_elements_disable:"Disarm elements on homepage",ui_toggle_elements_tip:"Be rid of homepage elements like 'runs on' etc",ui_site_description:"Site Description",ui_site_description_hint:"Use plain text, Markdown, or raw HTML",ui_default_wallet_name:"Default Wallet Name",lnbits_wallet:"LNbits wallet",denomination:"Denomination",denomination_hint:"The name fer the FakeWallet doubloon",ui_qr_code_logo:"QR Code Logo",ui_qr_code_logo_hint:"URL t' logo image in QR code",ui_custom_badge:"Custom Badge",ui_custom_badge_label:"Custom Badge 'USE WITH CAUTION - LNbits wallet be still in BETA'",ui_custom_badge_color_label:"Custom Bauble Color",themes:"Themes",themes_hint:"Choose themes available for users",custom_logo:"Custom Logo",custom_logo_hint:"URL to logo image",ad_space_title:"Ad Space Title",ad_space_title_label:"Supported by",ad_slots:"Adversment Sprogs",ad_slots_hint:"Ad url an' image filepaths in CSV format, extensions can choose t' honor",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Ads Enabled",ads_disabled:"Ads Keelhauled",user_management:"User Matey-handlin'",admin_users:"Admin Scurvy Dogs",admin_users_hint:"Scallywags with cap'n privileges",admin_users_label:"User ID",allowed_users:"Allowed Users",allowed_users_hint:"Only these scallywags can use LNbits",allowed_users_label:"User ID",allow_creation_user:"Permit creation of new scallywags",allow_creation_user_desc:"Allow creation o' new users on th' index page",components:"Components",long_running_endpoints:"Top 5 Long Runnin' Endpoints",http_request_methods:"HTTP Request Methods",http_response_codes:"HTTP Response Codes",request_details:"Request Details",http_request_details:"HTTP Request Details"},window.localisation.pl={confirm:"Tak",server:"Serwer",theme:"Motyw",site_customisation:"Dostosowanie witryny",funding:"Finansowanie",users:"Użytkownicy",audit:"Audyt",apps:"Aplikacje",channels:"Kanały",transactions:"Transakcje",dashboard:"Panel kontrolny",node:"Węzeł",export_users:"Eksportuj użytkowników",no_users:"Nie znaleziono użytkowników",total_capacity:"Całkowita Pojemność",avg_channel_size:"Średni rozmiar kanału",biggest_channel_size:"Największy Rozmiar Kanału",smallest_channel_size:"Najmniejszy Rozmiar Kanału",number_of_channels:"Ilość kanałów",active_channels:"Aktywne kanały",connect_peer:"Połącz z węzłem równorzędnym",connect:"Połącz",open_channel:"Otwarty Kanał",open:"Otwórz",close_channel:"Zamknij kanał",close:"Zamknij",restart:"Restart serwera",save:"Zapisz",save_tooltip:"Zapisz zmiany",credit_debit:"Kredyt / Debet",credit_hint:"Naciśnij Enter aby doładować konto",credit_label:"{denomination} doładowanie",credit_ok:"Pomyślne zaksięgowanie/obciążenie wirtualnych środków ({amount} sats). Płatności zależą od rzeczywistych środków na źródle finansowania.",restart_tooltip:"Zrestartuj serwer aby aktywować zmiany",add_funds_tooltip:"Dodaj środki do portfela.",reset_defaults:"Powrót do ustawień domyślnych",reset_defaults_tooltip:"Wymaż wszystkie ustawienia i ustaw domyślne.",download_backup:"Pobierz kopię zapasową bazy danych",name_your_wallet:"Nazwij swój portfel {name}",paste_invoice_label:"Wklej fakturę, żądanie zapłaty lub kod lnurl *",lnbits_description:"Łatwy i lekki w konfiguracji, LNbits może działać w oparciu o dowolne źródło finansowania w sieci lightning czy nawet inną instancję LNbits! Możesz uruchomić instancję LNbits dla siebie lub dla innych. Każdy portfel ma swoje klucze API i nie ma ograniczeń jeśli chodzi o ilość portfeli. LNbits umożliwia dzielenie środków w celu zarządzania nimi, jest również dobrym narzędziem deweloperskim. Rozszerzenia zwiększają funkcjonalność LNbits co umożliwia eksperymentowanie z nowym technologiami w sieci lightning. Tworzenie rozszerzeń jest proste dlatego zachęcamy innych deweloperów do tworzenia dodatkowych funkcjonalności i wysyłanie do nas PR",export_to_phone:"Eksport kodu QR na telefon",export_to_phone_desc:"Ten kod QR zawiera adres URL Twojego portfela z pełnym dostępem do niego. Możesz go zeskanować na swoim telefonie aby otworzyć na nim ten portfel.",wallet:"Portfel:",wallets:"Portfele",add_wallet:"Dodaj portfel",delete_wallet:"Usuń portfel",delete_wallet_desc:"Ten portfel zostanie usunięty, środków na nim zgromadzonych NIE BĘDZIE MOŻNA ODZYSKAĆ.",rename_wallet:"Zmień nazwę portfela",update_name:"Zaktualizuj nazwę",fiat_tracking:"Śledzenie Fiata",currency:"Waluta",update_currency:"Aktualizuj walutę",press_to_claim:"Naciśnij aby odebrać Bitcoiny",donate:"Podaruj",view_github:"Otwórz GitHub",voidwallet_active:"VoidWallet jest aktywny! Płatności są niemożliwe",use_with_caution:"KORZYSTAJ Z ROZWAGĄ - portfel {name} jest w wersji BETA",service_fee:"Opłata serwisowa: {amount} % za transakcję",service_fee_max:"Opłata serwisowa: {amount} % za transakcję (maks {max} sat)",service_fee_tooltip:"Opłata serwisowa pobierana przez administratora serwera LNbits za każdą wychodzącą transakcję",toggle_darkmode:"Tryb nocny",payment_reactions:"Reakcje na płatność",view_swagger_docs:"Dokumentacja Swagger API",api_docs:"Dokumentacja API",api_keys_api_docs:"Adres URL węzła, klucze API i dokumentacja API",lnbits_version:"Wersja LNbits",runs_on:"Działa na",paste:"Wklej",paste_from_clipboard:"Wklej ze schowka",paste_request:"Wklej żądanie",create_invoice:"Utwórz fakturę",camera_tooltip:"Użyj kamery aby zeskanować fakturę lub kod QR",export_csv:"Eksport do CSV",chart_tooltip:"Wykres",pending:"W toku",copy_invoice:"Skopiuj fakturę",withdraw_from:"Wypłać z",cancel:"Anuluj",scan:"Skanuj",read:"Odczytaj",pay:"Zapłać",memo:"Memo",date:"Data",payment_processing:"Przetwarzam płatność...",not_enough_funds:"Brak wystarczających środków!",search_by_tag_memo_amount:"Szukaj po tagu, memo czy wartości",invoice_waiting:"Faktura oczekuje na zapłatę",payment_received:"Otrzymano płatność",payment_sent:"Wysłano płatność",receive:"odbierać",send:"wysłać",outgoing_payment_pending:"Płatność wychodząca w toku",drain_funds:"Opróżnij środki",drain_funds_desc:"To jest kod QR służący do opróżnienia portfela (LNURL-withdraw). Nie udostępniaj go nikomu. Ten kod jest kompatybilny z funkcjami, które umożliwiają wielokrotne żądania aż do zupełnego opróżnienia portfela.",i_understand:"Rozumiem",copy_wallet_url:"Skopiuj URL portfela",disclaimer_dialog_title:"Ważne!",disclaimer_dialog:"Funkcja logowania zostanie uruchomiona w przyszłości. Póki co upewnij się, że zapisałeś adres URL tej strony aby mieć dostęp do tego portfela. Nie udostępniaj adresu tej strony nikomu, kto nie ma mieć do tego portfela dostępu! Ta usługa działa w wersji BETA, nie odpowiadamy za utratę dostępu do środków przez osoby używające LNbits.",no_transactions:"Brak transakcji",manage:"Zarządzaj",exchanges:"Giełdy",extensions:"Rozszerzenia",no_extensions:"Nie masz zainstalowanych żadnych rozszerzeń :(",created:"Utworzono",search_extensions:"Szukaj rozszerzeń",extension_sources:"Źródła rozszerzeń",ext_sources_hint:"Repozytoria, z których można pobrać rozszerzenia",ext_sources_label:"URL źródłowy (używaj tylko oficjalnego źródła rozszerzenia LNbits oraz źródeł, którym możesz zaufać)",warning:"Ostrzeżenie",repository:"Repozytorium",confirm_continue:"Czy na pewno chcesz kontynuować?",manage_extension_details:"Instaluj/odinstaluj rozszerzenie",install:"Zainstaluj",uninstall:"Odinstaluj",drop_db:"Usuń dane",enable:"Włącz",pay_to_enable:"Zapłać, aby włączyć",enable_extension_details:"Włącz rozszerzenie dla aktualnego użytkownika",disable:"Wyłącz",delete:"Usuń",installed:"Zainstalowano",activated:"Aktywowany",deactivated:"Dezaktywowany",release_notes:"Informacje o wydaniu",activate_extension_details:"Udostępnij/nie udostępniaj rozszerzenia użytkownikom",featured:"Polecane",all:"Wszystko",only_admins_can_install:"Tylko konta administratorów mogą instalować rozszerzenia",admin_only:"Tylko dla administratora",new_version:"Nowa wersja",extension_depends_on:"Zależy od:",extension_rating_soon:"Oceny będą dostępne wkrótce",extension_installed_version:"Zainstalowana wersja",extension_uninstall_warning:"Za chwilę usuniesz rozszerzenie dla wszystkich użytkowników.",uninstall_confirm:"Tak, Odinstaluj",extension_db_drop_info:"Wszystkie dane dla rozszerzenia zostaną trwale usunięte. Nie ma sposobu, aby cofnąć tę operację!",extension_db_drop_warning:"Za chwilę usuniesz wszystkie dane dla rozszerzenia. Proszę wpisz nazwę rozszerzenia, aby kontynuować:",extension_required_lnbits_version:"To wymaga przynajmniej wersji LNbits",min_version:"Minimum (włącznie)",max_version:"Maksymalna (wyłączona)",payment_hash:"Hash Płatności",fee:"Opłata",amount:"Wartość",amount_sats:"Kwota (sats)",tag:"Etykieta",unit:"Jednostka",description:"Opis",expiry:"Wygasa",webhook:"Webhook",payment_proof:"Potwierdzenie płatności",update:"Aktualizuj",update_available:"Aktualizacja {version} dostępna!",latest_update:"Korzystasz z najnowszej wersji {version}.",notifications:"Powiadomienia",no_notifications:"Brak powiadomień",notifications_disabled:"Powiadomienia o statusie LNbits są wyłączone.",enable_notifications:"Włącz powiadomienia",enable_notifications_desc:"Jeśli ta opcja zostanie włączona, będzie pobierać najnowsze informacje o statusie LNbits, takie jak incydenty bezpieczeństwa i aktualizacje.",enable_watchdog:"Włącz Watchdog",enable_watchdog_desc:"Jeśli zostanie włączone, automatycznie zmieni źródło finansowania na VoidWallet, jeśli saldo jest niższe niż saldo LNbits. Po aktualizacji trzeba będzie włączyć ręcznie.",watchdog_interval:"Interwał Watchdog",watchdog_interval_desc:"Jak często zadanie w tle powinno sprawdzać sygnał wyłącznika awaryjnego w delcie strażnika [node_balance - lnbits_balance] (w minutach).",watchdog_delta:"Strażnik Delta",watchdog_delta_desc:"Limit przed aktywacją wyłącznika zmienia źródło finansowania na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stan",notification_source:"Źródło powiadomień",notification_source_label:"Adres URL źródła (używaj tylko oficjalnego źródła statusu LNbits oraz źródeł, którym możesz zaufać)",more:"więcej",less:"mniej",releases:"Wydania",watchdog:"Pies gończy",server_logs:"Dzienniki serwera",ip_blocker:"Blokada IP",security:"Bezpieczeństwo",security_tools:"Narzędzia bezpieczeństwa",block_access_hint:"Zablokuj dostęp przez IP",allow_access_hint:"Zezwól na dostęp przez IP (zignoruje zablokowane adresy IP)",enter_ip:"Wpisz adres IP i naciśnij enter",rate_limiter:"Ogranicznik Częstotliwości",wallet_limiter:"Ogranicznik Portfela",wallet_limit_max_withdraw_per_day:"Maksymalna dzienna wypłata z portfela w satoshi (0 aby wyłączyć)",wallet_max_ballance:"Maksymalny stan portfela w satoshi (0 aby wyłączyć)",wallet_limit_secs_between_trans:"Min sekund pomiędzy transakcjami na portfel (0 aby wyłączyć)",number_of_requests:"Liczba żądań",time_unit:"Jednostka czasu",minute:"minuta",second:"sekunda",hour:"godzina",disable_server_log:"Wyłącz log serwera",enable_server_log:"Włącz dziennik serwera",coming_soon:"Funkcja wkrótce będzie dostępna",session_has_expired:"Twoja sesja wygasła. Proszę zaloguj się ponownie.",instant_access_question:"Chcesz mieć natychmiastowy dostęp?",login_with_user_id:"Zaloguj się za pomocą identyfikatora użytkownika",or:"lub",create_new_wallet:"Utwórz nowy portfel",login_to_account:"Zaloguj się do swojego konta",create_account:"Załóż konto",account_settings:"Ustawienia konta",signin_with_nostr:"Kontynuuj z Nostr",signin_with_google:"Zaloguj się przez Google",signin_with_github:"Zaloguj się przez GitHub",signin_with_keycloak:"Zaloguj się przez Keycloak",username_or_email:"Nazwa użytkownika lub Email",password:"Hasło",password_config:"Konfiguracja Hasła",password_repeat:"Powtórz hasło",change_password:"Zmień hasło",update_credentials:"Aktualizuj dane logowania",update_pubkey:"Zaktualizuj klucz publiczny",set_password:"Ustaw hasło",invalid_password:"Hasło musi zawierać co najmniej 8 znaków",login:"Logowanie",register:"Zarejestruj",username:"Nazwa użytkownika",pubkey:"Klucz publiczny",user_id:"Identyfikator użytkownika",email:"Email",first_name:"Imię",last_name:"Nazwisko",picture:"Zdjęcie",verify_email:"Zweryfikuj email za pomocą",account:"Konto",update_account:"Aktualizuj konto",invalid_username:"Nieprawidłowa nazwa użytkownika",auth_provider:"Dostawca uwierzytelniania",my_account:"Moje Konto",back:"Wstecz",logout:"Wyloguj",look_and_feel:"Wygląd i zachowanie",toggle_gradient:"Przełącz gradient",gradient_background:"Tło gradientowe",language:"Język",color_scheme:"Schemat kolorów",admin_settings:"Ustawienia administratora",extension_cost:"To niniejsze wydanie wymaga zapłaty minimalnej {cost} satów.",extension_paid_sats:"Już zapłaciłeś {paid_sats} satów.",release_details_error:"Nie można uzyskać szczegółów wydania.",pay_from_wallet:"Zapłać z portfela",wallet_required:"Portfel *",show_qr:"Pokaż kod QR",retry_install:"Ponów instalację",new_payment:"Dokonaj nowej płatności",update_payment:"Zaktualizuj płatność",already_paid_question:"Czy już zapłaciłeś?",sell:"Sprzedaj",sell_require:"Poproś o płatność, aby włączyć rozszerzenie",sell_info:"Rozszerzenie {name} wymaga płatności w wysokości minimum {amount} sats, aby je włączyć.",hide_empty_wallets:"Ukryj puste portfele",recheck:"Sprawdź ponownie",contributors:"Współpracownicy",license:"Licencja",reset_key:"Resetuj klucz",reset_password:"Zresetuj hasło",border_choices:"Wybory granicy",select_all:"Zaznacz wszystko",nfc_supported:"Obsługa NFC",nfc_not_supported:"NFC nieobsługiwane",expire_date:"Data wygaśnięcia:",hash:"Hash:",welcome_lnbits:"Witamy w LNbits",setup_su_account:"Skonfiguruj konto Superuser poniżej.",create_ticker_converter:"Stwórz Konwerter Kursu Walutowego",enable_audit:"Włącz Audyt",recommended:"Zalecane",audit_desc:"Rejestruj żądania HTTP zgodnie z określonymi filtrami",audit_record_req:"Zarejestruj treść żądania",audit_record_warning:"Ostrzeżenie:",audit_record_req_warning_1:"dane poufne (takie jak hasła) będą rejestrowane.",audit_record_req_warning_2:"treść żądania może mieć duży rozmiar.",audit_record_use:"Używaj tego ostrożnie.",audit_ip:"Zapisz adres IP",audit_ip_desc:"Zarejestruj adres IP klienta",audit_path_params:"Zarejestruj parametry ścieżki",audit_query_params:"Zarejestruj parametry zapytania",audit_http_methods:"Uwzględnij metody HTTP",audit_http_methods_hint:"Lista metod HTTP do uwzględnienia. Pusta lista oznacza wszystkie.",audit_http_methods_label:"Metody HTTP",audit_resp_codes:"Uwzględnij kody odpowiedzi HTTP",audit_resp_codes_hint:"Lista kodów HTTP do uwzględnienia (dopasowanie do wyrażenia regularnego). Puste listy oznaczają wszystkie. Np: 4.*, 5.*",audit_resp_codes_label:"Kod odpowiedzi HTTP (wyrażenie regularne)",audit_paths:"Ścieżki dołączania",audit_paths_hint:"Lista ścieżek do uwzględnienia (dopasowanie regex). Pusta lista oznacza wszystkie.",audit_paths_label:"Ścieżka HTTP (regex)",audit_paths_exclude:"Wyklucz ścieżki",audit_paths_exclude_hint:"Lista ścieżek do wykluczenia (dopasowanie do wyrażenia regularnego). Pusta lista oznacza brak.",audit_paths_exclude_label:"Ścieżka HTTP (wyrażenie regularne)",exchange_providers:"Dostawcy wymiany",admin_extensions:"Rozszerzenia administracyjne",admin_extensions_label:"Rozszerzenia administracyjne",admin_extensions_hint:"Tylko użytkownik rozszerzeń z uprawnieniami administratora może używać",user_default_extensions:"Domyślne Rozszerzenia Użytkownika",user_default_extensions_label:"Rozszerzenia użytkownika",user_default_extensions_hint:"Rozszerzenia, które będą domyślnie włączone dla użytkowników.",miscellanous:"Różne",misc_disable_extensions:"Wyłącz rozszerzenia",misc_disable_extensions_label:"Wyłącz wszystkie rozszerzenia",misc_hide_api:"Ukryj API",misc_hide_api_label:"Ukrywa interfejs API portfela, rozszerzenia mogą zdecydować się na honorowanie",wallets_management:"Zarządzanie portfelami",funding_source_info:"Informacje o źródle finansowania",funding_source:"Źródło finansowania: {wallet_class}",node_balance:"Saldo węzła: {balance} sats",lnbits_balance:"Saldo LNbits: {balance} sats",funding_reserve_percent:"Rezerwa procentowa: {percent} %",node_management:"Zarządzanie węzłami",node_management_not_supported:"Zarządzanie węzłami nie jest obsługiwane przez aktywne źródło finansowania.",toggle_node_ui:"Interfejs użytkownika węzła",toggle_public_node_ui:"Interfejs węzła publicznego",toggle_transactions_node_ui:"Karta transakcji (wyłącz na dużych węzłach CLN)",invoice_expiry:"Wygaśnięcie faktury",invoice_expiry_label:"Termin wygaśnięcia faktury (sekundy)",fee_reserve:"Rezerwa Opłat",fee_reserve_msats:"Opłata rezerwowa w msats",fee_reserve_percent:"Opłata rezerwacyjna w procentach",server_management:"Zarządzanie serwerem",base_url:"Podstawowy adres URL",base_url_label:"Adres URL statyczny/bazowy dla serwera",authentication:"Uwierzytelnianie",auth_token_expiry_label:"Minuty wygaśnięcia tokenu",auth_token_expiry_hint:"Czas w minutach do wygaśnięcia tokenu",auth_allowed_methods_label:"Dopuszczalne metody autoryzacji",auth_allowed_methods_hint:"Wybierz metody autoryzacji",auth_nostr_label:"Żądanie URL Nostr",auth_nostr_hint:"Absolutny URL, którego klienci będą używać do logowania.",auth_google_ci_label:"Identyfikator klienta Google",auth_google_ci_hint:"Upewnij się, że autoryzowane URI przekierowania zawierają https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Hasło tajne klienta Google",auth_gh_client_id_label:"Identyfikator klienta GitHub",auth_gh_client_id_hint:"Upewnij się, że adres URL wywołania zwrotnego autoryzacji jest ustawiony na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Adres URL Discovery Keycloak",auth_keycloak_ci_label:"Identyfikator klienta Keycloak",auth_keycloak_ci_hint:"Upewnij się, że URL zwrotu autoryzacji jest ustawiony na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Hasło klienta Keycloak",currency_settings:"Ustawienia waluty",allowed_currencies:"Dozwolone waluty",allowed_currencies_hint:"Ogranicz liczbę dostępnych walut fiducjarnych",default_account_currency:"Domyślna waluta konta",default_account_currency_hint:"Domyślna waluta dla księgowości",service_fee_label:"Opłata serwisowa (%)",service_fee_hint:"Opłata pobierana za transakcję (%)",service_fee_max_label:"Opłata za usługę max (sats)",service_fee_max_hint:"Maksymalna opłata serwisowa do pobrania w (sats)",fee_wallet:"Portfel opłat",fee_wallet_label:"Portfel opłat (ID portfela)",fee_wallet_hint:"Identyfikator portfela, do którego wysłać środki",disable_fee:"Wyłącz opłatę",disable_fee_internal:"Wyłącz opłatę za usługę dla płatności wewnętrznych",disable_fee_internal_desc:"Wyłącz opłatę serwisową dla wewnętrznych płatności Lightning",ui_management:"Zarządzanie interfejsem użytkownika",ui_site_title:"Tytuł strony",ui_site_tagline:"Podpis strony",ui_elements_enable:"Włącz elementy na stronie głównej",ui_elements_disable:"Wyłącz elementy na stronie głównej",ui_toggle_elements_tip:"Usuń elementy strony głównej takie jak 'runs on' itp.",ui_site_description:"Opis strony",ui_site_description_hint:"Użyj zwykłego tekstu, Markdown lub surowego HTML",ui_default_wallet_name:"Domyślna nazwa portfela",lnbits_wallet:"Portfel LNbits",denomination:"Nominacja",denomination_hint:"Nazwa dla tokena FakeWallet",ui_qr_code_logo:"Logo kodu QR",ui_qr_code_logo_hint:"Adres URL do obrazu logo w kodzie QR",ui_custom_badge:"Niestandardowa odznaka",ui_custom_badge_label:"Znak niestandardowy 'UŻYWAJ OSTROŻNIE - portfel LNbits wciąż jest w WERSJI BETA'",ui_custom_badge_color_label:"Niestandardowy kolor odznaki",themes:"Motywy",themes_hint:"Wybierz motywy dostępne dla użytkowników",custom_logo:"Logo niestandardowe",custom_logo_hint:"URL do obrazu logo",ad_space_title:"Tytuł reklamy",ad_space_title_label:"Wspierane przez",ad_slots:"Sloty reklamowe",ad_slots_hint:"Adres URL i ścieżki plików obrazów w formacie CSV, rozszerzenia mogą zdecydować się na honorowanie",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy włączone",ads_disabled:"Reklamy wyłączone",user_management:"Zarządzanie użytkownikami",admin_users:"Użytkownicy administratorzy",admin_users_hint:"Użytkownicy z uprawnieniami administratora",admin_users_label:"Identyfikator użytkownika",allowed_users:"Dozwoleni użytkownicy",allowed_users_hint:"Tylko ci użytkownicy mogą używać LNbits",allowed_users_label:"Identyfikator użytkownika",allow_creation_user:"Zezwól na tworzenie nowych użytkowników",allow_creation_user_desc:"Zezwól na tworzenie nowych użytkowników na stronie głównej indeksu",components:"Komponenty",long_running_endpoints:"5 najdłużej działających punktów końcowych",http_request_methods:"Metody żądań HTTP",http_response_codes:"Kody Odpowiedzi HTTP",request_details:"Szczegóły żądania",http_request_details:"Szczegóły żądania HTTP"},window.localisation.fr={confirm:"Oui",server:"Serveur",theme:"Thème",site_customisation:"Personnalisation du site",funding:"Financement",users:"Utilisateurs",audit:"Audit",apps:"Applications",channels:"Canaux",transactions:"Transactions",dashboard:"Tableau de bord",node:"Noeud",export_users:"Exporter les utilisateurs",no_users:"Aucun utilisateur trouvé",total_capacity:"Capacité totale",avg_channel_size:"Taille moyenne du canal",biggest_channel_size:"Taille de canal maximale",smallest_channel_size:"Taille de canal la plus petite",number_of_channels:"Nombre de canaux",active_channels:"Canaux actifs",connect_peer:"Connecter un pair",connect:"Connecter",open_channel:"Ouvrir le canal",open:"Ouvrir",close_channel:"Fermer le canal",close:"Fermer",restart:"Redémarrer le serveur",save:"Enregistrer",save_tooltip:"Enregistrer vos modifications",credit_debit:"Crédit / Débit",credit_hint:"Appuyez sur Entrée pour créditer le compte",credit_label:"{denomination} à créditer",credit_ok:"Succès du crédit/débit des fonds virtuels ({amount} sats). Les paiements dépendent des fonds réels sur la source de financement.",restart_tooltip:"Redémarrez le serveur pour que les changements prennent effet",add_funds_tooltip:"Ajouter des fonds à un portefeuille.",reset_defaults:"Réinitialiser aux valeurs par défaut",reset_defaults_tooltip:"Supprimer tous les paramètres et les réinitialiser aux valeurs par défaut.",download_backup:"Télécharger la sauvegarde de la base de données",name_your_wallet:"Nommez votre portefeuille {name}",paste_invoice_label:"Coller une facture, une demande de paiement ou un code lnurl *",lnbits_description:"Facile à installer et léger, LNbits peut fonctionner sur n'importe quelle source de financement du réseau Lightning et même LNbits lui-même! Vous pouvez exécuter LNbits pour vous-même ou offrir facilement une solution de gardien pour les autres. Chaque portefeuille a ses propres clés API et il n'y a pas de limite au nombre de portefeuilles que vous pouvez créer. La capacité de partitionner les fonds rend LNbits un outil utile pour la gestion de l'argent et comme outil de développement. Les extensions ajoutent une fonctionnalité supplémentaire à LNbits afin que vous puissiez expérimenter une gamme de technologies de pointe sur le réseau Lightning. Nous avons rendu le développement d'extensions aussi simple que possible et, en tant que projet gratuit et open source, nous encourageons les gens à développer et à soumettre les leurs.",export_to_phone:"Exporter vers le téléphone avec un code QR",export_to_phone_desc:"Ce code QR contient l'URL de votre portefeuille avec un accès complet. Vous pouvez le scanner depuis votre téléphone pour ouvrir votre portefeuille depuis là-bas.",wallet:"Portefeuille :",wallets:"Portefeuilles",add_wallet:"Ajouter un nouveau portefeuille",delete_wallet:"Supprimer le portefeuille",delete_wallet_desc:"Ce portefeuille entier sera supprimé et les fonds seront IRRECUPERABLES.",rename_wallet:"Renommer le portefeuille",update_name:"Mettre à jour le nom",fiat_tracking:"Suivi Fiat",currency:"Devise",update_currency:"Mettre à jour la devise",press_to_claim:"Appuyez pour demander du Bitcoin",donate:"Donner",view_github:"Voir sur GitHub",voidwallet_active:"VoidWallet est actif! Paiements désactivés",use_with_caution:"UTILISER AVEC PRUDENCE - Le portefeuille {name} est toujours en version BETA",service_fee:"Frais de service : {amount} % par transaction",service_fee_max:"Frais de service : {amount} % par transaction (max {max} sats)",service_fee_tooltip:"Frais de service facturés par l'administrateur du serveur LNbits pour chaque transaction sortante",toggle_darkmode:"Basculer le mode sombre",payment_reactions:"Réactions de paiement",view_swagger_docs:"Voir les documentation de l'API Swagger de LNbits",api_docs:"Documentation de l'API",api_keys_api_docs:"URL du nœud, clés API et documentation API",lnbits_version:"Version de LNbits",runs_on:"Fonctionne sur",paste:"Coller",paste_from_clipboard:"Coller depuis le presse-papiers",paste_request:"Coller la requête",create_invoice:"Créer une facture",camera_tooltip:"Utiliser la caméra pour scanner une facture / un code QR",export_csv:"Exporter vers CSV",chart_tooltip:"Afficher le graphique",pending:"En attente",copy_invoice:"Copier la facture",withdraw_from:"Retirer de",cancel:"Annuler",scan:"Scanner",read:"Lire",pay:"Payer",memo:"Mémo",date:"Date",payment_processing:"Traitement du paiement...",not_enough_funds:"Fonds insuffisants !",search_by_tag_memo_amount:"Rechercher par tag, mémo, montant",invoice_waiting:"Facture en attente de paiement",payment_received:"Paiement reçu",payment_sent:"Paiement envoyé",receive:"recevoir",send:"envoyer",outgoing_payment_pending:"Paiement sortant en attente",drain_funds:"Vider les fonds",drain_funds_desc:"Il s'agit d'un code QR LNURL-withdraw pour tout aspirer de ce portefeuille. Ne le partagez avec personne. Il est compatible avec balanceCheck et balanceNotify, de sorte que votre portefeuille peut continuer à retirer les fonds continuellement à partir d'ici après le premier retrait.",i_understand:"J'ai compris",copy_wallet_url:"Copier l'URL du portefeuille",disclaimer_dialog_title:"Important !",disclaimer_dialog:"La fonctionnalité de connexion sera publiée dans une future mise à jour, pour l'instant, assurez-vous de mettre cette page en favori pour accéder à votre portefeuille ultérieurement ! Ce service est en BETA, et nous ne sommes pas responsables des personnes qui perdent l'accès à leurs fonds.",no_transactions:"Aucune transaction effectuée pour le moment",manage:"Gérer",exchanges:"Échanges",extensions:"Extensions",no_extensions:"Vous n'avez installé aucune extension :(",created:"Créé",search_extensions:"Rechercher des extensions",extension_sources:"Sources d'extension",ext_sources_hint:"Dépôts à partir desquels les extensions peuvent être téléchargées",ext_sources_label:"URL source (utilisez uniquement la source officielle de l'extension LNbits et des sources fiables)",warning:"Avertissement",repository:"Référentiel",confirm_continue:"Êtes-vous sûr de vouloir continuer ?",manage_extension_details:"Installer/désinstaller l'extension",install:"Installer",uninstall:"Désinstaller",drop_db:"Supprimer les données",enable:"Activer",pay_to_enable:"Payer pour activer",enable_extension_details:"Activer l'extension pour l'utilisateur actuel",disable:"Désactiver",delete:"Supprimer",installed:"Installé",activated:"Activé",deactivated:"Désactivé",release_notes:"Notes de version",activate_extension_details:"Rendre l'extension disponible/indisponible pour les utilisateurs",featured:"Mis en avant",all:"Tout",only_admins_can_install:"Seuls les comptes administrateurs peuvent installer des extensions",admin_only:"Réservé aux administrateurs",new_version:"Nouvelle version",extension_depends_on:"Dépend de :",extension_rating_soon:"Notes des utilisateurs à venir bientôt",extension_installed_version:"Version installée",extension_uninstall_warning:"Vous êtes sur le point de supprimer l'extension pour tous les utilisateurs.",uninstall_confirm:"Oui, Désinstaller",extension_db_drop_info:"Toutes les données pour l'extension seront supprimées de manière permanente. Il n'est pas possible d'annuler cette opération !",extension_db_drop_warning:"Vous êtes sur le point de supprimer toutes les données de l'extension. Veuillez taper le nom de l'extension pour continuer :",extension_required_lnbits_version:"Cette version nécessite au moins LNbits version",min_version:"Minimum (inclus)",max_version:"Maximum (exclu)",payment_hash:"Hash de paiement",fee:"Frais",amount:"Montant",amount_sats:"Montant (sats)",tag:"Étiqueter",unit:"Unité",description:"Description",expiry:"Expiration",webhook:"Webhook",payment_proof:"Preuve de paiement",update:"Mettre à jour",update_available:"Mise à jour {version} disponible !",latest_update:"Vous êtes sur la dernière version {version}.",notifications:"Notifications",no_notifications:"Aucune notification",notifications_disabled:"Les notifications de statut LNbits sont désactivées.",enable_notifications:"Activer les notifications",enable_notifications_desc:"Si activé, il récupérera les dernières mises à jour du statut LNbits, telles que les incidents de sécurité et les mises à jour.",enable_watchdog:"Activer le Watchdog",enable_watchdog_desc:"Si elle est activée, elle changera automatiquement votre source de financement en VoidWallet si votre solde est inférieur au solde LNbits. Vous devrez activer manuellement après une mise à jour.",watchdog_interval:"Intervalle du gardien",watchdog_interval_desc:"À quelle fréquence la tâche en arrière-plan doit-elle vérifier la présence d'un signal d'arrêt d'urgence dans le delta du gardien [node_balance - lnbits_balance] (en minutes).",watchdog_delta:"Chien de garde Delta",watchdog_delta_desc:"Limite avant que l'interrupteur d'arrêt ne change la source de financement pour VoidWallet [lnbits_balance - node_balance > delta]",status:"Statut",notification_source:"Source de notification",notification_source_label:"URL source (utilisez uniquement la source officielle de statut LNbits et des sources de confiance)",more:"plus",less:"moins",releases:"Versions",watchdog:"Chien de garde",server_logs:"Journaux du serveur",ip_blocker:"Bloqueur d'IP",security:"Sécurité",security_tools:"Outils de sécurité",block_access_hint:"Bloquer l'accès par IP",allow_access_hint:"Autoriser l'accès par IP (cela passera outre les IP bloquées)",enter_ip:"Entrez l'adresse IP et appuyez sur Entrée",rate_limiter:"Limiteur de débit",wallet_limiter:"Limiteur de portefeuille",wallet_limit_max_withdraw_per_day:"Retrait quotidien maximum du portefeuille en sats (0 pour désactiver)",wallet_max_ballance:"Solde maximum du portefeuille en sats (0 pour désactiver)",wallet_limit_secs_between_trans:"Minutes et secondes entre les transactions par portefeuille (0 pour désactiver)",number_of_requests:"Nombre de requêtes",time_unit:"Unité de temps",minute:"minute",second:"seconde",hour:"heure",disable_server_log:"Désactiver le journal du serveur",enable_server_log:"Activer le journal du serveur",coming_soon:"Fonctionnalité à venir bientôt",session_has_expired:"Votre session a expiré. Veuillez vous reconnecter.",instant_access_question:"Voulez-vous un accès instantané ?",login_with_user_id:"Connexion avec l'identifiant utilisateur",or:"ou",create_new_wallet:"Créer un nouveau portefeuille",login_to_account:"Connectez-vous à votre compte",create_account:"Créer un compte",account_settings:"Paramètres du compte",signin_with_nostr:"Continuer avec Nostr",signin_with_google:"Connectez-vous avec Google",signin_with_github:"Connectez-vous avec GitHub",signin_with_keycloak:"Connectez-vous avec Keycloak",username_or_email:"Nom d'utilisateur ou e-mail",password:"Mot de passe",password_config:"Configuration du mot de passe",password_repeat:"Répétition du mot de passe",change_password:"Changer le mot de passe",update_credentials:"Mettre à jour les informations d'identification",update_pubkey:"Mettre à jour la clé publique",set_password:"Définir le mot de passe",invalid_password:"Le mot de passe doit comporter au moins 8 caractères",login:"Connexion",register:"Inscrire",username:"Nom d'utilisateur",pubkey:"Clé publique",user_id:"Identifiant utilisateur",email:"E-mail",first_name:"Prénom",last_name:"Nom de famille",picture:"Image",verify_email:"Vérifiez l'e-mail avec",account:"Compte",update_account:"Mettre à jour le compte",invalid_username:"Nom d'utilisateur invalide",auth_provider:"Fournisseur d'authentification",my_account:"Mon compte",back:"Retour",logout:"Déconnexion",look_and_feel:"Apparence",toggle_gradient:"Basculer le dégradé",gradient_background:"Fond en dégradé",language:"Langue",color_scheme:"Schéma de couleurs",admin_settings:"Paramètres administrateur",extension_cost:"Cette version nécessite un paiement minimum de {cost} sats.",extension_paid_sats:"Vous avez déjà payé {paid_sats} sats.",release_details_error:"Impossible d'obtenir les détails de la version.",pay_from_wallet:"Payer depuis le portefeuille",wallet_required:"Portefeuille *",show_qr:"Afficher le QR",retry_install:"Réessayer l'installation",new_payment:"Effectuer un nouveau paiement",update_payment:"Mettre à jour le paiement",already_paid_question:"Avez-vous déjà payé ?",sell:"Vendre",sell_require:"Demander un paiement pour activer l'extension",sell_info:"L'extension {name} nécessite un paiement minimum de {amount} sats pour être activée.",hide_empty_wallets:"Masquer les portefeuilles vides",recheck:"Revérifier",contributors:"Contributeurs",license:"Licence",reset_key:"Réinitialiser la clé",reset_password:"Réinitialiser le mot de passe",border_choices:"Choix de bordure",select_all:"Sélectionner tout",nfc_supported:"NFC pris en charge",nfc_not_supported:"NFC non pris en charge",expire_date:"Date d'expiration :",hash:"Hash :",welcome_lnbits:"Bienvenue à LNbits",setup_su_account:"Configurez le compte Superuser ci-dessous.",create_ticker_converter:"Créer un convertisseur de code de devise",enable_audit:"Activer l'audit",recommended:"Recommandé",audit_desc:"Enregistrer les requêtes HTTP selon les filtres spécifiés",audit_record_req:"Enregistrer le corps de la demande",audit_record_warning:"Avertissement :",audit_record_req_warning_1:"les données confidentielles (comme les mots de passe) seront enregistrées.",audit_record_req_warning_2:"le corps de la requête peut être de grande taille.",audit_record_use:"Utilisez-le avec précaution.",audit_ip:"Enregistrer l'adresse IP",audit_ip_desc:"Enregistrer l'adresse IP du client",audit_path_params:"Enregistrer les paramètres de chemin",audit_query_params:"Enregistrer les paramètres de la requête",audit_http_methods:"Inclure les méthodes HTTP",audit_http_methods_hint:"Liste des méthodes HTTP à inclure. Listes vides signifie toutes.",audit_http_methods_label:"Méthodes HTTP",audit_resp_codes:"Inclure les codes de réponse HTTP",audit_resp_codes_hint:"Liste des codes HTTP à inclure (correspondance regex). Les listes vides signifient tout. Ex : 4.*, 5.*",audit_resp_codes_label:"Code de réponse HTTP (regex)",audit_paths:"Inclure des chemins",audit_paths_hint:"Liste des chemins à inclure (correspondance regex). Liste vide signifie tout.",audit_paths_label:"Chemin HTTP (regex)",audit_paths_exclude:"Exclure les chemins",audit_paths_exclude_hint:"Liste des chemins à exclure (correspondance regex). Liste vide signifie aucun.",audit_paths_exclude_label:"Chemin HTTP (regex)",exchange_providers:"Fournisseurs d'échange",admin_extensions:"Extensions d'administration",admin_extensions_label:"Extensions d'administration",admin_extensions_hint:"Seuls les utilisateurs avec des privilèges d'administrateur peuvent utiliser les extensions.",user_default_extensions:"Extensions par défaut de l'utilisateur",user_default_extensions_label:"Extensions utilisateur",user_default_extensions_hint:"Extensions qui seront activées par défaut pour les utilisateurs.",miscellanous:"Divers",misc_disable_extensions:"Désactiver les extensions",misc_disable_extensions_label:"Désactiver toutes les extensions",misc_hide_api:"Masquer l'API",misc_hide_api_label:"Masque l'API du portefeuille, les extensions peuvent choisir de respecter",wallets_management:"Gestion des portefeuilles",funding_source_info:"Informations sur la source de financement",funding_source:"Source de financement : {wallet_class}",node_balance:"Solde du nœud : {balance} sats",lnbits_balance:"Solde LNbits : {balance} sats",funding_reserve_percent:"Pourcentage de Réserve : {percent} %",node_management:"Gestion des nœuds",node_management_not_supported:"La gestion des nœuds n'est pas prise en charge par la source de financement active",toggle_node_ui:"Interface utilisateur de nœud",toggle_public_node_ui:"Interface utilisateur du nœud public",toggle_transactions_node_ui:"Onglet des transactions (Désactiver sur les grands nœuds CLN)",invoice_expiry:"Expiration de la facture",invoice_expiry_label:"Expiration de la facture (secondes)",fee_reserve:"Réserve de frais",fee_reserve_msats:"Frais de réservation en msats",fee_reserve_percent:"Frais de réservation en pourcentage",server_management:"Gestion de serveur",base_url:"URL de base",base_url_label:"URL statique/de base pour le serveur",authentication:"Authentification",auth_token_expiry_label:"Durée d'expiration du jeton (en minutes)",auth_token_expiry_hint:"Durée en minutes avant l'expiration du jeton",auth_allowed_methods_label:"Méthodes d'autorisation autorisées",auth_allowed_methods_hint:"Sélectionnez les méthodes d'autorisation",auth_nostr_label:"URL de requête Nostr",auth_nostr_hint:"URL absolue que les clients utiliseront pour se connecter.",auth_google_ci_label:"ID Client Google",auth_google_ci_hint:"Assurez-vous que les URIs de redirection autorisées contiennent https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secret client Google",auth_gh_client_id_label:"Identifiant client GitHub",auth_gh_client_id_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secret Client GitHub",auth_keycloak_label:"URL de découverte Keycloak",auth_keycloak_ci_label:"ID Client Keycloak",auth_keycloak_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secret client Keycloak",currency_settings:"Paramètres de devise",allowed_currencies:"Devises autorisées",allowed_currencies_hint:"Limiter le nombre de devises fiduciaires disponibles",default_account_currency:"Devise par défaut du compte",default_account_currency_hint:"Devise par défaut pour la comptabilité",service_fee_label:"Frais de service (%)",service_fee_hint:"Frais facturés par tx (%)",service_fee_max_label:"Frais de service max (sats)",service_fee_max_hint:"Frais de service maximum à facturer en (sats)",fee_wallet:"Portefeuille de frais",fee_wallet_label:"Portefeuille de frais (ID de portefeuille)",fee_wallet_hint:"Identifiant de portefeuille pour envoyer des fonds à",disable_fee:"Désactiver les frais",disable_fee_internal:"Désactiver les frais de service pour les paiements internes",disable_fee_internal_desc:"Désactiver les frais de service pour les paiements Lightning internes",ui_management:"Gestion de l'interface utilisateur",ui_site_title:"Titre du site",ui_site_tagline:"Slogan du site",ui_elements_enable:"Activer les éléments sur la page d'accueil",ui_elements_disable:"Désactiver les éléments sur la page d'accueil",ui_toggle_elements_tip:"Supprimer les éléments de la page d'accueil comme 'fonctionne avec', etc.",ui_site_description:"Description du site",ui_site_description_hint:"Utilisez du texte brut, du Markdown ou du HTML brut",ui_default_wallet_name:"Nom par Défaut du Portefeuille",lnbits_wallet:"Portefeuille LNbits",denomination:"Dénomination",denomination_hint:"Le nom du jeton FakeWallet",ui_qr_code_logo:"Logo de code QR",ui_qr_code_logo_hint:"URL de l'image du logo dans le code QR",ui_custom_badge:"Badge personnalisé",ui_custom_badge_label:"Badge personnalisé 'À UTILISER AVEC PRÉCAUTION - Le portefeuille LNbits est encore en BÊTA'",ui_custom_badge_color_label:"Couleur de badge personnalisée",themes:"Thèmes",themes_hint:"Choisissez des thèmes disponibles pour les utilisateurs",custom_logo:"Logo personnalisé",custom_logo_hint:"URL de l'image du logo",ad_space_title:"Titre de l'espace publicitaire",ad_space_title_label:"Soutenu par",ad_slots:"Emplacements publicitaires",ad_slots_hint:"URL de l'annonce et chemins des fichiers image au format CSV, les extensions peuvent choisir de respecter",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annonces activées",ads_disabled:"Publicités désactivées",user_management:"Gestion des utilisateurs",admin_users:"Utilisateurs administrateurs",admin_users_hint:"Utilisateurs avec des privilèges d'administration",admin_users_label:"Identifiant utilisateur",allowed_users:"Utilisateurs autorisés",allowed_users_hint:"Seuls ces utilisateurs peuvent utiliser LNbits",allowed_users_label:"ID utilisateur",allow_creation_user:"Autoriser la création de nouveaux utilisateurs",allow_creation_user_desc:"Permettre la création de nouveaux utilisateurs sur la page d’index",components:"Composants",long_running_endpoints:"Top 5 points de terminaison longue durée",http_request_methods:"Méthodes de requête HTTP",http_response_codes:"Codes de réponse HTTP",request_details:"Détails de la demande",http_request_details:"Détails de la requête HTTP"},window.localisation.nl={confirm:"Ja",server:"Server",theme:"Thema",site_customisation:"Site-aanpassing",funding:"Financiering",users:"Gebruikers",audit:"Controle",apps:"Apps",channels:"Kanalen",transactions:"Transacties",dashboard:"Dashboard",node:"Knooppunt",export_users:"Gebruikers exporteren",no_users:"Geen gebruikers gevonden",total_capacity:"Totale capaciteit",avg_channel_size:"Gem. Kanaalgrootte",biggest_channel_size:"Grootste Kanaalgrootte",smallest_channel_size:"Kleinste Kanaalgrootte",number_of_channels:"Aantal kanalen",active_channels:"Actieve Kanalen",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Open Kanaal",open:"Open",close_channel:"Kanaal Sluiten",close:"Sluiten",restart:"Server opnieuw opstarten",save:"Opslaan",save_tooltip:"Sla uw wijzigingen op",credit_debit:"Credit / Debet",credit_hint:"Druk op Enter om de rekening te crediteren",credit_label:"{denomination} te crediteren",credit_ok:"Succesvol crediteren/debiteren van virtuele gelden ({amount} sats). Betalingen zijn afhankelijk van de werkelijke fondsen op de financieringsbron.",restart_tooltip:"Start de server opnieuw op zodat wijzigingen van kracht worden",add_funds_tooltip:"Voeg geld toe aan een portemonnee.",reset_defaults:"Standaardinstellingen herstellen",reset_defaults_tooltip:"Wis alle instellingen en herstel de standaardinstellingen.",download_backup:"Databaseback-up downloaden",name_your_wallet:"Geef je {name} portemonnee een naam",paste_invoice_label:"Plak een factuur, betalingsverzoek of lnurl-code*",lnbits_description:"Gemakkelijk in te stellen en lichtgewicht, LNbits kan op elke lightning-netwerkfinancieringsbron draaien en zelfs LNbits zelf! U kunt LNbits voor uzelf laten draaien of gemakkelijk een bewaardersoplossing voor anderen bieden. Elke portemonnee heeft zijn eigen API-sleutels en er is geen limiet aan het aantal portemonnees dat u kunt maken. Het kunnen partitioneren van fondsen maakt LNbits een nuttige tool voor geldbeheer en als ontwikkelingstool. Extensies voegen extra functionaliteit toe aan LNbits, zodat u kunt experimenteren met een reeks toonaangevende technologieën op het bliksemschichtnetwerk. We hebben het ontwikkelen van extensies zo eenvoudig mogelijk gemaakt en als een gratis en opensource-project moedigen we mensen aan om hun eigen ontwikkelingen in te dienen.",export_to_phone:"Exporteren naar telefoon met QR-code",export_to_phone_desc:"Deze QR-code bevat uw portemonnee-URL met volledige toegang. U kunt het vanaf uw telefoon scannen om uw portemonnee van daaruit te openen.",wallet:"Wallet:",wallets:"Portemonnees",add_wallet:"Een nieuwe portemonnee toevoegen",delete_wallet:"Portemonnee verwijderen",delete_wallet_desc:"Deze hele portemonnee wordt verwijderd, de fondsen worden NIET TERUGGEVONDEN.",rename_wallet:"Portemonnee hernoemen",update_name:"Naam bijwerken",fiat_tracking:"Volgfunctie voor fiat-valuata",currency:"Valuta",update_currency:"Valuta bijwerken",press_to_claim:"Druk om bitcoin te claimen",donate:"Doneren",view_github:"Bekijken op GitHub",voidwallet_active:"VoidWallet is actief! Betalingen uitgeschakeld",use_with_caution:"GEBRUIK MET VOORZICHTIGHEID - {name} portemonnee is nog in BETA",service_fee:"Servicekosten: {amount} % per transactie",service_fee_max:"Servicekosten: {amount} % per transactie (max {max} sats)",service_fee_tooltip:"Transactiekosten in rekening gebracht door de LNbits serverbeheerder per uitgaande transactie",toggle_darkmode:"Donkere modus aan/uit",payment_reactions:"Betalingsreacties",view_swagger_docs:"Bekijk LNbits Swagger API-documentatie",api_docs:"API-documentatie",api_keys_api_docs:"Node URL, API-sleutels en API-documentatie",lnbits_version:"LNbits-versie",runs_on:"Draait op",paste:"Plakken",paste_from_clipboard:"Plakken van klembord",paste_request:"Verzoek plakken",create_invoice:"Factuur aanmaken",camera_tooltip:"Gebruik de camera om een factuur/QR-code te scannen",export_csv:"Exporteer naar CSV",chart_tooltip:"Toon grafiek",pending:"In behandeling",copy_invoice:"Kopieer factuur",withdraw_from:"Opnemen van",cancel:"Annuleren",scan:"Scannen",read:"Lezen",pay:"Betalen",memo:"Memo",date:"Datum",payment_processing:"Verwerking betaling...",not_enough_funds:"Onvoldoende saldo!",search_by_tag_memo_amount:"Zoeken op tag, memo, bedrag",invoice_waiting:"Factuur wachtend op betaling",payment_received:"Betaling ontvangen",payment_sent:"Betaling verzonden",receive:"ontvangen",send:"versturen",outgoing_payment_pending:"Uitgaande betaling in behandeling",drain_funds:"Geld opnemen",drain_funds_desc:"Dit is een LNURL-withdraw QR-code om alles uit deze portemonnee te halen. Deel deze code niet met anderen. Het is compatibel met balanceCheck en balanceNotify zodat jouw portemonnee continu geld kan blijven opnemen vanaf hier na de eerste opname.",i_understand:"Ik begrijp het",copy_wallet_url:"Kopieer portemonnee-URL",disclaimer_dialog_title:"Belangrijk!",disclaimer_dialog:"Inlogfunctionaliteit wordt uitgebracht in een toekomstige update. Zorg er nu voor dat je deze pagina als favoriet markeert om in de toekomst toegang te krijgen tot je portemonnee! Deze service is in BETA en we zijn niet verantwoordelijk voor mensen die de toegang tot hun fondsen verliezen.",no_transactions:"Er zijn nog geen transacties gedaan",manage:"Beheer",exchanges:"Beurzen",extensions:"Extensies",no_extensions:"Je hebt geen extensies geïnstalleerd :(",created:"Aangemaakt",search_extensions:"Zoekextensies",extension_sources:"Extensiebronnen",ext_sources_hint:"Repositories van waar de extensies kunnen worden gedownload",ext_sources_label:"Bron-URL (gebruik alleen de officiële LNbits-extensiebron en bronnen die je kunt vertrouwen)",warning:"Waarschuwing",repository:"Repository",confirm_continue:"Weet je zeker dat je wilt doorgaan?",manage_extension_details:"Installeren/verwijderen van extensie",install:"Installeren",uninstall:"Deïnstalleren",drop_db:"Gegevens verwijderen",enable:"Inschakelen",pay_to_enable:"Betalen om te activeren",enable_extension_details:"Schakel extensie in voor huidige gebruiker",disable:"Uitschakelen",delete:"Verwijderen",installed:"Geïnstalleerd",activated:"Geactiveerd",deactivated:"Gedeactiveerd",release_notes:"Release-opmerkingen",activate_extension_details:"Maak extensie beschikbaar/niet beschikbaar voor gebruikers",featured:"Uitgelicht",all:"Alles",only_admins_can_install:"Alleen beheerdersaccounts kunnen extensies installeren",admin_only:"Alleen beheerder",new_version:"Nieuwe Versie",extension_depends_on:"Afhankelijk van:",extension_rating_soon:"Beoordelingen binnenkort beschikbaar",extension_installed_version:"Geïnstalleerde versie",extension_uninstall_warning:"U staat op het punt de extensie voor alle gebruikers te verwijderen.",uninstall_confirm:"Ja, de-installeren",extension_db_drop_info:"Alle gegevens voor de extensie zullen permanent worden verwijderd. Er is geen manier om deze bewerking ongedaan te maken!",extension_db_drop_warning:"U staat op het punt alle gegevens voor de extensie te verwijderen. Typ de naam van de extensie om door te gaan:",extension_required_lnbits_version:"Deze release vereist ten minste LNbits-versie",min_version:"Minimum (inbegrepen)",max_version:"Maximum (uitgesloten)",payment_hash:"Betalings-hash",fee:"Kosten",amount:"Bedrag",amount_sats:"Bedrag (sats)",tag:"Label",unit:"Eenheid",description:"Beschrijving",expiry:"Vervaldatum",webhook:"Webhook",payment_proof:"Betalingsbewijs",update:"Bijwerken",update_available:"Update {version} beschikbaar!",latest_update:"U bent op de nieuwste versie {version}.",notifications:"Meldingen",no_notifications:"Geen meldingen",notifications_disabled:"LNbits-statusmeldingen zijn uitgeschakeld.",enable_notifications:"Schakel meldingen in",enable_notifications_desc:"Indien ingeschakeld zal het de laatste LNbits Status updates ophalen, zoals veiligheidsincidenten en updates.",enable_watchdog:"Inschakelen Watchdog",enable_watchdog_desc:"Indien ingeschakeld, wordt uw betaalbron automatisch gewijzigd naar VoidWallet als uw saldo lager is dan het saldo van LNbits. U zult dit na een update handmatig moeten inschakelen.",watchdog_interval:"Watchdog-interval",watchdog_interval_desc:"Hoe vaak de achtergrondtaak moet controleren op een killswitch signaal in het watchdog verschil [node_balance - lnbits_balance] (in minuten).",watchdog_delta:"Waakhond Delta",watchdog_delta_desc:"Limiet voordat de killswitch de financieringsbron verandert naar VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notificatiebron",notification_source_label:"Bron-URL (gebruik alleen de officiële LNbits-statusbron en bronnen die u vertrouwt)",more:"meer",less:"minder",releases:"Uitgaven",watchdog:"Waakhond",server_logs:"Serverlogboeken",ip_blocker:"IP-blokkering",security:"Beveiliging",security_tools:"Beveiligingstools",block_access_hint:"Toegang blokkeren per IP",allow_access_hint:"Toegang verlenen op basis van IP (zal geblokkeerde IP's overschrijven)",enter_ip:"Voer IP in en druk op enter",rate_limiter:"Snelheidsbegrenzer",wallet_limiter:"Portemonnee Limietsteller",wallet_limit_max_withdraw_per_day:"Maximale dagelijkse opname van wallet in sats (0 om uit te schakelen)",wallet_max_ballance:"Maximale portefeuillesaldo in sats (0 om uit te schakelen)",wallet_limit_secs_between_trans:"Min seconden tussen transacties per portemonnee (0 om uit te schakelen)",number_of_requests:"Aantal verzoeken",time_unit:"Tijdeenheid",minute:"minuut",second:"seconde",hour:"uur",disable_server_log:"Serverlog uitschakelen",enable_server_log:"Activeer Serverlog",coming_soon:"Functie binnenkort beschikbaar",session_has_expired:"Uw sessie is verlopen. Log alstublieft opnieuw in.",instant_access_question:"Wil je directe toegang?",login_with_user_id:"Inloggen met gebruikers-ID",or:"of",create_new_wallet:"Nieuwe portemonnee aanmaken",login_to_account:"Log in op je account",create_account:"Account aanmaken",account_settings:"Accountinstellingen",signin_with_nostr:"Doorgaan met Nostr",signin_with_google:"Inloggen met Google",signin_with_github:"Inloggen met GitHub",signin_with_keycloak:"Inloggen met Keycloak",username_or_email:"Gebruikersnaam of e-mail",password:"Wachtwoord",password_config:"Wachtwoordconfiguratie",password_repeat:"Wachtwoord herhalen",change_password:"Wachtwoord wijzigen",update_credentials:"Referenties bijwerken",update_pubkey:"Openbare Sleutel Bijwerken",set_password:"Wachtwoord instellen",invalid_password:"Wachtwoord moet ten minste 8 tekens bevatten",login:"Inloggen",register:"Registreren",username:"Gebruikersnaam",pubkey:"Publieke Sleutel",user_id:"Gebruikers-ID",email:"E-mail",first_name:"Voornaam",last_name:"Achternaam",picture:"Foto",verify_email:"E-mail verifiëren met",account:"Account",update_account:"Account bijwerken",invalid_username:"Ongeldige gebruikersnaam",auth_provider:"Auth Provider",my_account:"Mijn Account",back:"Terug",logout:"Afmelden",look_and_feel:"Uiterlijk en gedrag",toggle_gradient:"Gradiënt Schakelen",gradient_background:"Verloopachtergrond",language:"Taal",color_scheme:"Kleurenschema",admin_settings:"Beheerdersinstellingen",extension_cost:"Deze release vereist een betaling van minimaal {cost} sats.",extension_paid_sats:"U heeft al {paid_sats} sats betaald.",release_details_error:"Kan de gegevens van de release niet ophalen.",pay_from_wallet:"Betalen vanuit Portemonnee",wallet_required:"Wallet *",show_qr:"Toon QR",retry_install:"Opnieuw installeren",new_payment:"Nieuwe betaling maken",update_payment:"Betaling bijwerken",already_paid_question:"Heb je al betaald?",sell:"Verkopen",sell_require:"Vraag betaling om de extensie te activeren.",sell_info:"De {name} extensie vereist een betaling van minimaal {amount} sats om in te schakelen.",hide_empty_wallets:"Verberg lege portemonnees",recheck:"Opnieuw controleren",contributors:"Bijdragers",license:"Licentie",reset_key:"Hersteltoets",reset_password:"Wachtwoord Resetten",border_choices:"Randkeuzes",select_all:"Alles selecteren",nfc_supported:"NFC Ondersteund",nfc_not_supported:"NFC niet ondersteund",expire_date:"Vervaldatum:",hash:"Hash:",welcome_lnbits:"Welkom bij LNbits",setup_su_account:"Stel het Superuser-account hieronder in.",create_ticker_converter:"Maak Valuta Ticker Converter",enable_audit:"Audit inschakelen",recommended:"Aanbevolen",audit_desc:"HTTP-verzoeken vastleggen volgens de opgegeven filters",audit_record_req:"Verzoeklichaam registreren",audit_record_warning:"Waarschuwing:",audit_record_req_warning_1:"vertrouwelijke gegevens (zoals wachtwoorden) worden gelogd.",audit_record_req_warning_2:"de aanvraagbody kan een grote omvang hebben.",audit_record_use:"Gebruik het met voorzichtigheid.",audit_ip:"IP-adres vastleggen",audit_ip_desc:"Leg het IP-adres van de klant vast",audit_path_params:"Parameters van het pad opnemen",audit_query_params:"Queryparameters vastleggen",audit_http_methods:"Inclusief HTTP-methoden",audit_http_methods_hint:"Lijst van HTTP-methoden die moeten worden opgenomen. Lege lijsten betekenen alles.",audit_http_methods_label:"HTTP-methoden",audit_resp_codes:"Inclusief HTTP-responscodes",audit_resp_codes_hint:"Lijst van op te nemen HTTP-codes (regex-overeenkomst). Lege lijst betekent alles. Bijvoorbeeld: 4.*, 5.*",audit_resp_codes_label:"HTTP-responscode (regex)",audit_paths:"Inclusiepad",audit_paths_hint:"Lijst met paden die moeten worden opgenomen (regex match). Lege lijst betekent alles.",audit_paths_label:"HTTP-pad (regex)",audit_paths_exclude:"Paden uitsluiten",audit_paths_exclude_hint:"Lijst met paden die moeten worden uitgesloten (regex-overeenkomst). Een lege lijst betekent geen.",audit_paths_exclude_label:"HTTP-pad (regex)",exchange_providers:"Wisselaanbieders",admin_extensions:"Beheeruitbreidingen",admin_extensions_label:"Beheerdersuitbreidingen",admin_extensions_hint:"Alleen gebruikers met beheerdersrechten kunnen extensies gebruiken.",user_default_extensions:"Standaardextensies voor gebruikers",user_default_extensions_label:"Gebruikersuitbreidingen",user_default_extensions_hint:"Extensies die standaard voor de gebruikers worden ingeschakeld.",miscellanous:"Diversen",misc_disable_extensions:"Extensies uitschakelen",misc_disable_extensions_label:"Alle extensies uitschakelen",misc_hide_api:"API verbergen",misc_hide_api_label:"Verbergt de wallet-API, extensies kunnen ervoor kiezen dit te respecteren",wallets_management:"Beheer van portemonnees",funding_source_info:"Financieringsbroninfo",funding_source:"Financieringsbron: {wallet_class}",node_balance:"Node Balans: {balance} sats",lnbits_balance:"LNbits Saldo: {balance} sats",funding_reserve_percent:"Reservepercentage: {percent} %",node_management:"Nodebeheer",node_management_not_supported:"Nodebeheer wordt niet ondersteund door de actieve financieringsbron",toggle_node_ui:"Node UI",toggle_public_node_ui:"Openbare Node UI",toggle_transactions_node_ui:"Transacties Tabblad (Uitschakelen op grote CLN-nodes)",invoice_expiry:"Factuurvervaldatum",invoice_expiry_label:"Factuurverloop (seconden)",fee_reserve:"Toegangsvergoeding Reserve",fee_reserve_msats:"Reserveringskosten in msats",fee_reserve_percent:"Reserveringskosten in procent",server_management:"Serverbeheer",base_url:"Basis-URL",base_url_label:"Statisch/Basis-URL voor de server",authentication:"Authenticatie",auth_token_expiry_label:"Token vervalt over minuten",auth_token_expiry_hint:"Tijd in minuten totdat de token verloopt",auth_allowed_methods_label:"Toegestane autorisatiemethoden",auth_allowed_methods_hint:"Selecteer autorisatiemethoden",auth_nostr_label:"Nostr Aanvraag-URL",auth_nostr_hint:"Absolute URL die de klanten zullen gebruiken om in te loggen.",auth_google_ci_label:"Google Client-ID",auth_google_ci_hint:"Zorg ervoor dat de geautoriseerde omleidings-URL's https://{domain}/api/v1/auth/google/token bevatten.",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub client-ID",auth_gh_client_id_hint:"Zorg ervoor dat de autorisatie-callback-URL is ingesteld op https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Clientgeheim",auth_keycloak_label:"Keycloak Ontdekking URL",auth_keycloak_ci_label:"Keycloak-client-ID",auth_keycloak_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Clientgeheim",currency_settings:"Valuta-instellingen",allowed_currencies:"Toegestane valuta's",allowed_currencies_hint:"Beperk het aantal beschikbare fiatvaluta's",default_account_currency:"Standaardrekeningvaluta",default_account_currency_hint:"Standaardvaluta voor boekhouding",service_fee_label:"Servicekosten (%)",service_fee_hint:"Toeslag per transactie (%)",service_fee_max_label:"Servicekosten max (sats)",service_fee_max_hint:"Maximale servicekosten om in rekening te brengen in (sats)",fee_wallet:"Kosten Portemonnee",fee_wallet_label:"Kosten portemonnee (wallet ID)",fee_wallet_hint:"Wallet-ID om geld naar over te maken",disable_fee:"Kosten uitschakelen",disable_fee_internal:"Servicekosten uitschakelen voor interne betalingen",disable_fee_internal_desc:"Dienstenkosten uitschakelen voor interne Lightning-betalingen",ui_management:"UI-beheer",ui_site_title:"Site titel",ui_site_tagline:"Site-slogan",ui_elements_enable:"Elementen op de homepage inschakelen",ui_elements_disable:"Elementen op de homepage uitschakelen",ui_toggle_elements_tip:"Verwijder startpagina-elementen zoals 'werkt op' enz.",ui_site_description:"Sitebeschrijving",ui_site_description_hint:"Gebruik platte tekst, Markdown, of ruwe HTML",ui_default_wallet_name:"Standaard Wallet Naam",lnbits_wallet:"LNbits-portemonnee",denomination:"Denominatie",denomination_hint:"De naam voor de FakeWallet token",ui_qr_code_logo:"QR-code-logo",ui_qr_code_logo_hint:"URL naar logo-afbeelding in QR-code",ui_custom_badge:"Aangepaste badge",ui_custom_badge_label:"Aangepaste Badge 'GEBRUIK MET VOORZICHTIGHEID - LNbits-portemonnee is nog in BÈTA'",ui_custom_badge_color_label:"Aangepaste Badge Kleur",themes:"Thema's",themes_hint:"Kies thema's beschikbaar voor gebruikers",custom_logo:"Aangepast logo",custom_logo_hint:"URL naar logo-afbeelding",ad_space_title:"Advertentieruimte Titel",ad_space_title_label:"Ondersteund door",ad_slots:"Advertentieblokken",ad_slots_hint:"Ad URL en afbeeldingspad in CSV-formaat, extensies kunnen ervoor kiezen te honoreren",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Advertenties ingeschakeld",ads_disabled:"Advertenties uitgeschakeld",user_management:"Gebruikersbeheer",admin_users:"Beheerdersgebruikers",admin_users_hint:"Gebruikers met beheerdersrechten",admin_users_label:"Gebruikers-ID",allowed_users:"Toegestane gebruikers",allowed_users_hint:"Alleen deze gebruikers kunnen LNbits gebruiken",allowed_users_label:"Gebruikers-ID",allow_creation_user:"Sta het aanmaken van nieuwe gebruikers toe",allow_creation_user_desc:"Sta de aanmaak van nieuwe gebruikers op de indexpagina toe",components:"Componenten",long_running_endpoints:"Top 5 langlopende eindpunten",http_request_methods:"HTTP-aanvraagmethoden",http_response_codes:"HTTP-responscodes",request_details:"Aanvraagdetails",http_request_details:"HTTP-verzoekdetails"},window.localisation.we={confirm:"Ydw",server:"Gweinydd",theme:"Thema",site_customisation:"Addasu Safle",funding:"Arian fyndio",users:"Defnyddwyr",audit:"Archwilio",apps:"Apiau",channels:"Sianelau",transactions:"Trafodion",dashboard:"Panel Gweinyddol",node:"Nod",export_users:"Allfor Defnyddwyr",no_users:"Heb ganfod defnyddwyr",total_capacity:"Capasiti Cyfanswm",avg_channel_size:"Maint Sianel Cyf.",biggest_channel_size:"Maint Sianel Fwyaf",smallest_channel_size:"Maint Sianel Lleiaf",number_of_channels:"Nifer y Sianeli",active_channels:"Sianeli Gweithredol",connect_peer:"Cysylltu â Chymar",connect:"Cysylltu",open_channel:"Sianel Agored",open:"Agor",close_channel:"Cau Sianel",close:"cau",restart:"Ailgychwyn gweinydd",save:"Save",save_tooltip:"cadw eich newidiadau",credit_debit:"Credyd / Debyd",credit_hint:"Pwyswch Enter i gyfrif credyd",credit_label:"{denomination} i gredyd",credit_ok:"Credydu/dad-debydu llwyddiannus o gronfeydd rhithwir ({amount} sats). Mae taliadau yn dibynnu ar y cronfeydd gwirioneddol sydd ar y ffynhonnell ariannu.",restart_tooltip:"Ailgychwyn y gweinydd er mwyn i newidiadau ddod i rym",add_funds_tooltip:"Ychwanegu arian at waled.",reset_defaults:"Ailosod i`r rhagosodiadau",reset_defaults_tooltip:"Dileu pob gosodiad ac ailosod i`r rhagosodiadau.",download_backup:"Lawrlwytho copi wrth gefn cronfa ddata",name_your_wallet:"Enwch eich waled {name}",paste_invoice_label:"Gludwch anfoneb, cais am daliad neu god lnurl *",lnbits_description:"Yn hawdd iw sefydlu ac yn ysgafn, gall LNbits redeg ar unrhyw ffynhonnell ariannu rhwydwaith mellt a hyd yn oed LNbits ei hun! Gallwch redeg LNbits i chi`ch hun, neu gynnig datrysiad ceidwad i eraill yn hawdd. Mae gan bob waled ei allweddi API ei hun ac nid oes cyfyngiad ar nifer y waledi y gallwch eu gwneud. Mae gallu rhannu cronfeydd yn gwneud LNbits yn arf defnyddiol ar gyfer rheoli arian ac fel offeryn datblygu. Mae estyniadau yn ychwanegu ymarferoldeb ychwanegol at LNbits fel y gallwch arbrofi gydag ystod o dechnolegau blaengar ar y rhwydwaith mellt. Rydym wedi gwneud datblygu estyniadau mor hawdd â phosibl, ac fel prosiect ffynhonnell agored am ddim, rydym yn annog pobl i ddatblygu a chyflwyno eu rhai eu hunain.",export_to_phone:"Allforio i Ffôn gyda chod QR",export_to_phone_desc:"Mae`r cod QR hwn yn cynnwys URL eich waled gyda mynediad llawn. Gallwch ei sganio o`ch ffôn i agor eich waled oddi yno.",wallet:"Waled:",wallets:"Waledi",add_wallet:"Ychwanegu waled newydd",delete_wallet:"Dileu waled",delete_wallet_desc:"Bydd y waled gyfan hon yn cael ei dileu, ni fydd modd adennill yr arian.",rename_wallet:"Ailenwi waled",update_name:"Diweddaru enw",fiat_tracking:"Olrhain Fiat",currency:"Arian Cyfred",update_currency:"Diweddaru arian cyfred",press_to_claim:"Pwyswch i hawlio bitcoin",donate:"Rhoi",view_github:"Gweld ar GitHub",voidwallet_active:" Mae VoidWallet yn weithredol! Taliadau wedi`u hanalluogi",use_with_caution:"DEFNYDDIO GYDA GOFAL - mae waled {name} yn dal yn BETA",service_fee:"Ffi gwasanaeth: {amount} % y trafodiad",service_fee_max:"Ffi gwasanaeth: {amount} % y trafodiad (uchafswm {max} sats)",service_fee_tooltip:"Ffi gwasanaeth a godir gan weinyddwr gweinydd LNbits ym mhob trafodiad sy'n mynd allan",toggle_darkmode:"Toglo Modd Tywyll",payment_reactions:"Adweithiau Talu",view_swagger_docs:"Gweld dogfennau API LNbits Swagger",api_docs:"Dogfennau API",api_keys_api_docs:"URL y nod, allweddi API a dogfennau API",lnbits_version:"Fersiwn LNbits",runs_on:"Yn rhedeg ymlaen",paste:"Gludo",paste_from_clipboard:"Gludo o'r clipfwrdd",paste_request:"Gludo Cais",create_invoice:"Creu Anfoneb",camera_tooltip:"Defnyddio camera i sganio anfoneb/QR",export_csv:"Allforio i CSV",chart_tooltip:"Dangos siart",pending:"yn yr arfaeth",copy_invoice:"Copi anfoneb",withdraw_from:"Tynnu oddi ar",cancel:"Canslo",scan:"Sgan",read:"Darllen",pay:"Talu",memo:"Memo",date:"Dyddiad",payment_processing:"Prosesu taliad...",not_enough_funds:"Dim digon o arian!",search_by_tag_memo_amount:"Chwilio yn ôl tag, memo, swm",invoice_waiting:"Anfoneb yn aros i gael ei thalu",payment_received:"Taliad a Dderbyniwyd",payment_sent:"Taliad a Anfonwyd",receive:"derbyn",send:"anfon",outgoing_payment_pending:"Taliad sy`n aros yn yr arfaeth",drain_funds:"Cronfeydd Draenio",drain_funds_desc:"Cod QR Tynnu`n ôl LNURL yw hwn ar gyfer slurpio popeth o`r waled hon. Peidiwch â rhannu gyda neb. Mae`n gydnaws â balanceCheck a balanceNotify felly efallai y bydd eich waled yn tynnu`r arian yn barhaus o`r fan hon ar ôl y codiad cyntaf.",i_understand:"Rwy`n deall",copy_wallet_url:"Copi URL waled",disclaimer_dialog_title:"Pwysig!",disclaimer_dialog:"Swyddogaeth mewngofnodi i`w ryddhau mewn diweddariad yn y dyfodol, am y tro, gwnewch yn siŵr eich bod yn rhoi nod tudalen ar y dudalen hon ar gyfer mynediad i`ch waled yn y dyfodol! Mae`r gwasanaeth hwn yn BETA, ac nid ydym yn gyfrifol am bobl sy`n colli mynediad at arian.",no_transactions:"Dim trafodion wedi`u gwneud eto",manage:"Rheoli",exchanges:"Cyfnewidfeydd",extensions:"Estyniadau",no_extensions:"Nid oes gennych unrhyw estyniadau wedi'u gosod :(",created:"Crëwyd",search_extensions:"Chwilio estyniadau",extension_sources:"Ffynonellau Estyniad",ext_sources_hint:"Repoau o ble gellir lawrlwytho'r estyniadau",ext_sources_label:"URL Ffynhonnell (defnyddiwch ffynhonnell estyniad swyddogol LNbits yn unig, a ffynonellau y gallwch ymddiried ynddynt)",warning:"Rhybudd",repository:"Ystorfa",confirm_continue:"Ydych chi'n siŵr eich bod chi eisiau parhau?",manage_extension_details:"Gosod/dadosod estyniad",install:"Gosod",uninstall:"Dadgymhwyso",drop_db:"Dileu Data",enable:"Galluogi",pay_to_enable:"Talu I Alluogi",enable_extension_details:"Galluogi estyniad ar gyfer y defnyddiwr presennol",disable:"Analluogi",delete:"Dileu",installed:"Gosodwyd",activated:"Wedi'i actifadu",deactivated:"Anweithredol",release_notes:"Nodiadau Rhyddhau",activate_extension_details:"Gwneud estyniad ar gael/anar gael i ddefnyddwyr",featured:"Nodweddwyd",all:"Pob",only_admins_can_install:"Dim ond cyfrifon gweinyddwr all osod estyniadau",admin_only:"Dim ond Gweinyddwr",new_version:"Fersiwn Newydd",extension_depends_on:"Dibynnu ar:",extension_rating_soon:"Sgôr yn dod yn fuan",extension_installed_version:"Fersiwn wedi'i gosod",extension_uninstall_warning:"Rydych chi ar fin dileu'r estyniad ar gyfer pob defnyddiwr.",uninstall_confirm:"Ie, Dad-osod",extension_db_drop_info:"Bydd yr holl ddata ar gyfer yr estyniad yn cael ei ddileu'n barhaol. Does dim ffordd o dadwneud y weithrediad hwn!",extension_db_drop_warning:"Rydych chi ar fin dileu'r holl ddata ar gyfer yr estyniad. Teipiwch enw'r estyniad i barhau:",extension_required_lnbits_version:"Mae'r rhyddhau hwn yn gofyn o leiaf am fersiwn LNbits",min_version:"Isafswm (cynnwys)",max_version:"Uchafswm (wedi'i eithrio)",payment_hash:"Hais Taliad",fee:"Fee",amount:"swm",amount_sats:"Swm (sats)",tag:"Tag",unit:"Uned",description:"Disgrifiad",expiry:"dod i ben",webhook:"bachyn we",payment_proof:"prawf taliad",update:"Diweddariad",update_available:"Diweddariad {version} ar gael!",latest_update:"Rydych chi ar y fersiwn diweddaraf {version}.",notifications:"Hysbysiadau",no_notifications:"Dim hysbysiadau",notifications_disabled:"Hysbysiadau statws LNbits wedi'u analluogi.",enable_notifications:"Galluogi Hysbysiadau",enable_notifications_desc:"Os bydd wedi'i alluogi bydd yn nôl y diweddariadau Statws LNbits diweddaraf, fel digwyddiadau diogelwch a diweddariadau.",enable_watchdog:"Galluogi Watchdog",enable_watchdog_desc:"Os bydd yn cael ei alluogi bydd yn newid eich ffynhonnell ariannu i VoidWallet yn awtomatig os bydd eich balans yn is na balans LNbits. Bydd angen i chi alluogi â llaw ar ôl diweddariad.",watchdog_interval:"Amserlennu Gwylio",watchdog_interval_desc:"Pa mor aml y dylai'r dasg gefndir wirio am signal torri yn y gwarchodfa delta [node_balance - lnbits_balance] (mewn munudau).",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Terfyn cyn i'r switshladd newid ffynhonnell ariannu i VoidWallet [lnbits_balance - node_balance > delta]",status:"Statws",notification_source:"Ffynhonnell Hysbysiad",notification_source_label:"URL Ffynhonnell (defnyddiwch yn unig ffynhonnell statws swyddogol LNbits, a ffynonellau y gallwch ymddiried ynddynt)",more:"mwy",less:"llai",releases:"Rhyddhau",watchdog:"Gwyliwr",server_logs:"Logiau Gweinydd",ip_blocker:"Rheolydd IP",security:"Diogelwch",security_tools:"Offer teclynnau diogelwch",block_access_hint:"Atal mynediad gan IP",allow_access_hint:"Caniatáu mynediad gan IP (bydd yn diystyru IPs sydd wedi'u blocio)",enter_ip:"Rhowch IP a gwasgwch enter",rate_limiter:"Cyfyngydd Cyfradd",wallet_limiter:"Cyfyngwr Waled",wallet_limit_max_withdraw_per_day:"Uchafswm tynnu’n ôl waled dyddiol mewn sats (0 i analluogi)",wallet_max_ballance:"Uchafswm balans y waled mewn sats (0 i analluogi)",wallet_limit_secs_between_trans:"Eiliadau lleiaf rhwng trafodion fesul waled (0 i analluogi)",number_of_requests:"Nifer y ceisiadau",time_unit:"Uned amser",minute:"munud",second:"ail",hour:"awr",disable_server_log:"Analluogi Log Gweinydd",enable_server_log:"Galluogi Log Gweinydd",coming_soon:"Nodwedd yn dod yn fuan",session_has_expired:"Mae eich sesiwn wedi dod i ben. Mewngofnodwch eto.",instant_access_question:"Eisiau mynediad ar unwaith?",login_with_user_id:"Mewngofnodi gyda ID y defnyddiwr",or:"neu",create_new_wallet:"Creu Waled Newydd",login_to_account:"Mewngofnodwch i'ch cyfrif",create_account:"Creu cyfrif",account_settings:"Gosodiadau Cyfrif",signin_with_nostr:"Parhewch gyda Nostr",signin_with_google:"Mewngofnodi gyda Google",signin_with_github:"Mewngofnodi gyda GitHub",signin_with_keycloak:"Mewngofnodi gyda Keycloak",username_or_email:"Defnyddiwr neu E-bost",password:"Cyfrinair",password_config:"Ffurfweddiad Cyfrinair",password_repeat:"Ailadrodd cyfrinair",change_password:"Newid Cyfrinair",update_credentials:"Diweddaru Cyfrifoldebau",update_pubkey:"Diweddaru Allwedd Gyhoeddus",set_password:"Gosod Cyfrinair",invalid_password:"Rhaid i'r cyfrinair gynnwys o leiaf 8 nod.",login:"Mewngofnodi",register:"Cofrestru",username:"Enw defnyddiwr",pubkey:"Allwedd Gyhoeddus",user_id:"ID Defnyddiwr",email:"E-bost",first_name:"Enw Cyntaf",last_name:"Cyfenw",picture:"Llun",verify_email:"Gwirio e-bost gyda",account:"Cyfrif",update_account:"Diweddaru Cyfrif",invalid_username:"Enw Defnyddiwr Annilys",auth_provider:"Darparwr Dilysiad",my_account:"Fy Nghyfrif",back:"Yn ôl",logout:"Allgofnodi",look_and_feel:"Edrych a Theimlo",toggle_gradient:"Toglo Graddiênt",gradient_background:"Cefndir Graddiant",language:"Iaith",color_scheme:"Cynllun Lliw",admin_settings:"Gosodiadau Gweinyddol",extension_cost:"Mae'r rhyddhad hwn yn gofyn am daliad o leiaf {cost} sats.",extension_paid_sats:"Rydych chi eisoes wedi talu {paid_sats} sats.",release_details_error:"Methu cael manylion y rhyddhau.",pay_from_wallet:"Talu o'r Waled",wallet_required:"Waled *",show_qr:"Dangos QR",retry_install:"Ailgeisio Gosod",new_payment:"Gwneud Taliad Newydd",update_payment:"Diweddarwch Dalu",already_paid_question:"Ydych chi eisoes wedi talu?",sell:"Gwerthu",sell_require:"Gofynnwch am daliad i alluogi estyniad",sell_info:"Mae angen taliad o leiaf {amount} sats ar yr estyniad {name} i'w alluogi.",hide_empty_wallets:"Cuddio waledau gwag",recheck:"Ailwirio",contributors:"Cyfranwyr",license:"Trwydded",reset_key:"Ailosod Allwedd",reset_password:"Ailosod Cyfrinair",border_choices:"Dewisiadau Ffin",select_all:"Dewis Pob Un",nfc_supported:"Cefnogir NFC",nfc_not_supported:"NFC heb ei Gefnogi",expire_date:"Dyddiad Dod i Ben:",hash:"Hash:",welcome_lnbits:"Croeso i LNbits",setup_su_account:"Sefydlu'r cyfrif Superuser isod.",create_ticker_converter:"Creu Trosi Ticiwr Arian",enable_audit:"Galluogi Archwilio",recommended:"Argymhellir",audit_desc:"Cofnodi ceisiadau HTTP yn ôl y hidlwyr penodedig",audit_record_req:"Cofnodi Corff y Cais",audit_record_warning:"Rhybudd:",audit_record_req_warning_1:"data cyfrinachol (fel cyfrineiriau) yn cael eu logio.",audit_record_req_warning_2:"mae gan y corff cais faint mawr.",audit_record_use:"Defnyddiwch ef gyda gofal.",audit_ip:"Cofnodi Cyfeiriad IP",audit_ip_desc:"Cofnodwch gyfeiriad IP y cleient",audit_path_params:"Cofnod Paramedrau Llwybr",audit_query_params:"Cofnod Paramedrau Holiannau",audit_http_methods:"Cynnwys Dulliau HTTP",audit_http_methods_hint:"Rhestr o ddulliau HTTP i'w cynnwys. Yn golygu pob un yw rhestrau gwag.",audit_http_methods_label:"Dulliau HTTP",audit_resp_codes:"Cynnwys Codau Ymateb HTTP",audit_resp_codes_hint:"Rhestr o godau HTTP i'w cynnwys (cydweddu regex). Mae rhestrau gwag yn golygu popeth. Ee: 4.*, 5.*",audit_resp_codes_label:"Cod Ymateb HTTP (regex)",audit_paths:"Cynnwys Llwybrau",audit_paths_hint:"Rhestr o lwybrau i'w cynnwys (cydweddiad rhegiwlar). Mae rhestr wag yn golygu pob un.",audit_paths_label:"Llwybr HTTP (regex)",audit_paths_exclude:"Eithrio Llwybrau",audit_paths_exclude_hint:"Rhestr o lwybrau i'w heithrio (cydweddu regex). Mae rhestr wag yn golygu dim.",audit_paths_exclude_label:"Llwybr HTTP (regex)",exchange_providers:"Darparwyr Cyfnewid",admin_extensions:"Estyniadau Gweinyddol",admin_extensions_label:"Estyniadau gweinyddu",admin_extensions_hint:"Dim ond defnyddiwr Estyniadau gyda braint gweinyddwr sy'n gallu defnyddio",user_default_extensions:"Rhyngwyneb Diofyn Defnyddiwr",user_default_extensions_label:"Estyniadau defnyddiwr",user_default_extensions_hint:"Estyniadau a fydd yn cael eu galluogi yn ddiofyn ar gyfer y defnyddwyr.",miscellanous:"Amrywiol",misc_disable_extensions:"Analluogi Estyniadau",misc_disable_extensions_label:"Analluogi'r holl estynniadau",misc_hide_api:"Cuddio API",misc_hide_api_label:"Yn cuddio api waled, gall estyniadau ddewis anrhydeddu",wallets_management:"Rheoli Waledau",funding_source_info:"Gwybodaeth am Ffynhonnell Ariannu",funding_source:"Ffynhonnell Ariannu: {wallet_class}",node_balance:"Cydbwysedd Nôd: {balance} sats",lnbits_balance:"Cydbwysedd LNbits: {balance} sats",funding_reserve_percent:"Cadw Canran: {percent} %",node_management:"Rheoli Nodau",node_management_not_supported:"Nid yw Rheoli Nodau yn cael ei gefnogi gan ffynhonnell ariannu weithredol",toggle_node_ui:"Node UI",toggle_public_node_ui:"UI Nod Cyhoeddus",toggle_transactions_node_ui:"Tab Trafodion (Analluoga ar nodau CLN mawr)",invoice_expiry:"Dyddiad Dod i Ben yr Anfoneb",invoice_expiry_label:"Darfod anfoneb (eiliadau)",fee_reserve:"Cadw Ffi",fee_reserve_msats:"Ffi cadw yn msats",fee_reserve_percent:"Ffioedd cadw mewn canran",server_management:"Rheoli Gweinyddwr",base_url:"Prif URL",base_url_label:"Url statig/sylfaen ar gyfer y gweinydd",authentication:"Dilysiad",auth_token_expiry_label:"Cofnodi munudau dod i ben",auth_token_expiry_hint:"Amser mewn munudau tan fod y tocyn yn dod i ben",auth_allowed_methods_label:"Dulliau awdurdodi a ganiateir",auth_allowed_methods_hint:"Dewiswch ddulliau awdurdodi",auth_nostr_label:"URL Cais Nostr",auth_nostr_hint:"URL absoliwt y bydd y cleientiaid yn ei ddefnyddio i fewngofnodi.",auth_google_ci_label:"ID Cleient Google",auth_google_ci_hint:"Sicrhewch fod yr URIs adnewyddu awdurdodedig yn cynnwys https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Cwsmer Google Dirgel",auth_gh_client_id_label:"ID Cleient GitHub",auth_gh_client_id_hint:"Gwnewch yn siŵr bod y URL galwad yn ôl awdurdodi wedi'i osod i https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Cudd-wybodaeth Cleient GitHub",auth_keycloak_label:"URL Darganfod Keycloak",auth_keycloak_ci_label:"ID Cleient Keycloak",auth_keycloak_ci_hint:"Gwnewch yn siŵr bod URL adalw awdurdodiad wedi'i osod i https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Cyfrinach Cleient Keycloak",currency_settings:"Gosodiadau Arian Cyfred",allowed_currencies:"Ariannau a Ganiateir",allowed_currencies_hint:"Cyfyngu nifer yr arian cyfred fiat sydd ar gael",default_account_currency:"Arian Cyfred Diofyn y Cyfrif",default_account_currency_hint:"Arian cyfred diofyn ar gyfer cyfrifyddu",service_fee_label:"Ffioedd gwasanaeth (%)",service_fee_hint:"Ffi a godir fesul trx (%)",service_fee_max_label:"Ffioedd gwasanaeth uchaf (sats)",service_fee_max_hint:"Uchafswm ffi gwasanaeth i godi mewn (sats)",fee_wallet:"Waled Ffioedd",fee_wallet_label:"Ffi waled (ID waled)",fee_wallet_hint:"ID Cwlt hon i anfon cronfeydd i",disable_fee:"Analluogi Ffi",disable_fee_internal:"Analluogi Ffi Gwasanaeth ar gyfer Taliadau Mewnol",disable_fee_internal_desc:"Analluogi Ffi Gwasanaeth ar gyfer Taliadau Mellt Mewnol",ui_management:"Rheoli UI",ui_site_title:"Teitl y Safle",ui_site_tagline:"Tagline'r Safle",ui_elements_enable:"Galluogi elfennau ar hafan",ui_elements_disable:"Analluoga elfennau ar y dudalen gartref",ui_toggle_elements_tip:"Tynn elfennau tudalen gartref fel 'yn rhedeg ar' ayyb.",ui_site_description:"Disgrifiad Safle",ui_site_description_hint:"Defnyddiwch destun plaen, Markdown, neu HTML crai",ui_default_wallet_name:"Enw Diofyn y Waled",lnbits_wallet:"Cwdyn LNbits",denomination:"Enwad",denomination_hint:"Enw'r token FakeWallet",ui_qr_code_logo:"Logo Cod QR",ui_qr_code_logo_hint:"URL i ddelwedd logo yn y cod QR",ui_custom_badge:"Bathodyn Personol",ui_custom_badge_label:"Bathodyn Custom 'DEFNYDDIO GYDA RHYBUDD - mae waled LNbits dal mewn BETA'",ui_custom_badge_color_label:"Lliw Bathodyn Personol",themes:"Themâu",themes_hint:"Dewiswch themâu sydd ar gael i ddefnyddwyr",custom_logo:"Logo Personol",custom_logo_hint:"URL i ddelwedd logo",ad_space_title:"Teitl Gofod Hysbysebu",ad_space_title_label:"Cefnogir gan",ad_slots:"Slotiau Hysbysebu",ad_slots_hint:"Ychwanegu url a llwybrau ffeil delwedd yn y fformat CSV, gall estyniadau ddewis i barchu",ad_slots_label:"url;url_delwedd_ysgafn;url_delwedd_tywyll, url...",ads_enabled:"Hysbysebion wedi'u Galluogi",ads_disabled:"Hysbysebion Wedi'u Analluogi",user_management:"Rheoli Defnyddwyr",admin_users:"Defnyddwyr Gweinyddol",admin_users_hint:"Defnyddwyr â breintiau gweinyddol",admin_users_label:"ID Defnyddiwr",allowed_users:"Defnyddwyr a Ganiateir",allowed_users_hint:"Dim ond y defnyddwyr hyn all ddefnyddio LNbits",allowed_users_label:"ID defnyddiwr",allow_creation_user:"Caniatáu creu defnyddwyr newydd",allow_creation_user_desc:"Caniatáu creu defnyddwyr newydd ar y dudalen fynegai",components:"Cydrannau",long_running_endpoints:"5 Pwynt Terfyn Hir-rhediad Uchaf",http_request_methods:"Dulliau Cais HTTP",http_response_codes:"Codau Ymateb HTTP",request_details:"Manylion y Cais",http_request_details:"Manylion Cais HTTP"},window.localisation.pt={confirm:"Sim",server:"Servidor",theme:"Tema",site_customisation:"Customização do Site",funding:"Financiamento",users:"Usuários",audit:"Auditoria",apps:"Aplicativos",channels:"Canais",transactions:"Transações",dashboard:"Painel de Controle",node:"Nó",export_users:"Exportar Usuários",no_users:"Nenhum usuário encontrado",total_capacity:"Capacidade Total",avg_channel_size:"Tamanho Médio do Canal",biggest_channel_size:"Maior Tamanho do Canal",smallest_channel_size:"Menor Tamanho de Canal",number_of_channels:"Número de Canais",active_channels:"Canais Ativos",connect_peer:"Conectar Par",connect:"Conectar",open_channel:"Canal Aberto",open:"Abrir",close_channel:"Fechar Canal",close:"Fechar",restart:"Reiniciar servidor",save:"Gravar",save_tooltip:"Gravar as alterações",credit_debit:"Crédito / Débito",credit_hint:"Pressione Enter para creditar a conta",credit_label:"{denomination} para creditar",credit_ok:"Sucesso ao creditar/debitar fundos virtuais ({amount} sats). Os pagamentos dependem dos fundos reais na fonte de financiamento.",restart_tooltip:"Reinicie o servidor para que as alterações tenham efeito",add_funds_tooltip:"Adicionar fundos a uma carteira.",reset_defaults:"Redefinir para padrões",reset_defaults_tooltip:"Apagar todas as configurações e redefinir para os padrões.",download_backup:"Fazer backup da base de dados",name_your_wallet:"Nomeie sua carteira {name}",paste_invoice_label:"Cole uma fatura, pedido de pagamento ou código lnurl *",lnbits_description:"Fácil de configurar e leve, o LNbits pode ser executado em qualquer fonte de financiamento da Lightning Network e até mesmo o LNbits em si! Você pode executar o LNbits para si mesmo ou oferecer facilmente uma solução de custódia para outros. Cada carteira tem suas próprias chaves de API e não há limite para o número de carteiras que você pode criar. Ser capaz de particionar fundos torna o LNbits uma ferramenta útil para gerenciamento de dinheiro e como uma ferramenta de desenvolvimento. As extensões adicionam funcionalidades extras ao LNbits para que você possa experimentar uma série de tecnologias de ponta na rede lightning. Nós tornamos o desenvolvimento de extensões o mais fácil possível e, como um projeto gratuito e de código aberto, incentivamos as pessoas a desenvolver e enviar as suas próprias.",export_to_phone:"Exportar para o telefone com código QR",export_to_phone_desc:"Este código QR contém a URL da sua carteira com acesso total. Você pode escaneá-lo do seu telefone para abrir sua carteira a partir dele.",wallet:"Carteira:",wallets:"Carteiras",add_wallet:"Adicionar nova carteira",delete_wallet:"Excluir carteira",delete_wallet_desc:"Toda a carteira será excluída, os fundos serão IRRECUPERÁVEIS.",rename_wallet:"Renomear carteira",update_name:"Atualizar nome",fiat_tracking:"Rastreamento Fiat",currency:"Moeda",update_currency:"Atualizar moeda",press_to_claim:"Pressione para solicitar bitcoin",donate:"Doar",view_github:"Ver no GitHub",voidwallet_active:"VoidWallet está ativo! Pagamentos desabilitados",use_with_caution:"USE COM CAUTELA - a carteira {name} ainda está em BETA",service_fee:"Taxa de serviço: {amount} % por transação",service_fee_max:"Taxa de serviço: {amount} % por transação (máximo de {max} sats)",service_fee_tooltip:"Taxa de serviço cobrada pelo administrador do servidor LNbits por transação de saída",toggle_darkmode:"Alternar modo escuro",payment_reactions:"Reações de Pagamento",view_swagger_docs:"Ver a documentação da API do LNbits Swagger",api_docs:"Documentação da API",api_keys_api_docs:"URL do Nó, chaves de API e documentação de API",lnbits_version:"Versão do LNbits",runs_on:"Executa em",paste:"Colar",paste_from_clipboard:"Colar da área de transferência",paste_request:"Colar Pedido",create_invoice:"Criar Fatura",camera_tooltip:"Usar a câmara para escanear uma fatura / QR",export_csv:"Exportar para CSV",chart_tooltip:"Mostrar gráfico",pending:"Pendente",copy_invoice:"Copiar fatura",withdraw_from:"Retirar de",cancel:"Cancelar",scan:"Escanear",read:"Ler",pay:"Pagar",memo:"Memo",date:"Data",payment_processing:"Processando pagamento...",not_enough_funds:"Fundos insuficientes!",search_by_tag_memo_amount:"Pesquisar por tag, memo, quantidade",invoice_waiting:"Fatura aguardando pagamento",payment_received:"Pagamento Recebido",payment_sent:"Pagamento Enviado",receive:"receber",send:"enviar",outgoing_payment_pending:"Pagamento de saída pendente",drain_funds:"Esvasiar carteira",drain_funds_desc:"Este é um código QR de saque LNURL para sacar tudo desta carteira. Não o partilhe com ninguém. É compatível com balanceCheck e balanceNotify para que a sua carteira possa continuar levantando os fundos continuamente daqui após o primeiro saque.",i_understand:"Eu entendo",copy_wallet_url:"Copiar URL da carteira",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"Funcionalidade de login a ser lançada numa atualização futura, por enquanto, certifique-se que marca esta página para acesso futuro à sua carteira! Este serviço está em BETA, e não nos responsabilizamos por pessoas que perderem o acesso aos fundos.",no_transactions:"Ainda não foram feitas transações",manage:"Gerir",exchanges:"Trocas",extensions:"Extensões",no_extensions:"Não há nenhuma extensão instalada :(",created:"Criado",search_extensions:"Pesquisar extensões",extension_sources:"Fontes de Extensão",ext_sources_hint:"Repositórios de onde as extensões podem ser baixadas",ext_sources_label:"URL de origem (use apenas a fonte oficial da extensão LNbits e fontes em que você confia)",warning:"Aviso",repository:"Repositório",confirm_continue:"Tem certeza de que deseja continuar?",manage_extension_details:"Instalar/desinstalar extensão",install:"Instalar",uninstall:"Desinstalar",drop_db:"Remover Dados",enable:"Ativar",pay_to_enable:"Pagar para Ativar",enable_extension_details:"Ativar extensão para o usuário atual",disable:"Desativar",delete:"Excluir",installed:"Instalado",activated:"Ativado",deactivated:"Desativado",release_notes:"Notas de Lançamento",activate_extension_details:"Torne a extensão disponível/indisponível para usuários",featured:"Destacado",all:"Todos",only_admins_can_install:"Apenas contas de administrador podem instalar extensões.",admin_only:"Apenas para administradores",new_version:"Nova Versão",extension_depends_on:"Depende de:",extension_rating_soon:"Avaliações em breve",extension_installed_version:"Versão instalada",extension_uninstall_warning:"Você está prestes a remover a extensão para todos os usuários.",uninstall_confirm:"Sim, Desinstalar",extension_db_drop_info:"Todos os dados da extensão serão permanentemente excluídos. Não há como desfazer essa operação!",extension_db_drop_warning:"Você está prestes a remover todos os dados para a extensão. Por favor, digite o nome da extensão para continuar:",extension_required_lnbits_version:"Esta versão requer pelo menos a versão LNbits",min_version:"Mínimo (incluído)",max_version:"Máximo (excluído)",payment_hash:"Hash de pagamento",fee:"Taxa",amount:"Quantidade",amount_sats:"Quantidade (sats)",tag:"Etiqueta",unit:"Unidade",description:"Descrição",expiry:"Validade",webhook:"Webhook",payment_proof:"Comprovativo de pagamento",update:"Atualizar",update_available:"Atualização {version} disponível!",latest_update:"Você está na última versão {version}.",notifications:"Notificações",no_notifications:"Sem notificações",notifications_disabled:"As notificações de status do LNbits estão desativadas.",enable_notifications:"Ativar Notificações",enable_notifications_desc:"Se ativado, ele buscará as últimas atualizações de status do LNbits, como incidentes de segurança e atualizações.",enable_watchdog:"Ativar Watchdog",enable_watchdog_desc:"Se ativado, mudará automaticamente a sua fonte de financiamento para VoidWallet caso o seu saldo seja inferior ao saldo LNbits. Você precisará ativar manualmente após uma atualização.",watchdog_interval:"Intervalo do Watchdog",watchdog_interval_desc:"Com que frequência a tarefa de fundo deve verificar um sinal de desligamento no delta do watchdog [node_balance - lnbits_balance] (em minutos).",watchdog_delta:"Observador Delta",watchdog_delta_desc:"Limite antes que o killswitch altere a fonte de financiamento para VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fonte de Notificação",notification_source_label:"URL de Origem (use apenas a fonte oficial de status do LNbits e fontes em que confia)",more:"mais",less:"menos",releases:"Lançamentos",watchdog:"Cão de guarda",server_logs:"Registros do Servidor",ip_blocker:"Bloqueador de IP",security:"Segurança",security_tools:"Ferramentas de segurança",block_access_hint:"Bloquear acesso por IP",allow_access_hint:"Permitir acesso por IP (substituirá IPs bloqueados)",enter_ip:"Digite o IP e pressione enter.",rate_limiter:"Limitador de Taxa",wallet_limiter:"Limitador de Carteira",wallet_limit_max_withdraw_per_day:"Limite diário máximo de saque da carteira em sats (0 para desativar)",wallet_max_ballance:"Saldo máximo da carteira em sats (0 para desativar)",wallet_limit_secs_between_trans:"Minutos seg. entre transações por carteira (0 para desativar)",number_of_requests:"Número de solicitações",time_unit:"Unidade de tempo",minute:"minuto",second:"segundo",hour:"hora",disable_server_log:"Desativar Log do Servidor",enable_server_log:"Ativar Log do Servidor",coming_soon:"Funcionalidade em breve",session_has_expired:"Sua sessão expirou. Por favor, faça login novamente.",instant_access_question:"Quer acesso imediato?",login_with_user_id:"Entrar com ID do usuário",or:"ou",create_new_wallet:"Criar Nova Carteira",login_to_account:"Faça login na sua conta",create_account:"Criar conta",account_settings:"Configurações da Conta",signin_with_nostr:"Continue com Nostr",signin_with_google:"Entrar com o Google",signin_with_github:"Entrar com o GitHub",signin_with_keycloak:"Entrar com o Keycloak",username_or_email:"Nome de usuário ou Email",password:"Senha",password_config:"Configuração de Senha",password_repeat:"Repetição de senha",change_password:"Alterar Senha",update_credentials:"Atualizar Credenciais",update_pubkey:"Atualizar Chave Pública",set_password:"Definir Senha",invalid_password:"A senha deve ter pelo menos 8 caracteres",login:"Entrar",register:"Registrar",username:"Nome de usuário",pubkey:"Chave Pública",user_id:"ID do Usuário",email:"E-mail",first_name:"Nome próprio",last_name:"Sobrenome",picture:"Foto",verify_email:"Verifique o e-mail com",account:"Conta",update_account:"Atualizar Conta",invalid_username:"Nome de usuário inválido",auth_provider:"Provedor de Autenticação",my_account:"Minha Conta",back:"Voltar",logout:"Sair",look_and_feel:"Aparência e Sensação",toggle_gradient:"Alternar Gradiente",gradient_background:"Fundo Gradiente",language:"Idioma",color_scheme:"Esquema de Cores",admin_settings:"Configurações de Administração",extension_cost:"Este lançamento requer um pagamento mínimo de {cost} sats.",extension_paid_sats:"Você já pagou {paid_sats} sats.",release_details_error:"Não é possível obter os detalhes da versão.",pay_from_wallet:"Pague da Carteira",wallet_required:"Carteira *",show_qr:"Exibir QR",retry_install:"Reinstalar Tente Novamente",new_payment:"Realizar Novo Pagamento",update_payment:"Atualizar Pagamento",already_paid_question:"Já pagou?",sell:"Vender",sell_require:"Peça pagamento para habilitar a extensão",sell_info:"A extensão {name} requer um pagamento mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar carteiras vazias",recheck:"Rever",contributors:"Colaboradores",license:"Licença",reset_key:"Redefinir Chave",reset_password:"Redefinir Senha",border_choices:"Opções de Borda",select_all:"Selecionar tudo",nfc_supported:"NFC Suportado",nfc_not_supported:"NFC não suportado",expire_date:"Data de Expiração:",hash:"Hash:",welcome_lnbits:"Bem-vindo ao LNbits",setup_su_account:"Configure a conta Superusuário abaixo.",create_ticker_converter:"Criar Conversor de Moeda Ticker",enable_audit:"Ativar Auditoria",recommended:"Recomendado",audit_desc:"Registre solicitações HTTP de acordo com os filtros especificados",audit_record_req:"Registrar Corpo da Solicitação",audit_record_warning:"Aviso:",audit_record_req_warning_1:"dados confidenciais (como senhas) serão registrados.",audit_record_req_warning_2:"o corpo da solicitação pode ter um tamanho grande.",audit_record_use:"Use com cautela.",audit_ip:"Registrar Endereço IP",audit_ip_desc:"Registre o endereço IP do cliente",audit_path_params:"Registrar parâmetros de caminho",audit_query_params:"Registrar Parâmetros de Consulta",audit_http_methods:"Incluir métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a serem incluídos. Listas vazias significam todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Resposta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a serem incluídos (correspondência com expressões regulares). Listas vazias significam todos. Ex: 4.*, 5.*",audit_resp_codes_label:"Código de resposta HTTP (regex)",audit_paths:"Incluir Caminhos",audit_paths_hint:"Lista de caminhos a serem incluídos (correspondência regex). Lista vazia significa todos.",audit_paths_label:"Caminho HTTP (regex)",audit_paths_exclude:"Excluir Caminhos",audit_paths_exclude_hint:"Lista de caminhos a serem excluídos (correspondência com regex). Lista vazia significa nenhum.",audit_paths_exclude_label:"Caminho HTTP (regex)",exchange_providers:"Provedores de Câmbio",admin_extensions:"Extensões do Administrador",admin_extensions_label:"Extensões administrativas",admin_extensions_hint:"Somente usuários com privilégios de administrador podem usar extensões.",user_default_extensions:"Extensões Padrão do Usuário",user_default_extensions_label:"Extensões do usuário",user_default_extensions_hint:"Extensões que serão ativadas por padrão para os usuários.",miscellanous:"Diversos",misc_disable_extensions:"Desativar Extensões",misc_disable_extensions_label:"Desativar todas as extensões",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta a API da carteira, extensões podem optar por honrar",wallets_management:"Gestão de Carteiras",funding_source_info:"Informações da Fonte de Financiamento",funding_source:"Fonte de Financiamento: {wallet_class}",node_balance:"Saldo do Nó: {balance} sats",lnbits_balance:"Saldo do LNbits: {balance} sats",funding_reserve_percent:"Reserve Percentagem: {percent} %",node_management:"Gerenciamento de Nós",node_management_not_supported:"Gerenciamento de nós não suportado pela fonte de financiamento ativa",toggle_node_ui:"Interface do Usuário de Nó",toggle_public_node_ui:"Interface Pública do Nó",toggle_transactions_node_ui:"Aba de Transações (Desativar em nós grandes do CLN)",invoice_expiry:"Validade da Fatura",invoice_expiry_label:"Expiração da fatura (segundos)",fee_reserve:"Reserva de Taxa",fee_reserve_msats:"Taxa de reserva em msats",fee_reserve_percent:"Taxa de reserva em porcentagem",server_management:"Gerenciamento de Servidor",base_url:"URL base",base_url_label:"URL estático/base para o servidor",authentication:"Autenticação",auth_token_expiry_label:"Minutos de expiração do token",auth_token_expiry_hint:"Tempo em minutos até que o token expire",auth_allowed_methods_label:"Métodos de autorização permitidos",auth_allowed_methods_hint:"Selecione os métodos de autorização",auth_nostr_label:"URL de Solicitação Nostr",auth_nostr_hint:"URL absoluta que os clientes usarão para fazer login.",auth_google_ci_label:"ID do Cliente do Google",auth_google_ci_hint:"Certifique-se de que os URIs de redirecionamento autorizados contenham https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Segredo do Cliente do Google",auth_gh_client_id_label:"ID do Cliente do GitHub",auth_gh_client_id_hint:"Certifique-se de que a URL de retorno de chamada de autorização esteja definida como https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Cliente Secreto do GitHub",auth_keycloak_label:"URL de Descoberta do Keycloak",auth_keycloak_ci_label:"ID do Cliente do Keycloak",auth_keycloak_ci_hint:"Certifique-se de que o URL de retorno de chamada de autorização esteja definido como https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Segredo do Cliente do Keycloak",currency_settings:"Configurações de Moeda",allowed_currencies:"Moedas Permitidas",allowed_currencies_hint:"Limite o número de moedas fiduciárias disponíveis",default_account_currency:"Moeda Padrão da Conta",default_account_currency_hint:"Moeda padrão para contabilidade",service_fee_label:"Taxa de serviço (%)",service_fee_hint:"Taxa cobrada por transação (%)",service_fee_max_label:"Taxa de serviço máx (sats)",service_fee_max_hint:"Taxa máxima de serviço a cobrar em (sats)",fee_wallet:"Carteira de Taxas",fee_wallet_label:"Carteira de taxa (ID da carteira)",fee_wallet_hint:"ID da carteira para enviar fundos para",disable_fee:"Desativar taxa",disable_fee_internal:"Desativar Taxa de Serviço para Pagamentos Internos",disable_fee_internal_desc:"Desativar Taxa de Serviço para Pagamentos Internos Lightning",ui_management:"Gestão de UI",ui_site_title:"Título do Site",ui_site_tagline:"Tagline do site",ui_elements_enable:"Ativar elementos na página inicial",ui_elements_disable:"Desativar elementos na página inicial",ui_toggle_elements_tip:"Remova elementos da homepage como 'executa em' etc.",ui_site_description:"Descrição do Site",ui_site_description_hint:"Use texto simples, Markdown ou HTML bruto",ui_default_wallet_name:"Nome Padrão da Carteira",lnbits_wallet:"Carteira LNbits",denomination:"Denominação",denomination_hint:"O nome para o token FakeWallet",ui_qr_code_logo:"Logo do Código QR",ui_qr_code_logo_hint:"URL para imagem do logotipo no código QR",ui_custom_badge:"Distintivo Personalizado",ui_custom_badge_label:"Emblema Personalizado 'USE COM CAUTELA - A carteira LNbits ainda está em BETA'",ui_custom_badge_color_label:"Cor Personalizada do Distintivo",themes:"Temas",themes_hint:"Escolha os temas disponíveis para os usuários",custom_logo:"Logotipo Personalizado",custom_logo_hint:"URL para imagem do logotipo",ad_space_title:"Título do Espaço Publicitário",ad_space_title_label:"Suportado por",ad_slots:"Espaços Publicitários",ad_slots_hint:"Adicionar URL e caminhos de arquivo de imagem no formato CSV, extensões podem optar por respeitar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anúncios Ativados",ads_disabled:"Anúncios Desativados",user_management:"Gestão de Usuários",admin_users:"Usuários Administrativos",admin_users_hint:"Usuários com privilégios de administrador",admin_users_label:"ID do Usuário",allowed_users:"Usuários Permitidos",allowed_users_hint:"Somente estes usuários podem usar LNbits",allowed_users_label:"ID do usuário",allow_creation_user:"Permitir a criação de novos usuários",allow_creation_user_desc:"Permitir a criação de novos usuários na página inicial",components:"Componentes",long_running_endpoints:"Principais 5 Endpoints de Longa Execução",http_request_methods:"Métodos de Requisição HTTP",http_response_codes:"Códigos de Resposta HTTP",request_details:"Detalhes da solicitação",http_request_details:"Detalhes da Solicitação HTTP"},window.localisation.br={confirm:"Sim",server:"Servidor",theme:"Tema",site_customisation:"Customização do Site",funding:"Financiamento",users:"Usuários",audit:"Auditoria",api_watch:"Relógio da API",apps:"Aplicativos",channels:"Canais",transactions:"Transações",dashboard:"Painel de Controle",node:"Nó",export_users:"Exportar Usuários",no_users:"Nenhum usuário encontrado",total_capacity:"Capacidade Total",avg_channel_size:"Tamanho médio do canal",biggest_channel_size:"Maior Tamanho de Canal",smallest_channel_size:"Tamanho Mínimo do Canal",number_of_channels:"Número de Canais",active_channels:"Canais Ativos",connect_peer:"Conectar Par",connect:"Conectar",reconnect:"Reconectar",open_channel:"Canal Aberto",open:"Abrir",clear:"Limpar",close_channel:"Fechar Canal",close:"Fechar",restart:"Reiniciar servidor",image_library:"Biblioteca de Imagens",save:"Salvar",save_tooltip:"Salvar suas alterações",must_save:"Você tem alterações não salvas",credit_debit:"Crédito / Débito",credit_hint:"Pressione Enter para creditar a conta",credit_label:"{denomination} para creditar",credit_ok:"Sucesso ao creditar/debitar fundos virtuais ({amount} sats). Os pagamentos dependem dos fundos reais na fonte de financiamento.",restart_tooltip:"Reinicie o servidor para que as alterações tenham efeito",add_funds_tooltip:"Adicionar fundos a uma carteira.",reset_defaults:"Redefinir para padrões",reset_defaults_tooltip:"Apagar todas as configurações e redefinir para os padrões.",download_backup:"Fazer backup do banco de dados",name_your_wallet:"Nomeie sua carteira {name}",paste_invoice_label:"Cole uma fatura, pedido de pagamento ou código lnurl *",lnbits_description:"Fácil de configurar e leve, o LNbits pode ser executado em qualquer fonte de financiamento da Lightning Network e até mesmo o LNbits em si! Você pode executar o LNbits para si mesmo ou oferecer facilmente uma solução de custódia para outros. Cada carteira tem suas próprias chaves de API e não há limite para o número de carteiras que você pode criar. Ser capaz de particionar fundos torna o LNbits uma ferramenta útil para gerenciamento de dinheiro e como uma ferramenta de desenvolvimento. As extensões adicionam funcionalidades extras ao LNbits para que você possa experimentar uma série de tecnologias de ponta na rede lightning. Nós tornamos o desenvolvimento de extensões o mais fácil possível e, como um projeto gratuito e de código aberto, incentivamos as pessoas a desenvolver e enviar as suas próprias.",export_to_phone:"Exportar para o telefone com código QR",export_to_phone_desc:"Este código QR contém a URL da sua carteira com acesso total. Você pode escaneá-lo do seu telefone para abrir sua carteira a partir dele.",access_wallet_on_mobile:"Acesso Móvel",stored_paylinks:"Links LNURL de pagamento armazenados",wallet:"Carteira:",wallet_name:"Nome da carteira",wallet_type:"Tipo de carteira",shared_wallet:"Carteira Compartilhada",share_wallet:"Compartilhar Carteira",update_permissions:"Atualizar Permissões",shared_wallet_id:"ID da Carteira Compartilhada",shared_wallet_desc:"Você foi convidado(a) para ter acesso à carteira de outra pessoa.",wallets:"Carteiras",exclude_wallets:"Excluir Carteiras",add_wallet:"Adicionar nova carteira",reject_wallet:"Rejeitar carteira",add_new_wallet:"Adicionar uma nova carteira",pin_wallet:"Fixar carteira",delete_wallet:"Excluir carteira",delete_wallet_desc:"Toda a carteira será excluída, os fundos serão IRRECUPERÁVEIS.",rename_wallet:"Renomear carteira",update_name:"Atualizar nome",fiat_tracking:"Rastreamento Fiat",fiat_providers:"Provedores fiat",fiat_warning_bitcoin:'Provedores Fiat podem ficar nervosos com qualquer coisa relacionada ao bitcoin, portanto, evite usar a palavra "bitcoin" nos seus memorandos!',currency:"Moeda",update_currency:"Atualizar moeda",press_to_claim:"Pressione para solicitar bitcoin",claim_desc:"Parece que você tem um valor resgatável de bitcoin, mas ainda não tem uma carteira. Pressione o botão abaixo para reivindicá-lo. Isso criará uma nova carteira para você.",donate:"Doar",view_github:"Ver no GitHub",voidwallet_active:"VoidWallet está ativo! Pagamentos desabilitados",voidwallet_active_user:"Fonte de financiamento indisponível. Por favor, entre em contato com seu administrador para configurar.",voidwallet_active_admin:"Fonte de financiamento indisponível. Clique aqui para configurar.",service_fee_badge:"Taxa de serviço: {amount} % por transação",service_fee_max_badge:"Taxa de serviço: {amount} % por transação (máximo {max} {denom})",service_fee_tooltip:"Taxa de serviço cobrada pelo administrador do servidor LNbits por transação de saída",toggle_darkmode:"Alternar modo escuro",payment_reactions:"Reações de Pagamento",view_swagger_docs:"Ver a documentação da API do LNbits Swagger",api_docs:"Documentação da API",api_keys_api_docs:"URL do Node, chaves da API e documentação da API",lnbits_version:"Versão do LNbits",runs_on:"Executa em",paste:"Colar",paste_from_clipboard:"Cole do clipboard",paste_request:"Colar Pedido",create_invoice:"Criar Fatura",camera_tooltip:"Usar a câmara para escanear uma fatura / QR",export_csv:"Exportar para CSV",export_csv_details:"Exportar para CSV com detalhes",chart_tooltip:"Mostrar gráfico",pending:"Pendente",copy_invoice:"Copiar fatura",withdraw_from:"Sacar de",cancel:"Cancelar",scan:"Escanear",read:"Ler",write:"Escrever",pay:"Pagar",memo:"Memo",date:"Data",path:"Caminho",internal_memo:"Memorando interno (opcional)",internal_memo_hint_receive:"Este memorando não é mostrado ao pagador, mas é armazenado na fatura para sua referência.",internal_memo_hint_pay:"Este memorando não é exibido ao beneficiário, mas é armazenado no pagamento para sua referência.",payment_processing:"Processando pagamento...",payment_successful:"Pagamento bem-sucedido!",payment_pending:"Pagamento pendente...",payment_check:"Cheque pagamento",not_enough_funds:"Fundos insuficientes!",search_by_tag_memo_amount:"Pesquisar por tag, memo, quantidade",search:"Buscar",invoice_waiting:"Fatura aguardando pagamento",payment_received:"Pagamento Recebido",payment_sent:"Pagamento Enviado",payment_failed:"Pagamento Falhou",receive:"receber",send:"enviar",outgoing_payment_pending:"Pagamento pendente de saída",drain_funds:"Drenar Fundos",drain_funds_desc:"Este é um código QR de retirada do LNURL para sugar tudo desta carteira. Não compartilhe com ninguém. É compatível com balanceCheck e balanceNotify para que sua carteira possa continuar retirando os fundos continuamente daqui após a primeira retirada.",i_understand:"Eu entendo",copy_wallet_url:"Copiar URL da carteira",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"Funcionalidade de login a ser lançada em uma atualização futura, por enquanto, certifique-se de marcar esta página para acesso futuro à sua carteira! Este serviço está em BETA, e não nos responsabilizamos por pessoas que perderem o acesso aos fundos.",no_transactions:"Ainda não foram feitas transações",manage:"Gerenciar",exchanges:"Bolsas de valores",extensions:"Extensões",no_extensions:"Você não possui nenhuma extensão instalada :(",created:"Criado",created_at:"Criado em",updated_at:"Atualizado em",search_extensions:"Extensões de pesquisa",search_wallets:"Pesquisar carteiras",extension_sources:"Fontes de Extensão",ext_sources_hint:"Repositórios de onde as extensões podem ser baixadas",ext_sources_label:"URL de origem (use apenas a fonte oficial da extensão LNbits e fontes confiáveis)",warning:"Aviso",repository:"Repositório",confirm_continue:"Você tem certeza de que deseja continuar?",manage_extension_details:"Instalar/desinstalar extensão",upload:"Enviar",install:"Instalar",uninstall:"Desinstalar",drop_db:"Remover Dados",enable:"Ativar",enabled:"Habilitado",disabled:"Desativado",pay_to_enable:"Pague para Habilitar",enable_extension_details:"Ativar extensão para o usuário atual",disable:"Desativar",delete:"Excluir",installed:"Instalado",activated:"Ativado",deactivated:"Desativado",activate:"Ativar",deactivate:"Desativar",release_notes:"Notas de Lançamento",activate_extension_details:"Tornar a extensão disponível/indisponível para usuários",featured:"Destacado",all:"Tudo",only_admins_can_install:"Apenas contas de administrador podem instalar extensões.",only_admins_can_create_extensions:"Apenas contas de administrador podem criar extensões",admin_only:"Apenas para Administração",make_user_admin:"Tornar usuário administrador",revoke_admin:"Revogar Admin",new_version:"Nova Versão",reviews_url:"URL de Avaliações",reviews_url_label:"URL do servidor de avaliações",reviews_url_hint:"URL completa do PaidReviews incluindo o id das configurações (por exemplo, https://example.com/paidreviews/SETTINGS_ID)",reviews_open:"Ver avaliações",reviews_leave:"Deixe uma avaliação",reviews_name:"Seu nome",reviews_comment:"Sua avaliação",reviews_rating:"Avaliação",reviews_submit:"Enviar avaliação",reviews_loading:"Carregando avaliações...",reviews_refresh:"Atualizar avaliações",reviews_error_load:"Não foi possível carregar as avaliações",reviews_url_not_configured:"URL de avaliações não configurada",reviews_pay_invoice:"Pagar fatura",reviews_invoice_paid:"Fatura paga",reviews_invoice_title:"Pague esta fatura para enviar sua avaliação",reviews_count:"Avaliações",no_reviews:"Ainda não há avaliações",extension_has_free_release:"Tem lançamentos gratuitos",extension_has_paid_release:"Tem lançamentos pagos",extension_depends_on:"Depende de:",extension_rating_soon:"Avaliações estarão disponíveis em breve",extension_installed_version:"Versão instalada",extension_uninstall_warning:"Você está prestes a remover a extensão para todos os usuários.",uninstall_confirm:"Sim, Desinstalar",extension_db_drop_info:"Todos os dados da extensão serão permanentemente excluídos. Não há como desfazer essa operação!",extension_db_drop_warning:"Você está prestes a remover todos os dados para a extensão. Por favor, digite o nome da extensão para continuar:",extension_required_lnbits_version:"Esta versão requer no mínimo a versão do LNbits",min_version:"Mínimo (incluído)",max_version:"Máximo (excluído)",preimage:"Pré-imagem",preimage_hint:"Pré-imagem para liquidar a fatura de retenção",hold_invoice:"Reter Fatura",hold_invoice_description:"Esta fatura está em espera e requer uma pré-imagem para ser liquidada.",payment_hash:"Hash de pagamento",invoice_cancelled:"Fatura Cancelada",invoice_settled:"Fatura Liquidada",hold_invoice_payment_hash:"Hash de pagamento para fatura em espera (opcional)",settle_invoice:"Liquidar Fatura",cancel_invoice:"Cancelar Fatura",fee:"Taxa",amount:"Quantidade",amount_limits:"Limites de Quantia",amount_sats:"Quantidade (sats)",faucest_wallet:"Carteira de Torneira",faucest_wallet_desc_1:"Toda vez que um pagamento for confirmado pelo provedor {provider}, os fundos serão subtraídos desta carteira.",faucest_wallet_desc_2:"Isso ajuda a monitorar todos os pagamentos do {provider} e seu status.",faucest_wallet_desc_3:"Esta carteira deve ser recarregada com a quantia de sats que o administrador está disposto a oferecer em troca da moeda fiduciária.",faucest_wallet_desc_4:"Se esta carteira estiver configurada, mas estiver vazia, os pagamentos de {provider} não serão processados.",faucest_wallet_desc_5:"Esta carteira pode eventualmente ficar com saldo negativo se pagamentos fiduciários paralelos forem feitos.",faucest_wallet_id:"ID da Carteira de Torneira (opcional)",faucest_wallet_id_hint:"ID da carteira a ser usado para a torneira. Será usado para enviar os fundos ao usuário.",tag:"Etiqueta",unit:"Unidade",description:"Descrição",expiry:"Validade",webhook:"Webhook",webhook_url:"URL do Webhook",webhook_url_hint:"URL de Webhook para enviar os detalhes do pagamento. Será chamada quando o pagamento for concluído.",copy_webhook_url:"Copiar URL do webhook",webhook_events_list:"Os seguintes eventos devem ser suportados pelo webhook:",webhook_stripe_description:"No lado do Stripe, você deve configurar um webhook com um URL que aponta para o seu servidor LNbits.",payment_proof:"Comprovante de pagamento",update:"Atualizar",update_available:"Atualização {version} disponível!",funding_sources:"Fontes de Financiamento",latest_update:"Você está na versão mais recente {version}.",notifications:"Notificações",notifications_configure:"Configurar Notificações",notifications_nostr_config:"Configuração do Nostr",notifications_enable_nostr:"Ativar Nostr",notifications_enable_nostr_desc:"Enviar notificações pelo Nostr",notifications_nostr_private_key:"Chave Privada Nostr",notifications_nostr_private_key_desc:"Chave privada (hex ou nsec) para assinar as mensagens enviadas para Nostr",notifications_nostr_identifier:"Identificador Nostr",notifications_nostr_identifier_desc:"Identificador Nip5 para enviar notificações para",notifications_nostr_identifiers:"Identificadores Nostr",notifications_nostr_identifiers_desc:"Lista de identificadores para enviar notificações.",notifications_telegram_config:"Configuração do Telegram",notifications_enable_telegram:"Ativar Telegram",notifications_enable_telegram_desc:"Enviar notificações pelo Telegram",notifications_telegram_access_token:"Token de Acesso",notifications_telegram_access_token_desc:"Token de acesso para o bot",notifications_chat_id:"ID de bate-papo do Telegram",notifications_chat_id_desc:"ID do chat do Telegram para enviar as notificações para",notifications_excluded_wallets_desc:"Não envie notificações para essas carteiras",notifications_email_config:"Configuração de Email",notifications_enable_email:"Habilitar Email",notifications_enable_email_desc:"Enviar notificações por e-mail",notifications_send_test_email:"Enviar e-mail de teste",notifications_send_email:"Enviar e-mail",notifications_send_email_desc:"Email que você enviará de",notifications_send_email_username:"Nome de usuário",notifications_send_email_username_desc:"Nome de usuário, usará o e-mail se não estiver definido",notifications_send_email_password:"Enviar senha de e-mail",notifications_send_email_password_desc:"Senha para o e-mail que você enviará de",notifications_send_email_server_port:"Enviar e-mail porta SMTP",notifications_send_email_server_port_desc:"Porta para o servidor SMTP",notifications_send_email_server:"Enviar e-mail servidor SMTP",notifications_send_email_server_desc:"Servidor SMTP para o e-mail de que você enviará",notifications_send_to_emails:"Emails para enviar para",notifications_send_to_emails_desc:"Notificações de e-mails serão enviadas para",notification_settings_update:"Configurações atualizadas",notification_settings_update_desc:"Notificar quando as configurações do servidor forem atualizadas",notification_server_start_stop:"Iniciar/Parar Servidor",notification_server_start_stop_desc:"Notificar quando o servidor tiver sido iniciado/parado",notification_watchdog_limit:"Notificação de Limite do Watchdog",notification_watchdog_limit_desc:"Notifique quando o limite do watchdog for alcançado (não afeta a fonte de financiamento)",notification_server_status:"Status do Servidor",notification_server_status_desc:"Enviar notificações regulares sobre o status do servidor (valor do intervalo em horas)",notification_incoming_payment:"Pagamentos Recebidos",notification_incoming_payment_desc:"Notificar quando uma carteira tiver recebido um pagamento acima do valor especificado (sats)",notification_outgoing_payment:"Pagamentos Saída",notification_outgoing_payment_desc:"Notificar quando uma carteira tiver enviado um pagamento acima do valor especificado (sats)",notification_credit_debit:"Crédito / Débito",notification_credit_debit_desc:"Notificar quando uma carteira tiver sido creditada/debitada pelo superusuário",notification_balance_delta_changed:"Mudança no Delta de Saldo",notification_balance_delta_changed_desc:"Notifique quando a diferença entre o saldo do nó e o saldo do LNbits tiver mudado mais do que a quantidade especificada (em sats). Defina como 0 para desativar. Isso é executado a cada minuto.",enable_watchdog:"Ativar Watchdog",enable_watchdog_desc:"Se ativado, ele mudará automaticamente sua fonte de financiamento para VoidWallet se o seu saldo for inferior ao saldo do LNbits. Você precisará ativar manualmente após uma atualização.",watchdog_interval:"Intervalo do Watchdog",watchdog_interval_desc:"Com que frequência a tarefa de fundo deve verificar um sinal de interrupção no delta do monitor [node_balance - lnbits_balance] (em minutos).",watchdog_delta:"Observador Delta",watchdog_delta_desc:"Limite antes da mudança do mecanismo de segurança alterar a fonte de financiamento para VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fonte de Notificação",notification_source_label:"URL de origem (use apenas a fonte de status oficial do LNbits e fontes de confiança)",more:"mais",more_count:"Mais {count}",less:"menos",releases:"Lançamentos",watchdog:"Cão de guarda",server_logs:"Registros do Servidor",ip_blocker:"Bloqueador de IP",security:"Segurança",security_tools:"Ferramentas de segurança",block_access_hint:"Bloquear acesso por IP",allow_access_hint:"Permitir acesso por IP (substituirá os IPs bloqueados)",enter_ip:"Digite o IP e pressione enter",rate_limiter:"Limitador de Taxa",callback_url_rules:"Regras de URL de Retorno",enter_callback_url_rule:"Digite a regra de URL como regex e pressione enter",callback_url_rule_hint:"URLs de retorno de chamada (como a de LNURL) serão validados conforme estas regras. Pelo menos uma regra deve corresponder. Nenhuma regra significa que todas as URLs são permitidas.",wallet_limiter:"Limitador de Carteira",wallet_config:"Configuração da Carteira",wallet_charts:"Gráficos da Carteira",wallet_limit_max_withdraw_per_day:"Retirada máxima diária da carteira em sats (0 para desativar)",wallet_max_ballance:"Saldo máximo da carteira em sats (0 para desativar)",wallet_limit_secs_between_trans:"Minutos e segundos entre transações por carteira (0 para desativar)",only_incoming_payments_allowed:"Apenas pagamentos recebidos são permitidos",disable_outgoing_payments:"Desativar pagamentos de saída",number_of_requests:"Número de solicitações",time_unit:"Unidade de tempo",minute:"minuto",settings:"Configurações",second:"segundo",hour:"hora",disable_server_log:"Desativar Log do Servidor",enable_server_log:"Ativar Registro do Servidor",coming_soon:"Funcionalidade em breve",session_has_expired:"Sua sessão expirou. Por favor, faça login novamente.",instant_access_question:"Quer acesso imediato?",login_with_user_id:"Faça login com ID do usuário",or:"ou",create_new_wallet:"Criar Nova Carteira",delete_all_wallets:"Excluir Todas as Carteiras",confirm_delete_all_wallets:"Tem certeza de que deseja excluir TODAS as carteiras deste usuário?",login_to_account:"Faça login na sua conta",create_account:"Criar conta",account_settings:"Configurações da Conta",signin_with_oauth:"Entrar com",signin_with_oauth_or:"ou entre com",signin_with_nostr:"Continuar com Nostr",signin_with_google:"Entrar com o Google",signin_with_github:"Entrar com GitHub",signin_with_custom_org:"Entrar com {custom_org}",username_or_email:"Nome de usuário ou E-mail",password:"Senha",password_config:"Configuração de Senha",password_repeat:"Repetição de senha",update_password:"Atualizar Senha",change_password:"Alterar Senha",update_credentials:"Atualizar credenciais",update_pubkey:"Atualizar Chave Pública",nostr_pubkey_tooltip:"Insira a chave pública Nostr deste usuário (valor hexadecimal)",set_password:"Definir Senha",set_password_tooltip:"Defina uma senha para este usuário",invalid_password:"A senha deve ter pelo menos 8 caracteres",invalid_password_repeat:"As senhas não coincidem",reset_key_generated:"Uma chave de reinicialização foi gerada.",reset_key_copy:"Clique em OK para copiar o URL de redefinição para sua área de transferência.",login:"Entrar",register:"Registrar",username:"Nome de usuário",pubkey:"Chave Pública",user_id:"ID do Usuário",id:"ID",email:"E-mail",first_name:"Primeiro Nome",last_name:"Sobrenome",picture:"Foto",user_picture_desc:"URL para uma imagem a ser usada como foto de perfil. Você pode carregá-la como um ativo.",verify_email:"Verifique o e-mail com",account:"Conta",update_account:"Atualizar Conta",invalid_username:"Nome de usuário inválido",auth_provider:"Provedor de Autenticação",external_id:"ID Externo",my_account:"Minha Conta",existing_account_question:"Já tem uma conta?",background_image:"Imagem de Fundo",back:"Voltar",logout:"Sair",look_and_feel:"Aparência",endpoint:"Ponto de extremidade",api:"API",api_stripe:"API",api_token:"Token de API",api_tokens:"Tokens da API",access_control_list:"Lista de Controle de Acesso",access_control_list_admin_warning:"Esta é uma conta de administrador. Os tokens gerados terão privilégios de administrador.",new_api_acl:"Nova Lista de Controle de Acesso",api_token_id:"Id do Token",toggle_gradient:"Alternar Gradiente",gradient_background:"Fundo em Degradê",rounded_ui:"Cartões e Botões Arredondados",toggle_rounded_ui:"Alternar cantos arredondados para cartões e botões",card_gradient:"Gradiente do Cartão",toggle_card_gradient:"Alternar gradiente nos cartões",card_shadow:"Sombra do Cartão",toggle_card_shadow:"Alternar sombra nas cartas",language:"Idioma",assets:"Ativos",max_asset_size_mb:"Tamanho Máximo do Ativo (MB)",max_asset_size_mb_desc:"O tamanho máximo permitido para uploads de ativos em megabytes (pode usar valores decimais).",assets_allowed_mime_types:"Tipos MIME permitidos",assets_allowed_mime_types_desc:"Os tipos MIME permitidos para uploads de ativos. Nenhum valor significa que todos os uploads são permitidos.",thumbnail_width:"Largura da Miniatura",thumbnail_width_desc:"Largura da miniatura gerada em pixels.",thumbnail_height:"Altura da miniatura",thumbnail_height_desc:"Altura da miniatura gerada em pixels.",thumbnail_format:"Formato da Miniatura",thumbnail_format_desc:"Formato de imagem da miniatura gerada (PNG, JPEG, etc.).",max_assets_per_user:"Máximo de ativos por usuário",max_assets_per_user_desc:"O número máximo de ativos que um usuário pode fazer upload. Zero significa que o upload está proibido.",assets_no_limit_users:"Usuários sem Limites de Ativos",assets_no_limit_users_desc:"Esses usuários podem enviar um número ilimitado de ativos (com base no ID do usuário).",color_scheme:"Esquema de Cores",visible_wallet_count:"Contagem de Carteiras Visíveis",admin_settings:"Configurações do Administrador",extension_cost:"Este lançamento requer um pagamento mínimo de {cost} sats.",extension_paid_sats:"Você já pagou {paid_sats} sats.",create_extension:"Criar Extensão",release_details_error:"Não é possível obter os detalhes da versão.",pay_from_wallet:"Pagar com a Carteira",pay_with:"Pague com {provider}",select_payment_provider:"Selecione o provedor de pagamento",wallet_required:"Carteira *",show_qr:"Exibir QR",retry_install:"Repetir Instalação",new_payment:"Efetuar Novo Pagamento",update_payment:"Atualizar Pagamento",already_paid_question:"Você já pagou?",sell:"Vender",sell_require:"Peça pagamento para habilitar a extensão",sell_info:"A extensão {name} requer um pagamento mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar carteiras vazias",recheck:"Verificar novamente",check:"Verificar",check_connection:"Verificar Conexão",check_webhook:"Verificar Webhook",contributors:"Contribuidores",license:"Licença",reset_key:"Redefinir Chave",reset_password:"Redefinir senha",border_choices:"Opções de Borda",select_all:"Selecionar tudo",nfc_supported:"Compatível com NFC",nfc_not_supported:"NFC não suportado",expire_date:"Data de Expiração:",hash:"Hash:",welcome_lnbits:"Bem-vindo ao LNbits",setup_su_account:"Configure a conta Superuser abaixo.",first_install_token:"Primeiro Token de Instalação",create_ticker_converter:"Criar Conversor de Ticker de Moeda",enable_audit:"Habilitar Auditoria",recommended:"Recomendado",audit_desc:"Gravar solicitações HTTP de acordo com os filtros especificados",audit_record_req:"Gravar Corpo da Requisição",audit_record_warning:"Aviso:",audit_record_req_warning_1:"dados confidenciais (como senhas) serão registrados.",audit_record_req_warning_2:"o corpo da solicitação pode ter um tamanho grande.",audit_record_use:"Use com cuidado.",audit_ip:"Registrar endereço IP",audit_ip_desc:"Registre o endereço IP do cliente",audit_path_params:"Registrar Parâmetros de Caminho",audit_query_params:"Registrar Parâmetros de Consulta",audit_http_methods:"Incluir métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a serem incluídos. Listas vazias significam todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Resposta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a serem incluídos (correspondência regex). Listas vazias significam todos. Ex: 4.*, 5.*",audit_resp_codes_label:"Código de resposta HTTP (regex)",audit_paths:"Incluir Caminhos",audit_paths_hint:"Lista de caminhos a serem incluídos (correspondência de regex). Lista vazia significa todos.",audit_paths_label:"Caminho HTTP (regex)",audit_paths_exclude:"Excluir Caminhos",audit_paths_exclude_hint:"Lista de caminhos a serem excluídos (correspondência regex). Lista vazia significa nenhum.",audit_paths_exclude_label:"Caminho HTTP (regex)",exchange_providers:"Provedores de Câmbio",admin_extensions:"Extensões de Administração",admin_extensions_label:"Extensões de administração",admin_extensions_hint:"Somente usuários com privilégios de administrador podem usar extensões.",user_default_extensions:"Extensões Padrão do Usuário",user_default_extensions_label:"Extensões do usuário",user_default_extensions_hint:"Extensões que serão ativadas por padrão para os usuários.",extension_builder:"Construtor de Extensão",extension_builder_manifest_url:"URL do Manifesto do Criador de Extensões",extension_builder_manifest_url_hint:"URL para um arquivo JSON manifest com detalhes do extension builder",miscellanous:"Diversos",misc_disable_extensions:"Desativar extensões",misc_disable_extensions_label:"Desativar todas as extensões",misc_disable_extensions_builder:"Habilitar Extensions Builder",misc_disable_extensions_builder_label:"Habilitar Extensions Builder para usuários não administradores.",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta a API de carteira, extensões podem optar por honrar",wallets_management:"Gerenciamento de Carteiras",funding_source_info:"Informações da Fonte de Financiamento",funding_source:"Fonte de Financiamento: {wallet_class}",node_balance:"Saldo do Nó: {balance} sats",lnbits_balance:"Saldo do LNbits: {balance} sats",funding_reserve_percent:"Reserve Percentual: {percent} %",node_management:"Gerenciamento de Nós",node_management_not_supported:"Gerenciamento de nó não suportado pela fonte de financiamento ativa",toggle_node_ui:"Interface do Nó",toggle_public_node_ui:"Interface Pública do Nó",toggle_transactions_node_ui:"Guia de Transações (Desativar em nós grandes CLN)",invoice_expiry:"Expiração da Fatura",invoice_expiry_label:"Validade da fatura",routing_fee_reserve_calculations:"Cálculos de Reserva de Taxa de Roteamento",routing_fee_reserve_calculations_desc:'LNbits reserva um "valor de reserva" para cada pagamento para cobrir as taxas de roteamento. A taxa de roteamento máxima passada para a fonte de financiamento é a que for maior: a reserva mínima de taxa de roteamento ou a percentagem de reserva de taxa de roteamento.',millisats:"milissats",fee_reserve:"Reserva Mínima de Taxa de Encaminhamento",fee_reserve_percent:"Porcentagem da Reserva de Taxa de Roteamento",fee_reserve_min_hint:"A taxa mínima reservada por pagamento.
Isso atua como um piso - a taxa de roteamento máxima nunca será inferior a este valor, independentemente do tamanho do pagamento.",fee_reserve_percent_hint:"A porcentagem do valor do pagamento a reservar para taxas de roteamento.",payment_timeouts:"Tempos de Espera de Pagamento",payment_wait_time:"Tempo de Espera do Pagamento",seconds:"segundos",payment_wait_time_desc:"Tempo de espera antes de marcar um pagamento de saída como pendente. Padrão: 5s; aumentar para faturas de liquidação lenta.",payment_wait_time_tooltip:"Controla quanto tempo o LNbits espera para uma tentativa de pagamento de saída ser confirmada antes de marcá-la como pendente. Valores mais altos ajudam ao pagar faturas de liquidação lenta (por exemplo, faturas HODL, Boltz). O pagamento será verificado novamente mais tarde e atualizado automaticamente ou manualmente.",server_management:"Gerenciamento de Servidor",base_url:"URL base",base_url_label:"URL estática/base para o servidor",authentication:"Autenticação",auth_token_expiry_label:"Minutos para expiração do token",auth_token_expiry_hint:"Tempo em minutos até o token expirar",auth_authentication_cache_label:"Tempo de cache (minutos)",auth_authentication_cache_hint:"Tempo em minutos para armazenar em cache a autenticação bem-sucedida (0 para desativar)",auth_allowed_methods_label:"Métodos de autorização permitidos",auth_allowed_methods_hint:"Selecione métodos de autorização",auth_nostr_label:"URL de Solicitação Nostr",auth_nostr_hint:"URL absoluta que os clientes usarão para fazer login.",auth_google_ci_label:"ID do Cliente do Google",auth_google_ci_hint:"Certifique-se de que os URIs de redirecionamento autorizados contenham https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Segredo do Cliente do Google",auth_gh_client_id_label:"ID do Cliente do GitHub",auth_gh_client_id_hint:"Certifique-se de que a URL de callback de autorização esteja definida como https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Segredo do Cliente do GitHub",auth_keycloak_label:"URL de Descoberta do Keycloak",auth_keycloak_ci_label:"ID do Cliente Keycloak",auth_keycloak_ci_hint:"Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Segredo do Cliente Keycloak",auth_keycloak_custom_org_label:"Keycloak Custom Organization",auth_keycloak_custom_icon_label:"Ícone Personalizado do Keycloak (URL)",currency_settings:"Configurações de Moeda",allowed_currencies:"Moedas Permitidas",allowed_currencies_hint:"Limite o número de moedas fiduciárias disponíveis",default_account_currency:"Moeda Padrão da Conta",default_account_currency_hint:"Moeda padrão para contabilidade",min_incoming_payment_amount:"Quantia Mínima de Pagamento de Entrada",min_incoming_payment_amount_desc:"Quantidade mínima permitida para gerar uma fatura",max_incoming_payment_amount:"Valor Máximo do Pagamento Recebido",max_incoming_payment_amount_desc:"Quantidade máxima permitida para gerar uma fatura",max_outgoing_payment_amount:"Valor Máximo de Pagamento de Saída",max_outgoing_payment_amount_desc:"Valor máximo permitido para efetuar um pagamento",service_fee:"Taxa de serviço: {amount} % por transação",service_fee_label:"Taxa de serviço (%)",service_fee_hint:"Taxa cobrada por tx (%)",service_fee_max:"Taxa de serviço: {amount} % por transação (máx {max} sats)",service_fee_max_label:"Taxa de serviço máx (sats)",service_fee_max_hint:"Taxa máxima de serviço a cobrar em (sats)",fee_wallet:"Carteira de Taxas",fee_wallet_label:"Carteira de tarifas (ID da carteira)",fee_wallet_hint:"ID da carteira para enviar fundos para",disable_fee:"Desativar Taxa",disable_fee_internal:"Desativar taxa de serviço para pagamentos internos",disable_fee_internal_desc:"Desativar Taxa de Serviço para Pagamentos Internos Lightning",ui_management:"Gerenciamento de UI",ui_site_title:"Título do Site",ui_changing_remove_lnbits_elements:"(alterar removerá os elementos LNbits na página inicial e rodapé)",ui_site_tagline:"Tagline do site",ui_elements_enable:"Habilitar elementos na página inicial",ui_elements_disable:"Desativar elementos na página inicial",ui_toggle_elements_tip:"Remover elementos da página inicial, como 'funciona com', etc.",ui_site_description:"Descrição do Site",ui_site_description_hint:"Use texto simples, Markdown ou HTML bruto",ui_default_wallet_name:"Nome Padrão da Carteira",ui_default_theme:"Tema Padrão",wallet_featured_button_label:"Carteira Rótulo do Botão em Destaque",wallet_featured_button_label_hint:"Mostrar botão em destaque na página inicial da carteira",wallet_featured_button_url:"URL do Botão em Destaque",wallet_featured_button_url_hint:"Ao clicar, o botão abrirá este URL. Deixe em branco para ocultar o botão.",wallet_featured_button_icon:"Ícone do Botão em Destaque",wallet_featured_button_icon_hint:"Ícone mostrado no botão de destaque (verifique os ícones quasar)",lnbits_wallet:"Carteira LNbits",denomination:"Denominação",denomination_hint:"O nome para o token FakeWallet",denomination_error:"A denominação deve ter 3 caracteres ou `sats`.",ui_qr_code_logo:"Logo do QR Code",ui_qr_code_logo_hint:"URL para imagem de logo no código QR",ui_apple_touch_icon:"Ícone de Toque da Apple",ui_apple_touch_icon_hint:"URL do ícone de toque da Apple",ui_custom_image:"Imagem Personalizada",ui_custom_image_label:"URL para imagem personalizada",ui_custom_image_hint:"Imagem exibida na página inicial/login",ui_custom_badge:"Distintivo Personalizado",ui_custom_badge_label:"Distintivo Personalizado 'USE COM CUIDADO - a carteira LNbits ainda está em BETA'",ui_custom_badge_color_label:"Cor Personalizada do Distintivo",themes:"Temas",themes_hint:"Escolha temas disponíveis para usuários",custom_logo:"Logotipo personalizado",custom_logo_hint:"URL para a imagem do logotipo",ad_space_title:"Título do Espaço Publicitário",ad_space_title_label:"Suportado por",ad_slots:"Slots de Anúncio",ad_slots_hint:"Adicionar URL e caminhos de arquivo de imagem no formato CSV, as extensões podem optar por honrar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anúncios Ativados",ads_disabled:"Anúncios Desativados",user_management:"Gerenciamento de Usuários",admin_users:"Usuários Administradores",admin_users_hint:"Usuários com privilégios de administrador",admin_users_label:"ID do Usuário",allowed_users:"Usuários Permitidos",allowed_users_hint:"Somente esses usuários podem usar o LNbits",allowed_users_hint_feature:"Somente estes usuários podem usar {feature}",allowed_users_label:"ID do Usuário",allow_creation_user:"Permitir a criação de novos usuários",allow_creation_user_desc:"Permitir a criação de novos usuários na página de índice",require_user_activation:"Requer ativação do usuário",require_user_activation_desc:"Novos usuários serão ativados somente após passarem por um dos métodos de confirmação. Administradores podem ativar usuários manualmente a partir do painel de administração.",reusable_activation_code:"Código de ativação reutilizável",reusable_activation_code_label:"Código de ativação reutilizável",reusable_activation_code_hint:"Este código de ativação pode ser usado várias vezes por diferentes usuários.",one_time_activation_code:"Códigos de ativação única",one_time_activation_code_label:"Adicionar código de ativação",one_time_activation_code_hint:"Lista de códigos de ativação únicos. Cada código pode ser usado apenas uma vez, depois será removido da lista.",invitation_code:"Código de Convite",invitation_code_hint:"O código de convite que você recebeu.",email_confirmation_hint:"Endereço de e-mail para enviar o código de confirmação.",nostr_identifier:"Identificador Nostr",nostr_identifier_hint:"Identificador nostr nip5 ou para enviar o código de confirmação.",new_user_not_allowed:"O registro está desativado.",start_user_impersonation:"Personificar este usuário",stop_user_impersonation:"Parar a Personificação do Usuário",components:"Componentes",long_running_endpoints:"Top 5 Endpoints de Longa Execução",http_request_methods:"Métodos de Requisição HTTP",http_response_codes:"Códigos de Resposta HTTP",request_details:"Detalhes do Pedido",http_request_details:"Detalhes da Requisição HTTP",payment_details:"Detalhes do Pagamento",payment_details_desc:"Informações detalhadas sobre o pagamento",payments:"Pagamentos",payment_show_internal:"Mostrar Pagamentos Internos",payment_chart_flow:"Fluxo de Pagamento Mensal",payment_chart_status:"Status do Pagamento",payment_chart_tx_per_wallet:"Transações por Carteira (saldo/contagem)",payment_details_back:"Voltar para Pagamentos",payment_chart_tags:"Pagamentos por Tags",payments_balance_in_out:"Entradas/Saídas de Saldo",payments_count_in_out:"Contar Entrada/Saída",payments_status_chart:"Gráfico de Status",payments_tag_chart:"Gráfico de Marcadores",payments_balance_chart:"Gráfico de Saldo",payments_wallets_chart:"Gráfico de Carteiras",payments_balance_in_out_chart:"Gráfico de Entrada/Saída de Saldo",payments_count_in_out_chart:"Gráfico de Entrada/Saída",reset_wallet_keys:"Redefinir Chaves",reset_wallet_keys_desc:"Redefina as chaves de API para esta carteira. Isso invalidará as chaves atuais e gerará novas.",view_list:"Visualizar carteiras como lista",view_column:"Visualizar carteiras como linhas",filter_payments:"Filtrar pagamentos",filter_labels:"Rótulos de filtro",filter_date:"Filtrar por data",websocket_example:"Exemplo de Websocket",client_id:"ID do Cliente",secret_key:"Chave Secreta",signing_secret:"Segredo de Assinatura",signing_secret_hint:"Segredo de assinatura para o webhook. As mensagens serão assinadas com este segredo.",webhook_id:"ID do Webhook",webhook_id_hint:"ID do webhook do PayPal usado para verificar eventos recebidos.",webhook_paypal_description:"No lado do PayPal, configure um webhook apontando para o seu servidor LNbits.",callback_success_url:"URL de Sucesso de Callback",callback_success_url_hint:"O usuário será redirecionado para este URL após o pagamento ser bem-sucedido.",connected:"Conectado",not_connected:"Não Conectado",free:"Grátis",paid:"Pago",funding_source_retries:"Máximo de tentativas",funding_source_retries_desc:"Número máximo de tentativas para fontes de financiamento, antes de voltar para VoidWallet.",add_label:"Adicionar Rótulo",label:"Etiqueta",labels:"Rótulos",label_filter:"Filtro de Rótulo",no_labels_defined:"Ainda não há rótulos definidos",manage_labels:"Gerenciar Etiquetas",update_label:"Atualizar Rótulo",delete_label:"Excluir Rótulo",add_remove_labels:"Adicionar ou Remover Rótulos",payment_labels_updated:"Rótulos de pagamento atualizados",color:"Cor",sort:"Ordenar",sort_by:"Ordenar por"},window.localisation.cs={confirm:"Ano",server:"Server",theme:"Téma",site_customisation:"Přizpůsobení stránek",funding:"Financování",users:"Uživatelé",audit:"Audit",apps:"Aplikace",channels:"Kanály",transactions:"Transakce",dashboard:"Přehled",node:"Uzel",export_users:"Exportovat uživatele",no_users:"Nebyli nalezeni žádní uživatelé",total_capacity:"Celková kapacita",avg_channel_size:"Průmerná velikost kanálu",biggest_channel_size:"Největší velikost kanálu",smallest_channel_size:"Nejmenší velikost kanálu",number_of_channels:"Počet kanálů",active_channels:"Aktivní kanály",connect_peer:"Připojit peer",connect:"Připojit",open_channel:"Otevřít kanál",open:"Otevřít",close_channel:"Zavřít kanál",close:"Zavřít",restart:"Restartovat server",save:"Uložit",save_tooltip:"Uložit změny",credit_debit:"Kreditní / Debetní",credit_hint:"Stiskněte Enter pro připsání na účet",credit_label:"{denomination} k připsání",credit_ok:"Úspěšné připsání/odepsání virtuálních prostředků ({amount} satů). Platby závisí na skutečných prostředcích z financujícího zdroje.",restart_tooltip:"Restartujte server pro aplikaci změn",add_funds_tooltip:"Přidat prostředky do peněženky.",reset_defaults:"Obnovit výchozí",reset_defaults_tooltip:"Smazat všechna nastavení a obnovit výchozí.",download_backup:"Stáhnout zálohu databáze",name_your_wallet:"Pojmenujte svou {name} peněženku",paste_invoice_label:"Vložte fakturu, platební požadavek nebo lnurl kód *",lnbits_description:"Snadno nastavitelný a lehkotonážní, LNbits může běžet na jakémkoliv zdroji financování Lightning Network a dokonce LNbits samotné! LNbits můžete provozovat pro sebe, nebo snadno nabízet správu peněženek pro ostatní. Každá peněženka má své vlastní API klíče a není omezen počet peněženek, které můžete vytvořit. Možnost rozdělení prostředků dělá z LNbits užitečný nástroj pro správu peněz a jako vývojový nástroj. Rozšíření přidávají extra funkčnost k LNbits, takže můžete experimentovat s řadou špičkových technologií na lightning network. Vývoj rozšíření jsme učinili co nejjednodušší a jako svobodný a open-source projekt podporujeme lidi ve vývoji a zasílání vlastních rozšíření.",export_to_phone:"Exportovat do telefonu pomocí QR kódu",export_to_phone_desc:"Tento QR kód obsahuje URL vaší peněženky s plným přístupem. Můžete jej naskenovat z telefonu a otevřít peněženku odtamtud.",wallet:"Peněženka:",wallets:"Peněženky",add_wallet:"Přidat novou peněženku",delete_wallet:"Smazat peněženku",delete_wallet_desc:"Celá peněženka bude smazána, prostředky budou NEOBNOVITELNÉ.",rename_wallet:"Přejmenovat peněženku",update_name:"Aktualizovat název",fiat_tracking:"Sledování fiatu",currency:"Měna",update_currency:"Aktualizovat měnu",press_to_claim:"Stiskněte pro nárokování bitcoinu",donate:"Darovat",view_github:"Zobrazit na GitHubu",voidwallet_active:"VoidWallet je aktivní! Platby zakázány",use_with_caution:"POUŽÍVEJTE S OBEZŘETNOSTÍ - {name} peněženka je stále v BETĚ",service_fee:"Servisný poplatek: {amount} % za transakci",service_fee_max:"Servisný poplatek: {amount} % za transakci (max {max} satoshi)",service_fee_tooltip:"Servisní poplatek účtovaný správcem LNbits serveru za odchozí transakci",toggle_darkmode:"Přepnout tmavý režim",payment_reactions:"Reakce na platby",view_swagger_docs:"Zobrazit LNbits Swagger API dokumentaci",api_docs:"API dokumentace",api_keys_api_docs:"Adresa uzlu, API klíče a API dokumentace",lnbits_version:"Verze LNbits",runs_on:"Běží na",paste:"Vložit",paste_from_clipboard:"Vložit ze schránky",paste_request:"Vložit požadavek",create_invoice:"Vytvořit fakturu",camera_tooltip:"Použijte kameru pro skenování faktury/QR",export_csv:"Exportovat do CSV",chart_tooltip:"Zobrazit graf",pending:"Čeká na vyřízení",copy_invoice:"Kopírovat fakturu",withdraw_from:"Vybrat z",cancel:"Zrušit",scan:"Skenovat",read:"Číst",pay:"Platit",memo:"Poznámka",date:"Datum",payment_processing:"Zpracování platby...",not_enough_funds:"Nedostatek prostředků!",search_by_tag_memo_amount:"Hledat podle tagu, poznámky, částky",invoice_waiting:"Faktura čeká na platbu",payment_received:"Platba přijata",payment_sent:"Platba odeslána",receive:"přijmout",send:"odeslat",outgoing_payment_pending:"Odchozí platba čeká na vyřízení",drain_funds:"Vyčerpat prostředky",drain_funds_desc:"Toto je LNURL-withdraw QR kód pro vyčerpání všeho z této peněženky. Nesdílejte s nikým. Je kompatibilní s balanceCheck a balanceNotify, takže vaše peněženka může kontinuálně čerpat prostředky odsud po prvním výběru.",i_understand:"Rozumím",copy_wallet_url:"Kopírovat URL peněženky",disclaimer_dialog_title:"Důležité!",disclaimer_dialog:"Funkcionalita přihlášení bude vydána v budoucí aktualizaci, zatím si ujistěte, že jste si tuto stránku uložili do záložek pro budoucí přístup k vaší peněžence! Tato služba je v BETA verzi a nepřebíráme žádnou zodpovědnost za ztrátu přístupu k prostředkům.",no_transactions:"Zatím žádné transakce",manage:"Spravovat",exchanges:"Burzy",extensions:"Rozšíření",no_extensions:"Nemáte nainstalováno žádné rozšíření :(",created:"Vytvořeno",search_extensions:"Hledat rozšíření",extension_sources:"Zdroje rozšíření",ext_sources_hint:"Úložiště, odkud lze rozšíření stáhnout.",ext_sources_label:"Zdrojová URL (používejte pouze oficiální zdroj rozšíření LNbits a zdroje, kterým můžete důvěřovat)",warning:"Varování",repository:"Repositář",confirm_continue:"Jste si jistí, že chcete pokračovat?",manage_extension_details:"Instalovat/odinstalovat rozšíření",install:"Instalovat",uninstall:"Odinstalovat",drop_db:"Odstranit data",enable:"Povolit",pay_to_enable:"Zaplatit pro aktivaci",enable_extension_details:"Povolit rozšíření pro aktuálního uživatele",disable:"Zakázat",delete:"Smazat",installed:"Nainstalováno",activated:"Aktivováno",deactivated:"Deaktivováno",release_notes:"Poznámky k vydání",activate_extension_details:"Zpřístupnit/zakázat rozšíření pro uživatele",featured:"Doporučené",all:"Vše",only_admins_can_install:"(Pouze administrátorské účty mohou instalovat rozšíření)",admin_only:"Pouze pro adminy",new_version:"Nová verze",extension_depends_on:"Závisí na:",extension_rating_soon:"Hodnocení brzy dostupné",extension_installed_version:"Nainstalovaná verze",extension_uninstall_warning:"Chystáte se odstranit rozšíření pro všechny uživatele.",uninstall_confirm:"Ano, odinstalovat",extension_db_drop_info:"Všechna data pro rozšíření budou trvale odstraněna. Tuto operaci nelze vrátit zpět!",extension_db_drop_warning:"Chystáte se odstranit všechna data pro rozšíření. Prosím, pokračujte zadáním názvu rozšíření:",extension_required_lnbits_version:"Toto vydání vyžaduje alespoň verzi LNbits",min_version:"Minimum (včetně)",max_version:"Maximální (vyloučeno)",payment_hash:"Hash platby",fee:"Poplatek",amount:"Částka",amount_sats:"Částka (sats)",tag:"Tag",unit:"Jednotka",description:"Popis",expiry:"Expirace",webhook:"Webhook",payment_proof:"Důkaz platby",update:"Aktualizovat",update_available:"Dostupná aktualizace {version}!",latest_update:"Máte nejnovější verzi {version}.",notifications:"Notifikace",no_notifications:"Žádné notifikace",notifications_disabled:"Notifikace stavu LNbits jsou zakázány.",enable_notifications:"Povolit notifikace",enable_notifications_desc:"Pokud je povoleno, bude stahovat nejnovější aktualizace stavu LNbits, jako jsou bezpečnostní incidenty a aktualizace.",watchdog_interval:"Interval Watchdog",watchdog_interval_desc:"Jak často by měl úkol na pozadí kontrolovat signál killswitch v watchdog delta [node_balance - lnbits_balance] (v minutách).",watchdog_delta:"Delta Watchdog",watchdog_delta_desc:"Limit předtím, než killswitch změní zdroj financování na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stav",notification_source:"Zdroj notifikací",notification_source_label:"URL zdroje (používejte pouze oficiální zdroj stavu LNbits a zdroje, kterým můžete věřit)",more:"více",less:"méně",releases:"Vydání",watchdog:"Watchdog",server_logs:"Logy serveru",ip_blocker:"Blokování IP",security:"Bezpečnost",security_tools:"Nástroje bezpečnosti",block_access_hint:"Blokovat přístup podle IP",allow_access_hint:"Povolit přístup podle IP (přepíše blokované IP)",enter_ip:"Zadejte IP a stiskněte enter",rate_limiter:"Omezovač počtu požadavků",wallet_limiter:"Omezení peněženky",wallet_limit_max_withdraw_per_day:"Maximální denní limit pro výběr z peněženky v sats (0 pro deaktivaci)",wallet_max_ballance:"Maximální zůstatek v peněžence v sats (0 pro zakázání)",wallet_limit_secs_between_trans:"Minimální počet sekund mezi transakcemi na peněženku (0 pro vypnutí)",number_of_requests:"Počet požadavků",time_unit:"Časová jednotka",minute:"minuta",second:"sekunda",hour:"hodina",disable_server_log:"Zakázat log serveru",enable_server_log:"Povolit log serveru",coming_soon:"Funkce brzy dostupná",session_has_expired:"Vaše relace vypršela. Prosím, přihlašte se znovu.",instant_access_question:"Chcete okamžitý přístup?",login_with_user_id:"Přihlásit se s uživatelským ID",or:"nebo",create_new_wallet:"Vytvořit novou peněženku",login_to_account:"Přihlaste se ke svému účtu",create_account:"Vytvořit účet",account_settings:"Nastavení účtu",signin_with_nostr:"Pokračovat s Nostr",signin_with_google:"Přihlásit se přes Google",signin_with_github:"Přihlásit se přes GitHub",signin_with_keycloak:"Přihlásit se přes Keycloak",username_or_email:"Uživatelské jméno nebo Email",password:"Heslo",password_config:"Konfigurace hesla",password_repeat:"Opakujte heslo",change_password:"Změnit heslo",update_credentials:"Aktualizovat přihlašovací údaje",update_pubkey:"Aktualizovat veřejný klíč",set_password:"Nastavit heslo",invalid_password:"Heslo musí mít alespoň 8 znaků",login:"Přihlášení",register:"Registrovat",username:"Uživatelské jméno",pubkey:"Veřejný klíč",user_id:"ID uživatele",email:"Email",first_name:"Křestní jméno",last_name:"Příjmení",picture:"Obrázek",verify_email:"Ověřte e-mail s",account:"Účet",update_account:"Aktualizovat účet",invalid_username:"Neplatné uživatelské jméno",auth_provider:"Poskytovatel ověření",my_account:"Můj účet",back:"Zpět",logout:"Odhlásit se",look_and_feel:"Vzhled a chování",toggle_gradient:"Přepnout gradient",gradient_background:"Barevný přechod pozadí",language:"Jazyk",color_scheme:"Barevné schéma",admin_settings:"Nastavení administrátora",extension_cost:"Toto vydání vyžaduje minimální platbu {cost} satoshi.",extension_paid_sats:"Již jste zaplatili {paid_sats} sats.",release_details_error:"Nelze získat podrobnosti o vydání.",pay_from_wallet:"Platit z peněženky",wallet_required:"Peněženka *",show_qr:"Zobrazit QR",retry_install:"Zkusit znovu nainstalovat",new_payment:"Vytvořit novou platbu",update_payment:"Aktualizovat platbu",already_paid_question:"Už jste zaplatili?",sell:"Prodat",sell_require:"Požádejte o platbu, abyste povolili rozšíření",sell_info:"Rozšíření {name} vyžaduje platbu minimálně {amount} sats pro aktivaci.",hide_empty_wallets:"Skrýt prázdné peněženky",recheck:"Znovu zkontrolovat",contributors:"Přispěvatelé",license:"Licence",reset_key:"Obnovit klíč",reset_password:"Obnovit heslo",border_choices:"Možnosti ohraničení",select_all:"Vybrat vše",nfc_supported:"Podpora NFC",nfc_not_supported:"NFC není podporováno",expire_date:"Datum expirace:",hash:"Hash:",welcome_lnbits:"Vítejte v LNbits",setup_su_account:"Nastavte účet Superuser níže.",create_ticker_converter:"Vytvořit převodník měnových tickerů",enable_audit:"Povolit audit",recommended:"Doporučeno",audit_desc:"Zaznamenávejte HTTP požadavky podle zadaných filtrů",audit_record_req:"Záznam Tělo Požadavku",audit_record_warning:"Varování:",audit_record_req_warning_1:"důvěrná data (jako hesla) budou zaznamenána.",audit_record_req_warning_2:"tělo žádosti může mít velkou velikost.",audit_record_use:"Používejte to opatrně.",audit_ip:"Zaznamenat IP adresu",audit_ip_desc:"Zaznamenejte IP adresu klienta",audit_path_params:"Zaznamenat parametry cesty",audit_query_params:"Zaznamenat parametry dotazu",audit_http_methods:"Zahrnout metody HTTP",audit_http_methods_hint:"Seznam metod HTTP, které mají být zahrnuty. Prázdné seznamy znamenají všechny.",audit_http_methods_label:"Metody HTTP",audit_resp_codes:"Zahrnout kódy odpovědí HTTP",audit_resp_codes_hint:"Seznam kódů HTTP, které mají být zahrnuty (regex match). Prázdné seznamy znamenají všechny. Např.: 4.*, 5.*",audit_resp_codes_label:"Kód odpovědi HTTP (regex)",audit_paths:"Zahrnout cesty",audit_paths_hint:"Seznam cest, které mají být zahrnuty (regex shoda). Prázdný seznam znamená vše.",audit_paths_label:"HTTP cesta (regex)",audit_paths_exclude:"Vyloučit cesty",audit_paths_exclude_hint:"Seznam cest, které mají být vyloučeny (regex shoda). Prázdný seznam znamená žádné.",audit_paths_exclude_label:"HTTP cesta (regex)",exchange_providers:"Poskytovatelé směny",admin_extensions:"Rozšíření pro správce",admin_extensions_label:"Administrátorské rozšíření",admin_extensions_hint:"Rozšíření může používat pouze uživatel s administrátorskými oprávněními.",user_default_extensions:"Výchozí rozšíření uživatele",user_default_extensions_label:"Uživatelská rozšíření",user_default_extensions_hint:"Rozšíření, která budou u uživatelů ve výchozím nastavení povolena.",miscellanous:"Různé",misc_disable_extensions:"Zakázat rozšíření",misc_disable_extensions_label:"Zakázat všechna rozšíření",misc_hide_api:"Skrýt API",misc_hide_api_label:"Skrývá API peněženky, rozšíření se mohou rozhodnout ctít",wallets_management:"Správa peněženek",funding_source_info:"Informace o zdroji financování",funding_source:"Zdroj financování: {wallet_class}",node_balance:"Stav uzlu: {balance} sats",lnbits_balance:"Zůstatek LNbits: {balance} sats",funding_reserve_percent:"Rezervovat procento: {percent} %",node_management:"Správa uzlů",node_management_not_supported:"Správa uzlů není podporována aktivním zdrojem financování",toggle_node_ui:"Uživatelské rozhraní uzlu",toggle_public_node_ui:"Veřejné rozhraní uzlu",toggle_transactions_node_ui:"Karta Transakce (Zakázat na velkých uzlech CLN)",invoice_expiry:"Datum vypršení faktury",invoice_expiry_label:"Vypršení faktury (sekundy)",fee_reserve:"Rezerva poplatku",fee_reserve_msats:"Rezervační poplatek v msats",fee_reserve_percent:"Rezervační poplatek v procentech",server_management:"Správa serveru",base_url:"Základní URL",base_url_label:"Statická/Základní URL pro server",authentication:"Ověření",auth_token_expiry_label:"Minuty vypršení platnosti tokenu",auth_token_expiry_hint:"Čas v minutách do vypršení tokenu",auth_allowed_methods_label:"Povolené metody autorizace",auth_allowed_methods_hint:"Vyberte metody autorizace",auth_nostr_label:"URL žádosti Nostr",auth_nostr_hint:"Absolutní URL, které klienti použijí pro přihlášení.",auth_google_ci_label:"ID klienta Google",auth_google_ci_hint:"Ujistěte se, že autorizované přesměrovací URI obsahují https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Heslo klienta Google",auth_gh_client_id_label:"ID klienta GitHub",auth_gh_client_id_hint:"Ujistěte se, že je nastavena zpětná adresa URL pro autorizaci na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Klientský tajný klíč",auth_keycloak_label:"URL pro zjištění Keycloak",auth_keycloak_ci_label:"ID klienta Keycloak",auth_keycloak_ci_hint:"Ujistěte se, že je autorizace callback URL nastavena na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Klíč k aplikaci Keycloak tajemství",currency_settings:"Nastavení měny",allowed_currencies:"Povolené měny",allowed_currencies_hint:"Omezte počet dostupných fiat měn",default_account_currency:"Výchozí měna účtu",default_account_currency_hint:"Výchozí měna pro účetnictví",service_fee_label:"Poplatek za službu (%)",service_fee_hint:"Poplatek účtovaný za transakci (%)",service_fee_max_label:"Poplatek za službu max (sats)",service_fee_max_hint:"Maximální poplatek za službu k účtování v (sats)",fee_wallet:"Poplatková peněženka",fee_wallet_label:"Poplatková peněženka (ID peněženky)",fee_wallet_hint:"ID peněženky, na kterou se mají odeslat prostředky",disable_fee:"Zakázat poplatek",disable_fee_internal:"Zakázat poplatek za službu pro interní platby",disable_fee_internal_desc:"Zakázat servisní poplatek za interní lightning platby",ui_management:"Správa uživatelského rozhraní",ui_site_title:"Název stránky",ui_site_tagline:"Stránkový slogan",ui_elements_enable:"Povolit prvky na domovské stránce",ui_elements_disable:"Zakázat prvky na úvodní stránce",ui_toggle_elements_tip:"Odebrat prvky z domovské stránky, jako je 'běží na' atd.",ui_site_description:"Popis webu",ui_site_description_hint:"Použijte prostý text, Markdown nebo surové HTML.",ui_default_wallet_name:"Výchozí název peněženky",lnbits_wallet:"Peněženka LNbits",denomination:"Nominální hodnota",denomination_hint:"Název pro token FakeWallet",ui_qr_code_logo:"Logo QR kódu",ui_qr_code_logo_hint:"URL k obrázku loga v QR kódu",ui_custom_badge:"Vlastní odznak",ui_custom_badge_label:"Vlastní odznak 'POUŽÍVEJTE S OPATRNOSTÍ - Peněženka LNbits je stále v BETA verzi'",ui_custom_badge_color_label:"Barva vlastního odznaku",themes:"Motivy",themes_hint:"Vyberte motivy dostupné pro uživatele",custom_logo:"Vlastní logo",custom_logo_hint:"URL k obrázku loga",ad_space_title:"Název reklamního prostoru",ad_space_title_label:"Podporováno",ad_slots:"Reklamní sloty",ad_slots_hint:"Adresa URL reklamy a cesty k souborům obrázků ve formátu CSV, rozšíření se mohou rozhodnout respektovat",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy povoleny",ads_disabled:"Reklamy deaktivovány",user_management:"Správa uživatelů",admin_users:"Administrátorští uživatelé",admin_users_hint:"Uživatelé s administrátorskými oprávněními",admin_users_label:"ID uživatele",allowed_users:"Povolení uživatelé",allowed_users_hint:"Pouze tito uživatelé mohou používat LNbits.",allowed_users_label:"Uživatelské ID",allow_creation_user:"Povolit vytvoření nových uživatelů",allow_creation_user_desc:"Povolit vytváření nových uživatelů na úvodní stránce",components:"Soubory",long_running_endpoints:"Top 5 dlouho běžících koncových bodů",http_request_methods:"Metody HTTP požadavků",http_response_codes:"Kódy HTTP odpovědí",request_details:"Podrobnosti žádosti",http_request_details:"Podrobnosti HTTP žádosti"},window.localisation.sk={confirm:"Áno",server:"Server",theme:"Téma",site_customisation:"Prispôsobenie lokality",funding:"Financovanie",users:"Používatelia",audit:"Audit",apps:"Aplikácie",channels:"Kanály",transactions:"Transakcie",dashboard:"Prehľad",node:"Uzol",export_users:"Exportovať používateľov",no_users:"Nenašli sa žiadni používatelia",total_capacity:"Celková kapacita",avg_channel_size:"Priemerná veľkosť kanálu",biggest_channel_size:"Najväčší kanál",smallest_channel_size:"Najmenší kanál",number_of_channels:"Počet kanálov",active_channels:"Aktívne kanály",connect_peer:"Pripojiť peer",connect:"Pripojiť",open_channel:"Otvoriť kanál",open:"Otvoriť",close_channel:"Zatvoriť kanál",close:"Zatvoriť",restart:"Reštartovať server",save:"Uložiť",save_tooltip:"Uložiť vaše zmeny",credit_debit:"Kreditná / Debetná",credit_hint:"Stlačte Enter pre pripísanie na účet",credit_label:"{denomination} na pripísanie",restart_tooltip:"Pre prejavenie zmien reštartujte server",add_funds_tooltip:"Pridať prostriedky do peňaženky.",reset_defaults:"Obnoviť predvolené",reset_defaults_tooltip:"Odstrániť všetky nastavenia a obnoviť predvolené.",download_backup:"Stiahnuť zálohu databázy",name_your_wallet:"Pomenujte vašu {name} peňaženku",paste_invoice_label:"Vložte faktúru, platobnú požiadavku alebo lnurl kód *",lnbits_description:"Ľahko nastaviteľný a ľahkotonážny, LNbits môže bežať na akomkoľvek zdroji financovania Lightning Network a dokonca LNbits samotný! LNbits môžete používať pre seba, alebo ľahko ponúknuť správcovské riešenie pre iných. Každá peňaženka má svoje vlastné API kľúče a nie je limit na počet peňaženiek, ktoré môžete vytvoriť. Schopnosť rozdeľovať finančné prostriedky robí z LNbits užitočný nástroj pre správu peňazí a ako vývojový nástroj. Rozšírenia pridávajú extra funkčnosť do LNbits, takže môžete experimentovať s radou najnovších technológií na lightning sieti. Vývoj rozšírení sme urobili čo najjednoduchší a ako voľný a open-source projekt, podporujeme ľudí vývoj a odovzdávanie vlastných rozšírení.",export_to_phone:"Exportovať do telefónu s QR kódom",export_to_phone_desc:"Tento QR kód obsahuje URL vašej peňaženky s plným prístupom. Môžete ho naskenovať z vášho telefónu a otvoriť vašu peňaženku odtiaľ.",wallet:"Peňaženka:",wallets:"Peňaženky",add_wallet:"Pridať novú peňaženku",delete_wallet:"Zmazať peňaženku",delete_wallet_desc:"Celá peňaženka bude zmazaná, prostriedky budú NEOBNOVITEĽNÉ.",rename_wallet:"Premenovať peňaženku",update_name:"Aktualizovať meno",fiat_tracking:"Sledovanie fiat",currency:"Mena",update_currency:"Aktualizovať menu",press_to_claim:"Stlačte pre nárok na bitcoin",donate:"Prispieť",view_github:"Zobraziť na GitHube",voidwallet_active:"VoidWallet je aktívny! Platby zakázané",use_with_caution:"POUŽÍVAJTE OPATRNE - {name} peňaženka je stále v BETE",service_fee:"Servisný poplatok: {amount} % za transakciu",service_fee_max:"Servisný poplatok: {amount} % za transakciu (max {max} satoshi)",service_fee_tooltip:"Servisný poplatok účtovaný správcom LNbits servera za odchádzajúcu transakciu",toggle_darkmode:"Prepnúť Tmavý režim",payment_reactions:"Reakcie na platbu",view_swagger_docs:"Zobraziť LNbits Swagger API dokumentáciu",api_docs:"API dokumentácia",api_keys_api_docs:"Adresa uzla, API kľúče a API dokumentácia",lnbits_version:"Verzia LNbits",runs_on:"Beží na",paste:"Vložiť",paste_from_clipboard:"Vložiť zo schránky",paste_request:"Vložiť požiadavku",create_invoice:"Vytvoriť faktúru",camera_tooltip:"Použite kameru na naskenovanie faktúry/QR",export_csv:"Exportovať do CSV",chart_tooltip:"Zobraziť graf",pending:"Čakajúce",copy_invoice:"Kopírovať faktúru",withdraw_from:"Vybrať z",cancel:"Zrušiť",scan:"Skenovať",read:"Čítať",pay:"Platiť",memo:"Poznámka",date:"Dátum",payment_processing:"Spracovávanie platby...",not_enough_funds:"Nedostatok prostriedkov!",search_by_tag_memo_amount:"Vyhľadať podľa značky, poznámky, sumy",invoice_waiting:"Faktúra čakajúca na zaplatenie",payment_received:"Platba prijatá",payment_sent:"Platba odoslaná",receive:"prijímať",send:"posielať",outgoing_payment_pending:"Odchádzajúca platba čaká",drain_funds:"Vyprázdniť prostriedky",drain_funds_desc:"Toto je LNURL-withdraw QR kód pre vyprázdnienie všetkého z tejto peňaženky. S nikým ho nezdieľajte. Je kompatibilný s balanceCheck a balanceNotify, takže vaša peňaženka môže naďalej kontinuálne vyťahovať prostriedky odtiaľto po prvom výbere.",i_understand:"Rozumiem",copy_wallet_url:"Kopírovať URL peňaženky",disclaimer_dialog_title:"Dôležité!",disclaimer_dialog:"Funkcionalita prihlásenia bude vydaná v budúcej aktualizácii, zatiaľ si uistite, že ste si túto stránku pridali medzi záložky pre budúci prístup k vašej peňaženke! Táto služba je v BETA verzii a nenesieme zodpovednosť za stratu prístupu k prostriedkom.",no_transactions:"Zatiaľ žiadne transakcie",manage:"Spravovať",exchanges:"Burzy",extensions:"Rozšírenia",no_extensions:"Nemáte nainštalované žiadne rozšírenia :(",created:"Vytvorené",search_extensions:"Hľadať rozšírenia",extension_sources:"Rozšírenie zdrojov",ext_sources_hint:"Úložiská, z ktorých sa môžu stiahnuť rozšírenia.",ext_sources_label:"Zdrojová URL (použite iba oficiálny zdroj rozšírenia LNbits a zdroje, ktorým môžete dôverovať)",warning:"Upozornenie",repository:"Repozitár",confirm_continue:"Ste si istí, že chcete pokračovať?",manage_extension_details:"Inštalovať/odinštalovať rozšírenie",install:"Inštalovať",uninstall:"Odinštalovať",drop_db:"Odstrániť údaje",enable:"Povoliť",pay_to_enable:"Zaplaťte na aktiváciu",enable_extension_details:"Povoliť rozšírenie pre aktuálneho používateľa",disable:"Zakázať",delete:"Odstrániť",installed:"Nainštalované",activated:"Aktivované",deactivated:"Deaktivované",release_notes:"Poznámky k vydaniu",activate_extension_details:"Sprístupniť/neprístupniť rozšírenie pre používateľov",featured:"Odporúčané",all:"Všetky",only_admins_can_install:"(Iba administrátorské účty môžu inštalovať rozšírenia)",admin_only:"Iba pre administrátorov",new_version:"Nová verzia",extension_depends_on:"Závisí na:",extension_rating_soon:"Hodnotenia budú čoskoro dostupné",extension_installed_version:"Nainštalovaná verzia",extension_uninstall_warning:"Chystáte sa odstrániť rozšírenie pre všetkých používateľov.",uninstall_confirm:"Áno, Odinštalovať",extension_db_drop_info:"Všetky údaje pre rozšírenie budú trvalo vymazané. Túto operáciu nie je možné vrátiť!",extension_db_drop_warning:"Chystáte sa odstrániť všetky údaje pre rozšírenie. Pre pokračovanie prosím napíšte názov rozšírenia:",extension_required_lnbits_version:"Toto vydanie vyžaduje aspoň verziu LNbits",min_version:"Minimum (vrátane)",max_version:"Maximálne (vylúčené)",payment_hash:"Hash platby",fee:"Poplatok",amount:"Suma",amount_sats:"Suma (sats)",tag:"Tag",unit:"Jednotka",description:"Popis",expiry:"Expirácia",webhook:"Webhook",payment_proof:"Dôkaz platby",update:"Aktualizovať",update_available:"Dostupná aktualizácia {version}!",latest_update:"Máte najnovšiu verziu {version}.",notifications:"Notifikácie",no_notifications:"Žiadne notifikácie",notifications_disabled:"Notifikácie stavu LNbits sú zakázané.",enable_notifications:"Povoliť Notifikácie",enable_notifications_desc:"Ak povolené, budú sa načítavať najnovšie aktualizácie stavu LNbits, ako sú bezpečnostné incidenty a aktualizácie.",enable_watchdog:"Povoliť Watchdog",enable_watchdog_desc:"Ak povolené, vaš zdroj financovania sa automaticky zmení na VoidWallet, ak je váš zostatok nižší ako zostatok LNbits. Po aktualizácii bude treba povoliť manuálne.",watchdog_interval:"Interval Watchdog",watchdog_interval_desc:"Ako často by malo pozadie kontrolovať signál killswitch v watchdog delta [node_balance - lnbits_balance] (v minútach).",watchdog_delta:"Delta Watchdog",watchdog_delta_desc:"Limit pred zmenou zdroja financovania na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stav",notification_source:"Zdroj notifikácií",notification_source_label:"URL zdroja (používajte len oficiálny LNbits zdroj stavu a zdroje, ktorým môžete dôverovať)",more:"viac",less:"menej",releases:"Vydania",watchdog:"Watchdog",server_logs:"Logy servera",ip_blocker:"Blokovanie IP",security:"Bezpečnosť",security_tools:"Nástroje bezpečnosti",block_access_hint:"Blokovať prístup podľa IP",allow_access_hint:"Povoliť prístup podľa IP (prebije blokované IP)",enter_ip:"Zadajte IP a stlačte enter",rate_limiter:"Obmedzovač počtu požiadaviek",wallet_limiter:"Obmedzovač peňaženky",wallet_limit_max_withdraw_per_day:"Maximálny denný výber z peňaženky v satošiach (0 pre zrušenie)",wallet_max_ballance:"Maximálny zostatok v peňaženke v satošiach (0 pre deaktiváciu)",wallet_limit_secs_between_trans:"Minimálny počet sekúnd medzi transakciami na peňaženku (0 na deaktiváciu)",number_of_requests:"Počet požiadaviek",time_unit:"Časová jednotka",minute:"minúta",second:"sekunda",hour:"hodina",disable_server_log:"Zakázať Log servera",enable_server_log:"Povoliť Log servera",coming_soon:"Funkcia bude čoskoro dostupná",session_has_expired:"Vaša relácia vypršala. Prosím, prihláste sa znova.",instant_access_question:"Chcete okamžitý prístup?",login_with_user_id:"Prihlásiť sa s používateľským ID",or:"alebo",create_new_wallet:"Vytvoriť novú peňaženku",login_to_account:"Prihláste sa do vášho účtu",create_account:"Vytvoriť účet",account_settings:"Nastavenia účtu",signin_with_nostr:"Pokračovať s Nostr",signin_with_google:"Prihlásiť sa pomocou Google",signin_with_github:"Prihlásiť sa pomocou GitHub",signin_with_keycloak:"Prihlásiť sa pomocou Keycloak",username_or_email:"Používateľské meno alebo email",password:"Heslo",password_config:"Konfigurácia hesla",password_repeat:"Opakovanie hesla",change_password:"Zmeniť heslo",update_credentials:"Aktualizovať poverenia",update_pubkey:"Aktualizovať verejný kľúč",set_password:"Nastaviť heslo",invalid_password:"Heslo musí mať aspoň 8 znakov",login:"Prihlásenie",register:"Registrovať",username:"Používateľské meno",pubkey:"Verejný kľúč",user_id:"ID používateľa",email:"Email",first_name:"Meno",last_name:"Priezvisko",picture:"Obrázok",verify_email:"Overiť e-mail s",account:"Účet",update_account:"Aktualizovať účet",invalid_username:"Neplatné užívateľské meno",auth_provider:"Poskytovateľ autentifikácie",my_account:"Môj účet",back:"Späť",logout:"Odhlásiť sa",look_and_feel:"Vzhľad a dojem",toggle_gradient:"Prepnúť prechodový režim",gradient_background:"Gradientné pozadie",language:"Jazyk",color_scheme:"Farebná schéma",admin_settings:"Nastavenia správcu",extension_cost:"Táto verzia vyžaduje minimálnu platbu {cost} satoshi.",extension_paid_sats:"Už ste zaplatili {paid_sats} sats.",release_details_error:"Nepodarilo sa získať podrobnosti o vydaní.",pay_from_wallet:"Zaplatiť z peňaženky",wallet_required:"Peňaženka *",show_qr:"Zobraziť QR",retry_install:"Skúste inštaláciu znova",new_payment:"Vytvoriť novú platbu",update_payment:"Aktualizovať platbu",already_paid_question:"Už ste zaplatili?",sell:"Predať",sell_require:"Požiadajte o platbu na povolenie rozšírenia",sell_info:"Rozšírenie {name} vyžaduje platbu minimálne {amount} sats na aktiváciu.",hide_empty_wallets:"Skryť prázdne peňaženky",recheck:"Prekontrolovať znova",contributors:"Prispievatelia",license:"Licencia",reset_key:"Resetovať kľúč",reset_password:"Obnoviť heslo",border_choices:"Výber obrysov",select_all:"Vybrať všetko",nfc_supported:"Podpora NFC",nfc_not_supported:"NFC nie je podporované",expire_date:"Dátum exspirácie:",hash:"Hash:",welcome_lnbits:"Vitajte v LNbits",setup_su_account:"Nastavte účet Superuser nižšie.",create_ticker_converter:"Vytvoriť prevodník mienových tickerov",enable_audit:"Povoliť audit",recommended:"Odporúčané",audit_desc:"Zaznamenávajte HTTP požiadavky podľa špecifikovaných filtrov.",audit_record_req:"Zaznamenať telo žiadosti",audit_record_warning:"Upozornenie:",audit_record_req_warning_1:"dôverné údaje (ako napríklad heslá) budú zaznamenané.",audit_record_req_warning_2:"telo žiadosti môže mať veľkú veľkosť.",audit_record_use:"Používajte to s opatrnosťou.",audit_ip:"Zaznamenať IP adresu",audit_ip_desc:"Zaznamenajte IP adresu klienta",audit_path_params:"Zaznamenať hodnoty cesty",audit_query_params:"Zaznamenať parametre dopytu",audit_http_methods:"Zahrnúť metódy HTTP",audit_http_methods_hint:"Zoznam zahrnutých metód HTTP. Prázdne zoznamy znamenajú všetky.",audit_http_methods_label:"HTTP metódy",audit_resp_codes:"Zahrnúť kódy odpovede HTTP",audit_resp_codes_hint:"Zoznam kódov HTTP, ktoré sa majú zahrnúť (zhoda s regexom). Prázdny zoznam znamená všetky. Napr: 4.*, 5.*",audit_resp_codes_label:"Kód odpovede HTTP (regex)",audit_paths:"Cesty zahrnúť",audit_paths_hint:"Zoznam ciest, ktoré sa majú zahrnúť (zhoda s regexom). Prázdny zoznam znamená všetky.",audit_paths_label:"HTTP cesta (regex)",audit_paths_exclude:"Vylúčiť cesty",audit_paths_exclude_hint:"Zoznam ciest, ktoré majú byť vylúčené (zhoda s regexom). Prázdny zoznam znamená žiadne.",audit_paths_exclude_label:"Cesta HTTP (regex)",exchange_providers:"Poskytovatelia výmeny",admin_extensions:"Rozšírenia administrátora",admin_extensions_label:"Rozšírenia správcu",admin_extensions_hint:"Rozšírenia môže používať iba používateľ s administrátorskými právami.",user_default_extensions:"Predvolené rozšírenia používateľa",user_default_extensions_label:"Používateľské rozšírenia",user_default_extensions_hint:"Rozšírenia, ktoré budú predvolene povolené pre používateľov.",miscellanous:"Rôzne",misc_disable_extensions:"Zakázať rozšírenia",misc_disable_extensions_label:"Zakázať všetky rozšírenia",misc_hide_api:"Skryť API",misc_hide_api_label:"Skryje API peňaženky, rozšírenia sa môžu rozhodnúť dodržiavať",wallets_management:"Správa peňaženiek",funding_source_info:"Informácie o zdroji financovania",funding_source:"Zdroj financovania: {wallet_class}",node_balance:"Stav uzla: {balance} sats",lnbits_balance:"Zostatok LNbits: {balance} sats",funding_reserve_percent:"Rezervovať percento: {percent} %",node_management:"Správa uzlov",node_management_not_supported:"Správa uzlov nie je podporovaná aktívnym zdrojom financovania",toggle_node_ui:"Používateľské rozhranie uzla",toggle_public_node_ui:"Verejné používateľské rozhranie uzla",toggle_transactions_node_ui:"Karta transakcií (Zakázať na veľkých CLN uzloch)",invoice_expiry:"Platnosť faktúry",invoice_expiry_label:"Doba platnosti faktúry (sekundy)",fee_reserve:"Rezerva poplatkov",fee_reserve_msats:"Rezervačný poplatok v msats",fee_reserve_percent:"Rezervačný poplatok v percentách",server_management:"Správa servera",base_url:"Základná URL adresa",base_url_label:"Statická/Základná URL adresa pre server",authentication:"Autentifikácia",auth_token_expiry_label:"Minúty do vypršania tokenu",auth_token_expiry_hint:"Čas v minútach do vypršania platnosti tokenu",auth_allowed_methods_label:"Povolené metódy autorizácie",auth_allowed_methods_hint:"Vyberte metódy autorizácie",auth_nostr_label:"Adresa URL žiadosti Nostr",auth_nostr_hint:"Absolútna URL adresa, ktorú klienti použijú na prihlásenie.",auth_google_ci_label:"ID klienta Google",auth_google_ci_hint:"Uistite sa, že autorizované presmerovacie URI obsahujú https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"Identifikátor klienta GitHub",auth_gh_client_id_hint:"Uistite sa, že URL adresa pre spätné volanie autorizácie je nastavená na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"URL zistenia Keycloak",auth_keycloak_ci_label:"ID klienta Keycloak",auth_keycloak_ci_hint:"Uistite sa, že URL spätného volania autorizácie je nastavená na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Tajný kľúč klienta Keycloak",currency_settings:"Nastavenia meny",allowed_currencies:"Povolené meny",allowed_currencies_hint:"Obmedzte počet dostupných fiat mien",default_account_currency:"Predvolená mena účtu",default_account_currency_hint:"Predvolená mena pre účtovníctvo",service_fee_label:"Poplatok za službu (%)",service_fee_hint:"Poplatok účtovaný za transakciu (%)",service_fee_max_label:"Poplatok za službu max (sats)",service_fee_max_hint:"Maximálny servisný poplatok na účtovanie v (sats)",fee_wallet:"Peňaženka s poplatkami",fee_wallet_label:"Peňaženka poplatkov (ID peňaženky)",fee_wallet_hint:"ID peňaženky, do ktorej sa majú odoslať prostriedky",disable_fee:"Zakázať poplatok",disable_fee_internal:"Zakázať poplatok za službu pre interné platby",disable_fee_internal_desc:"Zakázať poplatok za službu pre interné platby Lightning",ui_management:"Správa používateľského rozhrania",ui_site_title:"Názov stránky",ui_site_tagline:"Slogan webovej stránky",ui_elements_enable:"Povoliť prvky na domovskej stránke",ui_elements_disable:"Zakázať prvky na domovskej stránke",ui_toggle_elements_tip:"Odstrániť prvky úvodnej stránky, ako napríklad 'používa' atď.",ui_site_description:"Popis lokality",ui_site_description_hint:"Použite obyčajný text, Markdown alebo surové HTML.",ui_default_wallet_name:"Predvolený názov peňaženky",lnbits_wallet:"LNbits peňaženka",denomination:"Nominálna hodnota",denomination_hint:"Názov pre token FakeWallet",ui_qr_code_logo:"Logo QR kódu",ui_qr_code_logo_hint:"URL k obrázku loga v QR kóde",ui_custom_badge:"Vlastná odznak",ui_custom_badge_label:"Vlastný odznak 'POUŽÍVAŤ S OPATRNOSŤOU - LNbits peňaženka je stále v BETA verzii'",ui_custom_badge_color_label:"Vlastná farba odznaku",themes:"Motívy",themes_hint:"Vyberte témy dostupné pre používateľov",custom_logo:"Vlastné logo",custom_logo_hint:"URL k obrázku loga",ad_space_title:"Názov reklamného priestoru",ad_space_title_label:"Podporované spoločnosťou",ad_slots:"Reklamné sloty",ad_slots_hint:"Pridajte URL adresu a cesty k obrazovým súborom vo formáte CSV, rozšírenia sa môžu rozhodnúť dodržať",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy povolené",ads_disabled:"Reklamy deaktivované",user_management:"Správa používateľov",admin_users:"Administrátorskí používatelia",admin_users_hint:"Používatelia s administrátorskými oprávneniami",admin_users_label:"ID používateľa",allowed_users:"Povolení používatelia",allowed_users_hint:"Iba títo používatelia môžu používať LNbits.",allowed_users_label:"ID používateľa",allow_creation_user:"Povoliť vytváranie nových používateľov",allow_creation_user_desc:"Povoliť vytváranie nových používateľov na indexovej stránke",components:"Súčasti",long_running_endpoints:"Top 5 dlho bežiacich koncových bodov",http_request_methods:"Metódy HTTP žiadostí",http_response_codes:"Kódy odpovedí HTTP",request_details:"Podrobnosti žiadosti",http_request_details:"Podrobnosti požiadavky HTTP"},window.localisation.kr={confirm:"확인",server:"서버",theme:"테마",site_customisation:"사이트 사용자 정의",funding:"자금",users:"사용자",audit:"감사",apps:"앱",channels:"채널",transactions:"거래 내역",dashboard:"현황판",node:"노드",export_users:"사용자 내보내기",no_users:"사용자가 없습니다",total_capacity:"총 용량",avg_channel_size:"평균 채널 용량",biggest_channel_size:"가장 큰 채널 용량",smallest_channel_size:"가장 작은 채널 용량",number_of_channels:"채널 수",active_channels:"활성화된 채널",connect_peer:"피어 연결하기",connect:"연결하기",open_channel:"채널 개설하기",open:"개설",close_channel:"채널 폐쇄하기",close:"폐쇄",restart:"서버 재시작",save:"저장",save_tooltip:"변경 사항 저장",credit_debit:"크레딧 / 직불카드",credit_hint:"계정에 자금을 넣으려면 Enter를 눌러주세요",credit_label:"{denomination} 단위로 충전하기",credit_ok:"가상 자금({amount} sats) 입출금 성공. 지불은 자금 출처의 실제 자금에 따라 달라집니다.",restart_tooltip:"변경 사항을 적용하려면 서버를 재시작해야 합니다.",add_funds_tooltip:"지갑에 자금을 추가합니다.",reset_defaults:"기본 설정으로 돌아가기",reset_defaults_tooltip:"설정했던 내용들을 모두 지우고, 기본 설정으로 돌아갑니다.",download_backup:"데이터베이스 백업 다운로드",name_your_wallet:"사용할 {name}지갑의 이름을 정하세요",paste_invoice_label:"인보이스, 결제 요청, 혹은 lnurl 코드를 붙여넣으세요 *",lnbits_description:"설정이 쉽고 가벼운 LNbits는 어떤 라이트닝 네트워크의 예산 자원 위에서든 돌아갈 수 있습니다, 그리고 다른 LNbits 지갑들입니다. 스스로 사용하기 위해, 또는 다른 사람들에게 수탁형 솔루션을 제공하기 위해 LNbits를 운영할 수 있습니다. 각 지갑들은 자신만의 API key를 가지며, 생성 가능한 지갑의 수에는 제한이 없습니다. 자금을 분할할 수 있는 기능으로 인해, LNbits는 자금 운영 도구로써뿐만 아니라 개발 도구로써도 유용합니다. 확장 기능들은 LNbits에 여러분들이 라이트닝 네트워크의 다양한 최신 기술들을 수행해볼 수 있게 하는 추가 기능을 제공합니다. LNbits 개발진들은 확장 기능들의 개발 또한 가능한 쉽게 만들었으며, 무료 오픈 소스 프로젝트답게 사람들이 자신만의 확장 기능들을 개발하고 제출하기를 응원합니다.",export_to_phone:"QR 코드를 이용해 모바일 기기로 내보내기",export_to_phone_desc:"이 QR 코드는 선택된 지갑의 최대 접근 권한을 가진 전체 URL을 담고 있습니다. 스캔 후, 모바일 기기에서 지갑을 열 수 있습니다.",wallet:"지갑:",wallets:"지갑",add_wallet:"새로운 지갑을 추가합니다",delete_wallet:"지갑을 삭제합니다",delete_wallet_desc:"이 지갑은 삭제될 것이며, 삭제 시 지갑 내 자금은 복구가 불가능합니다.",rename_wallet:"지갑 이름 변경",update_name:"이름 변경하기",fiat_tracking:"법정통화 가격 표시",currency:"통화",update_currency:"통화 수정하기",press_to_claim:"비트코인을 수령하려면 눌러주세요",donate:"기부",view_github:"GitHub 페이지 보기",voidwallet_active:"VoidWallet이 활성화되었습니다! 결제가 불가능합니다.",use_with_caution:"주의하세요 - {name} 지갑은 아직 BETA 단계입니다.",service_fee:"서비스 수수료: 거래액의 {amount} %",service_fee_max:"서비스 수수료: 거래액의 {amount} % (최대 {max} sats)",service_fee_tooltip:"지불 결제 시마다 LNbits 서버 관리자에게 납부되는 서비스 수수료",toggle_darkmode:"다크 모드 전환",payment_reactions:"결제 반응",view_swagger_docs:"LNbits Swagger API 문서를 봅니다",api_docs:"API 문서",api_keys_api_docs:"노드 URL, API 키와 API 문서",lnbits_version:"LNbits 버전",runs_on:"Runs on",paste:"붙여넣기",paste_from_clipboard:"클립보드에서 붙여넣기",paste_request:"지불 요청 붙여넣기",create_invoice:"인보이스 생성하기",camera_tooltip:"카메라를 이용해서 인보이스/QR을 스캔하세요",export_csv:"CSV 형태로 내보내기",chart_tooltip:"그래프로 보여주기",pending:"대기 중",copy_invoice:"인보이스 복사하기",withdraw_from:"출금",cancel:"취소",scan:"스캔",read:"분석하기",pay:"지불하기",memo:"Memo",date:"일시",payment_processing:"결제 처리 중...",not_enough_funds:"자금이 부족합니다!",search_by_tag_memo_amount:"태그, memo, 수량으로 검색하기",invoice_waiting:"결제를 기다리는 인보이스",payment_received:"받은 결제액",payment_sent:"보낸 결제액",receive:"받기",send:"보내기",outgoing_payment_pending:"지불 대기 중",drain_funds:"자금 비우기",drain_funds_desc:"이는 선택된 지갑으로부터 모든 자금을 인출하는 LNURL-withdraw QR 코드입니다. 그 누구와도 공유하지 마세요. balanceCheck 및 balanceNotify 기능과 호환되며, 당신의 지갑은 첫 출금 이후로도 계속 자금을 끌어당기고 있을 수 있습니다.",i_understand:"이해하였습니다",copy_wallet_url:"지갑 URL 복사하기",disclaimer_dialog_title:"중요!",disclaimer_dialog:"로그인 기능은 향후 업데이트를 통해 지원될 계획이지만, 현재로써는 이 페이지에 향후 다시 접속하기 위해 북마크 설정하는 것을 잊지 마세요! 이 서비스는 아직 BETA 과정에 있고, LNbits 개발자들은 자금 손실에 대해 전혀 책임을 지지 않습니다.",no_transactions:"아직 아무런 거래도 이루어지지 않았습니다",manage:"관리",exchanges:"거래소",extensions:"확장 기능",no_extensions:"아직 설치된 확장 기능들이 없네요 :(",created:"생성됨",search_extensions:"확장 기능 검색하기",extension_sources:"확장 소스",ext_sources_hint:"확장 프로그램을 다운로드할 수 있는 저장소",ext_sources_label:"출처 URL (공식 LNbits 확장 소스만 사용하고, 신뢰할 수 있는 출처를 사용하세요)",warning:"주의",repository:"저장소",confirm_continue:"정말로 계속할까요?",manage_extension_details:"확장 기능 설치/삭제하기",install:"설치",uninstall:"삭제",drop_db:"데이터 삭제",enable:"활성화",pay_to_enable:"지불하여 활성화",enable_extension_details:"현재 사용자 계정에 해당 확장 기능을 활성화합니다",disable:"비활성화",delete:"삭제",installed:"설치됨",activated:"작동됨",deactivated:"작동 중지",release_notes:"배포 노트",activate_extension_details:"사용자들의 확장 기능 사용 가능 여부를 결정합니다",featured:"추천",all:"전체",only_admins_can_install:"(관리자 계정만이 확장 기능을 설치할 수 있습니다)",admin_only:"관리자 전용",new_version:"새로운 버전",extension_depends_on:"의존성 존재:",extension_rating_soon:"평점 기능도 곧 구현됩니다",extension_installed_version:"설치된 버전",extension_uninstall_warning:"모든 사용자들로부터 이 확장 기능을 제거한다는 점에 유의하세요.",uninstall_confirm:"네, 삭제합니다",extension_db_drop_info:"해당 확장 기능의 모든 데이터가 영구적으로 삭제됩니다. 작업 수행 후에는 되돌릴 수 없습니다!",extension_db_drop_warning:"해당 확장 기능의 모든 데이터가 영구적으로 삭제될 겁니다. 계속하려면 확장 기능의 이름을 입력해주세요:",extension_required_lnbits_version:"이 배포 버전은 더 높은 버전의 lnbits가 설치되어 있어야 합니다.",min_version:"최소값 (포함됨)",max_version:"최대값 (제외됨)",payment_hash:"결제 해쉬값",fee:"수수료",amount:"액수",amount_sats:"금액 (사토시)",tag:"태그",unit:"단위",description:"상세",expiry:"만료",webhook:"Webhook",payment_proof:"Payment 증거",update:"업데이트",update_available:"{version}으로 업데이트가 가능합니다.",latest_update:"이미 {version} 버전으로 업데이트되었습니다.",notifications:"알림",no_notifications:"알림 없음",notifications_disabled:"LNbits 상태 알림이 비활성화되었습니다.",enable_notifications:"알림 활성화",enable_notifications_desc:"활성화 시, 가장 최신의 보안 사고나 소프트웨어 업데이트 등의 LNbits 상황 업데이트를 불러옵니다.",enable_watchdog:"와치독 활성화",enable_watchdog_desc:"활성화 시, LNbits 잔금보다 당신의 잔금이 지정한 수준보다 더 낮아질 경우 자동으로 자금의 원천을 VoidWallet으로 변경합니다. 업데이트 이후 수동으로 활성화해 주어야 합니다.",watchdog_interval:"와치독 시간 간격",watchdog_interval_desc:"와치독 델타 값을 기반으로 하여 당신의 LNbits 서버에서 나오는 비상 정지 신호를 백그라운드 작업으로 얼마나 자주 확인할 것인지를 결정합니다. (분 단위)",watchdog_delta:"와치독 델타",watchdog_delta_desc:"당신의 자금 원천을 VoidWallet으로 변경하기까지의 기준 값 [LNbits 잔액 - 노드 잔액 > 델타 값]",status:"상황",notification_source:"알림 메세지 출처",notification_source_label:"알림 메세지를 가져올 URL (공식 LNbits 상황판 출처나, 당신이 신뢰할 수 있는 출처만을 사용하세요)",more:"더 알아보기",less:"적게",releases:"배포 버전들",watchdog:"와치독",server_logs:"서버 로그",ip_blocker:"IP 기반 차단기",security:"보안",security_tools:"보안 도구들",block_access_hint:"IP 기준으로 접속 차단하기",allow_access_hint:"IP 기준으로 접속 허용하기 (차단한 IP들을 무시합니다)",enter_ip:"IP 주소를 입력하고 Enter를 눌러주세요",rate_limiter:"횟수로 제한하기",wallet_limiter:"지갑 제한기",wallet_limit_max_withdraw_per_day:"일일 최대 지갑 출금액(sats) (0은 비활성화)",wallet_max_ballance:"지갑 최대 잔액(sats) (0은 비활성화)",wallet_limit_secs_between_trans:"지갑 당 거래 사이 최소 초 (0은 비활성화)",number_of_requests:"요청 횟수",time_unit:"시간 단위",minute:"분",second:"초",hour:"시간",disable_server_log:"서버 로깅 중단하기",enable_server_log:"서버 로깅 활성화하기",coming_soon:"곧 구현될 기능들입니다",session_has_expired:"세션 유효 기간이 만료되었습니다. 다시 로그인해 주세요.",instant_access_question:"즉시 액세스하시겠습니까?",login_with_user_id:"사용자 ID로 로그인",or:"또는",create_new_wallet:"새 지갑 만들기",login_to_account:"계정에 로그인하세요.",create_account:"계정 생성",account_settings:"계정 설정",signin_with_nostr:"Nostr로 계속하기",signin_with_google:"Google으로 로그인",signin_with_github:"GitHub으로 로그인",signin_with_keycloak:"Keycloak으로 로그인",username_or_email:"사용자 이름 또는 이메일",password:"비밀번호",password_config:"비밀번호 설정",password_repeat:"비밀번호 재입력",change_password:"비밀번호 변경",update_credentials:"자격 증명 업데이트",update_pubkey:"공개 키 업데이트",set_password:"비밀번호 설정",invalid_password:"비밀번호는 최소 8자 이상이어야 합니다",login:"로그인",register:"등록",username:"사용자 이름",pubkey:"공개 키",user_id:"사용자 ID",email:"이메일",first_name:"성명",last_name:"성",picture:"사진",verify_email:"이메일을 인증하려면",account:"계정",update_account:"계정 업데이트",invalid_username:"잘못된 사용자 이름",auth_provider:"인증 제공자",my_account:"내 계정",back:"뒤로",logout:"로그아웃",look_and_feel:"외관과 느낌",toggle_gradient:"그라디언트 전환",gradient_background:"그라디언트 배경",language:"언어",color_scheme:"색상 구성",admin_settings:"관리자 설정",extension_cost:"이 버전은 최소 {cost} sats의 지불이 필요합니다.",extension_paid_sats:"당신은 이미 {paid_sats} sats를 지불했습니다.",release_details_error:"릴리스 세부 정보를 가져올 수 없습니다.",pay_from_wallet:"지갑에서 결제하다",wallet_required:"지갑 *",show_qr:"QR 보기",retry_install:"다시 설치하세요",new_payment:"새로운 결제하기",update_payment:"결제 업데이트",already_paid_question:"이미 지불하셨나요?",sell:"판매",sell_require:"확장을 활성화하려면 결제를 요청하십시오.",sell_info:"{name} 확장 기능을 활성화하려면 최소 {amount} 사토시의 결제가 필요합니다.",hide_empty_wallets:"빈 지갑 숨기기",recheck:"재확인",contributors:"기여자",license:"라이선스",reset_key:"재설정 키",reset_password:"비밀번호 재설정",border_choices:"테두리 선택사항",select_all:"모두 선택",nfc_supported:"NFC 지원됨",nfc_not_supported:"NFC 지원되지 않음",expire_date:"만료 날짜:",hash:"해시:",welcome_lnbits:"LNbits에 오신 것을 환영합니다.",setup_su_account:"슈퍼유저 계정을 아래에 설정하십시오.",create_ticker_converter:"통화 티커 변환기 생성",enable_audit:"감사 활성화",recommended:"추천됨",audit_desc:"지정된 필터에 따라 HTTP 요청 기록",audit_record_req:"레코드 요청 본문",audit_record_warning:"경고:",audit_record_req_warning_1:"암호와 같은 기밀 데이터가 기록됩니다.",audit_record_req_warning_2:"요청 본문은 큰 크기를 가질 수 있습니다.",audit_record_use:"주의해서 사용하십시오.",audit_ip:"IP 주소 기록",audit_ip_desc:"클라이언트의 IP 주소를 기록하십시오.",audit_path_params:"경로 매개변수 기록",audit_query_params:"쿼리 매개변수 기록",audit_http_methods:"HTTP 메서드 포함",audit_http_methods_hint:"포함할 HTTP 메서드 목록. 목록이 비어 있으면 모두 포함됩니다.",audit_http_methods_label:"HTTP 방법",audit_resp_codes:"HTTP 응답 코드 포함",audit_resp_codes_hint:"포함할 HTTP 코드 목록(정규 표현식 일치). 빈 목록은 모두를 의미합니다. 예: 4.*, 5.*",audit_resp_codes_label:"HTTP 응답 코드 (정규식)",audit_paths:"포함 경로",audit_paths_hint:"포함할 경로 목록 (정규 표현식 일치). 빈 목록은 모두를 의미합니다.",audit_paths_label:"HTTP 경로 (정규식)",audit_paths_exclude:"제외 경로",audit_paths_exclude_hint:"제외할 경로 목록 (정규 표현식 일치). 빈 목록은 없음을 의미합니다.",audit_paths_exclude_label:"HTTP 경로 (정규식)",exchange_providers:"거래소 공급자",admin_extensions:"관리자 확장 프로그램",admin_extensions_label:"관리자 확장 기능",admin_extensions_hint:"확장 기능은 관리자 권한이 있는 사용자만 사용할 수 있습니다.",user_default_extensions:"사용자 기본 확장자",user_default_extensions_label:"사용자 확장 기능",user_default_extensions_hint:"사용자에게 기본적으로 활성화될 확장 기능.",miscellanous:"기타",misc_disable_extensions:"확장 프로그램 사용 안 함",misc_disable_extensions_label:"모든 확장 프로그램 비활성화",misc_hide_api:"API 숨기기",misc_hide_api_label:"지갑 API 숨기기, 확장 기능은 준수할 수 있음",wallets_management:"지갑 관리",funding_source_info:"자금 출처 정보",funding_source:"자금 출처: {wallet_class}",node_balance:"노드 잔액: {balance} 사토시",lnbits_balance:"LNbits 잔액: {balance} sats",funding_reserve_percent:"예약 비율: {percent} %",node_management:"노드 관리",node_management_not_supported:"활성화된 자금 출처에 의해 노드 관리는 지원되지 않습니다.",toggle_node_ui:"노드 UI",toggle_public_node_ui:"공개 노드 UI",toggle_transactions_node_ui:"트랜잭션 탭 (대형 CLN 노드에서는 비활성화)",invoice_expiry:"송장 만료",invoice_expiry_label:"송장 만료 (초)",fee_reserve:"수수료 예약",fee_reserve_msats:"msats의 예약 수수료",fee_reserve_percent:"예약 수수료(%)",server_management:"서버 관리",base_url:"기본 URL",base_url_label:"서버의 정적/기본 URL",authentication:"인증",auth_token_expiry_label:"토큰 만료 시간(분)",auth_token_expiry_hint:"토큰이 만료되기까지 남은 시간(분)",auth_allowed_methods_label:"허용된 인증 방법",auth_allowed_methods_hint:"인증 방법 선택",auth_nostr_label:"Nostr 요청 URL",auth_nostr_hint:"클라이언트가 로그인하는 데 사용할 절대 URL.",auth_google_ci_label:"Google 클라이언트 ID",auth_google_ci_hint:"허가된 리디렉션 URI에 https://{domain}/api/v1/auth/google/token이 포함되어 있는지 확인하세요.",auth_google_cs_label:"Google 클라이언트 시크릿",auth_gh_client_id_label:"GitHub 클라이언트 ID",auth_gh_client_id_hint:"인가 콜백 URL이 https://{domain}/api/v1/auth/github/token으로 설정되어 있는지 확인하십시오.",auth_gh_client_secret_label:"GitHub 클라이언트 비밀키",auth_keycloak_label:"Keycloak 디스커버리 URL",auth_keycloak_ci_label:"키클록 클라이언트 ID",auth_keycloak_ci_hint:"승인 콜백 URL이 https://{domain}/api/v1/auth/keycloak/token으로 설정되어 있는지 확인하십시오.",auth_keycloak_cs_label:"Keycloak 클라이언트 시크릿",currency_settings:"통화 설정",allowed_currencies:"허용되는 통화",allowed_currencies_hint:"사용 가능한 법정 화폐의 수를 제한하십시오.",default_account_currency:"기본 계좌 통화",default_account_currency_hint:"회계 기본 통화",service_fee_label:"서비스 수수료 (%)",service_fee_hint:"트랜잭션당 수수료 (%)",service_fee_max_label:"서비스 수수료 최대 (sats)",service_fee_max_hint:"(사토시)로 부과할 최대 서비스 요금",fee_wallet:"수수료 지갑",fee_wallet_label:"수수료 지갑 (지갑 ID)",fee_wallet_hint:"자금을 보낼 지갑 ID",disable_fee:"수수료 비활성화",disable_fee_internal:"내부 결제에 대한 서비스 요금 비활성화",disable_fee_internal_desc:"내부 라이트닝 결제에 대한 서비스 요금 비활성화",ui_management:"UI 관리",ui_site_title:"사이트 제목",ui_site_tagline:"사이트 태그라인",ui_elements_enable:"홈페이지의 요소 활성화",ui_elements_disable:"홈페이지의 요소 비활성화",ui_toggle_elements_tip:"'에 의해 구동됨' 등의 홈페이지 요소 제거",ui_site_description:"사이트 설명",ui_site_description_hint:"일반 텍스트, Markdown, 또는 원시 HTML을 사용하십시오.",ui_default_wallet_name:"기본 지갑 이름",lnbits_wallet:"LNbits 지갑",denomination:"액면가",denomination_hint:"FakeWallet 토큰의 이름",ui_qr_code_logo:"QR 코드 로고",ui_qr_code_logo_hint:"QR 코드의 로고 이미지 URL",ui_custom_badge:"맞춤 배지",ui_custom_badge_label:"사용자 지정 배지 '주의하여 사용 - LNbits 지갑은 여전히 BETA 상태입니다'",ui_custom_badge_color_label:"사용자 정의 배지 색상",themes:"테마",themes_hint:"사용자가 사용할 수 있는 테마 선택",custom_logo:"맞춤 로고",custom_logo_hint:"로고 이미지의 URL",ad_space_title:"광고 공간 제목",ad_space_title_label:"지원:",ad_slots:"광고 슬롯",ad_slots_hint:"광고 URL 및 이미지 파일 경로를 CSV 형식으로, 확장자는 준수할 수 있습니다.",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"광고 활성화됨",ads_disabled:"광고 비활성화됨",user_management:"사용자 관리",admin_users:"관리자 사용자",admin_users_hint:"관리자 권한이 있는 사용자",admin_users_label:"사용자 ID",allowed_users:"허용된 사용자",allowed_users_hint:"LNbits는 이 사용자들만 사용할 수 있습니다.",allowed_users_label:"사용자 ID",allow_creation_user:"새 사용자 생성 허용",allow_creation_user_desc:"색인 페이지에서 새 사용자 생성 허용",components:"구성 요소",long_running_endpoints:"최상위 5개의 장시간 실행 엔드포인트",http_request_methods:"HTTP 요청 메서드",http_response_codes:"HTTP 응답 코드",request_details:"요청 세부사항",http_request_details:"HTTP 요청 세부사항"},window.localisation.fi={confirm:"Kyllä",server:"Palvelin",theme:"Teema",site_customisation:"Sivuston kustomointi",funding:"Rahoitus",users:"Käyttäjät",audit:"Seuranta",api_watch:"API-seuranta",apps:"Sovellukset",channels:"Kanavat",transactions:"Tapahtumat",dashboard:"Ohjauspaneeli",node:"Solmu",export_users:"Vie käyttäjät",no_users:"Käyttäjiä ei löytynyt",total_capacity:"Kokonaiskapasiteetti",avg_channel_size:"Keskimääräisen kanavan kapasiteetti",biggest_channel_size:"Suurimman kanavan kapasiteetti",smallest_channel_size:"Pienimmän kanavan kapasiteetti",number_of_channels:"Kanavien lukumäärä",active_channels:"Aktiivisia kanavia",connect_peer:"Yhdistä naapuriin",connect:"Yhdistä",reconnect:"Uudista yhteys",open_channel:"Avaa kanava",open:"Avaa",close_channel:"Sulje kanava",close:"Sulje",restart:"Palvelimen uudelleen käynnistys",image_library:"Kuvakirjasto",save:"Tallenna",save_tooltip:"Tallenna muutokset",credit_debit:"Hyvitä / Veloita",credit_hint:"Hyväksy painamalla Enter (negatiivisetkin arvot ovat sallittuja)",credit_label:"Hyvitä / Veloita tilille {denomination}-varoja",credit_ok:"Virtuaalivarojen ({amount} sat) hyvitys-/veloitustapahtuma onnistui. Maksukyky riippuuu rahoituslähteen todellisista varoista.",restart_tooltip:"Uudelleenkäynnistä palvelu muutosten käyttöönottamiseksi",add_funds_tooltip:"Lisää varoja lompakkoon",reset_defaults:"Palauta oletusasetukset",reset_defaults_tooltip:"Poista kaikki asetusten muutokset ja palauta järjestelmän oletusasetukset.",download_backup:"Lataa tietokannan varmuuskopio",name_your_wallet:"Nimeä lompakkosi {name}",paste_invoice_label:"Liita lasku, maksupyyntö tai LNURL-koodi*",lnbits_description:"Kevyt ja helppokäyttöinen LNbits voi käyttää rahoituslähteinään mitä vain Lightning-palveluita ja jopa LNbits-palvelua! Voit käyttää sitä itsenäisesti ja helposti tarjota erilaisia Lightning-palveluita. Pystyt luomaan sillä salamaverkkolompakoita eikä niiden määrää ole rajoitettu. Jokaiselle lompakolle saat yksilölliset API-avaimet. Varojen osittaminen tekee siitä erittäin kätevän varojen hallinnassa sekä myös ohjelmistokehityksen työkalun. Laajennukset lisäävät LNbits:in toiminnallisuuksia. Näinpä voit helposti testailla useita erilaisia ja viimeisimpiä salamaverkon teknologioita. Laajennuksien kehittämisen olemme pyrkineet tekemään mahdollisimman helpoksi pitämällä LNbits:in ilmaisena OpenSource-projektina. Kannustamme kaikkia kehittämään ja jakelemaan omia laajennuksia!",export_to_phone:"Käytä puhelimessa lukemalla QR-koodi",export_to_phone_desc:"Tämä QR-koodi sisältää URL-osoitteen, jolla saa lompakkoosi täydet valtuudet. Voit lukea sen puhelimellasi ja avata sillä lompakkosi. Voit myös lisätä lompakkosi selaimella käytettäväksi PWA-sovellukseksi puhelimen aloitusruudulle. ",access_wallet_on_mobile:"Mobiili käyttö",wallet:"Lompakko:",wallet_name:"Lompakon nimi",wallets:"Lompakot",add_wallet:"Lisää lompakko",add_new_wallet:"Lisää uusi lompakko",pin_wallet:"Kiinnitä lompakko",delete_wallet:"Poista lompakko",delete_wallet_desc:"Lompakko poistetaan pysyvästi. Siirrä lompakosta varat ennalta muualle, sillä tämä toiminto on PERUUTTAMATON!",rename_wallet:"Nimeä lompakko uudelleen",update_name:"Tallenna",fiat_tracking:"Käytettävä valuutta",fiat_providers:"Valuutan välittäjät",currency:"Valuutta",update_currency:"Tallenna",press_to_claim:"Lunasta varat painamalla tästä",claim_desc:"Näyttää että sinulla on lunastamattomia bitcoin varoja, mutta sinulla ei vielä ole lompakkoa. Lunasta varat allaolevaa nappia painamalla, ja sinulle luodaan lompakko.",donate:"Lahjoita",view_github:"Näytä GitHub:ssa",voidwallet_active:"VoidWallet on aktiivinen. Se ei tue maksutapahtumia!",use_with_caution:"KÄYTÄ VAROEN - BETA-ohjelmisto on käytössä palvelussa: {name}",service_fee_tooltip:"LNbits palvelimen ylläpitäjä veloittaa lähtevästä maksusta palvelumaksun.",toggle_darkmode:"Tumma näkymä",payment_reactions:"Maksureaktiot",view_swagger_docs:"Näytä LNbits Swagger API-dokumentit",api_docs:"API-dokumentaatio",api_keys_api_docs:"Solmun URL, API-avaimet ja -dokumentaatio",lnbits_version:"LNbits versio",runs_on:"Mukana menossa",paste:"Liitä",paste_from_clipboard:"Liitä leikepöydältä",paste_request:"Liitä pyyntö",create_invoice:"Laskuta",camera_tooltip:"Kuvaa lasku tai QR-koodi",export_csv:"Vie CSV-tiedostoon",export_csv_details:"Vie CSV-tiedostoon lisätietoineen",chart_tooltip:"Näytä kaaviokuva",pending:"Odottaa",copy_invoice:"Kopioi lasku",withdraw_from:"Nosta kohteesta",cancel:"Peruuta",scan:"Scannaa",read:"Lue",write:"Kirjoita",pay:"Maksa",memo:"Kuvaus",date:"Päiväys",path:"Path",payment_processing:"Maksua käsitellään...",not_enough_funds:"Varat eivät riitä!",search_by_tag_memo_amount:"Etsi tunnisteella, muistiolla tai määrällä",invoice_waiting:"Lasku odottaa maksua",payment_received:"Maksu vastaanotettu",payment_sent:"Maksu lähetetty",payment_failed:"Maksu epäonnistui",receive:"vastaanota",send:"lähetä",outgoing_payment_pending:"Lähtevä maksu odottaa",drain_funds:"Tyhjennä varat",drain_funds_desc:"Tämä LNURL-withdraw -tyyppinen QR-koodi on tarkoitettu kaikkien varojen imurointiin lompakosta. ÄLÄ JAA SITÄ KENELLEKÄÄN! Se on balanceCheck- ja balanceNotify-toimintojen kanssa yhteensopiva, joten sitä voi käyttää lompakon tyhjentämiseen ensimmäisen käytön jälleen jatkuvasti.",i_understand:"Vakuutan ymmärtäväni",copy_wallet_url:"Kopioi lompakon URL",disclaimer_dialog_title:"Tärkeää!",disclaimer_dialog:"Sinun *PITÄÄ TALLETTAA* kirjautumistietosi turvallisesta ja helposti saataville, jotta pääset jatkossa kirjautumaan lompakkoosi! Löydät kirjautumistiedot Tilin asetukset -sivulta. Kukaan ei ota mitään vastuuta varojen säilymisestä tai niiden käytettävyyden takaamisesta.",no_transactions:"Lompakossa ei ole yhtään tapahtumaa",manage:"Hallinnointi",exchanges:"Vaihtokurssit",extensions:"Laajennukset",no_extensions:"Laajennuksia ei ole asennettu :(",created:"Luotu",search_extensions:"Etsi laajennuksia",search_wallets:"Etsi lompakkoa",extension_sources:"Laajennuslähteet",ext_sources_hint:"Lähteet joista laajennuksia voi ladata",ext_sources_label:"Lähde-URL (käytä vain virallista LNbits tai muuta luotettaa laajennuslähdettä)",warning:"Varoitus",repository:"Laajennuksien lähde",confirm_continue:"Haluatko varmasti jatkaa?",manage_extension_details:"Asenna/Poista laajennus",install:"Asenna",uninstall:"Poista",drop_db:"Poista tiedot",enable:"Ota käyttöön",enabled:"Käytössä",pay_to_enable:"Maksa ottaaksesi käyttöön",enable_extension_details:"Ota laajennus käyttöön tälle käyttäjälle",disable:"Poista käytöstä",delete:"Poista",installed:"Asennettu",activated:"Käytössä",deactivated:"Poissa käytöstä",release_notes:"Julkaisutiedot",activate_extension_details:"Aseta/Poista laajennus käyttäjien saatavilta",featured:"Esittelyssä",all:"Kaikki",only_admins_can_install:"(Vain pääkäyttäjät voivat asentaa laajennuksia)",admin_only:"Pääkäyttäjille",new_version:"Uusi versio",extension_depends_on:"Edellyttää:",extension_rating_soon:"Arvostelut on tulossa pian",extension_installed_version:"Nykyinen versio",extension_uninstall_warning:"Olet poistamassa laajennuksen kaikilta käyttäjiltä.",uninstall_confirm:"Kyllä, poista asennus",extension_db_drop_info:"Kaikki laajennuksen tallettama tieto poistetaan pysyvästi. Poistoa ei voi jälkikäteen peruuttaa!",extension_db_drop_warning:"Olet tuhoamassa laajennuksen tallettamat tiedot. Vahvista poisto kirjoittamalla viivalle seuraavassa näkyvä laajennuksen nimi:",extension_required_lnbits_version:"Tämä laajennus vaatii vähintään LNbits-version",min_version:"Minimi (sisältyy)",max_version:"Enimmäismäärä (ei sisälly)",payment_hash:"Maksun tiiviste",fee:"Kulu",amount:"Määrä",amount_limits:"Määrien rajat",amount_sats:"Määrä (sat)",faucest_wallet:"Faucet Wallet",faucest_wallet_desc_1:"Each time a payment is confirmed by the {provider} provider funds will be subtracted from this wallet.",faucest_wallet_desc_2:"This helps monitor all {provider} payments and their status.",faucest_wallet_desc_3:"This wallet must be topped up with the amount of sats that the admin is willing to offer in exchange for the fiat currency.",faucest_wallet_desc_4:"If this wallet is configured, but is empty, the {provider} payments will not be processed.",faucest_wallet_desc_5:"This wallet can eventually get to a negative balance if parallel fiat payments are made.",faucest_wallet_id:"Faucet Wallet ID (optional)",faucest_wallet_id_hint:"Wallet ID to use for the faucet. It will be used to send the funds to the user.",tag:"Tunniste",unit:"Yksikkö",description:"Kuvaus",expiry:"Vanhenee",webhook:"Webhook",webhook_url:"Webhook URL",webhook_url_hint:"Webhook URL to send the payment details to. It will be called when the payment is completed.",webhook_events_list:"The following events must be supported by the webhook:",webhook_stripe_description:"One the stripe side you must configure a webhook with a URL that points to your LNbits server.",payment_proof:"Maksun varmenne",update:"Päivitä",update_available:"Saatavilla on päivitys {version}-versioon!",update_available:"Rahoituslähteet",latest_update:"Käytössä oleva versio {version}, on viimeisin saatavilla oleva.",notifications:"Tiedotteet",notifications_configure:"Määritä tiedotukset",notifications_nostr_config:"Nostr-määritykset",notifications_enable_nostr:"Kaytä Nostr:ia",notifications_enable_nostr_desc:"Lähetä tietodukset Nostr:in kautta",notifications_nostr_private_key:"Nostr-yksityisavain",notifications_nostr_private_key_desc:"Yksityinen avain (hex tai nsec) Nostr-viestien lähettämisen allekirjoitukseen",notifications_nostr_identifiers:"Nostr-tunnisteet",notifications_nostr_identifiers_desc:"Lista tunnisteista kenelle tiedotukset lähetetään",notifications_telegram_config:"Telegram-määritykset",notifications_enable_telegram:"Käytä Telegram:ia",notifications_enable_telegram_desc:"Lähetä tietodukset Telegram:in kautta",notifications_telegram_access_token:"Access Token",notifications_telegram_access_token_desc:"Telegram botin Access token",notifications_chat_id:"Keskustelun tunnus",notifications_chat_id_desc:"Keskustelun tunnus minne tiedotukset lähetetään",notifications_email_config:"Sähköposti määritykset",notifications_enable_email:"Käytä sähköpostia",notifications_enable_email_desc:"Lähetä tiedotteet sähköpostilla",notifications_send_test_email:"Lähetä testiposti",notifications_send_email:"Lähetä sähköpostiosoitteella",notifications_send_email_desc:"Lähettäjänä näkyvä sähköpostiosoite",notifications_send_email_username:"Käyttäjätunnus",notifications_send_email_username_desc:"Käyttäjätunnus, mikäli tyhjä, käytetään sähköpostiosoitetta",notifications_send_email_password:"Lähtevän sähköpostin salasana",notifications_send_email_password_desc:"Salasana lähettävälle sähköpostille",notifications_send_email_server_port:"Lähtevän sähköpostin SMTP-portti",notifications_send_email_server_port_desc:"SMTP-palvelimen portti",notifications_send_email_server:"Lähtevän sähköpostin SMTP-palvelin",notifications_send_email_server_desc:"SMTP-palvelin jonka kautta sähköpostit lähetetään",notifications_send_to_emails:"Sähköpostien vastaanottaja",notifications_send_to_emails_desc:"Kenelle sähköpostit lähetetään",notification_settings_update:"Asetuksia päivitetty",notification_settings_update_desc:"Tiedota kun palvelimen asetuksia on päivitetty",notification_server_start_stop:"Palvelimen Käynnystys/Sammutus",notification_server_start_stop_desc:"Tiedota kun palvelin on käynnistetty tai sammutettu",notification_watchdog_limit:"Watchdog-raja -tiedote",notification_watchdog_limit_desc:"Tiedota kun watchdog-raja on saavutettu (ei vaikuta rahoituslähteeseen)",notification_server_status:"Palvelimen tila",notification_server_status_desc:"Lähetä säännölliset tiedotteet palvelimen tilasta (anna tiedotusväli tunteina)",notification_incoming_payment:"Saapuvat maksut",notification_incoming_payment_desc:"Tiedota kun lompakon vastaanottaman ja saapuvan maksun määrä ylittää rajan (sat)",notification_outgoing_payment:"Lähtevät maksut",notification_outgoing_payment_desc:"Tiedota kun lompakon lähettävän ja maksettavan maksun määrä ylittää rajan (sat)",notification_credit_debit:"Hyvitys / Veloitus",notification_credit_debit_desc:"Tiedota kun Superuser tekee lompakon hyvitys- tai veloitustapahtumia",notification_balance_delta_changed:"Saldon määrän muutos",notification_balance_delta_changed_desc:"Tiedota kun solmun ja LNbits saldojen eri poikkeaa edes yhden satoshin. Tämä tarkastus tehdään joka minuuttu.",enable_watchdog:"Watchdog-kytkin",enable_watchdog_desc:"Tämän ollessa käytössä, ja solmun varojen laskiessa alle LNbits-varojen määrän, otetaan automaattisesti käyttöön VoidWallet. Päivityksen jälkeen tämä asetus pitää tarkastaa uudelleen.",watchdog_interval:"Watchdog-aikaväli",watchdog_interval_desc:"Tällä määritetään kuinka usein taustatoiminto tarkistaa varojen Delta-muutokset [node_balance - lnbits_balance] killswitch-signaalille. Hakujen väli ilmoitetaan minuutteina.",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Mikäli rahoituslähteen saldo laskee alle LNbits kokonaissaldon, muutetaan rahoituslähteeksi heti VoidWallet. Päivittämisen jälkeen asetus pitää päivittää manuaalisestsi.",status:"Tilanne",notification_source:"Tiedotteiden lähde",notification_source_label:"Lähde-URL (käytä ainoastaan LNbits:iä tai muuta luotettavaa lähdettä)",more:"näytä lisää",more_count:"näytä {count} lisää",less:"supista",releases:"Julkaisut",watchdog:"Watchdog",server_logs:"Palvelimen lokit",ip_blocker:"Palvelimen suojaus IP-osoitesuodattimella",security:"Turvallisuus",security_tools:"Turvallisuus työkalut",block_access_hint:"Estä pääsy IP-osoitteen perusteella",allow_access_hint:"Salli pääsy IP-osoitteen perusteella (ohittaa estot)",enter_ip:"Anna IP ja paina +",rate_limiter:"Toiston rajoitin",callback_url_rules:"Callback URL -säännöt",enter_callback_url_rule:"Anna URL-sääntö regex-muodossa ja paina enter",callback_url_rule_hint:"Callback URL:it (kuten LNURL) tarkistetaan kaikkien näiden sääntöjen mukaisesti. Jos sääntöjä ei ole määritetty, kaikki URL:it ovat sallittuja.",wallet_limiter:"Lompakon käyttörajoitin",wallet_config:"Wallet Config",wallet_charts:"Wallet Charts",wallet_limit_max_withdraw_per_day:"Päivittäin nostettavissa sat maksimi (0 poistaa käytöstä)",wallet_max_ballance:"Maksimisaldo (sat) (0 poistaa käytöstä)",wallet_limit_secs_between_trans:"Tapahtumien välinen minimi (sec) (0 poistaa käytöstä)",only_incoming_payments_allowed:"Vain saapuvat maksut sallittuna",disable_outgoing_payments:"Poista lähtevät maksut käytöstä",number_of_requests:"Pyyntöjen lukumäärä",time_unit:"aikayksikkö",minute:"minuutti",settings:"Asetukset",second:"sekunti",hour:"tunti",disable_server_log:"Piilota palvelimen loki",enable_server_log:"Näytä palvelimen loki",coming_soon:"Ominaisuus on tulossa pian",session_has_expired:"Käyttämätön sessio on vanhentunut. Kirjaudu uudelleen.",instant_access_question:"perinteinen kirjautuminen",login_with_user_id:"Kirjaudu käyttäjä-ID:llä",or:"tai",create_new_wallet:"Avaa uusi lompakko",delete_all_wallets:"Poista kaikki lompakot",confirm_delete_all_wallets:"Oletko todellakin varma, että haluat poistaa käyttäjältä KAIKKI lompakot?",login_to_account:"Kirjaudu käyttäjänimellä",create_account:"Luo tili",account_settings:"Tilin asetukset",signin_with_oauth:"Login with",signin_with_oauth_or:"or Login with",signin_with_nostr:"Kirjaudu Nostr:lla",signin_with_google:"Kirjaudu Google-tunnuksella",signin_with_github:"Kirjaudu GitHub-tunnuksella",signin_with_custom_org:"Kirjaudu {custom_org}-palvelulla",username_or_email:"Käyttäjänimi tai sähköposti",password:"Anna uusi salasana",password_config:"Salasanan määritys",password_repeat:"Toista uusi salasana",update_password:"Päivitä salasana",change_password:"Vaihda salasana",update_credentials:"Päivitä käyttöoikeustiedot",update_pubkey:"Päivitä julkinen avain",nostr_pubkey_tooltip:"Syötä tämän käyttäjän julkinen Nostr avain (hex arvona)",set_password:"Aseta salasana",set_password_tooltip:"Aseta käyttäjätunnukselle salasana",invalid_password:"Salasanassa tulee olla vähintään kahdeksan merkkiä",invalid_password_repeat:"Salasanat eivät täsmää",reset_key_generated:"Salasanan vaihtoavain on luotu.",reset_key_copy:"Kopioi vaihto-URL leikepöydälle painamalla OK.",login:"Kirjaudu",register:"Rekisteröidy",username:"Käyttäjänimi",pubkey:"Julkinen avain",user_id:"Käyttäjä tunnus",id:"tunnus",email:"Sähköposti",first_name:"Etunimi",last_name:"Sukunimi",picture:"Kuva",verify_email:"Vahvista sähköposti",account:"Tili",update_account:"Päivitä tiliä",invalid_username:"Virheellinen käyttäjänimi",auth_provider:"Tunnistamisen toimittaja",my_account:"Tilini",existing_account_question:"Onkohan sinulla jo tili?",background_image:"Taustakuva",back:"Takaisin",logout:"Poistu",look_and_feel:"Kieli ja värit",endpoint:"Endpoint",api:"API",api_token:"API Token",api_tokens:"API Tokens",access_control_list:"Access Control List",access_control_list_admin_warning:"This is an admin account. The generated tokens will have admin privileges.",new_api_acl:"New Access Control List",api_token_id:"Token Id",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",language:"Kieli",color_scheme:"Väriteema",visible_wallet_count:"Näytettävien lompakkojen määrä",admin_settings:"Pääkäyttäjän asetukset",extension_cost:"Tämä laajennus edellyttää vähintään {cost} sat maksua.",extension_paid_sats:"Olet jo maksanut {paid_sats} satsia.",release_details_error:"Ei voi hakea julkaisun tietoja.",pay_from_wallet:"Maksa lompakosta",pay_with:"Maksa {provider}:lla",select_payment_provider:"Valitse maksun välittäjä",wallet_required:"Lompakko *",show_qr:"Näytä QR",retry_install:"Yritä asennusta uudelleen",new_payment:"Luo uusi maksu",update_payment:"Päivitä maksu",already_paid_question:"Kenties maksoit jo?",sell:"Myy",sell_require:"Pyydä maksua laajennuksen käytöstä",sell_info:"{name} -laajennuksen aktivointi edellyttää vähintään {amount} sat maksua.",hide_empty_wallets:"Piilota tyhjät lompakot",recheck:"Tarkista uudelleen",check:"Tarkista",check_connection:"Tarkista yhteys",check_webhook:"Tarkista Webhook",contributors:"Avustajat",license:"Lisenssi",reset_key:"Vaihda avain",reset_password:"Vaihda salasana",border_choices:"Reunuksen vaihtoehdot",select_all:"Valitse kaikki",nfc_supported:"NFC on tuettu",nfc_not_supported:"NFC:tä ei tueta",expire_date:"Vanhenemispäivämäärä:",hash:"Tiiviste:",welcome_lnbits:"Tervetuloa LNbits-palveluun",setup_su_account:"Määritä Superuser-tili alta.",create_ticker_converter:"Luo valuuttamuuntimen Ticker",enable_audit:"Ota seuranta käyttöön",recommended:"Suositeltu",audit_desc:"Tallenna HTTP-pyyntöjä seuraavien suodattimien mukaisesti",audit_record_req:"Tallenna pyynnön Body",audit_record_warning:"Varoitus:",audit_record_req_warning_1:"Luottamukselliset tiedot (kuten salasanat) tallennetaan.",audit_record_req_warning_2:"Body-datamäätä voi olla iso.",audit_record_use:"Käytä varoen!",audit_ip:"Tallenna IP-osoite",audit_ip_desc:"Tallenna asiakkaan IP-osoite",audit_path_params:"Tallenna Path-parametrit",audit_query_params:"Tallenna Query-parametrit",audit_http_methods:"Tallenna HTTP-menetelmät",audit_http_methods_hint:"Luettelo mukaan otettavista HTTP-menetelmistä. Tyhjä luettelo tallettaa kaikki.",audit_http_methods_label:"HTTP-metodit",audit_resp_codes:"Tallenna HTTP-vastauskoodit",audit_resp_codes_hint:"HTTP-koodien lista, jotka sisällytetään (regex-match). Tyhjä luettelo tallettaa kaikki. Esim: 4.*, 5.*",audit_resp_codes_label:"HTTP-vastauskoodi (säännöllinen lauseke)",audit_paths:"Sisällytä polut",audit_paths_hint:"Luettelo poluista, jotka sisällytetään (regex-vastaavuus). Tyhjä luettelo tarkoittaa kaikkia.",audit_paths_label:"HTTP-polku (regex)",audit_paths_exclude:"Ohita polut",audit_paths_exclude_hint:"Lista poluista, jotka jätetään pois (regex-vastaavuus). Tyhjällä listalla mitään ei jätetä pois.",audit_paths_exclude_label:"HTTP-polku (regex)",exchange_providers:"Vaihtokurssin tarjoajat",admin_extensions:"Pääkäyttäjän laajennukset",admin_extensions_label:"Pääkäyttäjän laajennukset",admin_extensions_hint:"Laajennuksia voi käyttää vain käyttäjä, jolla on pääkäyttäjäoikeudet",user_default_extensions:"Käyttäjän oletuslaajennukset",user_default_extensions_label:"Käyttäjän laajennukset",user_default_extensions_hint:"Laajennukset, jotka otetaan oletusarvoisesti käyttöön kaikille käyttäjille.",miscellanous:"Sekalaiset",misc_disable_extensions:"Poista laajennukset käytöstä",misc_disable_extensions_label:"Poista kaikki laajennukset käytöstä",misc_hide_api:"Piilota API",misc_hide_api_label:"Piilottaa lompakon rajapinnan, laajennukset voivat valita välittävätkö tästä asetuksesta",wallets_management:"Lompakoiden hallinta",funding_source_info:"Rahoituslähteen tiedot",funding_source:"Rahoituslähde: {wallet_class}",node_balance:"Solmun saldo: {balance} sats",lnbits_balance:"LNbits-saldo: {balance} sat",funding_reserve_percent:"Omavaraisuusaste: {percent} %",node_management:"Solmun hallinta",node_management_not_supported:"Solmun hallinta ei ole mahdollista valitun rahoituslähteen kanssa.",toggle_node_ui:"Solmun käyttöliittymä",toggle_public_node_ui:"Julkinen näkymä solmun tietoihin",toggle_transactions_node_ui:"Tapahtumat-välilehti (Poista käytöstä suurilla CLN-solmuilla)",invoice_expiry:"Laskun vanhenemisaika",invoice_expiry_label:"Laskun vanhentuminen (sekunteina)",fee_reserve:"Kuluvaraus",fee_reserve_percent:"Kuluvaraus prosentteina",fee_reserve_msats:"Kuluvaraus milli-sat",reserve_fee_in_percent:"Kuluvaraus prosentteina",payment_wait_time:"Maksun odotusaika (sekuntia)",payment_wait_time_desc:"Kuinka pitkään maksua odotetaan saapuvaksi, ennen kuin se merkitään Odotetaan-tilaan. Aseta pidemmäksi käytettäessä HODL-laskuja, Boltz-palvelua, tms",server_management:"Palvelimen hallinta",base_url:"Palvelimen URL-osoite",base_url_label:"Palvelun staattinen pohja-URL",authentication:"Käyttäjän todennus",auth_token_expiry_label:"Kirjautumisen vanhentumisaika minuutteina",auth_token_expiry_hint:"Aika minuuteissa, jossa kirjautuminen vanhenee",auth_allowed_methods_label:"Sallitut kirjautumismenetelmät",auth_allowed_methods_hint:"Valitse kirjautumismenetelmät",auth_nostr_label:"Nostr kutsujen URL",auth_nostr_hint:"Asiakkaiden kirjautumiseen käyttämä absoluuttinen URL-osoite.",auth_google_ci_label:"Google-asiakastunnus",auth_google_ci_hint:"Varmista, että valtuutetut uudelleenohjaus-URI:t sisältävät https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google-asiakassalasana",auth_gh_client_id_label:"GitHub-asiakastunnus",auth_gh_client_id_hint:"Varmista, että valtuutuksen paluuosoite-URL on asetettu osoitteeseen https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub-asiakassalaisuusavain",auth_keycloak_label:"Keycloak-discovery-URL",auth_keycloak_ci_label:"Keycloak-asiakastunnus",auth_keycloak_ci_hint:"Varmista, että valtuutuksen palautus-URL on asetettu muotoon https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak-asiakassalasana",auth_keycloak_custom_org_label:"Valinnainen Keycloak-organisaatio",auth_keycloak_custom_icon_label:"Valinnainen Keycloak-kuvake (URL)",currency_settings:"Valuutta-asetukset",allowed_currencies:"Käytettävät valuutat",allowed_currencies_hint:"Valitse käytettävissä olevat fiat-valuutat",default_account_currency:"Tilin oletusvaluutta",default_account_currency_hint:"Kirjanpidon oletusvaluutta",min_incoming_payment_amount:"Pienin vastaanotettava maksun määrä",min_incoming_payment_amount_desc:"Pienin maksun määrä jolle voi luoda laskun",max_incoming_payment_amount:"Saapuvan maksun enimmäismäärä",max_incoming_payment_amount_desc:"Enimmäismäärä jonka voi laskuttaa",max_outgoing_payment_amount:"Lähtevän maksun enimmäismäärä",max_outgoing_payment_amount_desc:"Enimmäismäärä jonka voi maksaa",service_fee:"Palvelumaksut",service_fee_label:"Palvelumaksu (%)",service_fee_hint:"Tapahtumastakohtainen palvelumaksu (%)",service_fee_max:"Palvelumaksun enimmäismäärä",service_fee_max_label:"Palvelumaksu max (sat)",service_fee_max_hint:"Suurin veloitettava palvelumaksu (sat)",fee_wallet:"Palvelumaksujen lompakko",fee_wallet_label:"Palvelumaksujen tilityslompakko (lompakon tunnus)",fee_wallet_hint:"Lompakon tunnus, johon palvelumaksut tilitetään",disable_fee:"Poista maksu käytöstä",disable_fee_internal:"Poista palvelumaksu sisäisiltä maksuilta",disable_fee_internal_desc:"Poista palvelumaksu sisäisiltä salamaksuilta",ui_management:"Käyttöliittymän hallinta",ui_site_title:"Sivuston nimi",ui_changing_remove_lnbits_elements:" (tämän muuttamalla LNbits elementit poistuvat kotisivulla ja alareunasta)",ui_site_tagline:"Sivuston iskulause",ui_elements_enable:"Ota käyttöön elementit etusivulla/alareunassa",ui_elements_disable:"Poista elementit käytöstä etusivulla/alareunassa",ui_toggle_elements_tip:"Poista kotisivuelementit kuten 'toimii' jne.",ui_site_description:"Sivuston kuvaus",ui_site_description_hint:"Käytä tavallista tekstiä, Markdownia tai puhdasta HTML:ää",ui_default_wallet_name:"Oletuslompakon nimi",ui_default_theme:"Oletusteema",lnbits_wallet:"LNbits-lompakko",denomination:"Valuutan nimi",denomination_hint:"FakeWallet-lompakon valuutan nimi",denomination_error:"Valuutta tunnisssa on oltava 3 merkkiä, tai `sat`",ui_qr_code_logo:"QR- ja Favicon-logo",ui_qr_code_logo_hint:"Anna QR-koodissa ja Faviconissa käytettävän logo-kuvan URL",ui_custom_image:"Yksilöity kuva",ui_custom_image_label:"Anna yksilöidyn kuvan URL-osoite",ui_custom_image_hint:"Yksilöity kuva näytetään aloitus- ja kirjautumissivuilla",ui_custom_badge:"Yksilöity tunnus",ui_custom_badge_label:"Yksilöity tunnus 'KÄYTÄ VAROVAISUUTTA - LNbits-lompakko on edelleen BETA-versiossa'",ui_custom_badge_color_label:"Kustomoidun tunnuksen väri",themes:"Teemat",themes_hint:"Valitse käyttäjille saatavilla olevat teemat",custom_logo:"Mukautettu logo",custom_logo_hint:"Logokuvan sisältävä URL-osoite",ad_space_title:"Mainospaikan otsikko",ad_space_title_label:"Palvelua tukevat ",ad_slots:"Mainospaikat",ad_slots_hint:"Mainoslinkit ja kuvatiedostopolut CSV-muodossa, lisäosat voivat valita välittävätkö asetuksesta",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Mainokset käytössä",ads_disabled:"Mainokset poistettu käytöstä",user_management:"Käyttäjänhallinta",admin_users:"Pääkäyttäjät",admin_users_hint:"Käyttäjät, joilla on pääkäyttäjän oikeudet",admin_users_label:"Käyttäjätunnus",allowed_users:"Sallitut käyttäjät",allowed_users_hint:"Vain nämä käyttäjät voivat käyttää LNbitsiä",allowed_users_hint_feature:"Ainoastaan nämä käyttäjät voivat käyttää ominaisuutta {feature}",allowed_users_label:"Käyttäjätunnus",allow_creation_user:"Salli uusien käyttäjien luominen",allow_creation_user_desc:"Etusivulta on mahdollisuus luoda uusia käyttäjiä",new_user_not_allowed:"Tunnusten luonti on estetty.",components:"Komponentit",long_running_endpoints:"Top 5 pisimpään yhteydessä ollutta päätepistettä",http_request_methods:"HTTP-pyynnön menetelmät",http_response_codes:"HTTP-vastaukset koodit",request_details:"Pyynnön tiedot",http_request_details:"HTTP-pyynnön tiedot",payment_details:"Maksun yksityiskohdat",payment_details_desc:"Yksityiskohtaisen maksun sisältö",payments:"Maksut",payment_show_internal:"Näytä sisäiset maksut",payment_chart_flow:"Kuukausittainen maksuvirta",payment_chart_status:"Maksun Tila",payment_chart_tx_per_wallet:"Lompakkokohtaiset tapahtumat (saldo/kappaletta)",payment_details_back:"Takaisin Maksuihin",payment_chart_tags:"Maksut Tag:eittäin",payments_balance_in_out:"Saldo Sisään/Ulos",payments_count_in_out:"Tapahtumia Sisään/Ulos",payments_status_chart:"Tilakaavio",payments_tag_chart:"Tag-kaavio",payments_balance_chart:"Saldo-kaavio",payments_wallets_chart:"Lompakko-kaavio",payments_balance_in_out_chart:"Saldo Sisään/Ulos -kaavio",payments_count_in_out_chart:"Lukumäärä Sisään/Ulos -kaavio",reset_wallet_keys:"Uusi API-avaimet",reset_wallet_keys_desc:"Tämän lompakon API-avaimet uusitaan. Edelliset API-avaimet lakkaavat toimimasta ja uudet luodaan niiden tilalle..",view_list:"Näytä lompakot allekain",view_column:"Näytä lompakot rinnakkain",filter_payments:"Suodata maksuja",filter_date:"Suodata päiväyksellä",websocket_example:"Websocket example",client_id:"Client ID",secret_key:"Secret Key",signing_secret:"Signing Secret",signing_secret_hint:"Signing secret for the webhook. Messages will be signed with this secret.",webhook_id:"Webhook ID",webhook_id_hint:"PayPal webhook ID used to verify incoming events.",webhook_paypal_description:"On the PayPal side configure a webhook pointing to your LNbits server.",callback_success_url:"Callback Success URL",callback_success_url_hint:"The user will be redirected to this URL after the payment is successful"},window._lnbitsUtils={url_for(e){const t=new URL(e,window.location.origin);return t.searchParams.set("v",window.g.settings.cacheKey),t.toString()},loadScript(e){return new Promise((t,n)=>{const a=document.createElement("script");a.src=this.url_for(e),a.onload=()=>{t()},a.onerror=()=>{n(new Error(`Failed to load script ${e}`))},document.body.appendChild(a)})},async loadTemplate(e){return fetch(this.url_for(e)).then(t=>{if(!t.ok)throw new Error(`Failed to load template from ${e}`);return t.text()}).then(e=>{const t=document.createElement("div");t.innerHTML=e.trim(),document.body.appendChild(t)})},copyText(e,t,n){Quasar.copyToClipboard(e).then(()=>{Quasar.Notify.create({message:t||"Copied to clipboard!",position:n||"bottom"})})},confirmDialog:e=>Quasar.Dialog.create({message:e,ok:{flat:!0,color:"orange"},cancel:{flat:!0,color:"grey"}}),async logout(){LNbits.utils.confirmDialog('Do you really want to logout? Please visit "My Account" page to check your credentials!').onOk(async()=>{try{await LNbits.api.logout(),window.location="/"}catch(e){LNbits.utils.notifyApiError(e)}})},backupLocalStorage(e,t=!1){const n=Object.entries(Quasar.LocalStorage.getAll()).filter(([t,n])=>t.startsWith("lnbits.")&&t!==`lnbits.${e}`)||[];Quasar.LocalStorage.setItem(`lnbits.${e}`,n),t&&n.forEach(([e,t])=>Quasar.LocalStorage.remove(e))},restoreLocalStorage(e){Object.entries(Quasar.LocalStorage.getAll()).filter(([t,n])=>t.startsWith("lnbits.")&&t!==`lnbits.${e}`).forEach(([e,t])=>Quasar.LocalStorage.remove(e));(Quasar.LocalStorage.getItem(`lnbits.${e}`)||[]).forEach(([e,t])=>Quasar.LocalStorage.setItem(e,t)),Quasar.LocalStorage.remove(`lnbits.${e}`)},async digestMessage(e){const t=(new TextEncoder).encode(e),n=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")},formatTimestamp:(e,t=null)=>(t=t||window.dateFormat,Quasar.date.formatDate(new Date(1e3*e),t)),formatDateString(e){this.formatDate(e)},formatDate:(e,t=null)=>(t=t||window.dateFormat,Quasar.date.formatDate(new Date(e),t)),formatTimestampFrom:e=>moment.utc(1e3*e).local().fromNow(),formatDateFrom(e){const t=new Date(e).getTime();return moment.utc(t).local().fromNow()},formatBalance:(e,t="sats")=>"sats"===t?LNbits.utils.formatSat(e)+" sats":LNbits.utils.formatCurrency(e/100,t),formatCurrency:(e,t)=>new Intl.NumberFormat(window.i18n.global.locale,{style:"currency",currency:t||"sat"}).format(e),getCurrencySymbol(e){const t=(e||"").toUpperCase();if("BTC"===t||"XBT"===t||"SAT"===t||"SATS"===t)return"₿";try{const e=new Intl.NumberFormat(window.i18n.global.locale,{style:"currency",currency:t}).formatToParts(0).find(e=>"currency"===e.type);return e?.value||t||"¤"}catch(e){return t||"¤"}},formatSat:e=>new Intl.NumberFormat(window.i18n.global.locale).format(e),formatMsat(e){return this.formatSat(e/1e3)},parseJSONSafe(e){try{return JSON.parse(e)}catch(e){return null}},async notifyApiError(e){if(!e.response)return console.error(e);const t={400:"warning",401:"warning",500:"negative"};let n=e.response.data.detail;if(!n){const t=await(e.response.data?.text());n=this.parseJSONSafe(t)?.detail}n=n?Array.isArray(n)?n.map(e=>e.msg+` (${e.loc?.join("/")})`):n=[n]:[e.response.data.message||e.response.data.detail],n.forEach(n=>Quasar.Notify.create({timeout:5e3,type:t[e.response.status]||"warning",message:n,caption:[e.response.status," ",e.response.statusText].join("").toUpperCase()||null,icon:null,closeBtn:!0}))},search(e,t,n,a){try{const i=t.toLowerCase().split(a||" ");return e.filter(e=>{let t=0;return _.each(i,a=>{-1!==e[n].indexOf(a)&&t++}),t===i.length})}catch(t){return e}},prepareFilterQuery(e,t,n){e.filter=n||e.filter||{},t&&(e.pagination=t.pagination,Object.assign(e.filter,t.filter));const a=e.pagination;e.loading=!0;const i={limit:a.rowsPerPage,offset:(a.page-1)*a.rowsPerPage,sortby:a.sortBy??"",direction:a.descending?"desc":"asc",...e.filter};return e.search&&(i.search=e.search),new URLSearchParams(i)},exportCSV(e,t,n){const a=(e,t)=>{let n=void 0!==t?t(e):e;return n=null==n?"":String(n),n=n.split('"').join('""'),`"${n}"`},i=[e.map(e=>a(e.label))].concat(t.map(t=>e.map(e=>a("function"==typeof e.field?e.field(t):t[void 0===e.field?e.name:e.field],e.format)).join(","))).join("\r\n");!0!==Quasar.exportFile(`${n||"table-export"}.csv`,i,"text/csv")&&Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null})},convertMarkdown(e){const t=new showdown.Converter;return t.setFlavor("github"),t.setOption("simpleLineBreaks",!0),t.makeHtml(e)},async decryptLnurlPayAES(e,t){let n=new Uint8Array(t.match(/[\da-f]{2}/gi).map(e=>parseInt(e,16)));return crypto.subtle.importKey("raw",n,{name:"AES-CBC",length:256},!1,["decrypt"]).then(t=>{let n=Uint8Array.from(window.atob(e.iv),e=>e.charCodeAt(0)),a=Uint8Array.from(window.atob(e.ciphertext),e=>e.charCodeAt(0));return crypto.subtle.decrypt({name:"AES-CBC",iv:n},t,a)}).then(e=>new TextDecoder("utf-8").decode(e))}},window._lnbitsApi={request:(e,t,n,a,i={})=>axios({method:e,url:t,headers:{"X-Api-Key":n},data:a,...i}),getServerHealth(){return this.request("get","/api/v1/health")},async createInvoice(e,t,n,a="sat",i=null,o=null,r=null,s=null){const l={out:!1,amount:t,memo:n,unit:a,lnurl_withdraw:i,fiat_provider:o,payment_hash:s};return r&&(l.extra={internal_memo:String(r)}),this.request("post","/api/v1/payments",e.inkey,l)},payInvoice(e,t,n=null){const a={out:!0,bolt11:t};return n&&(a.extra={internal_memo:String(n)}),this.request("post","/api/v1/payments",e.adminkey,a)},cancelInvoice(e,t){return this.request("post","/api/v1/payments/cancel",e.adminkey,{payment_hash:t})},settleInvoice(e,t){return this.request("post","/api/v1/payments/settle",e.adminkey,{preimage:t})},createAccount(e){return this.request("post","/api/v1/account",null,{name:e})},register:(e,t,n,a,i)=>axios({method:"POST",url:"/api/v1/auth/register",data:{username:e,email:t,password:n,password_repeat:a,invitation_code:i}}),reset:(e,t,n)=>axios({method:"PUT",url:"/api/v1/auth/reset",data:{reset_key:e,password:t,password_repeat:n}}),getAuthUser:()=>axios({method:"GET",url:"/api/v1/auth"}),login:(e,t)=>axios({method:"POST",url:"/api/v1/auth",data:{username:e,password:t}}),loginByProvider:(e,t,n)=>axios({method:"POST",url:`/api/v1/auth/${e}`,headers:t,data:n}),loginUsr:e=>axios({method:"POST",url:"/api/v1/auth/usr",data:{usr:e}}),logout:()=>axios({method:"POST",url:"/api/v1/auth/logout"}),impersonateUser:e=>axios({method:"POST",url:"/api/v1/auth/impersonate",data:{usr:e}}),stopImpersonation:()=>axios({method:"DELETE",url:"/api/v1/auth/impersonate"}),getAuthenticatedUser(){return this.request("get","/api/v1/auth")},getWallet(e){return this.request("get","/api/v1/wallet",e.inkey)},createWallet(e,t,n={}){return this.request("post","/api/v1/wallet",null,{name:e,wallet_type:t,...n})},updateWallet(e,t){return this.request("patch","/api/v1/wallet",t.adminkey,{name:e})},updateUiCustomization(e={}){return this.request("patch","/api/v1/auth/ui",null,e)},resetWalletKeys(e){return this.request("put",`/api/v1/wallet/reset/${e.id}`).then(e=>e.data)},deleteWallet(e){return this.request("delete",`/api/v1/wallet/${e.id}`)},getPayments(e,t){return this.request("get","/api/v1/payments/paginated?"+t,e.inkey)},getPayment(e,t){return this.request("get","/api/v1/payments/"+t,e.inkey)},updateBalance(e,t){return this.request("PUT","/users/api/v1/balance",null,{amount:e,id:t})},getCurrencies(){return this.request("GET","/api/v1/currencies").then(e=>["sats",...e.data])},getDefaultSetting:e=>LNbits.api.request("GET",`/admin/api/v1/settings/default?field_name=${e}`).catch(LNbits.utils.notifyApiError)};const localStore=(e,t)=>{const n=Quasar.LocalStorage.getItem(e);return null!==n&&"null"!==n&&void 0!==n&&"undefined"!==n?n:t};window.g=Vue.reactive({settings:SETTINGS,currencies:CURRENCIES,extensions:SETTINGS.extensions,allowedCurrencies:SETTINGS.allowedCurrencies,denomination:SETTINGS.denomination,isSatsDenomination:"sats"==SETTINGS.denomination,themeChoice:localStore("lnbits.theme",SETTINGS.defaultTheme),borderChoice:localStore("lnbits.border",SETTINGS.defaultBorder),gradientChoice:localStore("lnbits.gradientBg",SETTINGS.defaultGradient),cardRoundedChoice:localStore("lnbits.cardRounded",SETTINGS.defaultCardRounded),cardGradientChoice:localStore("lnbits.cardGradient",SETTINGS.defaultCardGradient),cardShadowChoice:localStore("lnbits.cardShadow",SETTINGS.defaultCardShadow),reactionChoice:localStore("lnbits.reactions",SETTINGS.defaultReaction),bgimageChoice:localStore("lnbits.backgroundImage",SETTINGS.defaultBgimage||""),locale:localStore("lnbits.lang",navigator.languages[1]??"en"),disclaimerShown:localStore("lnbits.disclaimerShown",!1),isFiatPriority:localStore("lnbits.isFiatPriority",!1),mobileSimple:localStore("lnbits.mobileSimple",!0),walletFlip:localStore("lnbits.walletFlip",!1),lastActiveWallet:localStore("lnbits.lastActiveWallet",null),darkChoice:localStore("lnbits.darkMode",SETTINGS.defaultDark),isUserAuthorized:!!Quasar.Cookies.get("is_lnbits_user_authorized"),isUserImpersonated:!!Quasar.Cookies.get("is_lnbits_user_impersonated"),errorCode:null,errorMessage:null,user:null,wallet:null,isPublicPage:!0,offline:!navigator.onLine,hasCamera:!1,visibleDrawer:!1,fiatBalance:0,exchangeRate:0,fiatTracking:!1,payments:[],walletEventListeners:[],updatePayments:!1,updatePaymentsHash:!1,scanner:null,newWalletType:null}),window.dateFormat="YYYY-MM-DD HH:mm";const websocketPrefix="http:"===window.location.protocol?"ws://":"wss://",websocketUrl=`${websocketPrefix}${window.location.host}/api/v1/ws`,_access_cookies_for_safari_refresh_do_not_delete=document.cookie;function eventReaction(e){if(localUrl="",reaction=localStorage.getItem("lnbits.reactions"),reaction&&"None"!==reaction)try{if(e<0)return;reaction=localStorage.getItem("lnbits.reactions"),reaction&&window[reaction.split("|")[1]]()}catch(e){console.log(e)}}function confettiTop(){document.getElementById("vue").disabled=!0;var e=Date.now()+200,t=[localStorage.getItem("lnbits.primaryColor")||"#FFD700",localStorage.getItem("lnbits.secondaryColor")||"E89400","#ffffff"];!function n(){confetti({particleCount:3,angle:270,spread:1e3,origin:{y:0},colors:t,zIndex:999999}),Date.now(){e.substring(0,n.length)===n&&(t=n)}),null==t)throw"Malformed request: unknown prefix";let n=decodeAmount(e.substring(t.length,e.length));return{prefix:t,amount:n}}function decodeData(e,t){let n=e.substring(0,7),a=bech32ToInt(n),i=e.substring(e.length-104,e.length),o=e.substring(7,e.length-104),r=decodeTags(o),s=bech32ToFiveBitArray(n+o);return s=fiveBitArrayTo8BitArray(s,!0),s=textToHexString(t).concat(byteArrayToHexString(s)),{time_stamp:a,tags:r,signature:decodeSignature(i),signing_data:s}}function decodeSignature(e){let t=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(e)),n=t[t.length-1];return{r:byteArrayToHexString(t.slice(0,32)),s:byteArrayToHexString(t.slice(32,t.length-1)),recovery_flag:n}}function decodeAmount(e){let t=e.charAt(e.length-1),n=e.substring(0,e.length-1);if("0"===n.substring(0,1))throw"Malformed request: amount cannot contain leading zeros";if(n=Number(n),n<0||!Number.isInteger(n))throw"Malformed request: amount must be a positive decimal integer";switch(t){case"":return"Any amount";case"p":return n/10;case"n":return 100*n;case"u":return 1e5*n;case"m":return 1e8*n;default:throw"Malformed request: undefined amount multiplier"}}function decodeTags(e){let t=extractTags(e),n=[];return t.forEach(e=>n.push(decodeTag(e.type,e.length,e.data))),n}function extractTags(e){let t=[];for(;e.length>0;){let n=e.charAt(0),a=bech32ToInt(e.substring(1,3)),i=e.substring(3,a+3);t.push({type:n,length:a,data:i}),e=e.substring(3+a,e.length)}return t}function decodeTag(e,t,n){switch(e){case"p":if(52!==t)break;return{type:e,length:t,description:"payment_hash",value:byteArrayToHexString(fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n)))};case"d":return{type:e,length:t,description:"description",value:bech32ToUTF8String(n)};case"n":if(53!==t)break;return{type:e,length:t,description:"payee_public_key",value:byteArrayToHexString(fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n)))};case"h":if(52!==t)break;return{type:e,length:t,description:"description_hash",value:n};case"x":return{type:e,length:t,description:"expiry",value:bech32ToInt(n)};case"c":return{type:e,length:t,description:"min_final_cltv_expiry",value:bech32ToInt(n)};case"f":let a=bech32ToFiveBitArray(n.charAt(0))[0];if(a<0||a>18)break;return{type:e,length:t,description:"fallback_address",value:{version:a,fallback_address:n=n.substring(1,n.length)}};case"r":let i=(n=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n))).slice(0,33),o=n.slice(33,41),r=n.slice(41,45),s=n.slice(45,49),l=n.slice(49,51);return{type:e,length:t,description:"routing_information",value:{public_key:byteArrayToHexString(i),short_channel_id:byteArrayToHexString(o),fee_base_msat:byteArrayToInt(r),fee_proportional_millionths:byteArrayToInt(s),cltv_expiry_delta:byteArrayToInt(l)}}}}function polymod(e){let t=[996825010,642813549,513874426,1027748829,705979059],n=1;return e.forEach(e=>{let a=n>>25;n=(33554431&n)<<5^e;for(let e=0;e<5;e++)n^=1==(a>>e&1)?t[e]:0}),n}function expand(e){let t=[];for(let n=0;n>5);t.push(0);for(let n=0;n{console.log("offline",e),this.g.offline=!0}),addEventListener("online",e=>{console.log("back online",e),this.g.offline=!1}),null!=navigator.serviceWorker&&navigator.serviceWorker.register("/service-worker.js").then(e=>{console.log("Registered events at scope: ",e.scope)}),navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(e=>{window.g.hasCamera=e.some(e=>"videoinput"===e.kind)}),window.LNbits={g:window.g,utils:window._lnbitsUtils,api:window._lnbitsApi,map:{user(e){const t={id:e.id,username:e.username,admin:e.admin,email:e.email,extensions:e.extensions,wallets:e.wallets,fiat_providers:e.fiat_providers||[],super_user:e.super_user,extra:e.extra??{},hasPassword:e.has_password??!1,uiCustomization:e.ui_customization||{}},n=this.wallet;return t.wallets=t.wallets.map(n).sort((e,t)=>e.extra.pinned!==t.extra.pinned?e.extra.pinned?-1:1:e.name.localeCompare(t.name)),t.walletOptions=t.wallets.map(e=>({label:[e.name," - ",e.id.substring(0,5),"..."].join(""),value:e.id})),t.hiddenWalletsCount=Math.max(0,e.wallets.length-e.extra.visible_wallet_count),t.walletInvitesCount=e.extra.wallet_invite_requests?.length||0,t},wallet(e){if(newWallet={id:e.id,name:e.name,walletType:e.wallet_type,sharePermissions:e.share_permissions,sharedWalletId:e.shared_wallet_id,adminkey:e.adminkey,inkey:e.inkey,currency:e.currency,extra:e.extra,canReceivePayments:!0,canSendPayments:!0},newWallet.msat=e.balance_msat,newWallet.sat=Math.floor(e.balance_msat/1e3),"lightning-shared"===newWallet.walletType){const e=newWallet.sharePermissions;newWallet.canReceivePayments=e.includes("receive-payments"),newWallet.canSendPayments=e.includes("send-payments")}return newWallet.url=`/wallet?&wal=${e.id}`,newWallet.storedPaylinks=e.stored_paylinks.links,newWallet}}},window.windowMixin={},function(e,t){!function e(t,n,a,i){var o=!!(t.Worker&&t.Blob&&t.Promise&&t.OffscreenCanvas&&t.OffscreenCanvasRenderingContext2D&&t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype.transferControlToOffscreen&&t.URL&&t.URL.createObjectURL);function r(){}function s(e){var a=n.exports.Promise,i=void 0!==a?a:t.Promise;return"function"==typeof i?new i(e):(e(r,r),null)}var l,u,c,d,h,p,f,m,g=(c=Math.floor(1e3/60),d={},h=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(l=function(e){var t=Math.random();return d[t]=requestAnimationFrame(function n(a){h===a||h+c-1{a=(a<<5)+e,n+=5,n>=8&&(i.push(a>>n-8&255),n-=8)}),t&&n>0&&i.push(a<<8-n&255),i}function bech32ToUTF8String(e){let t=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(e)),n="";for(let e=0;e20&&(t-=20,e/=Math.pow(10,t),e+=new Array(t+1).join("0"));return e} \ No newline at end of file + */function ve(e){return e+.5|0}const be=(e,t,n)=>Math.max(Math.min(e,n),t);function ye(e){return be(ve(2.55*e),0,255)}function we(e){return be(ve(255*e),0,255)}function ke(e){return be(ve(e/2.55)/100,0,1)}function xe(e){return be(ve(100*e),0,100)}const Se={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Ce=[..."0123456789ABCDEF"],Te=e=>Ce[15&e],Pe=e=>Ce[(240&e)>>4]+Ce[15&e],Ee=e=>(240&e)>>4==(15&e);const Ae=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function Le(e,t,n){const a=t*Math.min(n,1-n),i=(t,i=(t+e/30)%12)=>n-a*Math.max(Math.min(i-3,9-i,1),-1);return[i(0),i(8),i(4)]}function Me(e,t,n){const a=(a,i=(a+e/60)%6)=>n-n*t*Math.max(Math.min(i,4-i,1),0);return[a(5),a(3),a(1)]}function Re(e,t,n){const a=Le(e,1,.5);let i;for(t+n>1&&(i=1/(t+n),t*=i,n*=i),i=0;i<3;i++)a[i]*=1-t-n,a[i]+=t;return a}function ze(e){const t=e.r/255,n=e.g/255,a=e.b/255,i=Math.max(t,n,a),r=Math.min(t,n,a),o=(i+r)/2;let s,l,u;return i!==r&&(u=i-r,l=o>.5?u/(2-i-r):u/(i+r),s=function(e,t,n,a,i){return e===i?(t-n)/a+(te<=.0031308?12.92*e:1.055*Math.pow(e,1/2.4)-.055,Ve=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4);function Ue(e,t,n){if(e){let a=ze(e);a[t]=Math.max(0,Math.min(a[t]+a[t]*n,0===t?360:1)),a=Ne(a),e.r=a[0],e.g=a[1],e.b=a[2]}}function $e(e,t){return e?Object.assign(t||{},e):e}function He(e){var t={r:0,g:0,b:0,a:255};return Array.isArray(e)?e.length>=3&&(t={r:e[0],g:e[1],b:e[2],a:255},e.length>3&&(t.a=we(e[3]))):(t=$e(e,{r:0,g:0,b:0,a:1})).a=we(t.a),t}function We(e){return"r"===e.charAt(0)?function(e){const t=Be.exec(e);let n,a,i,r=255;if(t){if(t[7]!==n){const e=+t[7];r=t[8]?ye(e):be(255*e,0,255)}return n=+t[1],a=+t[3],i=+t[5],n=255&(t[2]?ye(n):be(n,0,255)),a=255&(t[4]?ye(a):be(a,0,255)),i=255&(t[6]?ye(i):be(i,0,255)),{r:n,g:a,b:i,a:r}}}(e):function(e){const t=Ae.exec(e);let n,a=255;if(!t)return;t[5]!==n&&(a=t[6]?ye(+t[5]):we(+t[5]));const i=Oe(+t[2]),r=+t[3]/100,o=+t[4]/100;return n="hwb"===t[1]?function(e,t,n){return Ie(Re,e,t,n)}(i,r,o):"hsv"===t[1]?function(e,t,n){return Ie(Me,e,t,n)}(i,r,o):Ne(i,r,o),{r:n[0],g:n[1],b:n[2],a:a}}(e)}class Ge{constructor(e){if(e instanceof Ge)return e;const t=typeof e;let n;var a,i,r;"object"===t?n=He(e):"string"===t&&(r=(a=e).length,"#"===a[0]&&(4===r||5===r?i={r:255&17*Se[a[1]],g:255&17*Se[a[2]],b:255&17*Se[a[3]],a:5===r?17*Se[a[4]]:255}:7!==r&&9!==r||(i={r:Se[a[1]]<<4|Se[a[2]],g:Se[a[3]]<<4|Se[a[4]],b:Se[a[5]]<<4|Se[a[6]],a:9===r?Se[a[7]]<<4|Se[a[8]]:255})),n=i||function(e){qe||(qe=function(){const e={},t=Object.keys(De),n=Object.keys(je);let a,i,r,o,s;for(a=0;a>16&255,r>>8&255,255&r]}return e}(),qe.transparent=[0,0,0,0]);const t=qe[e.toLowerCase()];return t&&{r:t[0],g:t[1],b:t[2],a:4===t.length?t[3]:255}}(e)||We(e)),this._rgb=n,this._valid=!!n}get valid(){return this._valid}get rgb(){var e=$e(this._rgb);return e&&(e.a=ke(e.a)),e}set rgb(e){this._rgb=He(e)}rgbString(){return this._valid?(e=this._rgb)&&(e.a<255?`rgba(${e.r}, ${e.g}, ${e.b}, ${ke(e.a)})`:`rgb(${e.r}, ${e.g}, ${e.b})`):void 0;var e}hexString(){return this._valid?function(e){var t=(e=>Ee(e.r)&&Ee(e.g)&&Ee(e.b)&&Ee(e.a))(e)?Te:Pe;return e?"#"+t(e.r)+t(e.g)+t(e.b)+((e,t)=>e<255?t(e):"")(e.a,t):void 0}(this._rgb):void 0}hslString(){return this._valid?function(e){if(!e)return;const t=ze(e),n=t[0],a=xe(t[1]),i=xe(t[2]);return e.a<255?`hsla(${n}, ${a}%, ${i}%, ${ke(e.a)})`:`hsl(${n}, ${a}%, ${i}%)`}(this._rgb):void 0}mix(e,t){if(e){const n=this.rgb,a=e.rgb;let i;const r=t===i?.5:t,o=2*r-1,s=n.a-a.a,l=((o*s==-1?o:(o+s)/(1+o*s))+1)/2;i=1-l,n.r=255&l*n.r+i*a.r+.5,n.g=255&l*n.g+i*a.g+.5,n.b=255&l*n.b+i*a.b+.5,n.a=r*n.a+(1-r)*a.a,this.rgb=n}return this}interpolate(e,t){return e&&(this._rgb=function(e,t,n){const a=Ve(ke(e.r)),i=Ve(ke(e.g)),r=Ve(ke(e.b));return{r:we(Fe(a+n*(Ve(ke(t.r))-a))),g:we(Fe(i+n*(Ve(ke(t.g))-i))),b:we(Fe(r+n*(Ve(ke(t.b))-r))),a:e.a+n*(t.a-e.a)}}(this._rgb,e._rgb,t)),this}clone(){return new Ge(this.rgb)}alpha(e){return this._rgb.a=we(e),this}clearer(e){return this._rgb.a*=1-e,this}greyscale(){const e=this._rgb,t=ve(.3*e.r+.59*e.g+.11*e.b);return e.r=e.g=e.b=t,this}opaquer(e){return this._rgb.a*=1+e,this}negate(){const e=this._rgb;return e.r=255-e.r,e.g=255-e.g,e.b=255-e.b,this}lighten(e){return Ue(this._rgb,2,e),this}darken(e){return Ue(this._rgb,2,-e),this}saturate(e){return Ue(this._rgb,1,e),this}desaturate(e){return Ue(this._rgb,1,-e),this}rotate(e){return function(e,t){var n=ze(e);n[0]=Oe(n[0]+t),n=Ne(n),e.r=n[0],e.g=n[1],e.b=n[2]}(this._rgb,e),this}}function Ke(e){if(e&&"object"==typeof e){const t=e.toString();return"[object CanvasPattern]"===t||"[object CanvasGradient]"===t}return!1}function Ye(e){return Ke(e)?e:new Ge(e)}function Qe(e){return Ke(e)?e:new Ge(e).saturate(.5).darken(.1).hexString()}const Ze=["x","y","borderWidth","radius","tension"],Je=["color","borderColor","backgroundColor"],Xe=new Map;function et(e,t,n){return function(e,t){t=t||{};const n=e+JSON.stringify(t);let a=Xe.get(n);return a||(a=new Intl.NumberFormat(e,t),Xe.set(n,a)),a}(t,n).format(e)}const tt={values:e=>i(e)?e:""+e,numeric(e,t,n){if(0===e)return"0";const a=this.chart.options.locale;let i,r=e;if(n.length>1){const t=Math.max(Math.abs(n[0].value),Math.abs(n[n.length-1].value));(t<1e-4||t>1e15)&&(i="scientific"),r=function(e,t){let n=t.length>3?t[2].value-t[1].value:t[1].value-t[0].value;return Math.abs(n)>=1&&e!==Math.floor(e)&&(n=e-Math.floor(e)),n}(e,n)}const o=O(Math.abs(r)),s=isNaN(o)?1:Math.max(Math.min(-1*Math.floor(o),20),0),l={notation:i,minimumFractionDigits:s,maximumFractionDigits:s};return Object.assign(l,this.options.ticks.format),et(e,a,l)},logarithmic(e,t,n){if(0===e)return"0";const a=n[t].significand||e/Math.pow(10,Math.floor(O(e)));return[1,2,3,5,10,15].includes(a)||t>.8*n.length?tt.numeric.call(this,e,t,n):""}};var nt={formatters:tt};const at=Object.create(null),it=Object.create(null);function rt(e,t){if(!t)return e;const n=t.split(".");for(let t=0,a=n.length;te.chart.platform.getDevicePixelRatio(),this.elements={},this.events=["mousemove","mouseout","click","touchstart","touchmove"],this.font={family:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",size:12,style:"normal",lineHeight:1.2,weight:null},this.hover={},this.hoverBackgroundColor=(e,t)=>Qe(t.backgroundColor),this.hoverBorderColor=(e,t)=>Qe(t.borderColor),this.hoverColor=(e,t)=>Qe(t.color),this.indexAxis="x",this.interaction={mode:"nearest",intersect:!0,includeInvisible:!1},this.maintainAspectRatio=!0,this.onHover=null,this.onClick=null,this.parsing=!0,this.plugins={},this.responsive=!0,this.scale=void 0,this.scales={},this.showLine=!0,this.drawActiveElementsOnTop=!0,this.describe(e),this.apply(t)}set(e,t){return ot(this,e,t)}get(e){return rt(this,e)}describe(e,t){return ot(it,e,t)}override(e,t){return ot(at,e,t)}route(e,t,n,a){const i=rt(this,e),o=rt(this,n),s="_"+t;Object.defineProperties(i,{[s]:{value:i[t],writable:!0},[t]:{enumerable:!0,get(){const e=this[s],t=o[a];return r(e)?Object.assign({},t,e):l(e,t)},set(e){this[s]=e}}})}apply(e){e.forEach(e=>e(this))}}({_scriptable:e=>!e.startsWith("on"),_indexable:e=>"events"!==e,hover:{_fallback:"interaction"},interaction:{_scriptable:!1,_indexable:!1}},[function(e){e.set("animation",{delay:void 0,duration:1e3,easing:"easeOutQuart",fn:void 0,from:void 0,loop:void 0,to:void 0,type:void 0}),e.describe("animation",{_fallback:!1,_indexable:!1,_scriptable:e=>"onProgress"!==e&&"onComplete"!==e&&"fn"!==e}),e.set("animations",{colors:{type:"color",properties:Je},numbers:{type:"number",properties:Ze}}),e.describe("animations",{_fallback:"animation"}),e.set("transitions",{active:{animation:{duration:400}},resize:{animation:{duration:0}},show:{animations:{colors:{from:"transparent"},visible:{type:"boolean",duration:0}}},hide:{animations:{colors:{to:"transparent"},visible:{type:"boolean",easing:"linear",fn:e=>0|e}}}})},function(e){e.set("layout",{autoPadding:!0,padding:{top:0,right:0,bottom:0,left:0}})},function(e){e.set("scale",{display:!0,offset:!1,reverse:!1,beginAtZero:!1,bounds:"ticks",clip:!0,grace:0,grid:{display:!0,lineWidth:1,drawOnChartArea:!0,drawTicks:!0,tickLength:8,tickWidth:(e,t)=>t.lineWidth,tickColor:(e,t)=>t.color,offset:!1},border:{display:!0,dash:[],dashOffset:0,width:1},title:{display:!1,text:"",padding:{top:4,bottom:4}},ticks:{minRotation:0,maxRotation:50,mirror:!1,textStrokeWidth:0,textStrokeColor:"",padding:3,display:!0,autoSkip:!0,autoSkipPadding:3,labelOffset:0,callback:nt.formatters.values,minor:{},major:{},align:"center",crossAlign:"near",showLabelBackdrop:!1,backdropColor:"rgba(255, 255, 255, 0.75)",backdropPadding:2}}),e.route("scale.ticks","color","","color"),e.route("scale.grid","color","","borderColor"),e.route("scale.border","color","","borderColor"),e.route("scale.title","color","","color"),e.describe("scale",{_fallback:!1,_scriptable:e=>!e.startsWith("before")&&!e.startsWith("after")&&"callback"!==e&&"parser"!==e,_indexable:e=>"borderDash"!==e&&"tickBorderDash"!==e&&"dash"!==e}),e.describe("scales",{_fallback:"scale"}),e.describe("scale.ticks",{_scriptable:e=>"backdropPadding"!==e&&"callback"!==e,_indexable:e=>"backdropPadding"!==e})}]);function lt(){return"undefined"!=typeof window&&"undefined"!=typeof document}function ut(e){let t=e.parentNode;return t&&"[object ShadowRoot]"===t.toString()&&(t=t.host),t}function ct(e,t,n){let a;return"string"==typeof e?(a=parseInt(e,10),-1!==e.indexOf("%")&&(a=a/100*t.parentNode[n])):a=e,a}const dt=e=>e.ownerDocument.defaultView.getComputedStyle(e,null);function ht(e,t){return dt(e).getPropertyValue(t)}const pt=["top","right","bottom","left"];function ft(e,t,n){const a={};n=n?"-"+n:"";for(let i=0;i<4;i++){const r=pt[i];a[r]=parseFloat(e[t+"-"+r+n])||0}return a.width=a.left+a.right,a.height=a.top+a.bottom,a}function mt(e,t){if("native"in e)return e;const{canvas:n,currentDevicePixelRatio:a}=t,i=dt(n),r="border-box"===i.boxSizing,o=ft(i,"padding"),s=ft(i,"border","width"),{x:l,y:u,box:c}=function(e,t){const n=e.touches,a=n&&n.length?n[0]:e,{offsetX:i,offsetY:r}=a;let o,s,l=!1;if(((e,t,n)=>(e>0||t>0)&&(!n||!n.shadowRoot))(i,r,e.target))o=i,s=r;else{const e=t.getBoundingClientRect();o=a.clientX-e.left,s=a.clientY-e.top,l=!0}return{x:o,y:s,box:l}}(e,n),d=o.left+(c&&s.left),h=o.top+(c&&s.top);let{width:p,height:f}=t;return r&&(p-=o.width+s.width,f-=o.height+s.height),{x:Math.round((l-d)/p*n.width/a),y:Math.round((u-h)/f*n.height/a)}}const _t=e=>Math.round(10*e)/10;function gt(e,t,n,a){const i=dt(e),r=ft(i,"margin"),o=ct(i.maxWidth,e,"clientWidth")||M,s=ct(i.maxHeight,e,"clientHeight")||M,l=function(e,t,n){let a,i;if(void 0===t||void 0===n){const r=e&&ut(e);if(r){const e=r.getBoundingClientRect(),o=dt(r),s=ft(o,"border","width"),l=ft(o,"padding");t=e.width-l.width-s.width,n=e.height-l.height-s.height,a=ct(o.maxWidth,r,"clientWidth"),i=ct(o.maxHeight,r,"clientHeight")}else t=e.clientWidth,n=e.clientHeight}return{width:t,height:n,maxWidth:a||M,maxHeight:i||M}}(e,t,n);let{width:u,height:c}=l;if("content-box"===i.boxSizing){const e=ft(i,"border","width"),t=ft(i,"padding");u-=t.width+e.width,c-=t.height+e.height}return u=Math.max(0,u-r.width),c=Math.max(0,a?u/a:c-r.height),u=_t(Math.min(u,o,l.maxWidth)),c=_t(Math.min(c,s,l.maxHeight)),u&&!c&&(c=_t(u/2)),(void 0!==t||void 0!==n)&&a&&l.height&&c>l.height&&(c=l.height,u=_t(Math.floor(c*a))),{width:u,height:c}}function vt(e,t,n){const a=t||1,i=_t(e.height*a),r=_t(e.width*a);e.height=_t(e.height),e.width=_t(e.width);const o=e.canvas;return o.style&&(n||!o.style.height&&!o.style.width)&&(o.style.height=`${e.height}px`,o.style.width=`${e.width}px`),(e.currentDevicePixelRatio!==a||o.height!==i||o.width!==r)&&(e.currentDevicePixelRatio=a,o.height=i,o.width=r,e.ctx.setTransform(a,0,0,a,0,0),!0)}const bt=function(){let e=!1;try{const t={get passive(){return e=!0,!1}};lt()&&(window.addEventListener("test",null,t),window.removeEventListener("test",null,t))}catch(e){}return e}();function yt(e,t){const n=ht(e,t),a=n&&n.match(/^(\d+)(\.\d+)?px$/);return a?+a[1]:void 0}function wt(e){return!e||a(e.size)||a(e.family)?null:(e.style?e.style+" ":"")+(e.weight?e.weight+" ":"")+e.size+"px "+e.family}function kt(e,t,n,a,i){let r=t[i];return r||(r=t[i]=e.measureText(i).width,n.push(i)),r>a&&(a=r),a}function xt(e,t,n,a){let r=(a=a||{}).data=a.data||{},o=a.garbageCollect=a.garbageCollect||[];a.font!==t&&(r=a.data={},o=a.garbageCollect=[],a.font=t),e.save(),e.font=t;let s=0;const l=n.length;let u,c,d,h,p;for(u=0;un.length){for(u=0;u0&&e.stroke()}}function Et(e,t,n){return n=n||.5,!t||e&&e.x>t.left-n&&e.xt.top-n&&e.y0&&""!==s.strokeColor;let c,d;for(e.save(),e.font=o.string,function(e,t){t.translation&&e.translate(t.translation[0],t.translation[1]),a(t.rotation)||e.rotate(t.rotation),t.color&&(e.fillStyle=t.color),t.textAlign&&(e.textAlign=t.textAlign),t.textBaseline&&(e.textBaseline=t.textBaseline)}(e,s),c=0;ce[0]){const r=n||e;void 0===a&&(a=Kt("_fallback",e));const o={[Symbol.toStringTag]:"Object",_cacheable:!0,_scopes:e,_rootScopes:r,_fallback:a,_getTarget:i,override:n=>jt([n,...e],t,r,a)};return new Proxy(o,{deleteProperty:(t,n)=>(delete t[n],delete t._keys,delete e[0][n],!0),get:(n,a)=>Vt(n,a,()=>function(e,t,n,a){let i;for(const r of t)if(i=Kt(Bt(r,e),n),void 0!==i)return Ft(e,i)?Wt(n,a,e,i):i}(a,t,e,n)),getOwnPropertyDescriptor:(e,t)=>Reflect.getOwnPropertyDescriptor(e._scopes[0],t),getPrototypeOf:()=>Reflect.getPrototypeOf(e[0]),has:(e,t)=>Yt(e).includes(t),ownKeys:e=>Yt(e),set(e,t,n){const a=e._storage||(e._storage=i());return e[t]=a[t]=n,delete e._keys,!0}})}function Dt(e,t,n,a){const o={_cacheable:!1,_proxy:e,_context:t,_subProxy:n,_stack:new Set,_descriptors:qt(e,a),setContext:t=>Dt(e,t,n,a),override:i=>Dt(e.override(i),t,n,a)};return new Proxy(o,{deleteProperty:(t,n)=>(delete t[n],delete e[n],!0),get:(e,t,n)=>Vt(e,t,()=>function(e,t,n){const{_proxy:a,_context:o,_subProxy:s,_descriptors:l}=e;let u=a[t];return C(u)&&l.isScriptable(t)&&(u=function(e,t,n,a){const{_proxy:i,_context:r,_subProxy:o,_stack:s}=n;if(s.has(e))throw new Error("Recursion detected: "+Array.from(s).join("->")+"->"+e);s.add(e);let l=t(r,o||a);return s.delete(e),Ft(e,l)&&(l=Wt(i._scopes,i,e,l)),l}(t,u,e,n)),i(u)&&u.length&&(u=function(e,t,n,a){const{_proxy:i,_context:o,_subProxy:s,_descriptors:l}=n;if(void 0!==o.index&&a(e))return t[o.index%t.length];if(r(t[0])){const n=t,a=i._scopes.filter(e=>e!==n);t=[];for(const r of n){const n=Wt(a,i,e,r);t.push(Dt(n,o,s&&s[e],l))}}return t}(t,u,e,l.isIndexable)),Ft(t,u)&&(u=Dt(u,o,s&&s[t],l)),u}(e,t,n)),getOwnPropertyDescriptor:(t,n)=>t._descriptors.allKeys?Reflect.has(e,n)?{enumerable:!0,configurable:!0}:void 0:Reflect.getOwnPropertyDescriptor(e,n),getPrototypeOf:()=>Reflect.getPrototypeOf(e),has:(t,n)=>Reflect.has(e,n),ownKeys:()=>Reflect.ownKeys(e),set:(t,n,a)=>(e[n]=a,delete t[n],!0)})}function qt(e,t={scriptable:!0,indexable:!0}){const{_scriptable:n=t.scriptable,_indexable:a=t.indexable,_allKeys:i=t.allKeys}=e;return{allKeys:i,scriptable:n,indexable:a,isScriptable:C(n)?n:()=>n,isIndexable:C(a)?a:()=>a}}const Bt=(e,t)=>e?e+x(t):t,Ft=(e,t)=>r(t)&&"adapters"!==e&&(null===Object.getPrototypeOf(t)||t.constructor===Object);function Vt(e,t,n){if(Object.prototype.hasOwnProperty.call(e,t)||"constructor"===t)return e[t];const a=n();return e[t]=a,a}function Ut(e,t,n){return C(e)?e(t,n):e}const $t=(e,t)=>!0===e?t:"string"==typeof e?k(t,e):void 0;function Ht(e,t,n,a,i){for(const r of t){const t=$t(n,r);if(t){e.add(t);const r=Ut(t._fallback,n,i);if(void 0!==r&&r!==n&&r!==a)return r}else if(!1===t&&void 0!==a&&n!==a)return null}return!1}function Wt(e,t,n,a){const o=t._rootScopes,s=Ut(t._fallback,n,a),l=[...e,...o],u=new Set;u.add(a);let c=Gt(u,l,n,s||n,a);return null!==c&&(void 0===s||s===n||(c=Gt(u,l,s,c,a),null!==c))&&jt(Array.from(u),[""],o,s,()=>function(e,t,n){const a=e._getTarget();t in a||(a[t]={});const o=a[t];return i(o)&&r(n)?n:o||{}}(t,n,a))}function Gt(e,t,n,a,i){for(;n;)n=Ht(e,t,n,a,i);return n}function Kt(e,t){for(const n of t){if(!n)continue;const t=n[e];if(void 0!==t)return t}}function Yt(e){let t=e._keys;return t||(t=e._keys=function(e){const t=new Set;for(const n of e)for(const e of Object.keys(n).filter(e=>!e.startsWith("_")))t.add(e);return Array.from(t)}(e._scopes)),t}function Qt(e,t,n,a){const{iScale:i}=e,{key:r="r"}=this._parsing,o=new Array(a);let s,l,u,c;for(s=0,l=a;st"x"===e?"y":"x";function en(e,t,n,a){const i=e.skip?t:e,r=t,o=n.skip?t:n,s=K(r,i),l=K(o,r);let u=s/(s+l),c=l/(s+l);u=isNaN(u)?0:u,c=isNaN(c)?0:c;const d=a*u,h=a*c;return{previous:{x:r.x-d*(o.x-i.x),y:r.y-d*(o.y-i.y)},next:{x:r.x+h*(o.x-i.x),y:r.y+h*(o.y-i.y)}}}function tn(e,t="x"){const n=Xt(t),a=e.length,i=Array(a).fill(0),r=Array(a);let o,s,l,u=Jt(e,0);for(o=0;o!e.skip)),"monotone"===t.cubicInterpolationMode)tn(e,i);else{let n=a?e[e.length-1]:e[0];for(r=0,o=e.length;r0===e||1===e,on=(e,t,n)=>-Math.pow(2,10*(e-=1))*Math.sin((e-t)*A/n),sn=(e,t,n)=>Math.pow(2,-10*e)*Math.sin((e-t)*A/n)+1,ln={linear:e=>e,easeInQuad:e=>e*e,easeOutQuad:e=>-e*(e-2),easeInOutQuad:e=>(e/=.5)<1?.5*e*e:-.5*(--e*(e-2)-1),easeInCubic:e=>e*e*e,easeOutCubic:e=>(e-=1)*e*e+1,easeInOutCubic:e=>(e/=.5)<1?.5*e*e*e:.5*((e-=2)*e*e+2),easeInQuart:e=>e*e*e*e,easeOutQuart:e=>-((e-=1)*e*e*e-1),easeInOutQuart:e=>(e/=.5)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2),easeInQuint:e=>e*e*e*e*e,easeOutQuint:e=>(e-=1)*e*e*e*e+1,easeInOutQuint:e=>(e/=.5)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2),easeInSine:e=>1-Math.cos(e*z),easeOutSine:e=>Math.sin(e*z),easeInOutSine:e=>-.5*(Math.cos(E*e)-1),easeInExpo:e=>0===e?0:Math.pow(2,10*(e-1)),easeOutExpo:e=>1===e?1:1-Math.pow(2,-10*e),easeInOutExpo:e=>rn(e)?e:e<.5?.5*Math.pow(2,10*(2*e-1)):.5*(2-Math.pow(2,-10*(2*e-1))),easeInCirc:e=>e>=1?e:-(Math.sqrt(1-e*e)-1),easeOutCirc:e=>Math.sqrt(1-(e-=1)*e),easeInOutCirc:e=>(e/=.5)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1),easeInElastic:e=>rn(e)?e:on(e,.075,.3),easeOutElastic:e=>rn(e)?e:sn(e,.075,.3),easeInOutElastic(e){const t=.1125;return rn(e)?e:e<.5?.5*on(2*e,t,.45):.5+.5*sn(2*e-1,t,.45)},easeInBack(e){const t=1.70158;return e*e*((t+1)*e-t)},easeOutBack(e){const t=1.70158;return(e-=1)*e*((t+1)*e+t)+1},easeInOutBack(e){let t=1.70158;return(e/=.5)<1?e*e*((1+(t*=1.525))*e-t)*.5:.5*((e-=2)*e*((1+(t*=1.525))*e+t)+2)},easeInBounce:e=>1-ln.easeOutBounce(1-e),easeOutBounce(e){const t=7.5625,n=2.75;return e<1/n?t*e*e:e<2/n?t*(e-=1.5/n)*e+.75:e<2.5/n?t*(e-=2.25/n)*e+.9375:t*(e-=2.625/n)*e+.984375},easeInOutBounce:e=>e<.5?.5*ln.easeInBounce(2*e):.5*ln.easeOutBounce(2*e-1)+.5};function un(e,t,n,a){return{x:e.x+n*(t.x-e.x),y:e.y+n*(t.y-e.y)}}function cn(e,t,n,a){return{x:e.x+n*(t.x-e.x),y:"middle"===a?n<.5?e.y:t.y:"after"===a?n<1?e.y:t.y:n>0?t.y:e.y}}function dn(e,t,n,a){const i={x:e.cp2x,y:e.cp2y},r={x:t.cp1x,y:t.cp1y},o=un(e,i,n),s=un(i,r,n),l=un(r,t,n),u=un(o,s,n),c=un(s,l,n);return un(u,c,n)}const hn=/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/,pn=/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/;function fn(e,t){const n=(""+e).match(hn);if(!n||"normal"===n[1])return 1.2*t;switch(e=+n[2],n[3]){case"px":return e;case"%":e/=100}return t*e}const mn=e=>+e||0;function _n(e,t){const n={},a=r(t),i=a?Object.keys(t):t,o=r(e)?a?n=>l(e[n],e[t[n]]):t=>e[t]:()=>e;for(const e of i)n[e]=mn(o(e));return n}function gn(e){return _n(e,{top:"y",right:"x",bottom:"y",left:"x"})}function vn(e){return _n(e,["topLeft","topRight","bottomLeft","bottomRight"])}function bn(e){const t=gn(e);return t.width=t.left+t.right,t.height=t.top+t.bottom,t}function yn(e,t){e=e||{},t=t||st.font;let n=l(e.size,t.size);"string"==typeof n&&(n=parseInt(n,10));let a=l(e.style,t.style);a&&!(""+a).match(pn)&&(console.warn('Invalid font style specified: "'+a+'"'),a=void 0);const i={family:l(e.family,t.family),lineHeight:fn(l(e.lineHeight,t.lineHeight),n),size:n,style:a,weight:l(e.weight,t.weight),string:""};return i.string=wt(i),i}function wn(e,t,n,a){let r,o,s,l=!0;for(r=0,o=e.length;rn&&0===e?0:e+t;return{min:o(a,-Math.abs(r)),max:o(i,r)}}function xn(e,t){return Object.assign(Object.create(e),t)}function Sn(e,t,n){return e?function(e,t){return{x:n=>e+e+t-n,setWidth(e){t=e},textAlign:e=>"center"===e?e:"right"===e?"left":"right",xPlus:(e,t)=>e-t,leftForLtr:(e,t)=>e-t}}(t,n):{x:e=>e,setWidth(e){},textAlign:e=>e,xPlus:(e,t)=>e+t,leftForLtr:(e,t)=>e}}function Cn(e,t){let n,a;"ltr"!==t&&"rtl"!==t||(n=e.canvas.style,a=[n.getPropertyValue("direction"),n.getPropertyPriority("direction")],n.setProperty("direction",t,"important"),e.prevTextDirection=a)}function Tn(e,t){void 0!==t&&(delete e.prevTextDirection,e.canvas.style.setProperty("direction",t[0],t[1]))}function Pn(e){return"angle"===e?{between:Z,compare:Y,normalize:Q}:{between:ee,compare:(e,t)=>e-t,normalize:e=>e}}function En({start:e,end:t,count:n,loop:a,style:i}){return{start:e%n,end:t%n,loop:a&&(t-e+1)%n==0,style:i}}function An(e,t,n){if(!n)return[e];const{property:a,start:i,end:r}=n,o=t.length,{compare:s,between:l,normalize:u}=Pn(a),{start:c,end:d,loop:h,style:p}=function(e,t,n){const{property:a,start:i,end:r}=n,{between:o,normalize:s}=Pn(a),l=t.length;let u,c,{start:d,end:h,loop:p}=e;if(p){for(d+=l,h+=l,u=0,c=l;uv||l(i,g,m)&&0!==s(i,g),w=()=>!v||0===s(r,m)||l(r,g,m);for(let e=c,n=c;e<=d;++e)_=t[e%o],_.skip||(m=u(_[a]),m!==g&&(v=l(m,i,r),null===b&&y()&&(b=0===s(m,i)?e:n),null!==b&&w()&&(f.push(En({start:b,end:e,loop:h,count:o,style:p})),b=null),n=e,g=m));return null!==b&&f.push(En({start:b,end:d,loop:h,count:o,style:p})),f}function Ln(e,t){const n=[],a=e.segments;for(let i=0;ii&&e[r%t].skip;)r--;return r%=t,{start:i,end:r}}(n,i,r,a);return Rn(e,!0===a?[{start:o,end:s,loop:r}]:function(e,t,n,a){const i=e.length,r=[];let o,s=t,l=e[t];for(o=t+1;o<=n;++o){const n=e[o%i];n.skip||n.stop?l.skip||(a=!1,r.push({start:t%i,end:(o-1)%i,loop:a}),t=s=n.stop?o:null):(s=o,l.skip&&(t=o)),l=n}return null!==s&&r.push({start:t%i,end:s%i,loop:a}),r}(n,o,s!a(e[t.axis]));i.lo-=Math.max(0,o);const s=n.slice(i.hi).findIndex(e=>!a(e[t.axis]));i.hi+=Math.max(0,s)}return i}if(r._sharedOptions){const e=o[0],a="function"==typeof e.getRange&&e.getRange(t);if(a){const e=s(o,t,n-a),i=s(o,t,n+a);return{lo:e.lo,hi:i.hi}}}}return{lo:0,hi:o.length-1}}function qn(e,t,n,a,i){const r=e.getSortedVisibleDatasetMetas(),o=n[t];for(let e=0,n=r.length;e{e[o]&&e[o](t[n],i)&&(r.push({element:e,datasetIndex:a,index:l}),s=s||e.inRange(t.x,t.y,i))}),a&&!s?[]:r}var Un={evaluateInteractionItems:qn,modes:{index(e,t,n,a){const i=mt(t,e),r=n.axis||"x",o=n.includeInvisible||!1,s=n.intersect?Bn(e,i,r,a,o):Fn(e,i,r,!1,a,o),l=[];return s.length?(e.getSortedVisibleDatasetMetas().forEach(e=>{const t=s[0].index,n=e.data[t];n&&!n.skip&&l.push({element:n,datasetIndex:e.index,index:t})}),l):[]},dataset(e,t,n,a){const i=mt(t,e),r=n.axis||"xy",o=n.includeInvisible||!1;let s=n.intersect?Bn(e,i,r,a,o):Fn(e,i,r,!1,a,o);if(s.length>0){const t=s[0].datasetIndex,n=e.getDatasetMeta(t).data;s=[];for(let e=0;eBn(e,mt(t,e),n.axis||"xy",a,n.includeInvisible||!1),nearest(e,t,n,a){const i=mt(t,e),r=n.axis||"xy",o=n.includeInvisible||!1;return Fn(e,i,r,n.intersect,a,o)},x:(e,t,n,a)=>Vn(e,mt(t,e),"x",n.intersect,a),y:(e,t,n,a)=>Vn(e,mt(t,e),"y",n.intersect,a)}};const $n=["left","top","right","bottom"];function Hn(e,t){return e.filter(e=>e.pos===t)}function Wn(e,t){return e.filter(e=>-1===$n.indexOf(e.pos)&&e.box.axis===t)}function Gn(e,t){return e.sort((e,n)=>{const a=t?n:e,i=t?e:n;return a.weight===i.weight?a.index-i.index:a.weight-i.weight})}function Kn(e,t,n,a){return Math.max(e[n],t[n])+Math.max(e[a],t[a])}function Yn(e,t){e.top=Math.max(e.top,t.top),e.left=Math.max(e.left,t.left),e.bottom=Math.max(e.bottom,t.bottom),e.right=Math.max(e.right,t.right)}function Qn(e,t,n,a){const{pos:i,box:o}=n,s=e.maxPadding;if(!r(i)){n.size&&(e[i]-=n.size);const t=a[n.stack]||{size:0,count:1};t.size=Math.max(t.size,n.horizontal?o.height:o.width),n.size=t.size/t.count,e[i]+=n.size}o.getPadding&&Yn(s,o.getPadding());const l=Math.max(0,t.outerWidth-Kn(s,e,"left","right")),u=Math.max(0,t.outerHeight-Kn(s,e,"top","bottom")),c=l!==e.w,d=u!==e.h;return e.w=l,e.h=u,n.horizontal?{same:c,other:d}:{same:d,other:c}}function Zn(e,t){const n=t.maxPadding;return function(e){const a={left:0,top:0,right:0,bottom:0};return e.forEach(e=>{a[e]=Math.max(t[e],n[e])}),a}(e?["left","right"]:["top","bottom"])}function Jn(e,t,n,a){const i=[];let r,o,s,l,u,c;for(r=0,o=e.length,u=0;re.box.fullSize),!0),a=Gn(Hn(t,"left"),!0),i=Gn(Hn(t,"right")),r=Gn(Hn(t,"top"),!0),o=Gn(Hn(t,"bottom")),s=Wn(t,"x"),l=Wn(t,"y");return{fullSize:n,leftAndTop:a.concat(r),rightAndBottom:i.concat(l).concat(o).concat(s),chartArea:Hn(t,"chartArea"),vertical:a.concat(i).concat(l),horizontal:r.concat(o).concat(s)}}(e.boxes),l=s.vertical,u=s.horizontal;h(e.boxes,e=>{"function"==typeof e.beforeLayout&&e.beforeLayout()});const c=l.reduce((e,t)=>t.box.options&&!1===t.box.options.display?e:e+1,0)||1,d=Object.freeze({outerWidth:t,outerHeight:n,padding:i,availableWidth:r,availableHeight:o,vBoxMaxWidth:r/2/c,hBoxMaxHeight:o/2}),p=Object.assign({},i);Yn(p,bn(a));const f=Object.assign({maxPadding:p,w:r,h:o,x:i.left,y:i.top},i),m=function(e,t){const n=function(e){const t={};for(const n of e){const{stack:e,pos:a,stackWeight:i}=n;if(!e||!$n.includes(a))continue;const r=t[e]||(t[e]={count:0,placed:0,weight:0,size:0});r.count++,r.weight+=i}return t}(e),{vBoxMaxWidth:a,hBoxMaxHeight:i}=t;let r,o,s;for(r=0,o=e.length;r{const n=t.box;Object.assign(n,e.chartArea),n.update(f.w,f.h,{left:0,top:0,right:0,bottom:0})})}};class na{acquireContext(e,t){}releaseContext(e){return!1}addEventListener(e,t,n){}removeEventListener(e,t,n){}getDevicePixelRatio(){return 1}getMaximumSize(e,t,n,a){return t=Math.max(0,t||e.width),n=n||e.height,{width:t,height:Math.max(0,a?Math.floor(t/a):n)}}isAttached(e){return!0}updateConfig(e){}}class aa extends na{acquireContext(e){return e&&e.getContext&&e.getContext("2d")||null}updateConfig(e){e.options.animation=!1}}const ia="$chartjs",ra={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},oa=e=>null===e||""===e,sa=!!bt&&{passive:!0};function la(e,t,n){e&&e.canvas&&e.canvas.removeEventListener(t,n,sa)}function ua(e,t){for(const n of e)if(n===t||n.contains(t))return!0}function ca(e,t,n){const a=e.canvas,i=new MutationObserver(e=>{let t=!1;for(const n of e)t=t||ua(n.addedNodes,a),t=t&&!ua(n.removedNodes,a);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}function da(e,t,n){const a=e.canvas,i=new MutationObserver(e=>{let t=!1;for(const n of e)t=t||ua(n.removedNodes,a),t=t&&!ua(n.addedNodes,a);t&&n()});return i.observe(document,{childList:!0,subtree:!0}),i}const ha=new Map;let pa=0;function fa(){const e=window.devicePixelRatio;e!==pa&&(pa=e,ha.forEach((t,n)=>{n.currentDevicePixelRatio!==e&&t()}))}function ma(e,t,n){const a=e.canvas,i=a&&ut(a);if(!i)return;const r=ce((e,t)=>{const a=i.clientWidth;n(e,t),a{const t=e[0],n=t.contentRect.width,a=t.contentRect.height;0===n&&0===a||r(n,a)});return o.observe(i),function(e,t){ha.size||window.addEventListener("resize",fa),ha.set(e,t)}(e,r),o}function _a(e,t,n){n&&n.disconnect(),"resize"===t&&function(e){ha.delete(e),ha.size||window.removeEventListener("resize",fa)}(e)}function ga(e,t,n){const a=e.canvas,i=ce(t=>{null!==e.ctx&&n(function(e,t){const n=ra[e.type]||e.type,{x:a,y:i}=mt(e,t);return{type:n,chart:t,native:e,x:void 0!==a?a:null,y:void 0!==i?i:null}}(t,e))},e);return function(e,t,n){e&&e.addEventListener(t,n,sa)}(a,t,i),i}class va extends na{acquireContext(e,t){const n=e&&e.getContext&&e.getContext("2d");return n&&n.canvas===e?(function(e,t){const n=e.style,a=e.getAttribute("height"),i=e.getAttribute("width");if(e[ia]={initial:{height:a,width:i,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",n.boxSizing=n.boxSizing||"border-box",oa(i)){const t=yt(e,"width");void 0!==t&&(e.width=t)}if(oa(a))if(""===e.style.height)e.height=e.width/(t||2);else{const t=yt(e,"height");void 0!==t&&(e.height=t)}}(e,t),n):null}releaseContext(e){const t=e.canvas;if(!t[ia])return!1;const n=t[ia].initial;["height","width"].forEach(e=>{const i=n[e];a(i)?t.removeAttribute(e):t.setAttribute(e,i)});const i=n.style||{};return Object.keys(i).forEach(e=>{t.style[e]=i[e]}),t.width=t.width,delete t[ia],!0}addEventListener(e,t,n){this.removeEventListener(e,t);const a=e.$proxies||(e.$proxies={}),i={attach:ca,detach:da,resize:ma}[t]||ga;a[t]=i(e,t,n)}removeEventListener(e,t){const n=e.$proxies||(e.$proxies={}),a=n[t];a&&(({attach:_a,detach:_a,resize:_a}[t]||la)(e,t,a),n[t]=void 0)}getDevicePixelRatio(){return window.devicePixelRatio}getMaximumSize(e,t,n,a){return gt(e,t,n,a)}isAttached(e){const t=e&&ut(e);return!(!t||!t.isConnected)}}function ba(e){return!lt()||"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas?aa:va}var ya=Object.freeze({__proto__:null,BasePlatform:na,BasicPlatform:aa,DomPlatform:va,_detectPlatform:ba});const wa="transparent",ka={boolean:(e,t,n)=>n>.5?t:e,color(e,t,n){const a=Ye(e||wa),i=a.valid&&Ye(t||wa);return i&&i.valid?i.mix(a,n).hexString():t},number:(e,t,n)=>e+(t-e)*n};class xa{constructor(e,t,n,a){const i=t[n];a=wn([e.to,a,i,e.from]);const r=wn([e.from,i,a]);this._active=!0,this._fn=e.fn||ka[e.type||typeof r],this._easing=ln[e.easing]||ln.linear,this._start=Math.floor(Date.now()+(e.delay||0)),this._duration=this._total=Math.floor(e.duration),this._loop=!!e.loop,this._target=t,this._prop=n,this._from=r,this._to=a,this._promises=void 0}active(){return this._active}update(e,t,n){if(this._active){this._notify(!1);const a=this._target[this._prop],i=n-this._start,r=this._duration-i;this._start=n,this._duration=Math.floor(Math.max(r,e.duration)),this._total+=i,this._loop=!!e.loop,this._to=wn([e.to,t,a,e.from]),this._from=wn([e.from,a,t])}}cancel(){this._active&&(this.tick(Date.now()),this._active=!1,this._notify(!1))}tick(e){const t=e-this._start,n=this._duration,a=this._prop,i=this._from,r=this._loop,o=this._to;let s;if(this._active=i!==o&&(r||t1?2-s:s,s=this._easing(Math.min(1,Math.max(0,s))),this._target[a]=this._fn(i,o,s))}wait(){const e=this._promises||(this._promises=[]);return new Promise((t,n)=>{e.push({res:t,rej:n})})}_notify(e){const t=e?"res":"rej",n=this._promises||[];for(let e=0;e{const o=e[a];if(!r(o))return;const s={};for(const e of t)s[e]=o[e];(i(o.properties)&&o.properties||[a]).forEach(e=>{e!==a&&n.has(e)||n.set(e,s)})})}_animateOptions(e,t){const n=t.options,a=function(e,t){if(!t)return;let n=e.options;if(n)return n.$shared&&(e.options=n=Object.assign({},n,{$shared:!1,$animations:{}})),n;e.options=t}(e,n);if(!a)return[];const i=this._createAnimations(a,n);return n.$shared&&function(e,t){const n=[],a=Object.keys(t);for(let t=0;t{e.options=n},()=>{}),i}_createAnimations(e,t){const n=this._properties,a=[],i=e.$animations||(e.$animations={}),r=Object.keys(t),o=Date.now();let s;for(s=r.length-1;s>=0;--s){const l=r[s];if("$"===l.charAt(0))continue;if("options"===l){a.push(...this._animateOptions(e,t));continue}const u=t[l];let c=i[l];const d=n.get(l);if(c){if(d&&c.active()){c.update(d,u,o);continue}c.cancel()}d&&d.duration?(i[l]=c=new xa(d,e,l,u),a.push(c)):e[l]=u}return a}update(e,t){if(0===this._properties.size)return void Object.assign(e,t);const n=this._createAnimations(e,t);return n.length?(ge.add(this._chart,n),!0):void 0}}function Ca(e,t){const n=e&&e.options||{},a=n.reverse,i=void 0===n.min?t:0,r=void 0===n.max?t:0;return{start:a?r:i,end:a?i:r}}function Ta(e,t){const n=[],a=e._getSortedDatasetMetas(t);let i,r;for(i=0,r=a.length;i0||!n&&t<0)return i.index}return null}function Ma(e,t){const{chart:n,_cachedMeta:a}=e,i=n._stacks||(n._stacks={}),{iScale:r,vScale:o,index:s}=a,l=r.axis,u=o.axis,c=function(e,t,n){return`${e.id}.${t.id}.${n.stack||n.type}`}(r,o,a),d=t.length;let h;for(let e=0;en[e].axis===t).shift()}function za(e,t){const n=e.controller.index,a=e.vScale&&e.vScale.axis;if(a){t=t||e._parsed;for(const e of t){const t=e._stacks;if(!t||void 0===t[a]||void 0===t[a][n])return;delete t[a][n],void 0!==t[a]._visualValues&&void 0!==t[a]._visualValues[n]&&delete t[a]._visualValues[n]}}}const Ia=e=>"reset"===e||"none"===e,Na=(e,t)=>t?e:Object.assign({},e);class Oa{static defaults={};static datasetElementType=null;static dataElementType=null;constructor(e,t){this.chart=e,this._ctx=e.ctx,this.index=t,this._cachedDataOpts={},this._cachedMeta=this.getMeta(),this._type=this._cachedMeta.type,this.options=void 0,this._parsing=!1,this._data=void 0,this._objectData=void 0,this._sharedOptions=void 0,this._drawStart=void 0,this._drawCount=void 0,this.enableOptionSharing=!1,this.supportsDecimation=!1,this.$context=void 0,this._syncList=[],this.datasetElementType=new.target.datasetElementType,this.dataElementType=new.target.dataElementType,this.initialize()}initialize(){const e=this._cachedMeta;this.configure(),this.linkScales(),e._stacked=Ea(e.vScale,e),this.addElements(),this.options.fill&&!this.chart.isPluginEnabled("filler")&&console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options")}updateIndex(e){this.index!==e&&za(this._cachedMeta),this.index=e}linkScales(){const e=this.chart,t=this._cachedMeta,n=this.getDataset(),a=(e,t,n,a)=>"x"===e?t:"r"===e?a:n,i=t.xAxisID=l(n.xAxisID,Ra(e,"x")),r=t.yAxisID=l(n.yAxisID,Ra(e,"y")),o=t.rAxisID=l(n.rAxisID,Ra(e,"r")),s=t.indexAxis,u=t.iAxisID=a(s,i,r,o),c=t.vAxisID=a(s,r,i,o);t.xScale=this.getScaleForId(i),t.yScale=this.getScaleForId(r),t.rScale=this.getScaleForId(o),t.iScale=this.getScaleForId(u),t.vScale=this.getScaleForId(c)}getDataset(){return this.chart.data.datasets[this.index]}getMeta(){return this.chart.getDatasetMeta(this.index)}getScaleForId(e){return this.chart.scales[e]}_getOtherScale(e){const t=this._cachedMeta;return e===t.iScale?t.vScale:t.iScale}reset(){this._update("reset")}_destroy(){const e=this._cachedMeta;this._data&&se(this._data,this),e._stacked&&za(e)}_dataCheck(){const e=this.getDataset(),t=e.data||(e.data=[]),n=this._data;if(r(t)){const e=this._cachedMeta;this._data=function(e,t){const{iScale:n,vScale:a}=t,i="x"===n.axis?"x":"y",r="x"===a.axis?"x":"y",o=Object.keys(e),s=new Array(o.length);let l,u,c;for(l=0,u=o.length;l0&&n._parsed[e-1];if(!1===this._parsing)n._parsed=a,n._sorted=!0,d=a;else{d=i(a[e])?this.parseArrayData(n,a,e,t):r(a[e])?this.parseObjectData(n,a,e,t):this.parsePrimitiveData(n,a,e,t);const o=()=>null===c[l]||p&&c[l]e&&!t.hidden&&t._stacked&&{keys:Ta(n,!0),values:null})(t,n,this.chart),u={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY},{min:c,max:d}=function(e){const{min:t,max:n,minDefined:a,maxDefined:i}=e.getUserBounds();return{min:a?t:Number.NEGATIVE_INFINITY,max:i?n:Number.POSITIVE_INFINITY}}(s);let h,p;function f(){p=a[h];const t=p[s.axis];return!o(p[e.axis])||c>t||d=0;--h)if(!f()){this.updateRangeFromParsed(u,e,p,l);break}return u}getAllParsedValues(e){const t=this._cachedMeta._parsed,n=[];let a,i,r;for(a=0,i=t.length;a=0&&ethis.getContext(n,a,t),c);return p.$shared&&(p.$shared=s,i[r]=Object.freeze(Na(p,s))),p}_resolveAnimations(e,t,n){const a=this.chart,i=this._cachedDataOpts,r=`animation-${t}`,o=i[r];if(o)return o;let s;if(!1!==a.options.animation){const a=this.chart.config,i=a.datasetAnimationScopeKeys(this._type,t),r=a.getOptionScopes(this.getDataset(),i);s=a.createResolver(r,this.getContext(e,n,t))}const l=new Sa(a,s&&s.animations);return s&&s._cacheable&&(i[r]=Object.freeze(l)),l}getSharedOptions(e){if(e.$shared)return this._sharedOptions||(this._sharedOptions=Object.assign({},e))}includeOptions(e,t){return!t||Ia(e)||this.chart._animationsDisabled}_getSharedOptions(e,t){const n=this.resolveDataElementOptions(e,t),a=this._sharedOptions,i=this.getSharedOptions(n),r=this.includeOptions(t,i)||i!==a;return this.updateSharedOptions(i,t,n),{sharedOptions:i,includeOptions:r}}updateElement(e,t,n,a){Ia(a)?Object.assign(e,n):this._resolveAnimations(t,a).update(e,n)}updateSharedOptions(e,t,n){e&&!Ia(t)&&this._resolveAnimations(void 0,t).update(e,n)}_setStyle(e,t,n,a){e.active=a;const i=this.getStyle(t,a);this._resolveAnimations(t,n,a).update(e,{options:!a&&this.getSharedOptions(i)||i})}removeHoverStyle(e,t,n){this._setStyle(e,n,"active",!1)}setHoverStyle(e,t,n){this._setStyle(e,n,"active",!0)}_removeDatasetHoverStyle(){const e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,"active",!1)}_setDatasetHoverStyle(){const e=this._cachedMeta.dataset;e&&this._setStyle(e,void 0,"active",!0)}_resyncElements(e){const t=this._data,n=this._cachedMeta.data;for(const[e,t,n]of this._syncList)this[e](t,n);this._syncList=[];const a=n.length,i=t.length,r=Math.min(i,a);r&&this.parse(0,r),i>a?this._insertElements(a,i-a,e):i{for(e.length+=t,o=e.length-1;o>=r;o--)e[o]=e[o-t]};for(s(i),o=e;o{a[e]=n[e]&&n[e].active()?n[e]._to:this[e]}),a}}function Da(e,t){const n=e.options.ticks,i=function(e){const t=e.options.offset,n=e._tickSize(),a=e._length/n+(t?0:1),i=e._maxLength/n;return Math.floor(Math.min(a,i))}(e),r=Math.min(n.maxTicksLimit||i,i),o=n.major.enabled?function(e){const t=[];let n,a;for(n=0,a=e.length;nr)return function(e,t,n,a){let i,r=0,o=n[0];for(a=Math.ceil(a),i=0;ii)return t}return Math.max(i,1)}(o,t,r);if(s>0){let e,n;const i=s>1?Math.round((u-l)/(s-1)):null;for(qa(t,c,d,a(i)?0:l-i,l),e=0,n=s-1;e"top"===t||"left"===t?e[t]+n:e[t]-n,Fa=(e,t)=>Math.min(t||e,e);function Va(e,t){const n=[],a=e.length/t,i=e.length;let r=0;for(;ro+s)))return u}function $a(e){return e.drawTicks?e.tickLength:0}function Ha(e,t){if(!e.display)return 0;const n=yn(e.font,t),a=bn(e.padding);return(i(e.text)?e.text.length:1)*n.lineHeight+a.height}function Wa(e,t,n){let a=he(e);return(n&&"right"!==t||!n&&"right"===t)&&(a=(e=>"left"===e?"right":"right"===e?"left":e)(a)),a}class Ga extends ja{constructor(e){super(),this.id=e.id,this.type=e.type,this.options=void 0,this.ctx=e.ctx,this.chart=e.chart,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this._margins={left:0,right:0,top:0,bottom:0},this.maxWidth=void 0,this.maxHeight=void 0,this.paddingTop=void 0,this.paddingBottom=void 0,this.paddingLeft=void 0,this.paddingRight=void 0,this.axis=void 0,this.labelRotation=void 0,this.min=void 0,this.max=void 0,this._range=void 0,this.ticks=[],this._gridLineItems=null,this._labelItems=null,this._labelSizes=null,this._length=0,this._maxLength=0,this._longestTextCache={},this._startPixel=void 0,this._endPixel=void 0,this._reversePixels=!1,this._userMax=void 0,this._userMin=void 0,this._suggestedMax=void 0,this._suggestedMin=void 0,this._ticksLength=0,this._borderValue=0,this._cache={},this._dataLimitsCached=!1,this.$context=void 0}init(e){this.options=e.setContext(this.getContext()),this.axis=e.axis,this._userMin=this.parse(e.min),this._userMax=this.parse(e.max),this._suggestedMin=this.parse(e.suggestedMin),this._suggestedMax=this.parse(e.suggestedMax)}parse(e,t){return e}getUserBounds(){let{_userMin:e,_userMax:t,_suggestedMin:n,_suggestedMax:a}=this;return e=s(e,Number.POSITIVE_INFINITY),t=s(t,Number.NEGATIVE_INFINITY),n=s(n,Number.POSITIVE_INFINITY),a=s(a,Number.NEGATIVE_INFINITY),{min:s(e,n),max:s(t,a),minDefined:o(e),maxDefined:o(t)}}getMinMax(e){let t,{min:n,max:a,minDefined:i,maxDefined:r}=this.getUserBounds();if(i&&r)return{min:n,max:a};const o=this.getMatchingVisibleMetas();for(let s=0,l=o.length;sa?a:n,a=i&&n>a?n:a,{min:s(n,s(a,n)),max:s(a,s(n,a))}}getPadding(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}}getTicks(){return this.ticks}getLabels(){const e=this.chart.data;return this.options.labels||(this.isHorizontal()?e.xLabels:e.yLabels)||e.labels||[]}getLabelItems(e=this.chart.chartArea){return this._labelItems||(this._labelItems=this._computeLabelItems(e))}beforeLayout(){this._cache={},this._dataLimitsCached=!1}beforeUpdate(){d(this.options.beforeUpdate,[this])}update(e,t,n){const{beginAtZero:a,grace:i,ticks:r}=this.options,o=r.sampleSize;this.beforeUpdate(),this.maxWidth=e,this.maxHeight=t,this._margins=n=Object.assign({left:0,right:0,top:0,bottom:0},n),this.ticks=null,this._labelSizes=null,this._gridLineItems=null,this._labelItems=null,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this._maxLength=this.isHorizontal()?this.width+n.left+n.right:this.height+n.top+n.bottom,this._dataLimitsCached||(this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this._range=kn(this,i,a),this._dataLimitsCached=!0),this.beforeBuildTicks(),this.ticks=this.buildTicks()||[],this.afterBuildTicks();const s=o=i||n<=1||!this.isHorizontal())return void(this.labelRotation=a);const u=this._getLabelSizes(),c=u.widest.width,d=u.highest.height,h=J(this.chart.width-c,0,this.maxWidth);r=e.offset?this.maxWidth/n:h/(n-1),c+6>r&&(r=h/(n-(e.offset?.5:1)),o=this.maxHeight-$a(e.grid)-t.padding-Ha(e.title,this.chart.options.font),s=Math.sqrt(c*c+d*d),l=H(Math.min(Math.asin(J((u.highest.height+6)/r,-1,1)),Math.asin(J(o/s,-1,1))-Math.asin(J(d/s,-1,1)))),l=Math.max(a,Math.min(i,l))),this.labelRotation=l}afterCalculateLabelRotation(){d(this.options.afterCalculateLabelRotation,[this])}afterAutoSkip(){}beforeFit(){d(this.options.beforeFit,[this])}fit(){const e={width:0,height:0},{chart:t,options:{ticks:n,title:a,grid:i}}=this,r=this._isVisible(),o=this.isHorizontal();if(r){const r=Ha(a,t.options.font);if(o?(e.width=this.maxWidth,e.height=$a(i)+r):(e.height=this.maxHeight,e.width=$a(i)+r),n.display&&this.ticks.length){const{first:t,last:a,widest:i,highest:r}=this._getLabelSizes(),s=2*n.padding,l=$(this.labelRotation),u=Math.cos(l),c=Math.sin(l);if(o){const t=n.mirror?0:c*i.width+u*r.height;e.height=Math.min(this.maxHeight,e.height+t+s)}else{const t=n.mirror?0:u*i.width+c*r.height;e.width=Math.min(this.maxWidth,e.width+t+s)}this._calculatePadding(t,a,c,u)}}this._handleMargins(),o?(this.width=this._length=t.width-this._margins.left-this._margins.right,this.height=e.height):(this.width=e.width,this.height=this._length=t.height-this._margins.top-this._margins.bottom)}_calculatePadding(e,t,n,a){const{ticks:{align:i,padding:r},position:o}=this.options,s=0!==this.labelRotation,l="top"!==o&&"x"===this.axis;if(this.isHorizontal()){const o=this.getPixelForTick(0)-this.left,u=this.right-this.getPixelForTick(this.ticks.length-1);let c=0,d=0;s?l?(c=a*e.width,d=n*t.height):(c=n*e.height,d=a*t.width):"start"===i?d=t.width:"end"===i?c=e.width:"inner"!==i&&(c=e.width/2,d=t.width/2),this.paddingLeft=Math.max((c-o+r)*this.width/(this.width-o),0),this.paddingRight=Math.max((d-u+r)*this.width/(this.width-u),0)}else{let n=t.height/2,a=e.height/2;"start"===i?(n=0,a=e.height):"end"===i&&(n=t.height,a=0),this.paddingTop=n+r,this.paddingBottom=a+r}}_handleMargins(){this._margins&&(this._margins.left=Math.max(this.paddingLeft,this._margins.left),this._margins.top=Math.max(this.paddingTop,this._margins.top),this._margins.right=Math.max(this.paddingRight,this._margins.right),this._margins.bottom=Math.max(this.paddingBottom,this._margins.bottom))}afterFit(){d(this.options.afterFit,[this])}isHorizontal(){const{axis:e,position:t}=this.options;return"top"===t||"bottom"===t||"x"===e}isFullSize(){return this.options.fullSize}_convertTicksToLabels(e){let t,n;for(this.beforeTickToLabelConversion(),this.generateTickLabels(e),t=0,n=e.length;t{const n=e.gc,a=n.length/2;let i;if(a>t){for(i=0;i({width:s[e]||0,height:l[e]||0});return{first:T(0),last:T(t-1),widest:T(S),highest:T(C),widths:s,heights:l}}getLabelForValue(e){return e}getPixelForValue(e,t){return NaN}getValueForPixel(e){}getPixelForTick(e){const t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e].value)}getPixelForDecimal(e){this._reversePixels&&(e=1-e);const t=this._startPixel+e*this._length;return X(this._alignToPixels?St(this.chart,t,0):t)}getDecimalForPixel(e){const t=(e-this._startPixel)/this._length;return this._reversePixels?1-t:t}getBasePixel(){return this.getPixelForValue(this.getBaseValue())}getBaseValue(){const{min:e,max:t}=this;return e<0&&t<0?t:e>0&&t>0?e:0}getContext(e){const t=this.ticks||[];if(e>=0&&eo*a?o/n:s/a:s*a0}_computeGridLineItems(e){const t=this.axis,n=this.chart,a=this.options,{grid:i,position:o,border:s}=a,u=i.offset,c=this.isHorizontal(),d=this.ticks.length+(u?1:0),h=$a(i),p=[],f=s.setContext(this.getContext()),m=f.display?f.width:0,_=m/2,g=function(e){return St(n,e,m)};let v,b,y,w,k,x,S,C,T,P,E,A;if("top"===o)v=g(this.bottom),x=this.bottom-h,C=v-_,P=g(e.top)+_,A=e.bottom;else if("bottom"===o)v=g(this.top),P=e.top,A=g(e.bottom)-_,x=v+_,C=this.top+h;else if("left"===o)v=g(this.right),k=this.right-h,S=v-_,T=g(e.left)+_,E=e.right;else if("right"===o)v=g(this.left),T=e.left,E=g(e.right)-_,k=v+_,S=this.left+h;else if("x"===t){if("center"===o)v=g((e.top+e.bottom)/2+.5);else if(r(o)){const e=Object.keys(o)[0],t=o[e];v=g(this.chart.scales[e].getPixelForValue(t))}P=e.top,A=e.bottom,x=v+_,C=x+h}else if("y"===t){if("center"===o)v=g((e.left+e.right)/2);else if(r(o)){const e=Object.keys(o)[0],t=o[e];v=g(this.chart.scales[e].getPixelForValue(t))}k=v-_,S=k-h,T=e.left,E=e.right}const L=l(a.ticks.maxTicksLimit,d),M=Math.max(1,Math.ceil(d/L));for(b=0;b0&&(r-=a/2)}d={left:r,top:i,width:a+t.width,height:n+t.height,color:e.backdropColor}}g.push({label:w,font:T,textOffset:A,options:{rotation:_,color:n,strokeColor:r,strokeWidth:u,textAlign:p,textBaseline:L,translation:[k,x],backdrop:d}})}return g}_getXAxisLabelAlignment(){const{position:e,ticks:t}=this.options;if(-$(this.labelRotation))return"top"===e?"left":"right";let n="center";return"start"===t.align?n="left":"end"===t.align?n="right":"inner"===t.align&&(n="inner"),n}_getYAxisLabelAlignment(e){const{position:t,ticks:{crossAlign:n,mirror:a,padding:i}}=this.options,r=e+i,o=this._getLabelSizes().widest.width;let s,l;return"left"===t?a?(l=this.right+i,"near"===n?s="left":"center"===n?(s="center",l+=o/2):(s="right",l+=o)):(l=this.right-r,"near"===n?s="right":"center"===n?(s="center",l-=o/2):(s="left",l=this.left)):"right"===t?a?(l=this.left+i,"near"===n?s="right":"center"===n?(s="center",l-=o/2):(s="left",l-=o)):(l=this.left+r,"near"===n?s="left":"center"===n?(s="center",l+=o/2):(s="right",l=this.right)):s="right",{textAlign:s,x:l}}_computeLabelArea(){if(this.options.ticks.mirror)return;const e=this.chart,t=this.options.position;return"left"===t||"right"===t?{top:0,left:this.left,bottom:e.height,right:this.right}:"top"===t||"bottom"===t?{top:this.top,left:0,bottom:this.bottom,right:e.width}:void 0}drawBackground(){const{ctx:e,options:{backgroundColor:t},left:n,top:a,width:i,height:r}=this;t&&(e.save(),e.fillStyle=t,e.fillRect(n,a,i,r),e.restore())}getLineWidthForValue(e){const t=this.options.grid;if(!this._isVisible()||!t.display)return 0;const n=this.ticks.findIndex(t=>t.value===e);return n>=0?t.setContext(this.getContext(n)).lineWidth:0}drawGrid(e){const t=this.options.grid,n=this.ctx,a=this._gridLineItems||(this._gridLineItems=this._computeGridLineItems(e));let i,r;const o=(e,t,a)=>{a.width&&a.color&&(n.save(),n.lineWidth=a.width,n.strokeStyle=a.color,n.setLineDash(a.borderDash||[]),n.lineDashOffset=a.borderDashOffset,n.beginPath(),n.moveTo(e.x,e.y),n.lineTo(t.x,t.y),n.stroke(),n.restore())};if(t.display)for(i=0,r=a.length;i{this.drawBackground(),this.drawGrid(e),this.drawTitle()}},{z:a,draw:()=>{this.drawBorder()}},{z:t,draw:e=>{this.drawLabels(e)}}]:[{z:t,draw:e=>{this.draw(e)}}]}getMatchingVisibleMetas(e){const t=this.chart.getSortedVisibleDatasetMetas(),n=this.axis+"AxisID",a=[];let i,r;for(i=0,r=t.length;i{const a=n.split("."),i=a.pop(),r=[e].concat(a).join("."),o=t[n].split("."),s=o.pop(),l=o.join(".");st.route(r,i,l,s)})}(t,e.defaultRoutes),e.descriptors&&st.describe(t,e.descriptors)}(e,r,n),this.override&&st.override(e.id,e.overrides)),r}get(e){return this.items[e]}unregister(e){const t=this.items,n=e.id,a=this.scope;n in t&&delete t[n],a&&n in st[a]&&(delete st[a][n],this.override&&delete at[n])}}var Ya=new class{constructor(){this.controllers=new Ka(Oa,"datasets",!0),this.elements=new Ka(ja,"elements"),this.plugins=new Ka(Object,"plugins"),this.scales=new Ka(Ga,"scales"),this._typedRegistries=[this.controllers,this.scales,this.elements]}add(...e){this._each("register",e)}remove(...e){this._each("unregister",e)}addControllers(...e){this._each("register",e,this.controllers)}addElements(...e){this._each("register",e,this.elements)}addPlugins(...e){this._each("register",e,this.plugins)}addScales(...e){this._each("register",e,this.scales)}getController(e){return this._get(e,this.controllers,"controller")}getElement(e){return this._get(e,this.elements,"element")}getPlugin(e){return this._get(e,this.plugins,"plugin")}getScale(e){return this._get(e,this.scales,"scale")}removeControllers(...e){this._each("unregister",e,this.controllers)}removeElements(...e){this._each("unregister",e,this.elements)}removePlugins(...e){this._each("unregister",e,this.plugins)}removeScales(...e){this._each("unregister",e,this.scales)}_each(e,t,n){[...t].forEach(t=>{const a=n||this._getRegistryForType(t);n||a.isForType(t)||a===this.plugins&&t.id?this._exec(e,a,t):h(t,t=>{const a=n||this._getRegistryForType(t);this._exec(e,a,t)})})}_exec(e,t,n){const a=x(e);d(n["before"+a],[],n),t[e](n),d(n["after"+a],[],n)}_getRegistryForType(e){for(let t=0;te.filter(e=>!t.some(t=>e.plugin.id===t.plugin.id));this._notify(a(t,n),e,"stop"),this._notify(a(n,t),e,"start")}}function Za(e,t){return t||!1!==e?!0===e?{}:e:null}function Ja(e,{plugin:t,local:n},a,i){const r=e.pluginScopeKeys(t),o=e.getOptionScopes(a,r);return n&&t.defaults&&o.push(t.defaults),e.createResolver(o,i,[""],{scriptable:!1,indexable:!1,allKeys:!0})}function Xa(e,t){const n=st.datasets[e]||{};return((t.datasets||{})[e]||{}).indexAxis||t.indexAxis||n.indexAxis||"x"}function ei(e){if("x"===e||"y"===e||"r"===e)return e}function ti(e,...t){if(ei(e))return e;for(const a of t){const t=a.axis||("top"===(n=a.position)||"bottom"===n?"x":"left"===n||"right"===n?"y":void 0)||e.length>1&&ei(e[0].toLowerCase());if(t)return t}var n;throw new Error(`Cannot determine type of '${e}' axis. Please provide 'axis' or 'position' option.`)}function ni(e,t,n){if(n[t+"AxisID"]===e)return{axis:t}}function ai(e){const t=e.options||(e.options={});t.plugins=l(t.plugins,{}),t.scales=function(e,t){const n=at[e.type]||{scales:{}},a=t.scales||{},i=Xa(e.type,t),o=Object.create(null);return Object.keys(a).forEach(t=>{const s=a[t];if(!r(s))return console.error(`Invalid scale configuration for scale: ${t}`);if(s._proxy)return console.warn(`Ignoring resolver passed as options for scale: ${t}`);const l=ti(t,s,function(e,t){if(t.data&&t.data.datasets){const n=t.data.datasets.filter(t=>t.xAxisID===e||t.yAxisID===e);if(n.length)return ni(e,"x",n[0])||ni(e,"y",n[0])}return{}}(t,e),st.scales[s.type]),u=function(e,t){return e===t?"_index_":"_value_"}(l,i),c=n.scales||{};o[t]=v(Object.create(null),[{axis:l},s,c[l],c[u]])}),e.data.datasets.forEach(n=>{const i=n.type||e.type,r=n.indexAxis||Xa(i,t),s=(at[i]||{}).scales||{};Object.keys(s).forEach(e=>{const t=function(e,t){let n=e;return"_index_"===e?n=t:"_value_"===e&&(n="x"===t?"y":"x"),n}(e,r),i=n[t+"AxisID"]||t;o[i]=o[i]||Object.create(null),v(o[i],[{axis:t},a[i],s[e]])})}),Object.keys(o).forEach(e=>{const t=o[e];v(t,[st.scales[t.type],st.scale])}),o}(e,t)}function ii(e){return(e=e||{}).datasets=e.datasets||[],e.labels=e.labels||[],e}const ri=new Map,oi=new Set;function si(e,t){let n=ri.get(e);return n||(n=t(),ri.set(e,n),oi.add(n)),n}const li=(e,t,n)=>{const a=k(t,n);void 0!==a&&e.add(a)};class ui{constructor(e){this._config=function(e){return(e=e||{}).data=ii(e.data),ai(e),e}(e),this._scopeCache=new Map,this._resolverCache=new Map}get platform(){return this._config.platform}get type(){return this._config.type}set type(e){this._config.type=e}get data(){return this._config.data}set data(e){this._config.data=ii(e)}get options(){return this._config.options}set options(e){this._config.options=e}get plugins(){return this._config.plugins}update(){const e=this._config;this.clearCache(),ai(e)}clearCache(){this._scopeCache.clear(),this._resolverCache.clear()}datasetScopeKeys(e){return si(e,()=>[[`datasets.${e}`,""]])}datasetAnimationScopeKeys(e,t){return si(`${e}.transition.${t}`,()=>[[`datasets.${e}.transitions.${t}`,`transitions.${t}`],[`datasets.${e}`,""]])}datasetElementScopeKeys(e,t){return si(`${e}-${t}`,()=>[[`datasets.${e}.elements.${t}`,`datasets.${e}`,`elements.${t}`,""]])}pluginScopeKeys(e){const t=e.id;return si(`${this.type}-plugin-${t}`,()=>[[`plugins.${t}`,...e.additionalOptionScopes||[]]])}_cachedScopes(e,t){const n=this._scopeCache;let a=n.get(e);return a&&!t||(a=new Map,n.set(e,a)),a}getOptionScopes(e,t,n){const{options:a,type:i}=this,r=this._cachedScopes(e,n),o=r.get(t);if(o)return o;const s=new Set;t.forEach(t=>{e&&(s.add(e),t.forEach(t=>li(s,e,t))),t.forEach(e=>li(s,a,e)),t.forEach(e=>li(s,at[i]||{},e)),t.forEach(e=>li(s,st,e)),t.forEach(e=>li(s,it,e))});const l=Array.from(s);return 0===l.length&&l.push(Object.create(null)),oi.has(t)&&r.set(t,l),l}chartOptionScopes(){const{options:e,type:t}=this;return[e,at[t]||{},st.datasets[t]||{},{type:t},st,it]}resolveNamedOptions(e,t,n,a=[""]){const r={$shared:!0},{resolver:o,subPrefixes:s}=ci(this._resolverCache,e,a);let l=o;(function(e,t){const{isScriptable:n,isIndexable:a}=qt(e);for(const r of t){const t=n(r),o=a(r),s=(o||t)&&e[r];if(t&&(C(s)||di(s))||o&&i(s))return!0}return!1})(o,t)&&(r.$shared=!1,l=Dt(o,n=C(n)?n():n,this.createResolver(e,n,s)));for(const e of t)r[e]=l[e];return r}createResolver(e,t,n=[""],a){const{resolver:i}=ci(this._resolverCache,e,n);return r(t)?Dt(i,t,void 0,a):i}}function ci(e,t,n){let a=e.get(t);a||(a=new Map,e.set(t,a));const i=n.join();let r=a.get(i);return r||(r={resolver:jt(t,n),subPrefixes:n.filter(e=>!e.toLowerCase().includes("hover"))},a.set(i,r)),r}const di=e=>r(e)&&Object.getOwnPropertyNames(e).some(t=>C(e[t])),hi=["top","bottom","left","right","chartArea"];function pi(e,t){return"top"===e||"bottom"===e||-1===hi.indexOf(e)&&"x"===t}function fi(e,t){return function(n,a){return n[e]===a[e]?n[t]-a[t]:n[e]-a[e]}}function mi(e){const t=e.chart,n=t.options.animation;t.notifyPlugins("afterRender"),d(n&&n.onComplete,[e],t)}function _i(e){const t=e.chart,n=t.options.animation;d(n&&n.onProgress,[e],t)}function gi(e){return lt()&&"string"==typeof e?e=document.getElementById(e):e&&e.length&&(e=e[0]),e&&e.canvas&&(e=e.canvas),e}const vi={},bi=e=>{const t=gi(e);return Object.values(vi).filter(e=>e.canvas===t).pop()};function yi(e,t,n){const a=Object.keys(e);for(const i of a){const a=+i;if(a>=t){const r=e[i];delete e[i],(n>0||a>t)&&(e[a+n]=r)}}}class wi{static defaults=st;static instances=vi;static overrides=at;static registry=Ya;static version="4.5.1";static getChart=bi;static register(...e){Ya.add(...e),ki()}static unregister(...e){Ya.remove(...e),ki()}constructor(e,t){const a=this.config=new ui(t),i=gi(e),r=bi(i);if(r)throw new Error("Canvas is already in use. Chart with ID '"+r.id+"' must be destroyed before the canvas with ID '"+r.canvas.id+"' can be reused.");const o=a.createResolver(a.chartOptionScopes(),this.getContext());this.platform=new(a.platform||ba(i)),this.platform.updateConfig(a);const s=this.platform.acquireContext(i,o.aspectRatio),l=s&&s.canvas,u=l&&l.height,c=l&&l.width;this.id=n(),this.ctx=s,this.canvas=l,this.width=c,this.height=u,this._options=o,this._aspectRatio=this.aspectRatio,this._layers=[],this._metasets=[],this._stacks=void 0,this.boxes=[],this.currentDevicePixelRatio=void 0,this.chartArea=void 0,this._active=[],this._lastEvent=void 0,this._listeners={},this._responsiveListeners=void 0,this._sortedMetasets=[],this.scales={},this._plugins=new Qa,this.$proxies={},this._hiddenIndices={},this.attached=!1,this._animationsDisabled=void 0,this.$context=void 0,this._doResize=de(e=>this.update(e),o.resizeDelay||0),this._dataChanges=[],vi[this.id]=this,s&&l?(ge.listen(this,"complete",mi),ge.listen(this,"progress",_i),this._initialize(),this.attached&&this.update()):console.error("Failed to create chart: can't acquire context from the given item")}get aspectRatio(){const{options:{aspectRatio:e,maintainAspectRatio:t},width:n,height:i,_aspectRatio:r}=this;return a(e)?t&&r?r:i?n/i:null:e}get data(){return this.config.data}set data(e){this.config.data=e}get options(){return this._options}set options(e){this.config.options=e}get registry(){return Ya}_initialize(){return this.notifyPlugins("beforeInit"),this.options.responsive?this.resize():vt(this,this.options.devicePixelRatio),this.bindEvents(),this.notifyPlugins("afterInit"),this}clear(){return Ct(this.canvas,this.ctx),this}stop(){return ge.stop(this),this}resize(e,t){ge.running(this)?this._resizeBeforeDraw={width:e,height:t}:this._resize(e,t)}_resize(e,t){const n=this.options,a=this.canvas,i=n.maintainAspectRatio&&this.aspectRatio,r=this.platform.getMaximumSize(a,e,t,i),o=n.devicePixelRatio||this.platform.getDevicePixelRatio(),s=this.width?"resize":"attach";this.width=r.width,this.height=r.height,this._aspectRatio=this.aspectRatio,vt(this,o,!0)&&(this.notifyPlugins("resize",{size:r}),d(n.onResize,[this,r],this),this.attached&&this._doResize(s)&&this.render())}ensureScalesHaveIDs(){h(this.options.scales||{},(e,t)=>{e.id=t})}buildOrUpdateScales(){const e=this.options,t=e.scales,n=this.scales,a=Object.keys(n).reduce((e,t)=>(e[t]=!1,e),{});let i=[];t&&(i=i.concat(Object.keys(t).map(e=>{const n=t[e],a=ti(e,n),i="r"===a,r="x"===a;return{options:n,dposition:i?"chartArea":r?"bottom":"left",dtype:i?"radialLinear":r?"category":"linear"}}))),h(i,t=>{const i=t.options,r=i.id,o=ti(r,i),s=l(i.type,t.dtype);void 0!==i.position&&pi(i.position,o)===pi(t.dposition)||(i.position=t.dposition),a[r]=!0;let u=null;r in n&&n[r].type===s?u=n[r]:(u=new(Ya.getScale(s))({id:r,type:s,ctx:this.ctx,chart:this}),n[u.id]=u),u.init(i,e)}),h(a,(e,t)=>{e||delete n[t]}),h(n,e=>{ta.configure(this,e,e.options),ta.addBox(this,e)})}_updateMetasets(){const e=this._metasets,t=this.data.datasets.length,n=e.length;if(e.sort((e,t)=>e.index-t.index),n>t){for(let e=t;et.length&&delete this._stacks,e.forEach((e,n)=>{0===t.filter(t=>t===e._dataset).length&&this._destroyDatasetMeta(n)})}buildOrUpdateControllers(){const e=[],t=this.data.datasets;let n,a;for(this._removeUnreferencedMetasets(),n=0,a=t.length;n{this.getDatasetMeta(t).controller.reset()},this)}reset(){this._resetElements(),this.notifyPlugins("reset")}update(e){const t=this.config;t.update();const n=this._options=t.createResolver(t.chartOptionScopes(),this.getContext()),a=this._animationsDisabled=!n.animation;if(this._updateScales(),this._checkEventBindings(),this._updateHiddenIndices(),this._plugins.invalidate(),!1===this.notifyPlugins("beforeUpdate",{mode:e,cancelable:!0}))return;const i=this.buildOrUpdateControllers();this.notifyPlugins("beforeElementsUpdate");let r=0;for(let e=0,t=this.data.datasets.length;e{e.reset()}),this._updateDatasets(e),this.notifyPlugins("afterUpdate",{mode:e}),this._layers.sort(fi("z","_idx"));const{_active:o,_lastEvent:s}=this;s?this._eventHandler(s,!0):o.length&&this._updateHoverStyles(o,o,!0),this.render()}_updateScales(){h(this.scales,e=>{ta.removeBox(this,e)}),this.ensureScalesHaveIDs(),this.buildOrUpdateScales()}_checkEventBindings(){const e=this.options,t=new Set(Object.keys(this._listeners)),n=new Set(e.events);T(t,n)&&!!this._responsiveListeners===e.responsive||(this.unbindEvents(),this.bindEvents())}_updateHiddenIndices(){const{_hiddenIndices:e}=this,t=this._getUniformDataChanges()||[];for(const{method:n,start:a,count:i}of t)yi(e,a,"_removeElements"===n?-i:i)}_getUniformDataChanges(){const e=this._dataChanges;if(!e||!e.length)return;this._dataChanges=[];const t=this.data.datasets.length,n=t=>new Set(e.filter(e=>e[0]===t).map((e,t)=>t+","+e.splice(1).join(","))),a=n(0);for(let e=1;ee.split(",")).map(e=>({method:e[1],start:+e[2],count:+e[3]}))}_updateLayout(e){if(!1===this.notifyPlugins("beforeLayout",{cancelable:!0}))return;ta.update(this,this.width,this.height,e);const t=this.chartArea,n=t.width<=0||t.height<=0;this._layers=[],h(this.boxes,e=>{n&&"chartArea"===e.position||(e.configure&&e.configure(),this._layers.push(...e._layers()))},this),this._layers.forEach((e,t)=>{e._idx=t}),this.notifyPlugins("afterLayout")}_updateDatasets(e){if(!1!==this.notifyPlugins("beforeDatasetsUpdate",{mode:e,cancelable:!0})){for(let e=0,t=this.data.datasets.length;e=0;--t)this._drawDataset(e[t]);this.notifyPlugins("afterDatasetsDraw")}_drawDataset(e){const t=this.ctx,n={meta:e,index:e.index,cancelable:!0},a=On(this,e);!1!==this.notifyPlugins("beforeDatasetDraw",n)&&(a&&At(t,a),e.controller.draw(),a&&Lt(t),n.cancelable=!1,this.notifyPlugins("afterDatasetDraw",n))}isPointInArea(e){return Et(e,this.chartArea,this._minPadding)}getElementsAtEventForMode(e,t,n,a){const i=Un.modes[t];return"function"==typeof i?i(this,e,n,a):[]}getDatasetMeta(e){const t=this.data.datasets[e],n=this._metasets;let a=n.filter(e=>e&&e._dataset===t).pop();return a||(a={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:t&&t.order||0,index:e,_dataset:t,_parsed:[],_sorted:!1},n.push(a)),a}getContext(){return this.$context||(this.$context=xn(null,{chart:this,type:"chart"}))}getVisibleDatasetCount(){return this.getSortedVisibleDatasetMetas().length}isDatasetVisible(e){const t=this.data.datasets[e];if(!t)return!1;const n=this.getDatasetMeta(e);return"boolean"==typeof n.hidden?!n.hidden:!t.hidden}setDatasetVisibility(e,t){this.getDatasetMeta(e).hidden=!t}toggleDataVisibility(e){this._hiddenIndices[e]=!this._hiddenIndices[e]}getDataVisibility(e){return!this._hiddenIndices[e]}_updateVisibility(e,t,n){const a=n?"show":"hide",i=this.getDatasetMeta(e),r=i.controller._resolveAnimations(void 0,a);S(t)?(i.data[t].hidden=!n,this.update()):(this.setDatasetVisibility(e,n),r.update(i,{visible:n}),this.update(t=>t.datasetIndex===e?a:void 0))}hide(e,t){this._updateVisibility(e,t,!1)}show(e,t){this._updateVisibility(e,t,!0)}_destroyDatasetMeta(e){const t=this._metasets[e];t&&t.controller&&t.controller._destroy(),delete this._metasets[e]}_stop(){let e,t;for(this.stop(),ge.remove(this),e=0,t=this.data.datasets.length;e{t.addEventListener(this,n,a),e[n]=a},a=(e,t,n)=>{e.offsetX=t,e.offsetY=n,this._eventHandler(e)};h(this.options.events,e=>n(e,a))}bindResponsiveEvents(){this._responsiveListeners||(this._responsiveListeners={});const e=this._responsiveListeners,t=this.platform,n=(n,a)=>{t.addEventListener(this,n,a),e[n]=a},a=(n,a)=>{e[n]&&(t.removeEventListener(this,n,a),delete e[n])},i=(e,t)=>{this.canvas&&this.resize(e,t)};let r;const o=()=>{a("attach",o),this.attached=!0,this.resize(),n("resize",i),n("detach",r)};r=()=>{this.attached=!1,a("resize",i),this._stop(),this._resize(0,0),n("attach",o)},t.isAttached(this.canvas)?o():r()}unbindEvents(){h(this._listeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._listeners={},h(this._responsiveListeners,(e,t)=>{this.platform.removeEventListener(this,t,e)}),this._responsiveListeners=void 0}updateHoverStyle(e,t,n){const a=n?"set":"remove";let i,r,o,s;for("dataset"===t&&(i=this.getDatasetMeta(e[0].datasetIndex),i.controller["_"+a+"DatasetHoverStyle"]()),o=0,s=e.length;o{const n=this.getDatasetMeta(e);if(!n)throw new Error("No dataset found at index "+e);return{datasetIndex:e,element:n.data[t],index:t}});!p(n,t)&&(this._active=n,this._lastEvent=null,this._updateHoverStyles(n,t))}notifyPlugins(e,t,n){return this._plugins.notify(this,e,t,n)}isPluginEnabled(e){return 1===this._plugins._cache.filter(t=>t.plugin.id===e).length}_updateHoverStyles(e,t,n){const a=this.options.hover,i=(e,t)=>e.filter(e=>!t.some(t=>e.datasetIndex===t.datasetIndex&&e.index===t.index)),r=i(t,e),o=n?e:i(e,t);r.length&&this.updateHoverStyle(r,a.mode,!1),o.length&&a.mode&&this.updateHoverStyle(o,a.mode,!0)}_eventHandler(e,t){const n={event:e,replay:t,cancelable:!0,inChartArea:this.isPointInArea(e)},a=t=>(t.options.events||this.options.events).includes(e.native.type);if(!1===this.notifyPlugins("beforeEvent",n,a))return;const i=this._handleEvent(e,t,n.inChartArea);return n.cancelable=!1,this.notifyPlugins("afterEvent",n,a),(i||n.changed)&&this.render(),this}_handleEvent(e,t,n){const{_active:a=[],options:i}=this,r=t,o=this._getActiveElements(e,a,n,r),s=P(e),l=function(e,t,n,a){return n&&"mouseout"!==e.type?a?t:e:null}(e,this._lastEvent,n,s);n&&(this._lastEvent=null,d(i.onHover,[e,o,this],this),s&&d(i.onClick,[e,o,this],this));const u=!p(o,a);return(u||t)&&(this._active=o,this._updateHoverStyles(o,a,t)),this._lastEvent=l,u}_getActiveElements(e,t,n,a){if("mouseout"===e.type)return[];if(!n)return t;const i=this.options.hover;return this.getElementsAtEventForMode(e,i.mode,i,a)}}function ki(){return h(wi.instances,e=>e._plugins.invalidate())}function xi(){throw new Error("This method is not implemented: Check that a complete date adapter is provided.")}class Si{static override(e){Object.assign(Si.prototype,e)}options;constructor(e){this.options=e||{}}init(){}formats(){return xi()}parse(){return xi()}format(){return xi()}add(){return xi()}diff(){return xi()}startOf(){return xi()}endOf(){return xi()}}var Ci={_date:Si};function Ti(e){const t=e.iScale,n=function(e,t){if(!e._cache.$bar){const n=e.getMatchingVisibleMetas(t);let a=[];for(let t=0,i=n.length;te-t))}return e._cache.$bar}(t,e.type);let a,i,r,o,s=t._length;const l=()=>{32767!==r&&-32768!==r&&(S(o)&&(s=Math.min(s,Math.abs(r-o)||s)),o=r)};for(a=0,i=n.length;aMath.abs(s)&&(l=s,u=o),t[n.axis]=u,t._custom={barStart:l,barEnd:u,start:i,end:r,min:o,max:s}}(e,t,n,a):t[n.axis]=n.parse(e,a),t}function Ei(e,t,n,a){const i=e.iScale,r=e.vScale,o=i.getLabels(),s=i===r,l=[];let u,c,d,h;for(u=n,c=n+a;ue.x,n="left",a="right"):(t=e.base"spacing"!==e,_indexable:e=>"spacing"!==e&&!e.startsWith("borderDash")&&!e.startsWith("hoverBorderDash")};static overrides={aspectRatio:1,plugins:{legend:{labels:{generateLabels(e){const t=e.data,{labels:{pointStyle:n,textAlign:a,color:i,useBorderRadius:r,borderRadius:o}}=e.legend.options;return t.labels.length&&t.datasets.length?t.labels.map((t,s)=>{const l=e.getDatasetMeta(0).controller.getStyle(s);return{text:t,fillStyle:l.backgroundColor,fontColor:i,hidden:!e.getDataVisibility(s),lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:l.borderWidth,strokeStyle:l.borderColor,textAlign:a,pointStyle:n,borderRadius:r&&(o||l.borderRadius),index:s}}):[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}}};constructor(e,t){super(e,t),this.enableOptionSharing=!0,this.innerRadius=void 0,this.outerRadius=void 0,this.offsetX=void 0,this.offsetY=void 0}linkScales(){}parse(e,t){const n=this.getDataset().data,a=this._cachedMeta;if(!1===this._parsing)a._parsed=n;else{let i,o,s=e=>+n[e];if(r(n[e])){const{key:e="value"}=this._parsing;s=t=>+k(n[t],e)}for(i=e,o=e+t;iZ(e,s,l,!0)?1:Math.max(t,t*n,a,a*n),f=(e,t,a)=>Z(e,s,l,!0)?-1:Math.min(t,t*n,a,a*n),m=p(0,u,d),_=p(z,c,h),g=f(E,u,d),v=f(E+z,c,h);a=(m-g)/2,i=(_-v)/2,r=-(m+g)/2,o=-(_+v)/2}return{ratioX:a,ratioY:i,offsetX:r,offsetY:o}}(h,d,s),g=(n.width-r)/p,v=(n.height-r)/f,b=Math.max(Math.min(g,v)/2,0),y=c(this.options.radius,b),w=(y-Math.max(y*s,0))/this._getVisibleDatasetWeightTotal();this.offsetX=m*y,this.offsetY=_*y,a.total=this.calculateTotal(),this.outerRadius=y-w*this._getRingWeightOffset(this.index),this.innerRadius=Math.max(this.outerRadius-w*l,0),this.updateElements(i,0,i.length,e)}_circumference(e,t){const n=this.options,a=this._cachedMeta,i=this._getCircumference();return t&&n.animation.animateRotate||!this.chart.getDataVisibility(e)||null===a._parsed[e]||a.data[e].hidden?0:this.calculateCircumference(a._parsed[e]*i/A)}updateElements(e,t,n,a){const i="reset"===a,r=this.chart,o=r.chartArea,s=r.options.animation,l=(o.left+o.right)/2,u=(o.top+o.bottom)/2,c=i&&s.animateScale,d=c?0:this.innerRadius,h=c?0:this.outerRadius,{sharedOptions:p,includeOptions:f}=this._getSharedOptions(t,a);let m,_=this._getRotation();for(m=0;m0&&!isNaN(e)?A*(Math.abs(e)/t):0}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart,a=n.data.labels||[],i=et(t._parsed[e],n.options.locale);return{label:a[e]||"",value:i}}getMaxBorderWidth(e){let t=0;const n=this.chart;let a,i,r,o,s;if(!e)for(a=0,i=n.data.datasets.length;a{const r=e.getDatasetMeta(0).controller.getStyle(i);return{text:t,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,fontColor:a,lineWidth:r.borderWidth,pointStyle:n,hidden:!e.getDataVisibility(i),index:i}})}return[]}},onClick(e,t,n){n.chart.toggleDataVisibility(t.index),n.chart.update()}}},scales:{r:{type:"radialLinear",angleLines:{display:!1},beginAtZero:!0,grid:{circular:!0},pointLabels:{display:!1},startAngle:0}}};constructor(e,t){super(e,t),this.innerRadius=void 0,this.outerRadius=void 0}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart,a=n.data.labels||[],i=et(t._parsed[e].r,n.options.locale);return{label:a[e]||"",value:i}}parseObjectData(e,t,n,a){return Qt.bind(this)(e,t,n,a)}update(e){const t=this._cachedMeta.data;this._updateRadius(),this.updateElements(t,0,t.length,e)}getMinMax(){const e=this._cachedMeta,t={min:Number.POSITIVE_INFINITY,max:Number.NEGATIVE_INFINITY};return e.data.forEach((e,n)=>{const a=this.getParsed(n).r;!isNaN(a)&&this.chart.getDataVisibility(n)&&(at.max&&(t.max=a))}),t}_updateRadius(){const e=this.chart,t=e.chartArea,n=e.options,a=Math.min(t.right-t.left,t.bottom-t.top),i=Math.max(a/2,0),r=(i-Math.max(n.cutoutPercentage?i/100*n.cutoutPercentage:1,0))/e.getVisibleDatasetCount();this.outerRadius=i-r*this.index,this.innerRadius=this.outerRadius-r}updateElements(e,t,n,a){const i="reset"===a,r=this.chart,o=r.options.animation,s=this._cachedMeta.rScale,l=s.xCenter,u=s.yCenter,c=s.getIndexAngle(0)-.5*E;let d,h=c;const p=360/this.countVisibleElements();for(d=0;d{!isNaN(this.getParsed(n).r)&&this.chart.getDataVisibility(n)&&t++}),t}_computeAngle(e,t,n){return this.chart.getDataVisibility(e)?$(this.resolveDataElementOptions(e,t).angle||n):0}}var Oi=Object.freeze({__proto__:null,BarController:class extends Oa{static id="bar";static defaults={datasetElementType:!1,dataElementType:"bar",categoryPercentage:.8,barPercentage:.9,grouped:!0,animations:{numbers:{type:"number",properties:["x","y","base","width","height"]}}};static overrides={scales:{_index_:{type:"category",offset:!0,grid:{offset:!0}},_value_:{type:"linear",beginAtZero:!0}}};parsePrimitiveData(e,t,n,a){return Ei(e,t,n,a)}parseArrayData(e,t,n,a){return Ei(e,t,n,a)}parseObjectData(e,t,n,a){const{iScale:i,vScale:r}=e,{xAxisKey:o="x",yAxisKey:s="y"}=this._parsing,l="x"===i.axis?o:s,u="x"===r.axis?o:s,c=[];let d,h,p,f;for(d=n,h=n+a;de.controller.options.grouped),r=n.options.stacked,o=[],s=this._cachedMeta.controller.getParsed(t),l=s&&s[n.axis],u=e=>{const t=e._parsed.find(e=>e[n.axis]===l),i=t&&t[e.vScale.axis];if(a(i)||isNaN(i))return!0};for(const n of i)if((void 0===t||!u(n))&&((!1===r||-1===o.indexOf(n.stack)||void 0===r&&void 0===n.stack)&&o.push(n.stack),n.index===e))break;return o.length||o.push(void 0),o}_getStackCount(e){return this._getStacks(void 0,e).length}_getAxisCount(){return this._getAxis().length}getFirstScaleIdForIndexAxis(){const e=this.chart.scales,t=this.chart.options.indexAxis;return Object.keys(e).filter(n=>e[n].axis===t).shift()}_getAxis(){const e={},t=this.getFirstScaleIdForIndexAxis();for(const n of this.chart.data.datasets)e[l("x"===this.chart.options.indexAxis?n.xAxisID:n.yAxisID,t)]=!0;return Object.keys(e)}_getStackIndex(e,t,n){const a=this._getStacks(e,n),i=void 0!==t?a.indexOf(t):-1;return-1===i?a.length-1:i}_getRuler(){const e=this.options,t=this._cachedMeta,n=t.iScale,a=[];let i,r;for(i=0,r=t.data.length;i=n?1:-1)}(h,t,s)*o,p===s&&(g-=h/2);const e=t.getPixelForDecimal(0),a=t.getPixelForDecimal(1),r=Math.min(e,a),u=Math.max(e,a);g=Math.max(Math.min(g,u),r),d=g+h,n&&!c&&(l._stacks[t.axis]._visualValues[i]=t.getValueForPixel(d)-t.getValueForPixel(g))}if(g===t.getPixelForValue(s)){const e=j(h)*t.getLineWidthForValue(s)/2;g+=e,h-=e}return{size:h,base:g,head:d,center:d+h/2}}_calculateBarIndexPixels(e,t){const n=t.scale,i=this.options,r=i.skipNull,o=l(i.maxBarThickness,1/0);let s,u;const c=this._getAxisCount();if(t.grouped){const n=r?this._getStackCount(e):t.stackCount,d="flex"===i.barThickness?function(e,t,n,a){const i=t.pixels,r=i[e];let o=e>0?i[e-1]:null,s=e=0;--n)t=Math.max(t,e[n].size(this.resolveDataElementOptions(n))/2);return t>0&&t}getLabelAndValue(e){const t=this._cachedMeta,n=this.chart.data.labels||[],{xScale:a,yScale:i}=t,r=this.getParsed(e),o=a.getLabelForValue(r.x),s=i.getLabelForValue(r.y),l=r._custom;return{label:n[e]||"",value:"("+o+", "+s+(l?", "+l:"")+")"}}update(e){const t=this._cachedMeta.data;this.updateElements(t,0,t.length,e)}updateElements(e,t,n,a){const i="reset"===a,{iScale:r,vScale:o}=this._cachedMeta,{sharedOptions:s,includeOptions:l}=this._getSharedOptions(t,a),u=r.axis,c=o.axis;for(let d=t;d0&&this.getParsed(t-1);for(let n=0;n=v){b.skip=!0;continue}const w=this.getParsed(n),k=a(w[p]),x=b[h]=o.getPixelForValue(w[h],n),S=b[p]=r||k?s.getBasePixel():s.getPixelForValue(l?this.applyStack(s,w,l):w[p],n);b.skip=isNaN(x)||isNaN(S)||k,b.stop=n>0&&Math.abs(w[h]-y[h])>_,m&&(b.parsed=w,b.raw=u.data[n]),d&&(b.options=c||this.resolveDataElementOptions(n,f.active?"active":i)),g||this.updateElement(f,n,b,i),y=w}}getMaxOverflow(){const e=this._cachedMeta,t=e.dataset,n=t.options&&t.options.borderWidth||0,a=e.data||[];if(!a.length)return n;const i=a[0].size(this.resolveDataElementOptions(0)),r=a[a.length-1].size(this.resolveDataElementOptions(a.length-1));return Math.max(n,i,r)/2}draw(){const e=this._cachedMeta;e.dataset.updateControlPoints(this.chart.chartArea,e.iScale.axis),super.draw()}},PieController:class extends Ii{static id="pie";static defaults={cutout:0,rotation:0,circumference:360,radius:"100%"}},PolarAreaController:Ni,RadarController:class extends Oa{static id="radar";static defaults={datasetElementType:"line",dataElementType:"point",indexAxis:"r",showLine:!0,elements:{line:{fill:"start"}}};static overrides={aspectRatio:1,scales:{r:{type:"radialLinear"}}};getLabelAndValue(e){const t=this._cachedMeta.vScale,n=this.getParsed(e);return{label:t.getLabels()[e],value:""+t.getLabelForValue(n[t.axis])}}parseObjectData(e,t,n,a){return Qt.bind(this)(e,t,n,a)}update(e){const t=this._cachedMeta,n=t.dataset,a=t.data||[],i=t.iScale.getLabels();if(n.points=a,"resize"!==e){const t=this.resolveDatasetElementOptions(e);this.options.showLine||(t.borderWidth=0);const r={_loop:!0,_fullLoop:i.length===a.length,options:t};this.updateElement(n,void 0,r,e)}this.updateElements(a,0,a.length,e)}updateElements(e,t,n,a){const i=this._cachedMeta.rScale,r="reset"===a;for(let o=t;o0&&this.getParsed(t-1);for(let c=t;c0&&Math.abs(n[p]-b[p])>g,_&&(m.parsed=n,m.raw=u.data[c]),h&&(m.options=d||this.resolveDataElementOptions(c,t.active?"active":i)),v||this.updateElement(t,c,m,i),b=n}this.updateSharedOptions(d,i,c)}getMaxOverflow(){const e=this._cachedMeta,t=e.data||[];if(!this.options.showLine){let e=0;for(let n=t.length-1;n>=0;--n)e=Math.max(e,t[n].size(this.resolveDataElementOptions(n))/2);return e>0&&e}const n=e.dataset,a=n.options&&n.options.borderWidth||0;if(!t.length)return a;const i=t[0].size(this.resolveDataElementOptions(0)),r=t[t.length-1].size(this.resolveDataElementOptions(t.length-1));return Math.max(a,i,r)/2}}});function ji(e,t,n,a){return{x:n+e*Math.cos(t),y:a+e*Math.sin(t)}}function Di(e,t,n,a,i,r){const{x:o,y:s,startAngle:l,pixelMargin:u,innerRadius:c}=t,d=Math.max(t.outerRadius+a+n-u,0),h=c>0?c+a+n+u:0;let p=0;const f=i-l;if(a){const e=((c>0?c-a:0)+(d>0?d-a:0))/2;p=(f-(0!==e?f*e/(e+a):f))/2}const m=(f-Math.max(.001,f*d-n/E)/d)/2,_=l+m+p,g=i-m-p,{outerStart:v,outerEnd:b,innerStart:y,innerEnd:w}=function(e,t,n,a){const i=_n(e.options.borderRadius,["outerStart","outerEnd","innerStart","innerEnd"]),r=(n-t)/2,o=Math.min(r,a*t/2),s=e=>{const t=(n-Math.min(r,e))*a/2;return J(e,0,Math.min(r,t))};return{outerStart:s(i.outerStart),outerEnd:s(i.outerEnd),innerStart:J(i.innerStart,0,o),innerEnd:J(i.innerEnd,0,o)}}(t,h,d,g-_),k=d-v,x=d-b,S=_+v/k,C=g-b/x,T=h+y,P=h+w,A=_+y/T,L=g-w/P;if(e.beginPath(),r){const t=(S+C)/2;if(e.arc(o,s,d,S,t),e.arc(o,s,d,t,C),b>0){const t=ji(x,C,o,s);e.arc(t.x,t.y,b,C,g+z)}const n=ji(P,g,o,s);if(e.lineTo(n.x,n.y),w>0){const t=ji(P,L,o,s);e.arc(t.x,t.y,w,g+z,L+Math.PI)}const a=(g-w/h+(_+y/h))/2;if(e.arc(o,s,h,g-w/h,a,!0),e.arc(o,s,h,a,_+y/h,!0),y>0){const t=ji(T,A,o,s);e.arc(t.x,t.y,y,A+Math.PI,_-z)}const i=ji(k,_,o,s);if(e.lineTo(i.x,i.y),v>0){const t=ji(k,S,o,s);e.arc(t.x,t.y,v,_-z,S)}}else{e.moveTo(o,s);const t=Math.cos(S)*d+o,n=Math.sin(S)*d+s;e.lineTo(t,n);const a=Math.cos(C)*d+o,i=Math.sin(C)*d+s;e.lineTo(a,i)}e.closePath()}function qi(e,t,n=t){e.lineCap=l(n.borderCapStyle,t.borderCapStyle),e.setLineDash(l(n.borderDash,t.borderDash)),e.lineDashOffset=l(n.borderDashOffset,t.borderDashOffset),e.lineJoin=l(n.borderJoinStyle,t.borderJoinStyle),e.lineWidth=l(n.borderWidth,t.borderWidth),e.strokeStyle=l(n.borderColor,t.borderColor)}function Bi(e,t,n){e.lineTo(n.x,n.y)}function Fi(e,t,n={}){const a=e.length,{start:i=0,end:r=a-1}=n,{start:o,end:s}=t,l=Math.max(i,o),u=Math.min(r,s),c=is&&r>s;return{count:a,start:l,loop:t.loop,ilen:u(o+(u?s-e:e))%r,b=()=>{p!==f&&(e.lineTo(_,f),e.lineTo(_,p),e.lineTo(_,m))};for(l&&(d=i[v(0)],e.moveTo(d.x,d.y)),c=0;c<=s;++c){if(d=i[v(c)],d.skip)continue;const t=d.x,n=d.y,a=0|t;a===h?(nf&&(f=n),_=(g*_+t)/++g):(b(),e.lineTo(t,n),h=a,g=0,p=f=n),m=n}b()}function $i(e){const t=e.options,n=t.borderDash&&t.borderDash.length;return e._decimated||e._loop||t.tension||"monotone"===t.cubicInterpolationMode||t.stepped||n?Vi:Ui}const Hi="function"==typeof Path2D;class Wi extends ja{static id="line";static defaults={borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",borderWidth:3,capBezierPoints:!0,cubicInterpolationMode:"default",fill:!1,spanGaps:!1,stepped:!1,tension:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};static descriptors={_scriptable:!0,_indexable:e=>"borderDash"!==e&&"fill"!==e};constructor(e){super(),this.animated=!0,this.options=void 0,this._chart=void 0,this._loop=void 0,this._fullLoop=void 0,this._path=void 0,this._points=void 0,this._segments=void 0,this._decimated=!1,this._pointsUpdated=!1,this._datasetIndex=void 0,e&&Object.assign(this,e)}updateControlPoints(e,t){const n=this.options;if((n.tension||"monotone"===n.cubicInterpolationMode)&&!n.stepped&&!this._pointsUpdated){const a=n.spanGaps?this._loop:this._fullLoop;an(this._points,n,e,a,t),this._pointsUpdated=!0}}set points(e){this._points=e,delete this._segments,delete this._path,this._pointsUpdated=!1}get points(){return this._points}get segments(){return this._segments||(this._segments=Mn(this,this.options.segment))}first(){const e=this.segments,t=this.points;return e.length&&t[e[0].start]}last(){const e=this.segments,t=this.points,n=e.length;return n&&t[e[n-1].end]}interpolate(e,t){const n=this.options,a=e[t],i=this.points,r=Ln(this,{property:t,start:a,end:a});if(!r.length)return;const o=[],s=function(e){return e.stepped?cn:e.tension||"monotone"===e.cubicInterpolationMode?dn:un}(n);let l,u;for(l=0,u=r.length;l"borderDash"!==e};circumference;endAngle;fullCircles;innerRadius;outerRadius;pixelMargin;startAngle;constructor(e){super(),this.options=void 0,this.circumference=void 0,this.startAngle=void 0,this.endAngle=void 0,this.innerRadius=void 0,this.outerRadius=void 0,this.pixelMargin=0,this.fullCircles=0,e&&Object.assign(this,e)}inRange(e,t,n){const a=this.getProps(["x","y"],n),{angle:i,distance:r}=G(a,{x:e,y:t}),{startAngle:o,endAngle:s,innerRadius:u,outerRadius:c,circumference:d}=this.getProps(["startAngle","endAngle","innerRadius","outerRadius","circumference"],n),h=(this.options.spacing+this.options.borderWidth)/2,p=l(d,s-o),f=Z(i,o,s)&&o!==s,m=p>=A||f,_=ee(r,u+h,c+h);return m&&_}getCenterPoint(e){const{x:t,y:n,startAngle:a,endAngle:i,innerRadius:r,outerRadius:o}=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],e),{offset:s,spacing:l}=this.options,u=(a+i)/2,c=(r+o+l+s)/2;return{x:t+Math.cos(u)*c,y:n+Math.sin(u)*c}}tooltipPosition(e){return this.getCenterPoint(e)}draw(e){const{options:t,circumference:n}=this,a=(t.offset||0)/4,i=(t.spacing||0)/2,r=t.circular;if(this.pixelMargin="inner"===t.borderAlign?.33:0,this.fullCircles=n>A?Math.floor(n/A):0,0===n||this.innerRadius<0||this.outerRadius<0)return;e.save();const o=(this.startAngle+this.endAngle)/2;e.translate(Math.cos(o)*a,Math.sin(o)*a);const s=a*(1-Math.sin(Math.min(E,n||0)));e.fillStyle=t.backgroundColor,e.strokeStyle=t.borderColor,function(e,t,n,a,i){const{fullCircles:r,startAngle:o,circumference:s}=t;let l=t.endAngle;if(r){Di(e,t,n,a,l,i);for(let t=0;ti?(u=i/l,e.arc(r,o,l,n+u,a-u,!0)):e.arc(r,o,i,n+z,a-z),e.closePath(),e.clip()}(e,t,m),l.selfJoin&&m-o>=E&&0===p&&"miter"!==c&&function(e,t,n){const{startAngle:a,x:i,y:r,outerRadius:o,innerRadius:s,options:l}=t,{borderWidth:u,borderJoinStyle:c}=l,d=Math.min(u/o,Q(a-n));if(e.beginPath(),e.arc(i,r,o-u/2,a+d/2,n-d/2),s>0){const t=Math.min(u/s,Q(a-n));e.arc(i,r,s+u/2,n-t/2,a+t/2,!0)}else{const t=Math.min(u/2,o*Q(a-n));if("round"===c)e.arc(i,r,t,n-E/2,a+E/2,!0);else if("bevel"===c){const o=2*t*t,s=-o*Math.cos(n+E/2)+i,l=-o*Math.sin(n+E/2)+r,u=o*Math.cos(a+E/2)+i,c=o*Math.sin(a+E/2)+r;e.lineTo(s,l),e.lineTo(u,c)}}e.closePath(),e.moveTo(0,0),e.rect(0,0,e.canvas.width,e.canvas.height),e.clip("evenodd")}(e,t,m),r||(Di(e,t,n,a,m,i),e.stroke())}(e,this,s,i,r),e.restore()}},BarElement:class extends ja{static id="bar";static defaults={borderSkipped:"start",borderWidth:0,borderRadius:0,inflateAmount:"auto",pointStyle:void 0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(e){super(),this.options=void 0,this.horizontal=void 0,this.base=void 0,this.width=void 0,this.height=void 0,this.inflateAmount=void 0,e&&Object.assign(this,e)}draw(e){const{inflateAmount:t,options:{borderColor:n,backgroundColor:a}}=this,{inner:i,outer:r}=Qi(this),o=(s=r.radius).topLeft||s.topRight||s.bottomLeft||s.bottomRight?Ot:Ji;var s;e.save(),r.w===i.w&&r.h===i.h||(e.beginPath(),o(e,Xi(r,t,i)),e.clip(),o(e,Xi(i,-t,r)),e.fillStyle=n,e.fill("evenodd")),e.beginPath(),o(e,Xi(i,t)),e.fillStyle=a,e.fill(),e.restore()}inRange(e,t,n){return Zi(this,e,t,n)}inXRange(e,t){return Zi(this,e,null,t)}inYRange(e,t){return Zi(this,null,e,t)}getCenterPoint(e){const{x:t,y:n,base:a,horizontal:i}=this.getProps(["x","y","base","horizontal"],e);return{x:i?(t+a)/2:t,y:i?n:(n+a)/2}}getRange(e){return"x"===e?this.width/2:this.height/2}},LineElement:Wi,PointElement:class extends ja{static id="point";parsed;skip;stop;static defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3,rotation:0};static defaultRoutes={backgroundColor:"backgroundColor",borderColor:"borderColor"};constructor(e){super(),this.options=void 0,this.parsed=void 0,this.skip=void 0,this.stop=void 0,e&&Object.assign(this,e)}inRange(e,t,n){const a=this.options,{x:i,y:r}=this.getProps(["x","y"],n);return Math.pow(e-i,2)+Math.pow(t-r,2)=0&&ea=t?a:e,o=e=>i=n?i:e;if(e){const e=j(a),t=j(i);e<0&&t<0?o(0):e>0&&t>0&&r(0)}if(a===i){let t=0===i?1:Math.abs(.05*i);o(i+t),e||r(a-t)}this.min=a,this.max=i}getTickLimit(){const e=this.options.ticks;let t,{maxTicksLimit:n,stepSize:a}=e;return a?(t=Math.ceil(this.max/a)-Math.floor(this.min/a)+1,t>1e3&&(console.warn(`scales.${this.id}.ticks.stepSize: ${a} would result generating up to ${t} ticks. Limiting to 1000.`),t=1e3)):(t=this.computeTickLimit(),n=n||11),n&&(t=Math.min(n,t)),t}computeTickLimit(){return Number.POSITIVE_INFINITY}buildTicks(){const e=this.options,t=e.ticks;let n=this.getTickLimit();n=Math.max(2,n);const i=function(e,t){const n=[],{bounds:i,step:r,min:o,max:s,precision:l,count:u,maxTicks:c,maxDigits:d,includeBounds:h}=e,p=r||1,f=c-1,{min:m,max:_}=t,g=!a(o),v=!a(s),b=!a(u),y=(_-m)/(d+1);let w,k,x,S,C=q((_-m)/f/p)*p;if(C<1e-14&&!g&&!v)return[{value:m},{value:_}];S=Math.ceil(_/C)-Math.floor(m/C),S>f&&(C=q(S*C/f/p)*p),a(l)||(w=Math.pow(10,l),C=Math.ceil(C*w)/w),"ticks"===i?(k=Math.floor(m/C)*C,x=Math.ceil(_/C)*C):(k=m,x=_),g&&v&&r&&V((s-o)/r,C/1e3)?(S=Math.round(Math.min((s-o)/C,c)),C=(s-o)/S,k=o,x=s):b?(k=g?o:k,x=v?s:x,S=u-1,C=(x-k)/S):(S=(x-k)/C,S=D(S,Math.round(S),C/1e3)?Math.round(S):Math.ceil(S));const T=Math.max(W(C),W(k));w=Math.pow(10,a(l)?T:l),k=Math.round(k*w)/w,x=Math.round(x*w)/w;let P=0;for(g&&(h&&k!==o?(n.push({value:o}),ks)break;n.push({value:e})}return v&&h&&x!==s?n.length&&D(n[n.length-1].value,s,nr(s,y,e))?n[n.length-1].value=s:n.push({value:s}):v&&x!==s||n.push({value:x}),n}({maxTicks:n,bounds:e.bounds,min:e.min,max:e.max,precision:t.precision,step:t.stepSize,count:t.count,maxDigits:this._maxDigits(),horizontal:this.isHorizontal(),minRotation:t.minRotation||0,includeBounds:!1!==t.includeBounds},this._range||this);return"ticks"===e.bounds&&U(i,this,"value"),e.reverse?(i.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),i}configure(){const e=this.ticks;let t=this.min,n=this.max;if(super.configure(),this.options.offset&&e.length){const a=(n-t)/Math.max(e.length-1,1)/2;t-=a,n+=a}this._startValue=t,this._endValue=n,this._valueRange=n-t}getLabelForValue(e){return et(e,this.chart.options.locale,this.options.ticks.format)}}class ir extends ar{static id="linear";static defaults={ticks:{callback:nt.formatters.numeric}};determineDataLimits(){const{min:e,max:t}=this.getMinMax(!0);this.min=o(e)?e:0,this.max=o(t)?t:1,this.handleTickRangeOptions()}computeTickLimit(){const e=this.isHorizontal(),t=e?this.width:this.height,n=$(this.options.ticks.minRotation),a=(e?Math.sin(n):Math.cos(n))||.001,i=this._resolveTickFontOptions(0);return Math.ceil(t/Math.min(40,i.lineHeight/a))}getPixelForValue(e){return null===e?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getValueForPixel(e){return this._startValue+this.getDecimalForPixel(e)*this._valueRange}}const rr=e=>Math.floor(O(e)),or=(e,t)=>Math.pow(10,rr(e)+t);function sr(e){return 1===e/Math.pow(10,rr(e))}function lr(e,t,n){const a=Math.pow(10,n),i=Math.floor(e/a);return Math.ceil(t/a)-i}class ur extends Ga{static id="logarithmic";static defaults={ticks:{callback:nt.formatters.logarithmic,major:{enabled:!0}}};constructor(e){super(e),this.start=void 0,this.end=void 0,this._startValue=void 0,this._valueRange=0}parse(e,t){const n=ar.prototype.parse.apply(this,[e,t]);if(0!==n)return o(n)&&n>0?n:null;this._zero=!0}determineDataLimits(){const{min:e,max:t}=this.getMinMax(!0);this.min=o(e)?Math.max(0,e):null,this.max=o(t)?Math.max(0,t):null,this.options.beginAtZero&&(this._zero=!0),this._zero&&this.min!==this._suggestedMin&&!o(this._userMin)&&(this.min=e===or(this.min,0)?or(this.min,-1):or(this.min,0)),this.handleTickRangeOptions()}handleTickRangeOptions(){const{minDefined:e,maxDefined:t}=this.getUserBounds();let n=this.min,a=this.max;const i=t=>n=e?n:t,r=e=>a=t?a:e;n===a&&(n<=0?(i(1),r(10)):(i(or(n,-1)),r(or(a,1)))),n<=0&&i(or(a,-1)),a<=0&&r(or(n,1)),this.min=n,this.max=a}buildTicks(){const e=this.options,t=function(e,{min:t,max:n}){t=s(e.min,t);const a=[],i=rr(t);let r=function(e,t){let n=rr(t-e);for(;lr(e,t,n)>10;)n++;for(;lr(e,t,n)<10;)n--;return Math.min(n,rr(e))}(t,n),o=r<0?Math.pow(10,Math.abs(r)):1;const l=Math.pow(10,r),u=i>r?Math.pow(10,i):0,c=Math.round((t-u)*o)/o,d=Math.floor((t-u)/l/10)*l*10;let h=Math.floor((c-d)/Math.pow(10,r)),p=s(e.min,Math.round((u+d+h*Math.pow(10,r))*o)/o);for(;p=10?h=h<15?15:20:h++,h>=20&&(r++,h=2,o=r>=0?1:o),p=Math.round((u+d+h*Math.pow(10,r))*o)/o;const f=s(e.max,p);return a.push({value:f,major:sr(f),significand:h}),a}({min:this._userMin,max:this._userMax},this);return"ticks"===e.bounds&&U(t,this,"value"),e.reverse?(t.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),t}getLabelForValue(e){return void 0===e?"0":et(e,this.chart.options.locale,this.options.ticks.format)}configure(){const e=this.min;super.configure(),this._startValue=O(e),this._valueRange=O(this.max)-O(e)}getPixelForValue(e){return void 0!==e&&0!==e||(e=this.min),null===e||isNaN(e)?NaN:this.getPixelForDecimal(e===this.min?0:(O(e)-this._startValue)/this._valueRange)}getValueForPixel(e){const t=this.getDecimalForPixel(e);return Math.pow(10,this._startValue+t*this._valueRange)}}function cr(e){const t=e.ticks;if(t.display&&e.display){const e=bn(t.backdropPadding);return l(t.font&&t.font.size,st.font.size)+e.height}return 0}function dr(e,t,n,a,i){return e===a||e===i?{start:t-n/2,end:t+n/2}:ei?{start:t-n,end:t}:{start:t,end:t+n}}function hr(e,t,n,a,i){const r=Math.abs(Math.sin(n)),o=Math.abs(Math.cos(n));let s=0,l=0;a.startt.r&&(s=(a.end-t.r)/r,e.r=Math.max(e.r,t.r+s)),i.startt.b&&(l=(i.end-t.b)/o,e.b=Math.max(e.b,t.b+l))}function pr(e,t,n){const a=e.drawingArea,{extra:i,additionalAngle:r,padding:o,size:s}=n,l=e.getPointPosition(t,a+i+o,r),u=Math.round(H(Q(l.angle+z))),c=function(e,t,n){return 90===n||270===n?e-=t/2:(n>270||n<90)&&(e-=t),e}(l.y,s.h,u),d=function(e){return 0===e||180===e?"center":e<180?"left":"right"}(u),h=function(e,t,n){return"right"===n?e-=t:"center"===n&&(e-=t/2),e}(l.x,s.w,d);return{visible:!0,x:l.x,y:c,textAlign:d,left:h,top:c,right:h+s.w,bottom:c+s.h}}function fr(e,t){if(!t)return!0;const{left:n,top:a,right:i,bottom:r}=e;return!(Et({x:n,y:a},t)||Et({x:n,y:r},t)||Et({x:i,y:a},t)||Et({x:i,y:r},t))}function mr(e,t,n){const{left:i,top:r,right:o,bottom:s}=n,{backdropColor:l}=t;if(!a(l)){const n=vn(t.borderRadius),a=bn(t.backdropPadding);e.fillStyle=l;const u=i-a.left,c=r-a.top,d=o-i+a.width,h=s-r+a.height;Object.values(n).some(e=>0!==e)?(e.beginPath(),Ot(e,{x:u,y:c,w:d,h:h,radius:n}),e.fill()):e.fillRect(u,c,d,h)}}function _r(e,t,n,a){const{ctx:i}=e;if(n)i.arc(e.xCenter,e.yCenter,t,0,A);else{let n=e.getPointPosition(0,t);i.moveTo(n.x,n.y);for(let r=1;re,padding:5,centerPointLabels:!1}};static defaultRoutes={"angleLines.color":"borderColor","pointLabels.color":"color","ticks.color":"color"};static descriptors={angleLines:{_fallback:"grid"}};constructor(e){super(e),this.xCenter=void 0,this.yCenter=void 0,this.drawingArea=void 0,this._pointLabels=[],this._pointLabelItems=[]}setDimensions(){const e=this._padding=bn(cr(this.options)/2),t=this.width=this.maxWidth-e.width,n=this.height=this.maxHeight-e.height;this.xCenter=Math.floor(this.left+t/2+e.left),this.yCenter=Math.floor(this.top+n/2+e.top),this.drawingArea=Math.floor(Math.min(t,n)/2)}determineDataLimits(){const{min:e,max:t}=this.getMinMax(!1);this.min=o(e)&&!isNaN(e)?e:0,this.max=o(t)&&!isNaN(t)?t:0,this.handleTickRangeOptions()}computeTickLimit(){return Math.ceil(this.drawingArea/cr(this.options))}generateTickLabels(e){ar.prototype.generateTickLabels.call(this,e),this._pointLabels=this.getLabels().map((e,t)=>{const n=d(this.options.pointLabels.callback,[e,t],this);return n||0===n?n:""}).filter((e,t)=>this.chart.getDataVisibility(t))}fit(){const e=this.options;e.display&&e.pointLabels.display?function(e){const t={l:e.left+e._padding.left,r:e.right-e._padding.right,t:e.top+e._padding.top,b:e.bottom-e._padding.bottom},n=Object.assign({},t),a=[],r=[],o=e._pointLabels.length,s=e.options.pointLabels,l=s.centerPointLabels?E/o:0;for(let h=0;h=0&&e=0;i--){const t=e._pointLabelItems[i];if(!t.visible)continue;const r=a.setContext(e.getPointLabelContext(i));mr(n,r,t);const o=yn(r.font),{x:s,y:l,textAlign:u}=t;Nt(n,e._pointLabels[i],s,l+o.lineHeight/2,o,{color:r.color,textAlign:u,textBaseline:"middle"})}}(this,r),a.display&&this.ticks.forEach((e,t)=>{if(0!==t||0===t&&this.min<0){s=this.getDistanceFromCenterForValue(e.value);const n=this.getContext(t),o=a.setContext(n),l=i.setContext(n);!function(e,t,n,a,i){const r=e.ctx,o=t.circular,{color:s,lineWidth:l}=t;!o&&!a||!s||!l||n<0||(r.save(),r.strokeStyle=s,r.lineWidth=l,r.setLineDash(i.dash||[]),r.lineDashOffset=i.dashOffset,r.beginPath(),_r(e,n,o,a),r.closePath(),r.stroke(),r.restore())}(this,o,s,r,l)}}),n.display){for(e.save(),o=r-1;o>=0;o--){const a=n.setContext(this.getPointLabelContext(o)),{color:i,lineWidth:r}=a;r&&i&&(e.lineWidth=r,e.strokeStyle=i,e.setLineDash(a.borderDash),e.lineDashOffset=a.borderDashOffset,s=this.getDistanceFromCenterForValue(t.reverse?this.min:this.max),l=this.getPointPosition(o,s),e.beginPath(),e.moveTo(this.xCenter,this.yCenter),e.lineTo(l.x,l.y),e.stroke())}e.restore()}}drawBorder(){}drawLabels(){const e=this.ctx,t=this.options,n=t.ticks;if(!n.display)return;const a=this.getIndexAngle(0);let i,r;e.save(),e.translate(this.xCenter,this.yCenter),e.rotate(a),e.textAlign="center",e.textBaseline="middle",this.ticks.forEach((a,o)=>{if(0===o&&this.min>=0&&!t.reverse)return;const s=n.setContext(this.getContext(o)),l=yn(s.font);if(i=this.getDistanceFromCenterForValue(this.ticks[o].value),s.showLabelBackdrop){e.font=l.string,r=e.measureText(a.label).width,e.fillStyle=s.backdropColor;const t=bn(s.backdropPadding);e.fillRect(-r/2-t.left,-i-l.size/2-t.top,r+t.width,l.size+t.height)}Nt(e,a.label,0,-i,l,{color:s.color,strokeColor:s.textStrokeColor,strokeWidth:s.textStrokeWidth})}),e.restore()}drawTitle(){}}const vr={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},br=Object.keys(vr);function yr(e,t){return e-t}function wr(e,t){if(a(t))return null;const n=e._adapter,{parser:i,round:r,isoWeekday:s}=e._parseOpts;let l=t;return"function"==typeof i&&(l=i(l)),o(l)||(l="string"==typeof i?n.parse(l,i):n.parse(l)),null===l?null:(r&&(l="week"!==r||!F(s)&&!0!==s?n.startOf(l,r):n.startOf(l,"isoWeek",s)),+l)}function kr(e,t,n,a){const i=br.length;for(let r=br.indexOf(e);r=t?n[a]:n[i]]=!0}}else e[t]=!0}function Sr(e,t,n){const a=[],i={},r=t.length;let o,s;for(o=0;o=0&&(t[l].major=!0);return t}(e,a,i,n):a}class Cr extends Ga{static id="time";static defaults={bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{source:"auto",callback:!1,major:{enabled:!1}}};constructor(e){super(e),this._cache={data:[],labels:[],all:[]},this._unit="day",this._majorUnit=void 0,this._offsets={},this._normalized=!1,this._parseOpts=void 0}init(e,t={}){const n=e.time||(e.time={}),a=this._adapter=new Ci._date(e.adapters.date);a.init(t),v(n.displayFormats,a.formats()),this._parseOpts={parser:n.parser,round:n.round,isoWeekday:n.isoWeekday},super.init(e),this._normalized=t.normalized}parse(e,t){return void 0===e?null:wr(this,e)}beforeLayout(){super.beforeLayout(),this._cache={data:[],labels:[],all:[]}}determineDataLimits(){const e=this.options,t=this._adapter,n=e.time.unit||"day";let{min:a,max:i,minDefined:r,maxDefined:s}=this.getUserBounds();function l(e){r||isNaN(e.min)||(a=Math.min(a,e.min)),s||isNaN(e.max)||(i=Math.max(i,e.max))}r&&s||(l(this._getLabelBounds()),"ticks"===e.bounds&&"labels"===e.ticks.source||l(this.getMinMax(!1))),a=o(a)&&!isNaN(a)?a:+t.startOf(Date.now(),n),i=o(i)&&!isNaN(i)?i:+t.endOf(Date.now(),n)+1,this.min=Math.min(a,i-1),this.max=Math.max(a+1,i)}_getLabelBounds(){const e=this.getLabelTimestamps();let t=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;return e.length&&(t=e[0],n=e[e.length-1]),{min:t,max:n}}buildTicks(){const e=this.options,t=e.time,n=e.ticks,a="labels"===n.source?this.getLabelTimestamps():this._generate();"ticks"===e.bounds&&a.length&&(this.min=this._userMin||a[0],this.max=this._userMax||a[a.length-1]);const i=this.min,r=ie(a,i,this.max);return this._unit=t.unit||(n.autoSkip?kr(t.minUnit,this.min,this.max,this._getLabelCapacity(i)):function(e,t,n,a,i){for(let r=br.length-1;r>=br.indexOf(n);r--){const n=br[r];if(vr[n].common&&e._adapter.diff(i,a,n)>=t-1)return n}return br[n?br.indexOf(n):0]}(this,r.length,t.minUnit,this.min,this.max)),this._majorUnit=n.major.enabled&&"year"!==this._unit?function(e){for(let t=br.indexOf(e)+1,n=br.length;t+e.value))}initOffsets(e=[]){let t,n,a=0,i=0;this.options.offset&&e.length&&(t=this.getDecimalForValue(e[0]),a=1===e.length?1-t:(this.getDecimalForValue(e[1])-t)/2,n=this.getDecimalForValue(e[e.length-1]),i=1===e.length?n:(n-this.getDecimalForValue(e[e.length-2]))/2);const r=e.length<3?.5:.25;a=J(a,0,r),i=J(i,0,r),this._offsets={start:a,end:i,factor:1/(a+1+i)}}_generate(){const e=this._adapter,t=this.min,n=this.max,a=this.options,i=a.time,r=i.unit||kr(i.minUnit,t,n,this._getLabelCapacity(t)),o=l(a.ticks.stepSize,1),s="week"===r&&i.isoWeekday,u=F(s)||!0===s,c={};let d,h,p=t;if(u&&(p=+e.startOf(p,"isoWeek",s)),p=+e.startOf(p,u?"day":r),e.diff(n,t,r)>1e5*o)throw new Error(t+" and "+n+" are too far apart with stepSize of "+o+" "+r);const f="data"===a.ticks.source&&this.getDataTimestamps();for(d=p,h=0;d+e)}getLabelForValue(e){const t=this._adapter,n=this.options.time;return n.tooltipFormat?t.format(e,n.tooltipFormat):t.format(e,n.displayFormats.datetime)}format(e,t){const n=this.options.time.displayFormats,a=this._unit,i=t||n[a];return this._adapter.format(e,i)}_tickFormatFunction(e,t,n,a){const i=this.options,r=i.ticks.callback;if(r)return d(r,[e,t,n],this);const o=i.time.displayFormats,s=this._unit,l=this._majorUnit,u=s&&o[s],c=l&&o[l],h=n[t],p=l&&c&&h&&h.major;return this._adapter.format(e,a||(p?c:u))}generateTickLabels(e){let t,n,a;for(t=0,n=e.length;t0?o:1}getDataTimestamps(){let e,t,n=this._cache.data||[];if(n.length)return n;const a=this.getMatchingVisibleMetas();if(this._normalized&&a.length)return this._cache.data=a[0].controller.getAllParsedValues(this);for(e=0,t=a.length;e=e[s].pos&&t<=e[l].pos&&({lo:s,hi:l}=ne(e,"pos",t)),({pos:a,time:r}=e[s]),({pos:i,time:o}=e[l])):(t>=e[s].time&&t<=e[l].time&&({lo:s,hi:l}=ne(e,"time",t)),({time:a,pos:r}=e[s]),({time:i,pos:o}=e[l]));const u=i-a;return u?r+(o-r)*(t-a)/u:r}var Pr=Object.freeze({__proto__:null,CategoryScale:class extends Ga{static id="category";static defaults={ticks:{callback:tr}};constructor(e){super(e),this._startValue=void 0,this._valueRange=0,this._addedLabels=[]}init(e){const t=this._addedLabels;if(t.length){const e=this.getLabels();for(const{index:n,label:a}of t)e[n]===a&&e.splice(n,1);this._addedLabels=[]}super.init(e)}parse(e,t){if(a(e))return null;const n=this.getLabels();return((e,t)=>null===e?null:J(Math.round(e),0,t))(t=isFinite(t)&&n[t]===e?t:function(e,t,n,a){const i=e.indexOf(t);return-1===i?((e,t,n,a)=>("string"==typeof t?(n=e.push(t)-1,a.unshift({index:n,label:t})):isNaN(t)&&(n=null),n))(e,t,n,a):i!==e.lastIndexOf(t)?n:i}(n,e,l(t,e),this._addedLabels),n.length-1)}determineDataLimits(){const{minDefined:e,maxDefined:t}=this.getUserBounds();let{min:n,max:a}=this.getMinMax(!0);"ticks"===this.options.bounds&&(e||(n=0),t||(a=this.getLabels().length-1)),this.min=n,this.max=a}buildTicks(){const e=this.min,t=this.max,n=this.options.offset,a=[];let i=this.getLabels();i=0===e&&t===i.length-1?i:i.slice(e,t+1),this._valueRange=Math.max(i.length-(n?0:1),1),this._startValue=this.min-(n?.5:0);for(let n=e;n<=t;n++)a.push({value:n});return a}getLabelForValue(e){return tr.call(this,e)}configure(){super.configure(),this.isHorizontal()||(this._reversePixels=!this._reversePixels)}getPixelForValue(e){return"number"!=typeof e&&(e=this.parse(e)),null===e?NaN:this.getPixelForDecimal((e-this._startValue)/this._valueRange)}getPixelForTick(e){const t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e].value)}getValueForPixel(e){return Math.round(this._startValue+this.getDecimalForPixel(e)*this._valueRange)}getBasePixel(){return this.bottom}},LinearScale:ir,LogarithmicScale:ur,RadialLinearScale:gr,TimeScale:Cr,TimeSeriesScale:class extends Cr{static id="timeseries";static defaults=Cr.defaults;constructor(e){super(e),this._table=[],this._minPos=void 0,this._tableRange=void 0}initOffsets(){const e=this._getTimestampsForTable(),t=this._table=this.buildLookupTable(e);this._minPos=Tr(t,this.min),this._tableRange=Tr(t,this.max)-this._minPos,super.initOffsets(e)}buildLookupTable(e){const{min:t,max:n}=this,a=[],i=[];let r,o,s,l,u;for(r=0,o=e.length;r=t&&l<=n&&a.push(l);if(a.length<2)return[{time:t,pos:0},{time:n,pos:1}];for(r=0,o=a.length;re-t)}_getTimestampsForTable(){let e=this._cache.all||[];if(e.length)return e;const t=this.getDataTimestamps(),n=this.getLabelTimestamps();return e=t.length&&n.length?this.normalize(t.concat(n)):t.length?t:n,e=this._cache.all=e,e}getDecimalForValue(e){return(Tr(this._table,e)-this._minPos)/this._tableRange}getValueForPixel(e){const t=this._offsets,n=this.getDecimalForPixel(e)/t.factor-t.end;return Tr(this._table,n*this._tableRange+this._minPos,!0)}}});const Er=["rgb(54, 162, 235)","rgb(255, 99, 132)","rgb(255, 159, 64)","rgb(255, 205, 86)","rgb(75, 192, 192)","rgb(153, 102, 255)","rgb(201, 203, 207)"],Ar=Er.map(e=>e.replace("rgb(","rgba(").replace(")",", 0.5)"));function Lr(e){return Er[e%Er.length]}function Mr(e){return Ar[e%Ar.length]}function Rr(e){let t;for(t in e)if(e[t].borderColor||e[t].backgroundColor)return!0;return!1}var zr={id:"colors",defaults:{enabled:!0,forceOverride:!1},beforeLayout(e,t,n){if(!n.enabled)return;const{data:{datasets:a},options:i}=e.config,{elements:r}=i,o=Rr(a)||(s=i)&&(s.borderColor||s.backgroundColor)||r&&Rr(r)||"rgba(0,0,0,0.1)"!==st.borderColor||"rgba(0,0,0,0.1)"!==st.backgroundColor;var s;if(!n.forceOverride&&o)return;const l=function(e){let t=0;return(n,a)=>{const i=e.getDatasetMeta(a).controller;i instanceof Ii?t=function(e,t){return e.backgroundColor=e.data.map(()=>Lr(t++)),t}(n,t):i instanceof Ni?t=function(e,t){return e.backgroundColor=e.data.map(()=>Mr(t++)),t}(n,t):i&&(t=function(e,t){return e.borderColor=Lr(t),e.backgroundColor=Mr(t),++t}(n,t))}}(e);a.forEach(l)}};function Ir(e){if(e._decimated){const t=e._data;delete e._decimated,delete e._data,Object.defineProperty(e,"data",{configurable:!0,enumerable:!0,writable:!0,value:t})}}function Nr(e){e.data.datasets.forEach(e=>{Ir(e)})}var Or={id:"decimation",defaults:{algorithm:"min-max",enabled:!1},beforeElementsUpdate:(e,t,n)=>{if(!n.enabled)return void Nr(e);const i=e.width;e.data.datasets.forEach((t,r)=>{const{_data:o,indexAxis:s}=t,l=e.getDatasetMeta(r),u=o||t.data;if("y"===wn([s,e.options.indexAxis]))return;if(!l.controller.supportsDecimation)return;const c=e.scales[l.xAxisID];if("linear"!==c.type&&"time"!==c.type)return;if(e.options.parsing)return;let d,{start:h,count:p}=function(e,t){const n=t.length;let a,i=0;const{iScale:r}=e,{min:o,max:s,minDefined:l,maxDefined:u}=r.getUserBounds();return l&&(i=J(ne(t,r.axis,o).lo,0,n-1)),a=u?J(ne(t,r.axis,s).hi+1,i,n)-i:n-i,{start:i,count:a}}(l,u);if(p<=(n.threshold||4*i))Ir(t);else{switch(a(o)&&(t._data=u,delete t.data,Object.defineProperty(t,"data",{configurable:!0,enumerable:!0,get:function(){return this._decimated},set:function(e){this._data=e}})),n.algorithm){case"lttb":d=function(e,t,n,a,i){const r=i.samples||a;if(r>=n)return e.slice(t,t+n);const o=[],s=(n-2)/(r-2);let l=0;const u=t+n-1;let c,d,h,p,f,m=t;for(o[l++]=e[m],c=0;ch&&(h=p,d=e[a],f=a);o[l++]=d,m=f}return o[l++]=e[u],o}(u,h,p,i,n);break;case"min-max":d=function(e,t,n,i){let r,o,s,l,u,c,d,h,p,f,m=0,_=0;const g=[],v=t+n-1,b=e[t].x,y=e[v].x-b;for(r=t;rf&&(f=l,d=r),m=(_*m+o.x)/++_;else{const n=r-1;if(!a(c)&&!a(d)){const t=Math.min(c,d),a=Math.max(c,d);t!==h&&t!==n&&g.push({...e[t],x:m}),a!==h&&a!==n&&g.push({...e[a],x:m})}r>0&&n!==h&&g.push(e[n]),g.push(o),u=t,_=0,p=f=l,c=d=h=r}}return g}(u,h,p,i);break;default:throw new Error(`Unsupported decimation algorithm '${n.algorithm}'`)}t._decimated=d}})},destroy(e){Nr(e)}};function jr(e,t,n,a){if(a)return;let i=t[e],r=n[e];return"angle"===e&&(i=Q(i),r=Q(r)),{property:e,start:i,end:r}}function Dr(e,t,n){for(;t>e;t--){const e=n[t];if(!isNaN(e.x)&&!isNaN(e.y))break}return t}function qr(e,t,n,a){return e&&t?a(e[n],t[n]):e?e[n]:t?t[n]:0}function Br(e,t){let n=[],a=!1;return i(e)?(a=!0,n=e):n=function(e,t){const{x:n=null,y:a=null}=e||{},i=t.points,r=[];return t.segments.forEach(({start:e,end:t})=>{t=Dr(e,t,i);const o=i[e],s=i[t];null!==a?(r.push({x:o.x,y:a}),r.push({x:s.x,y:a})):null!==n&&(r.push({x:n,y:o.y}),r.push({x:n,y:s.y}))}),r}(e,t),n.length?new Wi({points:n,options:{tension:0},_loop:a,_fullLoop:a}):null}function Fr(e){return e&&!1!==e.fill}function Vr(e,t,n){let a=e[t].fill;const i=[t];let r;if(!n)return a;for(;!1!==a&&-1===i.indexOf(a);){if(!o(a))return a;if(r=e[a],!r)return!1;if(r.visible)return a;i.push(a),a=r.fill}return!1}function Ur(e,t,n){const a=function(e){const t=e.options,n=t.fill;let a=l(n&&n.target,n);return void 0===a&&(a=!!t.backgroundColor),!1!==a&&null!==a&&(!0===a?"origin":a)}(e);if(r(a))return!isNaN(a.value)&&a;let i=parseFloat(a);return o(i)&&Math.floor(i)===i?function(e,t,n,a){return"-"!==e&&"+"!==e||(n=t+n),!(n===t||n<0||n>=a)&&n}(a[0],t,i,n):["origin","start","end","stack","shape"].indexOf(a)>=0&&a}function $r(e,t,n){const a=[];for(let i=0;i=0;--t){const n=i[t].$filler;n&&(n.line.updateControlPoints(r,n.axis),a&&n.fill&&Kr(e.ctx,n,r))}},beforeDatasetsDraw(e,t,n){if("beforeDatasetsDraw"!==n.drawTime)return;const a=e.getSortedVisibleDatasetMetas();for(let t=a.length-1;t>=0;--t){const n=a[t].$filler;Fr(n)&&Kr(e.ctx,n,e.chartArea)}},beforeDatasetDraw(e,t,n){const a=t.meta.$filler;Fr(a)&&"beforeDatasetDraw"===n.drawTime&&Kr(e.ctx,a,e.chartArea)},defaults:{propagate:!0,drawTime:"beforeDatasetDraw"}};const to=(e,t)=>{let{boxHeight:n=t,boxWidth:a=t}=e;return e.usePointStyle&&(n=Math.min(n,t),a=e.pointStyleWidth||Math.min(a,t)),{boxWidth:a,boxHeight:n,itemHeight:Math.max(t,n)}};class no extends ja{constructor(e){super(),this._added=!1,this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1,this.chart=e.chart,this.options=e.options,this.ctx=e.ctx,this.legendItems=void 0,this.columnSizes=void 0,this.lineWidths=void 0,this.maxHeight=void 0,this.maxWidth=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.height=void 0,this.width=void 0,this._margins=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(e,t,n){this.maxWidth=e,this.maxHeight=t,this._margins=n,this.setDimensions(),this.buildLabels(),this.fit()}setDimensions(){this.isHorizontal()?(this.width=this.maxWidth,this.left=this._margins.left,this.right=this.width):(this.height=this.maxHeight,this.top=this._margins.top,this.bottom=this.height)}buildLabels(){const e=this.options.labels||{};let t=d(e.generateLabels,[this.chart],this)||[];e.filter&&(t=t.filter(t=>e.filter(t,this.chart.data))),e.sort&&(t=t.sort((t,n)=>e.sort(t,n,this.chart.data))),this.options.reverse&&t.reverse(),this.legendItems=t}fit(){const{options:e,ctx:t}=this;if(!e.display)return void(this.width=this.height=0);const n=e.labels,a=yn(n.font),i=a.size,r=this._computeTitleHeight(),{boxWidth:o,itemHeight:s}=to(n,i);let l,u;t.font=a.string,this.isHorizontal()?(l=this.maxWidth,u=this._fitRows(r,i,o,s)+10):(u=this.maxHeight,l=this._fitCols(r,a,o,s)+10),this.width=Math.min(l,e.maxWidth||this.maxWidth),this.height=Math.min(u,e.maxHeight||this.maxHeight)}_fitRows(e,t,n,a){const{ctx:i,maxWidth:r,options:{labels:{padding:o}}}=this,s=this.legendHitBoxes=[],l=this.lineWidths=[0],u=a+o;let c=e;i.textAlign="left",i.textBaseline="middle";let d=-1,h=-u;return this.legendItems.forEach((e,p)=>{const f=n+t/2+i.measureText(e.text).width;(0===p||l[l.length-1]+f+2*o>r)&&(c+=u,l[l.length-(p>0?0:1)]=0,h+=u,d++),s[p]={left:0,top:h,row:d,width:f,height:a},l[l.length-1]+=f+o}),c}_fitCols(e,t,n,a){const{ctx:i,maxHeight:r,options:{labels:{padding:o}}}=this,s=this.legendHitBoxes=[],l=this.columnSizes=[],u=r-e;let c=o,d=0,h=0,p=0,f=0;return this.legendItems.forEach((e,r)=>{const{itemWidth:m,itemHeight:_}=function(e,t,n,a,i){const r=function(e,t,n,a){let i=e.text;return i&&"string"!=typeof i&&(i=i.reduce((e,t)=>e.length>t.length?e:t)),t+n.size/2+a.measureText(i).width}(a,e,t,n),o=function(e,t,n){let a=e;return"string"!=typeof t.text&&(a=ao(t,n)),a}(i,a,t.lineHeight);return{itemWidth:r,itemHeight:o}}(n,t,i,e,a);r>0&&h+_+2*o>u&&(c+=d+o,l.push({width:d,height:h}),p+=d+o,f++,d=h=0),s[r]={left:p,top:h,col:f,width:m,height:_},d=Math.max(d,m),h+=_+o}),c+=d,l.push({width:d,height:h}),c}adjustHitBoxes(){if(!this.options.display)return;const e=this._computeTitleHeight(),{legendHitBoxes:t,options:{align:n,labels:{padding:a},rtl:i}}=this,r=Sn(i,this.left,this.width);if(this.isHorizontal()){let i=0,o=pe(n,this.left+a,this.right-this.lineWidths[i]);for(const s of t)i!==s.row&&(i=s.row,o=pe(n,this.left+a,this.right-this.lineWidths[i])),s.top+=this.top+e+a,s.left=r.leftForLtr(r.x(o),s.width),o+=s.width+a}else{let i=0,o=pe(n,this.top+e+a,this.bottom-this.columnSizes[i].height);for(const s of t)s.col!==i&&(i=s.col,o=pe(n,this.top+e+a,this.bottom-this.columnSizes[i].height)),s.top=o,s.left+=this.left+a,s.left=r.leftForLtr(r.x(s.left),s.width),o+=s.height+a}}isHorizontal(){return"top"===this.options.position||"bottom"===this.options.position}draw(){if(this.options.display){const e=this.ctx;At(e,this),this._draw(),Lt(e)}}_draw(){const{options:e,columnSizes:t,lineWidths:n,ctx:a}=this,{align:i,labels:r}=e,o=st.color,s=Sn(e.rtl,this.left,this.width),u=yn(r.font),{padding:c}=r,d=u.size,h=d/2;let p;this.drawTitle(),a.textAlign=s.textAlign("left"),a.textBaseline="middle",a.lineWidth=.5,a.font=u.string;const{boxWidth:f,boxHeight:m,itemHeight:_}=to(r,d),g=this.isHorizontal(),v=this._computeTitleHeight();p=g?{x:pe(i,this.left+c,this.right-n[0]),y:this.top+c+v,line:0}:{x:this.left+c,y:pe(i,this.top+v+c,this.bottom-t[0].height),line:0},Cn(this.ctx,e.textDirection);const b=_+c;this.legendItems.forEach((y,w)=>{a.strokeStyle=y.fontColor,a.fillStyle=y.fontColor;const k=a.measureText(y.text).width,x=s.textAlign(y.textAlign||(y.textAlign=r.textAlign)),S=f+h+k;let C=p.x,T=p.y;if(s.setWidth(this.width),g?w>0&&C+S+c>this.right&&(T=p.y+=b,p.line++,C=p.x=pe(i,this.left+c,this.right-n[p.line])):w>0&&T+b>this.bottom&&(C=p.x=C+t[p.line].width+c,p.line++,T=p.y=pe(i,this.top+v+c,this.bottom-t[p.line].height)),function(e,t,n){if(isNaN(f)||f<=0||isNaN(m)||m<0)return;a.save();const i=l(n.lineWidth,1);if(a.fillStyle=l(n.fillStyle,o),a.lineCap=l(n.lineCap,"butt"),a.lineDashOffset=l(n.lineDashOffset,0),a.lineJoin=l(n.lineJoin,"miter"),a.lineWidth=i,a.strokeStyle=l(n.strokeStyle,o),a.setLineDash(l(n.lineDash,[])),r.usePointStyle){const o={radius:m*Math.SQRT2/2,pointStyle:n.pointStyle,rotation:n.rotation,borderWidth:i},l=s.xPlus(e,f/2);Pt(a,o,l,t+h,r.pointStyleWidth&&f)}else{const r=t+Math.max((d-m)/2,0),o=s.leftForLtr(e,f),l=vn(n.borderRadius);a.beginPath(),Object.values(l).some(e=>0!==e)?Ot(a,{x:o,y:r,w:f,h:m,radius:l}):a.rect(o,r,f,m),a.fill(),0!==i&&a.stroke()}a.restore()}(s.x(C),T,y),C=fe(x,C+f+h,g?C+S:this.right,e.rtl),function(e,t,n){Nt(a,n.text,e,t+_/2,u,{strikethrough:n.hidden,textAlign:s.textAlign(n.textAlign)})}(s.x(C),T,y),g)p.x+=S+c;else if("string"!=typeof y.text){const e=u.lineHeight;p.y+=ao(y,e)+c}else p.y+=b}),Tn(this.ctx,e.textDirection)}drawTitle(){const e=this.options,t=e.title,n=yn(t.font),a=bn(t.padding);if(!t.display)return;const i=Sn(e.rtl,this.left,this.width),r=this.ctx,o=t.position,s=n.size/2,l=a.top+s;let u,c=this.left,d=this.width;if(this.isHorizontal())d=Math.max(...this.lineWidths),u=this.top+l,c=pe(e.align,c,this.right-d);else{const t=this.columnSizes.reduce((e,t)=>Math.max(e,t.height),0);u=l+pe(e.align,this.top,this.bottom-t-e.labels.padding-this._computeTitleHeight())}const h=pe(o,c,c+d);r.textAlign=i.textAlign(he(o)),r.textBaseline="middle",r.strokeStyle=t.color,r.fillStyle=t.color,r.font=n.string,Nt(r,t.text,h,u,n)}_computeTitleHeight(){const e=this.options.title,t=yn(e.font),n=bn(e.padding);return e.display?t.lineHeight+n.height:0}_getLegendItemAt(e,t){let n,a,i;if(ee(e,this.left,this.right)&&ee(t,this.top,this.bottom))for(i=this.legendHitBoxes,n=0;ne.chart.options.color,boxWidth:40,padding:10,generateLabels(e){const t=e.data.datasets,{labels:{usePointStyle:n,pointStyle:a,textAlign:i,color:r,useBorderRadius:o,borderRadius:s}}=e.legend.options;return e._getSortedDatasetMetas().map(e=>{const l=e.controller.getStyle(n?0:void 0),u=bn(l.borderWidth);return{text:t[e.index].label,fillStyle:l.backgroundColor,fontColor:r,hidden:!e.visible,lineCap:l.borderCapStyle,lineDash:l.borderDash,lineDashOffset:l.borderDashOffset,lineJoin:l.borderJoinStyle,lineWidth:(u.width+u.height)/4,strokeStyle:l.borderColor,pointStyle:a||l.pointStyle,rotation:l.rotation,textAlign:i||l.textAlign,borderRadius:o&&(s||l.borderRadius),datasetIndex:e.index}},this)}},title:{color:e=>e.chart.options.color,display:!1,position:"center",text:""}},descriptors:{_scriptable:e=>!e.startsWith("on"),labels:{_scriptable:e=>!["generateLabels","filter","sort"].includes(e)}}};class ro extends ja{constructor(e){super(),this.chart=e.chart,this.options=e.options,this.ctx=e.ctx,this._padding=void 0,this.top=void 0,this.bottom=void 0,this.left=void 0,this.right=void 0,this.width=void 0,this.height=void 0,this.position=void 0,this.weight=void 0,this.fullSize=void 0}update(e,t){const n=this.options;if(this.left=0,this.top=0,!n.display)return void(this.width=this.height=this.right=this.bottom=0);this.width=this.right=e,this.height=this.bottom=t;const a=i(n.text)?n.text.length:1;this._padding=bn(n.padding);const r=a*yn(n.font).lineHeight+this._padding.height;this.isHorizontal()?this.height=r:this.width=r}isHorizontal(){const e=this.options.position;return"top"===e||"bottom"===e}_drawArgs(e){const{top:t,left:n,bottom:a,right:i,options:r}=this,o=r.align;let s,l,u,c=0;return this.isHorizontal()?(l=pe(o,n,i),u=t+e,s=i-n):("left"===r.position?(l=n+e,u=pe(o,a,t),c=-.5*E):(l=i-e,u=pe(o,t,a),c=.5*E),s=a-t),{titleX:l,titleY:u,maxWidth:s,rotation:c}}draw(){const e=this.ctx,t=this.options;if(!t.display)return;const n=yn(t.font),a=n.lineHeight/2+this._padding.top,{titleX:i,titleY:r,maxWidth:o,rotation:s}=this._drawArgs(a);Nt(e,t.text,0,0,n,{color:t.color,maxWidth:o,rotation:s,textAlign:he(t.align),textBaseline:"middle",translation:[i,r]})}}var oo={id:"title",_element:ro,start(e,t,n){!function(e,t){const n=new ro({ctx:e.ctx,options:t,chart:e});ta.configure(e,n,t),ta.addBox(e,n),e.titleBlock=n}(e,n)},stop(e){const t=e.titleBlock;ta.removeBox(e,t),delete e.titleBlock},beforeUpdate(e,t,n){const a=e.titleBlock;ta.configure(e,a,n),a.options=n},defaults:{align:"center",display:!1,font:{weight:"bold"},fullSize:!0,padding:10,position:"top",text:"",weight:2e3},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const so=new WeakMap;var lo={id:"subtitle",start(e,t,n){const a=new ro({ctx:e.ctx,options:n,chart:e});ta.configure(e,a,n),ta.addBox(e,a),so.set(e,a)},stop(e){ta.removeBox(e,so.get(e)),so.delete(e)},beforeUpdate(e,t,n){const a=so.get(e);ta.configure(e,a,n),a.options=n},defaults:{align:"center",display:!1,font:{weight:"normal"},fullSize:!0,padding:0,position:"top",text:"",weight:1500},defaultRoutes:{color:"color"},descriptors:{_scriptable:!0,_indexable:!1}};const uo={average(e){if(!e.length)return!1;let t,n,a=new Set,i=0,r=0;for(t=0,n=e.length;te+t)/a.size,y:i/r}},nearest(e,t){if(!e.length)return!1;let n,a,i,r=t.x,o=t.y,s=Number.POSITIVE_INFINITY;for(n=0,a=e.length;n-1?e.split("\n"):e}function po(e,t){const{element:n,datasetIndex:a,index:i}=t,r=e.getDatasetMeta(a).controller,{label:o,value:s}=r.getLabelAndValue(i);return{chart:e,label:o,parsed:r.getParsed(i),raw:e.data.datasets[a].data[i],formattedValue:s,dataset:r.getDataset(),dataIndex:i,datasetIndex:a,element:n}}function fo(e,t){const n=e.chart.ctx,{body:a,footer:i,title:r}=e,{boxWidth:o,boxHeight:s}=t,l=yn(t.bodyFont),u=yn(t.titleFont),c=yn(t.footerFont),d=r.length,p=i.length,f=a.length,m=bn(t.padding);let _=m.height,g=0,v=a.reduce((e,t)=>e+t.before.length+t.lines.length+t.after.length,0);v+=e.beforeBody.length+e.afterBody.length,d&&(_+=d*u.lineHeight+(d-1)*t.titleSpacing+t.titleMarginBottom),v&&(_+=f*(t.displayColors?Math.max(s,l.lineHeight):l.lineHeight)+(v-f)*l.lineHeight+(v-1)*t.bodySpacing),p&&(_+=t.footerMarginTop+p*c.lineHeight+(p-1)*t.footerSpacing);let b=0;const y=function(e){g=Math.max(g,n.measureText(e).width+b)};return n.save(),n.font=u.string,h(e.title,y),n.font=l.string,h(e.beforeBody.concat(e.afterBody),y),b=t.displayColors?o+2+t.boxPadding:0,h(a,e=>{h(e.before,y),h(e.lines,y),h(e.after,y)}),b=0,n.font=c.string,h(e.footer,y),n.restore(),g+=m.width,{width:g,height:_}}function mo(e,t,n,a){const{x:i,width:r}=n,{width:o,chartArea:{left:s,right:l}}=e;let u="center";return"center"===a?u=i<=(s+l)/2?"left":"right":i<=r/2?u="left":i>=o-r/2&&(u="right"),function(e,t,n,a){const{x:i,width:r}=a,o=n.caretSize+n.caretPadding;return"left"===e&&i+r+o>t.width||"right"===e&&i-r-o<0||void 0}(u,e,t,n)&&(u="center"),u}function _o(e,t,n){const a=n.yAlign||t.yAlign||function(e,t){const{y:n,height:a}=t;return ne.height-a/2?"bottom":"center"}(e,n);return{xAlign:n.xAlign||t.xAlign||mo(e,t,n,a),yAlign:a}}function go(e,t,n,a){const{caretSize:i,caretPadding:r,cornerRadius:o}=e,{xAlign:s,yAlign:l}=n,u=i+r,{topLeft:c,topRight:d,bottomLeft:h,bottomRight:p}=vn(o);let f=function(e,t){let{x:n,width:a}=e;return"right"===t?n-=a:"center"===t&&(n-=a/2),n}(t,s);const m=function(e,t,n){let{y:a,height:i}=e;return"top"===t?a+=n:a-="bottom"===t?i+n:i/2,a}(t,l,u);return"center"===l?"left"===s?f+=u:"right"===s&&(f-=u):"left"===s?f-=Math.max(c,h)+i:"right"===s&&(f+=Math.max(d,p)+i),{x:J(f,0,a.width-t.width),y:J(m,0,a.height-t.height)}}function vo(e,t,n){const a=bn(n.padding);return"center"===t?e.x+e.width/2:"right"===t?e.x+e.width-a.right:e.x+a.left}function bo(e){return co([],ho(e))}function yo(e,t){const n=t&&t.dataset&&t.dataset.tooltip&&t.dataset.tooltip.callbacks;return n?e.override(n):e}const wo={beforeTitle:t,title(e){if(e.length>0){const t=e[0],n=t.chart.data.labels,a=n?n.length:0;if(this&&this.options&&"dataset"===this.options.mode)return t.dataset.label||"";if(t.label)return t.label;if(a>0&&t.dataIndex{const t={before:[],lines:[],after:[]},i=yo(n,e);co(t.before,ho(ko(i,"beforeLabel",this,e))),co(t.lines,ko(i,"label",this,e)),co(t.after,ho(ko(i,"afterLabel",this,e))),a.push(t)}),a}getAfterBody(e,t){return bo(ko(t.callbacks,"afterBody",this,e))}getFooter(e,t){const{callbacks:n}=t,a=ko(n,"beforeFooter",this,e),i=ko(n,"footer",this,e),r=ko(n,"afterFooter",this,e);let o=[];return o=co(o,ho(a)),o=co(o,ho(i)),o=co(o,ho(r)),o}_createItems(e){const t=this._active,n=this.chart.data,a=[],i=[],r=[];let o,s,l=[];for(o=0,s=t.length;oe.filter(t,a,i,n))),e.itemSort&&(l=l.sort((t,a)=>e.itemSort(t,a,n))),h(l,t=>{const n=yo(e.callbacks,t);a.push(ko(n,"labelColor",this,t)),i.push(ko(n,"labelPointStyle",this,t)),r.push(ko(n,"labelTextColor",this,t))}),this.labelColors=a,this.labelPointStyles=i,this.labelTextColors=r,this.dataPoints=l,l}update(e,t){const n=this.options.setContext(this.getContext()),a=this._active;let i,r=[];if(a.length){const e=uo[n.position].call(this,a,this._eventPosition);r=this._createItems(n),this.title=this.getTitle(r,n),this.beforeBody=this.getBeforeBody(r,n),this.body=this.getBody(r,n),this.afterBody=this.getAfterBody(r,n),this.footer=this.getFooter(r,n);const t=this._size=fo(this,n),o=Object.assign({},e,t),s=_o(this.chart,n,o),l=go(n,o,s,this.chart);this.xAlign=s.xAlign,this.yAlign=s.yAlign,i={opacity:1,x:l.x,y:l.y,width:t.width,height:t.height,caretX:e.x,caretY:e.y}}else 0!==this.opacity&&(i={opacity:0});this._tooltipItems=r,this.$context=void 0,i&&this._resolveAnimations().update(this,i),e&&n.external&&n.external.call(this,{chart:this.chart,tooltip:this,replay:t})}drawCaret(e,t,n,a){const i=this.getCaretPosition(e,n,a);t.lineTo(i.x1,i.y1),t.lineTo(i.x2,i.y2),t.lineTo(i.x3,i.y3)}getCaretPosition(e,t,n){const{xAlign:a,yAlign:i}=this,{caretSize:r,cornerRadius:o}=n,{topLeft:s,topRight:l,bottomLeft:u,bottomRight:c}=vn(o),{x:d,y:h}=e,{width:p,height:f}=t;let m,_,g,v,b,y;return"center"===i?(b=h+f/2,"left"===a?(m=d,_=m-r,v=b+r,y=b-r):(m=d+p,_=m+r,v=b-r,y=b+r),g=m):(_="left"===a?d+Math.max(s,u)+r:"right"===a?d+p-Math.max(l,c)-r:this.caretX,"top"===i?(v=h,b=v-r,m=_-r,g=_+r):(v=h+f,b=v+r,m=_+r,g=_-r),y=v),{x1:m,x2:_,x3:g,y1:v,y2:b,y3:y}}drawTitle(e,t,n){const a=this.title,i=a.length;let r,o,s;if(i){const l=Sn(n.rtl,this.x,this.width);for(e.x=vo(this,n.titleAlign,n),t.textAlign=l.textAlign(n.titleAlign),t.textBaseline="middle",r=yn(n.titleFont),o=n.titleSpacing,t.fillStyle=n.titleColor,t.font=r.string,s=0;s0!==e)?(e.beginPath(),e.fillStyle=i.multiKeyBackground,Ot(e,{x:t,y:f,w:u,h:l,radius:s}),e.fill(),e.stroke(),e.fillStyle=o.backgroundColor,e.beginPath(),Ot(e,{x:n,y:f+1,w:u-2,h:l-2,radius:s}),e.fill()):(e.fillStyle=i.multiKeyBackground,e.fillRect(t,f,u,l),e.strokeRect(t,f,u,l),e.fillStyle=o.backgroundColor,e.fillRect(n,f+1,u-2,l-2))}e.fillStyle=this.labelTextColors[n]}drawBody(e,t,n){const{body:a}=this,{bodySpacing:i,bodyAlign:r,displayColors:o,boxHeight:s,boxWidth:l,boxPadding:u}=n,c=yn(n.bodyFont);let d=c.lineHeight,p=0;const f=Sn(n.rtl,this.x,this.width),m=function(n){t.fillText(n,f.x(e.x+p),e.y+d/2),e.y+=d+i},_=f.textAlign(r);let g,v,b,y,w,k,x;for(t.textAlign=r,t.textBaseline="middle",t.font=c.string,e.x=vo(this,_,n),t.fillStyle=n.bodyColor,h(this.beforeBody,m),p=o&&"right"!==_?"center"===r?l/2+u:l+2+u:0,y=0,k=a.length;y0&&t.stroke()}_updateAnimationTarget(e){const t=this.chart,n=this.$animations,a=n&&n.x,i=n&&n.y;if(a||i){const n=uo[e.position].call(this,this._active,this._eventPosition);if(!n)return;const r=this._size=fo(this,e),o=Object.assign({},n,this._size),s=_o(t,e,o),l=go(e,o,s,t);a._to===l.x&&i._to===l.y||(this.xAlign=s.xAlign,this.yAlign=s.yAlign,this.width=r.width,this.height=r.height,this.caretX=n.x,this.caretY=n.y,this._resolveAnimations().update(this,l))}}_willRender(){return!!this.opacity}draw(e){const t=this.options.setContext(this.getContext());let n=this.opacity;if(!n)return;this._updateAnimationTarget(t);const a={width:this.width,height:this.height},i={x:this.x,y:this.y};n=Math.abs(n)<.001?0:n;const r=bn(t.padding),o=this.title.length||this.beforeBody.length||this.body.length||this.afterBody.length||this.footer.length;t.enabled&&o&&(e.save(),e.globalAlpha=n,this.drawBackground(i,e,a,t),Cn(e,t.textDirection),i.y+=r.top,this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),Tn(e,t.textDirection),e.restore())}getActiveElements(){return this._active||[]}setActiveElements(e,t){const n=this._active,a=e.map(({datasetIndex:e,index:t})=>{const n=this.chart.getDatasetMeta(e);if(!n)throw new Error("Cannot find a dataset at index "+e);return{datasetIndex:e,element:n.data[t],index:t}}),i=!p(n,a),r=this._positionChanged(a,t);(i||r)&&(this._active=a,this._eventPosition=t,this._ignoreReplayEvents=!0,this.update(!0))}handleEvent(e,t,n=!0){if(t&&this._ignoreReplayEvents)return!1;this._ignoreReplayEvents=!1;const a=this.options,i=this._active||[],r=this._getActiveElements(e,i,t,n),o=this._positionChanged(r,e),s=t||!p(r,i)||o;return s&&(this._active=r,(a.enabled||a.external)&&(this._eventPosition={x:e.x,y:e.y},this.update(!0,t))),s}_getActiveElements(e,t,n,a){const i=this.options;if("mouseout"===e.type)return[];if(!a)return t.filter(e=>this.chart.data.datasets[e.datasetIndex]&&void 0!==this.chart.getDatasetMeta(e.datasetIndex).controller.getParsed(e.index));const r=this.chart.getElementsAtEventForMode(e,i.mode,i,n);return i.reverse&&r.reverse(),r}_positionChanged(e,t){const{caretX:n,caretY:a,options:i}=this,r=uo[i.position].call(this,e,t);return!1!==r&&(n!==r.x||a!==r.y)}}var So={id:"tooltip",_element:xo,positioners:uo,afterInit(e,t,n){n&&(e.tooltip=new xo({chart:e,options:n}))},beforeUpdate(e,t,n){e.tooltip&&e.tooltip.initialize(n)},reset(e,t,n){e.tooltip&&e.tooltip.initialize(n)},afterDraw(e){const t=e.tooltip;if(t&&t._willRender()){const n={tooltip:t};if(!1===e.notifyPlugins("beforeTooltipDraw",{...n,cancelable:!0}))return;t.draw(e.ctx),e.notifyPlugins("afterTooltipDraw",n)}},afterEvent(e,t){if(e.tooltip){const n=t.replay;e.tooltip.handleEvent(t.event,n,t.inChartArea)&&(t.changed=!0)}},defaults:{enabled:!0,external:null,position:"average",backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",titleFont:{weight:"bold"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodyColor:"#fff",bodySpacing:2,bodyFont:{},bodyAlign:"left",footerColor:"#fff",footerSpacing:2,footerMarginTop:6,footerFont:{weight:"bold"},footerAlign:"left",padding:6,caretPadding:2,caretSize:5,cornerRadius:6,boxHeight:(e,t)=>t.bodyFont.size,boxWidth:(e,t)=>t.bodyFont.size,multiKeyBackground:"#fff",displayColors:!0,boxPadding:0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart"},animations:{numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:wo},defaultRoutes:{bodyFont:"font",footerFont:"font",titleFont:"font"},descriptors:{_scriptable:e=>"filter"!==e&&"itemSort"!==e&&"external"!==e,_indexable:!1,callbacks:{_scriptable:!1,_indexable:!1},animation:{_fallback:!1},animations:{_fallback:"animation"}},additionalOptionScopes:["interaction"]};return wi.register(Oi,Pr,er,e),wi.helpers={...jn},wi._adapters=Ci,wi.Animation=xa,wi.Animations=Sa,wi.animator=ge,wi.controllers=Ya.controllers.items,wi.DatasetController=Oa,wi.Element=ja,wi.elements=er,wi.Interaction=Un,wi.layouts=ta,wi.platforms=ya,wi.Scale=Ga,wi.Ticks=nt,Object.assign(wi,Oi,Pr,er,e,ya),wi.Chart=wi,"undefined"!=typeof window&&(window.Chart=wi),wi}),/*! showdown v 2.1.0 - 21-04-2022 */ +function(){function e(e){"use strict";var t={omitExtraWLInCodeBlocks:{defaultValue:!1,describe:"Omit the default extra whiteline added to code blocks",type:"boolean"},noHeaderId:{defaultValue:!1,describe:"Turn on/off generated header id",type:"boolean"},prefixHeaderId:{defaultValue:!1,describe:"Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic 'section-' prefix",type:"string"},rawPrefixHeaderId:{defaultValue:!1,describe:'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',type:"boolean"},ghCompatibleHeaderId:{defaultValue:!1,describe:"Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)",type:"boolean"},rawHeaderId:{defaultValue:!1,describe:"Remove only spaces, ' and \" from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids",type:"boolean"},headerLevelStart:{defaultValue:!1,describe:"The header blocks level start",type:"integer"},parseImgDimensions:{defaultValue:!1,describe:"Turn on/off image dimension parsing",type:"boolean"},simplifiedAutoLink:{defaultValue:!1,describe:"Turn on/off GFM autolink style",type:"boolean"},excludeTrailingPunctuationFromURLs:{defaultValue:!1,describe:"Excludes trailing punctuation from links generated with autoLinking",type:"boolean"},literalMidWordUnderscores:{defaultValue:!1,describe:"Parse midword underscores as literal underscores",type:"boolean"},literalMidWordAsterisks:{defaultValue:!1,describe:"Parse midword asterisks as literal asterisks",type:"boolean"},strikethrough:{defaultValue:!1,describe:"Turn on/off strikethrough support",type:"boolean"},tables:{defaultValue:!1,describe:"Turn on/off tables support",type:"boolean"},tablesHeaderId:{defaultValue:!1,describe:"Add an id to table headers",type:"boolean"},ghCodeBlocks:{defaultValue:!0,describe:"Turn on/off GFM fenced code blocks support",type:"boolean"},tasklists:{defaultValue:!1,describe:"Turn on/off GFM tasklist support",type:"boolean"},smoothLivePreview:{defaultValue:!1,describe:"Prevents weird effects in live previews due to incomplete input",type:"boolean"},smartIndentationFix:{defaultValue:!1,describe:"Tries to smartly fix indentation in es6 strings",type:"boolean"},disableForced4SpacesIndentedSublists:{defaultValue:!1,describe:"Disables the requirement of indenting nested sublists by 4 spaces",type:"boolean"},simpleLineBreaks:{defaultValue:!1,describe:"Parses simple line breaks as
(GFM Style)",type:"boolean"},requireSpaceBeforeHeadingText:{defaultValue:!1,describe:"Makes adding a space between `#` and the header text mandatory (GFM Style)",type:"boolean"},ghMentions:{defaultValue:!1,describe:"Enables github @mentions",type:"boolean"},ghMentionsLink:{defaultValue:"https://github.com/{u}",describe:"Changes the link generated by @mentions. Only applies if ghMentions option is enabled.",type:"string"},encodeEmails:{defaultValue:!0,describe:"Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities",type:"boolean"},openLinksInNewWindow:{defaultValue:!1,describe:"Open all links in new windows",type:"boolean"},backslashEscapesHTMLTags:{defaultValue:!1,describe:"Support for HTML Tag escaping. ex:
foo
",type:"boolean"},emoji:{defaultValue:!1,describe:"Enable emoji support. Ex: `this is a :smile: emoji`",type:"boolean"},underline:{defaultValue:!1,describe:"Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `` and ``",type:"boolean"},ellipsis:{defaultValue:!0,describe:"Replaces three dots with the ellipsis unicode character",type:"boolean"},completeHTMLDocument:{defaultValue:!1,describe:"Outputs a complete html document, including ``, `` and `` tags",type:"boolean"},metadata:{defaultValue:!1,describe:"Enable support for document metadata (defined at the top of the document between `«««` and `»»»` or between `---` and `---`).",type:"boolean"},splitAdjacentBlockquotes:{defaultValue:!1,describe:"Split adjacent blockquote blocks",type:"boolean"}};if(!1===e)return JSON.parse(JSON.stringify(t));var n={};for(var a in t)t.hasOwnProperty(a)&&(n[a]=t[a].defaultValue);return n}var t={},n={},a={},i=e(!0),r="vanilla",o={github:{omitExtraWLInCodeBlocks:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,disableForced4SpacesIndentedSublists:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghCompatibleHeaderId:!0,ghMentions:!0,backslashEscapesHTMLTags:!0,emoji:!0,splitAdjacentBlockquotes:!0},original:{noHeaderId:!0,ghCodeBlocks:!1},ghost:{omitExtraWLInCodeBlocks:!0,parseImgDimensions:!0,simplifiedAutoLink:!0,excludeTrailingPunctuationFromURLs:!0,literalMidWordUnderscores:!0,strikethrough:!0,tables:!0,tablesHeaderId:!0,ghCodeBlocks:!0,tasklists:!0,smoothLivePreview:!0,simpleLineBreaks:!0,requireSpaceBeforeHeadingText:!0,ghMentions:!1,encodeEmails:!0},vanilla:e(!0),allOn:function(){"use strict";var t=e(!0),n={};for(var a in t)t.hasOwnProperty(a)&&(n[a]=!0);return n}()};function s(e,n){"use strict";var a=n?"Error in "+n+" extension->":"Error in unnamed extension",i={valid:!0,error:""};t.helper.isArray(e)||(e=[e]);for(var r=0;r").replace(/&/g,"&")};var u=function(e,t,n,a){"use strict";var i,r,o,s,l,u=a||"",c=u.indexOf("g")>-1,d=new RegExp(t+"|"+n,"g"+u.replace(/g/g,"")),h=new RegExp(t,u.replace(/g/g,"")),p=[];do{for(i=0;o=d.exec(e);)if(h.test(o[0]))i++||(s=(r=d.lastIndex)-o[0].length);else if(i&&! --i){l=o.index+o[0].length;var f={left:{start:s,end:r},match:{start:r,end:o.index},right:{start:o.index,end:l},wholeMatch:{start:s,end:l}};if(p.push(f),!c)return p}}while(i&&(d.lastIndex=r));return p};t.helper.matchRecursiveRegExp=function(e,t,n,a){"use strict";for(var i=u(e,t,n,a),r=[],o=0;o0){var d=[];0!==s[0].wholeMatch.start&&d.push(e.slice(0,s[0].wholeMatch.start));for(var h=0;h=0?i+(a||0):i},t.helper.splitAtIndex=function(e,n){"use strict";if(!t.helper.isString(e))throw"InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string";return[e.substring(0,n),e.substring(n)]},t.helper.encodeEmailAddress=function(e){"use strict";var t=[function(e){return"&#"+e.charCodeAt(0)+";"},function(e){return"&#x"+e.charCodeAt(0).toString(16)+";"},function(e){return e}];return e=e.replace(/./g,function(e){if("@"===e)e=t[Math.floor(2*Math.random())](e);else{var n=Math.random();e=n>.9?t[2](e):n>.45?t[1](e):t[0](e)}return e})},t.helper.padEnd=function(e,t,n){"use strict";return t|=0,n=String(n||" "),e.length>t?String(e):((t-=e.length)>n.length&&(n+=n.repeat(t/n.length)),String(e)+n.slice(0,t))},"undefined"==typeof console&&(console={warn:function(e){"use strict";alert(e)},log:function(e){"use strict";alert(e)},error:function(e){"use strict";throw e}}),t.helper.regexes={asteriskDashAndColon:/([*_:~])/g},t.helper.emojis={"+1":"👍","-1":"👎",100:"💯",1234:"🔢","1st_place_medal":"🥇","2nd_place_medal":"🥈","3rd_place_medal":"🥉","8ball":"🎱",a:"🅰️",ab:"🆎",abc:"🔤",abcd:"🔡",accept:"🉑",aerial_tramway:"🚡",airplane:"✈️",alarm_clock:"⏰",alembic:"⚗️",alien:"👽",ambulance:"🚑",amphora:"🏺",anchor:"⚓️",angel:"👼",anger:"💢",angry:"😠",anguished:"😧",ant:"🐜",apple:"🍎",aquarius:"♒️",aries:"♈️",arrow_backward:"◀️",arrow_double_down:"⏬",arrow_double_up:"⏫",arrow_down:"⬇️",arrow_down_small:"🔽",arrow_forward:"▶️",arrow_heading_down:"⤵️",arrow_heading_up:"⤴️",arrow_left:"⬅️",arrow_lower_left:"↙️",arrow_lower_right:"↘️",arrow_right:"➡️",arrow_right_hook:"↪️",arrow_up:"⬆️",arrow_up_down:"↕️",arrow_up_small:"🔼",arrow_upper_left:"↖️",arrow_upper_right:"↗️",arrows_clockwise:"🔃",arrows_counterclockwise:"🔄",art:"🎨",articulated_lorry:"🚛",artificial_satellite:"🛰",astonished:"😲",athletic_shoe:"👟",atm:"🏧",atom_symbol:"⚛️",avocado:"🥑",b:"🅱️",baby:"👶",baby_bottle:"🍼",baby_chick:"🐤",baby_symbol:"🚼",back:"🔙",bacon:"🥓",badminton:"🏸",baggage_claim:"🛄",baguette_bread:"🥖",balance_scale:"⚖️",balloon:"🎈",ballot_box:"🗳",ballot_box_with_check:"☑️",bamboo:"🎍",banana:"🍌",bangbang:"‼️",bank:"🏦",bar_chart:"📊",barber:"💈",baseball:"⚾️",basketball:"🏀",basketball_man:"⛹️",basketball_woman:"⛹️‍♀️",bat:"🦇",bath:"🛀",bathtub:"🛁",battery:"🔋",beach_umbrella:"🏖",bear:"🐻",bed:"🛏",bee:"🐝",beer:"🍺",beers:"🍻",beetle:"🐞",beginner:"🔰",bell:"🔔",bellhop_bell:"🛎",bento:"🍱",biking_man:"🚴",bike:"🚲",biking_woman:"🚴‍♀️",bikini:"👙",biohazard:"☣️",bird:"🐦",birthday:"🎂",black_circle:"⚫️",black_flag:"🏴",black_heart:"🖤",black_joker:"🃏",black_large_square:"⬛️",black_medium_small_square:"◾️",black_medium_square:"◼️",black_nib:"✒️",black_small_square:"▪️",black_square_button:"🔲",blonde_man:"👱",blonde_woman:"👱‍♀️",blossom:"🌼",blowfish:"🐡",blue_book:"📘",blue_car:"🚙",blue_heart:"💙",blush:"😊",boar:"🐗",boat:"⛵️",bomb:"💣",book:"📖",bookmark:"🔖",bookmark_tabs:"📑",books:"📚",boom:"💥",boot:"👢",bouquet:"💐",bowing_man:"🙇",bow_and_arrow:"🏹",bowing_woman:"🙇‍♀️",bowling:"🎳",boxing_glove:"🥊",boy:"👦",bread:"🍞",bride_with_veil:"👰",bridge_at_night:"🌉",briefcase:"💼",broken_heart:"💔",bug:"🐛",building_construction:"🏗",bulb:"💡",bullettrain_front:"🚅",bullettrain_side:"🚄",burrito:"🌯",bus:"🚌",business_suit_levitating:"🕴",busstop:"🚏",bust_in_silhouette:"👤",busts_in_silhouette:"👥",butterfly:"🦋",cactus:"🌵",cake:"🍰",calendar:"📆",call_me_hand:"🤙",calling:"📲",camel:"🐫",camera:"📷",camera_flash:"📸",camping:"🏕",cancer:"♋️",candle:"🕯",candy:"🍬",canoe:"🛶",capital_abcd:"🔠",capricorn:"♑️",car:"🚗",card_file_box:"🗃",card_index:"📇",card_index_dividers:"🗂",carousel_horse:"🎠",carrot:"🥕",cat:"🐱",cat2:"🐈",cd:"💿",chains:"⛓",champagne:"🍾",chart:"💹",chart_with_downwards_trend:"📉",chart_with_upwards_trend:"📈",checkered_flag:"🏁",cheese:"🧀",cherries:"🍒",cherry_blossom:"🌸",chestnut:"🌰",chicken:"🐔",children_crossing:"🚸",chipmunk:"🐿",chocolate_bar:"🍫",christmas_tree:"🎄",church:"⛪️",cinema:"🎦",circus_tent:"🎪",city_sunrise:"🌇",city_sunset:"🌆",cityscape:"🏙",cl:"🆑",clamp:"🗜",clap:"👏",clapper:"🎬",classical_building:"🏛",clinking_glasses:"🥂",clipboard:"📋",clock1:"🕐",clock10:"🕙",clock1030:"🕥",clock11:"🕚",clock1130:"🕦",clock12:"🕛",clock1230:"🕧",clock130:"🕜",clock2:"🕑",clock230:"🕝",clock3:"🕒",clock330:"🕞",clock4:"🕓",clock430:"🕟",clock5:"🕔",clock530:"🕠",clock6:"🕕",clock630:"🕡",clock7:"🕖",clock730:"🕢",clock8:"🕗",clock830:"🕣",clock9:"🕘",clock930:"🕤",closed_book:"📕",closed_lock_with_key:"🔐",closed_umbrella:"🌂",cloud:"☁️",cloud_with_lightning:"🌩",cloud_with_lightning_and_rain:"⛈",cloud_with_rain:"🌧",cloud_with_snow:"🌨",clown_face:"🤡",clubs:"♣️",cocktail:"🍸",coffee:"☕️",coffin:"⚰️",cold_sweat:"😰",comet:"☄️",computer:"💻",computer_mouse:"🖱",confetti_ball:"🎊",confounded:"😖",confused:"😕",congratulations:"㊗️",construction:"🚧",construction_worker_man:"👷",construction_worker_woman:"👷‍♀️",control_knobs:"🎛",convenience_store:"🏪",cookie:"🍪",cool:"🆒",policeman:"👮",copyright:"©️",corn:"🌽",couch_and_lamp:"🛋",couple:"👫",couple_with_heart_woman_man:"💑",couple_with_heart_man_man:"👨‍❤️‍👨",couple_with_heart_woman_woman:"👩‍❤️‍👩",couplekiss_man_man:"👨‍❤️‍💋‍👨",couplekiss_man_woman:"💏",couplekiss_woman_woman:"👩‍❤️‍💋‍👩",cow:"🐮",cow2:"🐄",cowboy_hat_face:"🤠",crab:"🦀",crayon:"🖍",credit_card:"💳",crescent_moon:"🌙",cricket:"🏏",crocodile:"🐊",croissant:"🥐",crossed_fingers:"🤞",crossed_flags:"🎌",crossed_swords:"⚔️",crown:"👑",cry:"😢",crying_cat_face:"😿",crystal_ball:"🔮",cucumber:"🥒",cupid:"💘",curly_loop:"➰",currency_exchange:"💱",curry:"🍛",custard:"🍮",customs:"🛃",cyclone:"🌀",dagger:"🗡",dancer:"💃",dancing_women:"👯",dancing_men:"👯‍♂️",dango:"🍡",dark_sunglasses:"🕶",dart:"🎯",dash:"💨",date:"📅",deciduous_tree:"🌳",deer:"🦌",department_store:"🏬",derelict_house:"🏚",desert:"🏜",desert_island:"🏝",desktop_computer:"🖥",male_detective:"🕵️",diamond_shape_with_a_dot_inside:"💠",diamonds:"♦️",disappointed:"😞",disappointed_relieved:"😥",dizzy:"💫",dizzy_face:"😵",do_not_litter:"🚯",dog:"🐶",dog2:"🐕",dollar:"💵",dolls:"🎎",dolphin:"🐬",door:"🚪",doughnut:"🍩",dove:"🕊",dragon:"🐉",dragon_face:"🐲",dress:"👗",dromedary_camel:"🐪",drooling_face:"🤤",droplet:"💧",drum:"🥁",duck:"🦆",dvd:"📀","e-mail":"📧",eagle:"🦅",ear:"👂",ear_of_rice:"🌾",earth_africa:"🌍",earth_americas:"🌎",earth_asia:"🌏",egg:"🥚",eggplant:"🍆",eight_pointed_black_star:"✴️",eight_spoked_asterisk:"✳️",electric_plug:"🔌",elephant:"🐘",email:"✉️",end:"🔚",envelope_with_arrow:"📩",euro:"💶",european_castle:"🏰",european_post_office:"🏤",evergreen_tree:"🌲",exclamation:"❗️",expressionless:"😑",eye:"👁",eye_speech_bubble:"👁‍🗨",eyeglasses:"👓",eyes:"👀",face_with_head_bandage:"🤕",face_with_thermometer:"🤒",fist_oncoming:"👊",factory:"🏭",fallen_leaf:"🍂",family_man_woman_boy:"👪",family_man_boy:"👨‍👦",family_man_boy_boy:"👨‍👦‍👦",family_man_girl:"👨‍👧",family_man_girl_boy:"👨‍👧‍👦",family_man_girl_girl:"👨‍👧‍👧",family_man_man_boy:"👨‍👨‍👦",family_man_man_boy_boy:"👨‍👨‍👦‍👦",family_man_man_girl:"👨‍👨‍👧",family_man_man_girl_boy:"👨‍👨‍👧‍👦",family_man_man_girl_girl:"👨‍👨‍👧‍👧",family_man_woman_boy_boy:"👨‍👩‍👦‍👦",family_man_woman_girl:"👨‍👩‍👧",family_man_woman_girl_boy:"👨‍👩‍👧‍👦",family_man_woman_girl_girl:"👨‍👩‍👧‍👧",family_woman_boy:"👩‍👦",family_woman_boy_boy:"👩‍👦‍👦",family_woman_girl:"👩‍👧",family_woman_girl_boy:"👩‍👧‍👦",family_woman_girl_girl:"👩‍👧‍👧",family_woman_woman_boy:"👩‍👩‍👦",family_woman_woman_boy_boy:"👩‍👩‍👦‍👦",family_woman_woman_girl:"👩‍👩‍👧",family_woman_woman_girl_boy:"👩‍👩‍👧‍👦",family_woman_woman_girl_girl:"👩‍👩‍👧‍👧",fast_forward:"⏩",fax:"📠",fearful:"😨",feet:"🐾",female_detective:"🕵️‍♀️",ferris_wheel:"🎡",ferry:"⛴",field_hockey:"🏑",file_cabinet:"🗄",file_folder:"📁",film_projector:"📽",film_strip:"🎞",fire:"🔥",fire_engine:"🚒",fireworks:"🎆",first_quarter_moon:"🌓",first_quarter_moon_with_face:"🌛",fish:"🐟",fish_cake:"🍥",fishing_pole_and_fish:"🎣",fist_raised:"✊",fist_left:"🤛",fist_right:"🤜",flags:"🎏",flashlight:"🔦",fleur_de_lis:"⚜️",flight_arrival:"🛬",flight_departure:"🛫",floppy_disk:"💾",flower_playing_cards:"🎴",flushed:"😳",fog:"🌫",foggy:"🌁",football:"🏈",footprints:"👣",fork_and_knife:"🍴",fountain:"⛲️",fountain_pen:"🖋",four_leaf_clover:"🍀",fox_face:"🦊",framed_picture:"🖼",free:"🆓",fried_egg:"🍳",fried_shrimp:"🍤",fries:"🍟",frog:"🐸",frowning:"😦",frowning_face:"☹️",frowning_man:"🙍‍♂️",frowning_woman:"🙍",middle_finger:"🖕",fuelpump:"⛽️",full_moon:"🌕",full_moon_with_face:"🌝",funeral_urn:"⚱️",game_die:"🎲",gear:"⚙️",gem:"💎",gemini:"♊️",ghost:"👻",gift:"🎁",gift_heart:"💝",girl:"👧",globe_with_meridians:"🌐",goal_net:"🥅",goat:"🐐",golf:"⛳️",golfing_man:"🏌️",golfing_woman:"🏌️‍♀️",gorilla:"🦍",grapes:"🍇",green_apple:"🍏",green_book:"📗",green_heart:"💚",green_salad:"🥗",grey_exclamation:"❕",grey_question:"❔",grimacing:"😬",grin:"😁",grinning:"😀",guardsman:"💂",guardswoman:"💂‍♀️",guitar:"🎸",gun:"🔫",haircut_woman:"💇",haircut_man:"💇‍♂️",hamburger:"🍔",hammer:"🔨",hammer_and_pick:"⚒",hammer_and_wrench:"🛠",hamster:"🐹",hand:"✋",handbag:"👜",handshake:"🤝",hankey:"💩",hatched_chick:"🐥",hatching_chick:"🐣",headphones:"🎧",hear_no_evil:"🙉",heart:"❤️",heart_decoration:"💟",heart_eyes:"😍",heart_eyes_cat:"😻",heartbeat:"💓",heartpulse:"💗",hearts:"♥️",heavy_check_mark:"✔️",heavy_division_sign:"➗",heavy_dollar_sign:"💲",heavy_heart_exclamation:"❣️",heavy_minus_sign:"➖",heavy_multiplication_x:"✖️",heavy_plus_sign:"➕",helicopter:"🚁",herb:"🌿",hibiscus:"🌺",high_brightness:"🔆",high_heel:"👠",hocho:"🔪",hole:"🕳",honey_pot:"🍯",horse:"🐴",horse_racing:"🏇",hospital:"🏥",hot_pepper:"🌶",hotdog:"🌭",hotel:"🏨",hotsprings:"♨️",hourglass:"⌛️",hourglass_flowing_sand:"⏳",house:"🏠",house_with_garden:"🏡",houses:"🏘",hugs:"🤗",hushed:"😯",ice_cream:"🍨",ice_hockey:"🏒",ice_skate:"⛸",icecream:"🍦",id:"🆔",ideograph_advantage:"🉐",imp:"👿",inbox_tray:"📥",incoming_envelope:"📨",tipping_hand_woman:"💁",information_source:"ℹ️",innocent:"😇",interrobang:"⁉️",iphone:"📱",izakaya_lantern:"🏮",jack_o_lantern:"🎃",japan:"🗾",japanese_castle:"🏯",japanese_goblin:"👺",japanese_ogre:"👹",jeans:"👖",joy:"😂",joy_cat:"😹",joystick:"🕹",kaaba:"🕋",key:"🔑",keyboard:"⌨️",keycap_ten:"🔟",kick_scooter:"🛴",kimono:"👘",kiss:"💋",kissing:"😗",kissing_cat:"😽",kissing_closed_eyes:"😚",kissing_heart:"😘",kissing_smiling_eyes:"😙",kiwi_fruit:"🥝",koala:"🐨",koko:"🈁",label:"🏷",large_blue_circle:"🔵",large_blue_diamond:"🔷",large_orange_diamond:"🔶",last_quarter_moon:"🌗",last_quarter_moon_with_face:"🌜",latin_cross:"✝️",laughing:"😆",leaves:"🍃",ledger:"📒",left_luggage:"🛅",left_right_arrow:"↔️",leftwards_arrow_with_hook:"↩️",lemon:"🍋",leo:"♌️",leopard:"🐆",level_slider:"🎚",libra:"♎️",light_rail:"🚈",link:"🔗",lion:"🦁",lips:"👄",lipstick:"💄",lizard:"🦎",lock:"🔒",lock_with_ink_pen:"🔏",lollipop:"🍭",loop:"➿",loud_sound:"🔊",loudspeaker:"📢",love_hotel:"🏩",love_letter:"💌",low_brightness:"🔅",lying_face:"🤥",m:"Ⓜ️",mag:"🔍",mag_right:"🔎",mahjong:"🀄️",mailbox:"📫",mailbox_closed:"📪",mailbox_with_mail:"📬",mailbox_with_no_mail:"📭",man:"👨",man_artist:"👨‍🎨",man_astronaut:"👨‍🚀",man_cartwheeling:"🤸‍♂️",man_cook:"👨‍🍳",man_dancing:"🕺",man_facepalming:"🤦‍♂️",man_factory_worker:"👨‍🏭",man_farmer:"👨‍🌾",man_firefighter:"👨‍🚒",man_health_worker:"👨‍⚕️",man_in_tuxedo:"🤵",man_judge:"👨‍⚖️",man_juggling:"🤹‍♂️",man_mechanic:"👨‍🔧",man_office_worker:"👨‍💼",man_pilot:"👨‍✈️",man_playing_handball:"🤾‍♂️",man_playing_water_polo:"🤽‍♂️",man_scientist:"👨‍🔬",man_shrugging:"🤷‍♂️",man_singer:"👨‍🎤",man_student:"👨‍🎓",man_teacher:"👨‍🏫",man_technologist:"👨‍💻",man_with_gua_pi_mao:"👲",man_with_turban:"👳",tangerine:"🍊",mans_shoe:"👞",mantelpiece_clock:"🕰",maple_leaf:"🍁",martial_arts_uniform:"🥋",mask:"😷",massage_woman:"💆",massage_man:"💆‍♂️",meat_on_bone:"🍖",medal_military:"🎖",medal_sports:"🏅",mega:"📣",melon:"🍈",memo:"📝",men_wrestling:"🤼‍♂️",menorah:"🕎",mens:"🚹",metal:"🤘",metro:"🚇",microphone:"🎤",microscope:"🔬",milk_glass:"🥛",milky_way:"🌌",minibus:"🚐",minidisc:"💽",mobile_phone_off:"📴",money_mouth_face:"🤑",money_with_wings:"💸",moneybag:"💰",monkey:"🐒",monkey_face:"🐵",monorail:"🚝",moon:"🌔",mortar_board:"🎓",mosque:"🕌",motor_boat:"🛥",motor_scooter:"🛵",motorcycle:"🏍",motorway:"🛣",mount_fuji:"🗻",mountain:"⛰",mountain_biking_man:"🚵",mountain_biking_woman:"🚵‍♀️",mountain_cableway:"🚠",mountain_railway:"🚞",mountain_snow:"🏔",mouse:"🐭",mouse2:"🐁",movie_camera:"🎥",moyai:"🗿",mrs_claus:"🤶",muscle:"💪",mushroom:"🍄",musical_keyboard:"🎹",musical_note:"🎵",musical_score:"🎼",mute:"🔇",nail_care:"💅",name_badge:"📛",national_park:"🏞",nauseated_face:"🤢",necktie:"👔",negative_squared_cross_mark:"❎",nerd_face:"🤓",neutral_face:"😐",new:"🆕",new_moon:"🌑",new_moon_with_face:"🌚",newspaper:"📰",newspaper_roll:"🗞",next_track_button:"⏭",ng:"🆖",no_good_man:"🙅‍♂️",no_good_woman:"🙅",night_with_stars:"🌃",no_bell:"🔕",no_bicycles:"🚳",no_entry:"⛔️",no_entry_sign:"🚫",no_mobile_phones:"📵",no_mouth:"😶",no_pedestrians:"🚷",no_smoking:"🚭","non-potable_water":"🚱",nose:"👃",notebook:"📓",notebook_with_decorative_cover:"📔",notes:"🎶",nut_and_bolt:"🔩",o:"⭕️",o2:"🅾️",ocean:"🌊",octopus:"🐙",oden:"🍢",office:"🏢",oil_drum:"🛢",ok:"🆗",ok_hand:"👌",ok_man:"🙆‍♂️",ok_woman:"🙆",old_key:"🗝",older_man:"👴",older_woman:"👵",om:"🕉",on:"🔛",oncoming_automobile:"🚘",oncoming_bus:"🚍",oncoming_police_car:"🚔",oncoming_taxi:"🚖",open_file_folder:"📂",open_hands:"👐",open_mouth:"😮",open_umbrella:"☂️",ophiuchus:"⛎",orange_book:"📙",orthodox_cross:"☦️",outbox_tray:"📤",owl:"🦉",ox:"🐂",package:"📦",page_facing_up:"📄",page_with_curl:"📃",pager:"📟",paintbrush:"🖌",palm_tree:"🌴",pancakes:"🥞",panda_face:"🐼",paperclip:"📎",paperclips:"🖇",parasol_on_ground:"⛱",parking:"🅿️",part_alternation_mark:"〽️",partly_sunny:"⛅️",passenger_ship:"🛳",passport_control:"🛂",pause_button:"⏸",peace_symbol:"☮️",peach:"🍑",peanuts:"🥜",pear:"🍐",pen:"🖊",pencil2:"✏️",penguin:"🐧",pensive:"😔",performing_arts:"🎭",persevere:"😣",person_fencing:"🤺",pouting_woman:"🙎",phone:"☎️",pick:"⛏",pig:"🐷",pig2:"🐖",pig_nose:"🐽",pill:"💊",pineapple:"🍍",ping_pong:"🏓",pisces:"♓️",pizza:"🍕",place_of_worship:"🛐",plate_with_cutlery:"🍽",play_or_pause_button:"⏯",point_down:"👇",point_left:"👈",point_right:"👉",point_up:"☝️",point_up_2:"👆",police_car:"🚓",policewoman:"👮‍♀️",poodle:"🐩",popcorn:"🍿",post_office:"🏣",postal_horn:"📯",postbox:"📮",potable_water:"🚰",potato:"🥔",pouch:"👝",poultry_leg:"🍗",pound:"💷",rage:"😡",pouting_cat:"😾",pouting_man:"🙎‍♂️",pray:"🙏",prayer_beads:"📿",pregnant_woman:"🤰",previous_track_button:"⏮",prince:"🤴",princess:"👸",printer:"🖨",purple_heart:"💜",purse:"👛",pushpin:"📌",put_litter_in_its_place:"🚮",question:"❓",rabbit:"🐰",rabbit2:"🐇",racehorse:"🐎",racing_car:"🏎",radio:"📻",radio_button:"🔘",radioactive:"☢️",railway_car:"🚃",railway_track:"🛤",rainbow:"🌈",rainbow_flag:"🏳️‍🌈",raised_back_of_hand:"🤚",raised_hand_with_fingers_splayed:"🖐",raised_hands:"🙌",raising_hand_woman:"🙋",raising_hand_man:"🙋‍♂️",ram:"🐏",ramen:"🍜",rat:"🐀",record_button:"⏺",recycle:"♻️",red_circle:"🔴",registered:"®️",relaxed:"☺️",relieved:"😌",reminder_ribbon:"🎗",repeat:"🔁",repeat_one:"🔂",rescue_worker_helmet:"⛑",restroom:"🚻",revolving_hearts:"💞",rewind:"⏪",rhinoceros:"🦏",ribbon:"🎀",rice:"🍚",rice_ball:"🍙",rice_cracker:"🍘",rice_scene:"🎑",right_anger_bubble:"🗯",ring:"💍",robot:"🤖",rocket:"🚀",rofl:"🤣",roll_eyes:"🙄",roller_coaster:"🎢",rooster:"🐓",rose:"🌹",rosette:"🏵",rotating_light:"🚨",round_pushpin:"📍",rowing_man:"🚣",rowing_woman:"🚣‍♀️",rugby_football:"🏉",running_man:"🏃",running_shirt_with_sash:"🎽",running_woman:"🏃‍♀️",sa:"🈂️",sagittarius:"♐️",sake:"🍶",sandal:"👡",santa:"🎅",satellite:"📡",saxophone:"🎷",school:"🏫",school_satchel:"🎒",scissors:"✂️",scorpion:"🦂",scorpius:"♏️",scream:"😱",scream_cat:"🙀",scroll:"📜",seat:"💺",secret:"㊙️",see_no_evil:"🙈",seedling:"🌱",selfie:"🤳",shallow_pan_of_food:"🥘",shamrock:"☘️",shark:"🦈",shaved_ice:"🍧",sheep:"🐑",shell:"🐚",shield:"🛡",shinto_shrine:"⛩",ship:"🚢",shirt:"👕",shopping:"🛍",shopping_cart:"🛒",shower:"🚿",shrimp:"🦐",signal_strength:"📶",six_pointed_star:"🔯",ski:"🎿",skier:"⛷",skull:"💀",skull_and_crossbones:"☠️",sleeping:"😴",sleeping_bed:"🛌",sleepy:"😪",slightly_frowning_face:"🙁",slightly_smiling_face:"🙂",slot_machine:"🎰",small_airplane:"🛩",small_blue_diamond:"🔹",small_orange_diamond:"🔸",small_red_triangle:"🔺",small_red_triangle_down:"🔻",smile:"😄",smile_cat:"😸",smiley:"😃",smiley_cat:"😺",smiling_imp:"😈",smirk:"😏",smirk_cat:"😼",smoking:"🚬",snail:"🐌",snake:"🐍",sneezing_face:"🤧",snowboarder:"🏂",snowflake:"❄️",snowman:"⛄️",snowman_with_snow:"☃️",sob:"😭",soccer:"⚽️",soon:"🔜",sos:"🆘",sound:"🔉",space_invader:"👾",spades:"♠️",spaghetti:"🍝",sparkle:"❇️",sparkler:"🎇",sparkles:"✨",sparkling_heart:"💖",speak_no_evil:"🙊",speaker:"🔈",speaking_head:"🗣",speech_balloon:"💬",speedboat:"🚤",spider:"🕷",spider_web:"🕸",spiral_calendar:"🗓",spiral_notepad:"🗒",spoon:"🥄",squid:"🦑",stadium:"🏟",star:"⭐️",star2:"🌟",star_and_crescent:"☪️",star_of_david:"✡️",stars:"🌠",station:"🚉",statue_of_liberty:"🗽",steam_locomotive:"🚂",stew:"🍲",stop_button:"⏹",stop_sign:"🛑",stopwatch:"⏱",straight_ruler:"📏",strawberry:"🍓",stuck_out_tongue:"😛",stuck_out_tongue_closed_eyes:"😝",stuck_out_tongue_winking_eye:"😜",studio_microphone:"🎙",stuffed_flatbread:"🥙",sun_behind_large_cloud:"🌥",sun_behind_rain_cloud:"🌦",sun_behind_small_cloud:"🌤",sun_with_face:"🌞",sunflower:"🌻",sunglasses:"😎",sunny:"☀️",sunrise:"🌅",sunrise_over_mountains:"🌄",surfing_man:"🏄",surfing_woman:"🏄‍♀️",sushi:"🍣",suspension_railway:"🚟",sweat:"😓",sweat_drops:"💦",sweat_smile:"😅",sweet_potato:"🍠",swimming_man:"🏊",swimming_woman:"🏊‍♀️",symbols:"🔣",synagogue:"🕍",syringe:"💉",taco:"🌮",tada:"🎉",tanabata_tree:"🎋",taurus:"♉️",taxi:"🚕",tea:"🍵",telephone_receiver:"📞",telescope:"🔭",tennis:"🎾",tent:"⛺️",thermometer:"🌡",thinking:"🤔",thought_balloon:"💭",ticket:"🎫",tickets:"🎟",tiger:"🐯",tiger2:"🐅",timer_clock:"⏲",tipping_hand_man:"💁‍♂️",tired_face:"😫",tm:"™️",toilet:"🚽",tokyo_tower:"🗼",tomato:"🍅",tongue:"👅",top:"🔝",tophat:"🎩",tornado:"🌪",trackball:"🖲",tractor:"🚜",traffic_light:"🚥",train:"🚋",train2:"🚆",tram:"🚊",triangular_flag_on_post:"🚩",triangular_ruler:"📐",trident:"🔱",triumph:"😤",trolleybus:"🚎",trophy:"🏆",tropical_drink:"🍹",tropical_fish:"🐠",truck:"🚚",trumpet:"🎺",tulip:"🌷",tumbler_glass:"🥃",turkey:"🦃",turtle:"🐢",tv:"📺",twisted_rightwards_arrows:"🔀",two_hearts:"💕",two_men_holding_hands:"👬",two_women_holding_hands:"👭",u5272:"🈹",u5408:"🈴",u55b6:"🈺",u6307:"🈯️",u6708:"🈷️",u6709:"🈶",u6e80:"🈵",u7121:"🈚️",u7533:"🈸",u7981:"🈲",u7a7a:"🈳",umbrella:"☔️",unamused:"😒",underage:"🔞",unicorn:"🦄",unlock:"🔓",up:"🆙",upside_down_face:"🙃",v:"✌️",vertical_traffic_light:"🚦",vhs:"📼",vibration_mode:"📳",video_camera:"📹",video_game:"🎮",violin:"🎻",virgo:"♍️",volcano:"🌋",volleyball:"🏐",vs:"🆚",vulcan_salute:"🖖",walking_man:"🚶",walking_woman:"🚶‍♀️",waning_crescent_moon:"🌘",waning_gibbous_moon:"🌖",warning:"⚠️",wastebasket:"🗑",watch:"⌚️",water_buffalo:"🐃",watermelon:"🍉",wave:"👋",wavy_dash:"〰️",waxing_crescent_moon:"🌒",wc:"🚾",weary:"😩",wedding:"💒",weight_lifting_man:"🏋️",weight_lifting_woman:"🏋️‍♀️",whale:"🐳",whale2:"🐋",wheel_of_dharma:"☸️",wheelchair:"♿️",white_check_mark:"✅",white_circle:"⚪️",white_flag:"🏳️",white_flower:"💮",white_large_square:"⬜️",white_medium_small_square:"◽️",white_medium_square:"◻️",white_small_square:"▫️",white_square_button:"🔳",wilted_flower:"🥀",wind_chime:"🎐",wind_face:"🌬",wine_glass:"🍷",wink:"😉",wolf:"🐺",woman:"👩",woman_artist:"👩‍🎨",woman_astronaut:"👩‍🚀",woman_cartwheeling:"🤸‍♀️",woman_cook:"👩‍🍳",woman_facepalming:"🤦‍♀️",woman_factory_worker:"👩‍🏭",woman_farmer:"👩‍🌾",woman_firefighter:"👩‍🚒",woman_health_worker:"👩‍⚕️",woman_judge:"👩‍⚖️",woman_juggling:"🤹‍♀️",woman_mechanic:"👩‍🔧",woman_office_worker:"👩‍💼",woman_pilot:"👩‍✈️",woman_playing_handball:"🤾‍♀️",woman_playing_water_polo:"🤽‍♀️",woman_scientist:"👩‍🔬",woman_shrugging:"🤷‍♀️",woman_singer:"👩‍🎤",woman_student:"👩‍🎓",woman_teacher:"👩‍🏫",woman_technologist:"👩‍💻",woman_with_turban:"👳‍♀️",womans_clothes:"👚",womans_hat:"👒",women_wrestling:"🤼‍♀️",womens:"🚺",world_map:"🗺",worried:"😟",wrench:"🔧",writing_hand:"✍️",x:"❌",yellow_heart:"💛",yen:"💴",yin_yang:"☯️",yum:"😋",zap:"⚡️",zipper_mouth_face:"🤐",zzz:"💤",octocat:':octocat:',showdown:"S"},t.Converter=function(e){"use strict";var n={},l=[],u=[],c={},d=r,h={parsed:{},raw:"",format:""};function p(e,n){if(n=n||null,t.helper.isString(e)){if(n=e=t.helper.stdExtName(e),t.extensions[e])return console.warn("DEPRECATION WARNING: "+e+" is an old extension that uses a deprecated loading method.Please inform the developer that the extension should be updated!"),void function(e,n){"function"==typeof e&&(e=e(new t.Converter));t.helper.isArray(e)||(e=[e]);var a=s(e,n);if(!a.valid)throw Error(a.error);for(var i=0;i[ \t]+¨NBSP;<"),!n){if(!window||!window.document)throw new Error("HTMLParser is undefined. If in a webworker or nodejs environment, you need to provide a WHATWG DOM and HTML such as JSDOM");n=window.document}var a=n.createElement("div");a.innerHTML=e;var i={preList:function(e){for(var n=e.querySelectorAll("pre"),a=[],i=0;i'}else a.push(n[i].innerHTML),n[i].innerHTML="",n[i].setAttribute("prenum",i.toString());return a}(a)};!function e(t){for(var n=0;n? ?(['"].*['"])?\)$/m)>-1)o="";else if(!o){if(r||(r=i.toLowerCase().replace(/ ?\n/g," ")),o="#"+r,t.helper.isUndefined(a.gUrls[r]))return e;o=a.gUrls[r],t.helper.isUndefined(a.gTitles[r])||(u=a.gTitles[r])}var c='
"};return e=(e=(e=(e=(e=a.converter._dispatch("anchors.before",e,n,a)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g,i)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,i)).replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]??(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,i)).replace(/\[([^\[\]]+)]()()()()()/g,i),n.ghMentions&&(e=e.replace(/(^|\s)(\\)?(@([a-z\d]+(?:[a-z\d.-]+?[a-z\d]+)*))/gim,function(e,a,i,r,o){if("\\"===i)return a+r;if(!t.helper.isString(n.ghMentionsLink))throw new Error("ghMentionsLink option must be a string");var s=n.ghMentionsLink.replace(/\{u}/g,o),l="";return n.openLinksInNewWindow&&(l=' rel="noopener noreferrer" target="¨E95Eblank"'),a+'"+r+""})),e=a.converter._dispatch("anchors.after",e,n,a)});var c=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,d=/([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,h=/()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,p=/(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gim,f=/<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,m=function(e){"use strict";return function(n,a,i,r,o,s,l){var u=i=i.replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback),c="",d="",h=a||"",p=l||"";return/^www\./i.test(i)&&(i=i.replace(/^www\./i,"http://www.")),e.excludeTrailingPunctuationFromURLs&&s&&(c=s),e.openLinksInNewWindow&&(d=' rel="noopener noreferrer" target="¨E95Eblank"'),h+'"+u+""+c+p}},_=function(e,n){"use strict";return function(a,i,r){var o="mailto:";return i=i||"",r=t.subParser("unescapeSpecialChars")(r,e,n),e.encodeEmails?(o=t.helper.encodeEmailAddress(o+r),r=t.helper.encodeEmailAddress(r)):o+=r,i+''+r+""}};t.subParser("autoLinks",function(e,t,n){"use strict";return e=(e=(e=n.converter._dispatch("autoLinks.before",e,t,n)).replace(h,m(t))).replace(f,_(t,n)),e=n.converter._dispatch("autoLinks.after",e,t,n)}),t.subParser("simplifiedAutoLinks",function(e,t,n){"use strict";return t.simplifiedAutoLink?(e=n.converter._dispatch("simplifiedAutoLinks.before",e,t,n),e=(e=t.excludeTrailingPunctuationFromURLs?e.replace(d,m(t)):e.replace(c,m(t))).replace(p,_(t,n)),e=n.converter._dispatch("simplifiedAutoLinks.after",e,t,n)):e}),t.subParser("blockGamut",function(e,n,a){"use strict";return e=a.converter._dispatch("blockGamut.before",e,n,a),e=t.subParser("blockQuotes")(e,n,a),e=t.subParser("headers")(e,n,a),e=t.subParser("horizontalRule")(e,n,a),e=t.subParser("lists")(e,n,a),e=t.subParser("codeBlocks")(e,n,a),e=t.subParser("tables")(e,n,a),e=t.subParser("hashHTMLBlocks")(e,n,a),e=t.subParser("paragraphs")(e,n,a),e=a.converter._dispatch("blockGamut.after",e,n,a)}),t.subParser("blockQuotes",function(e,n,a){"use strict";e=a.converter._dispatch("blockQuotes.before",e,n,a),e+="\n\n";var i=/(^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+/gm;return n.splitAdjacentBlockquotes&&(i=/^ {0,3}>[\s\S]*?(?:\n\n)/gm),e=e.replace(i,function(e){return e=(e=(e=e.replace(/^[ \t]*>[ \t]?/gm,"")).replace(/¨0/g,"")).replace(/^[ \t]+$/gm,""),e=t.subParser("githubCodeBlocks")(e,n,a),e=(e=(e=t.subParser("blockGamut")(e,n,a)).replace(/(^|\n)/g,"$1 ")).replace(/(\s*
[^\r]+?<\/pre>)/gm,function(e,t){var n=t;return n=(n=n.replace(/^  /gm,"¨0")).replace(/¨0/g,"")}),t.subParser("hashBlock")("
\n"+e+"\n
",n,a)}),e=a.converter._dispatch("blockQuotes.after",e,n,a)}),t.subParser("codeBlocks",function(e,n,a){"use strict";e=a.converter._dispatch("codeBlocks.before",e,n,a);return e=(e=(e+="¨0").replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g,function(e,i,r){var o=i,s=r,l="\n";return o=t.subParser("outdent")(o,n,a),o=t.subParser("encodeCode")(o,n,a),o=(o=(o=t.subParser("detab")(o,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,""),n.omitExtraWLInCodeBlocks&&(l=""),o="
"+o+l+"
",t.subParser("hashBlock")(o,n,a)+s})).replace(/¨0/,""),e=a.converter._dispatch("codeBlocks.after",e,n,a)}),t.subParser("codeSpans",function(e,n,a){"use strict";return void 0===(e=a.converter._dispatch("codeSpans.before",e,n,a))&&(e=""),e=e.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,i,r,o){var s=o;return s=(s=s.replace(/^([ \t]*)/g,"")).replace(/[ \t]*$/g,""),s=i+""+(s=t.subParser("encodeCode")(s,n,a))+"",s=t.subParser("hashHTMLSpans")(s,n,a)}),e=a.converter._dispatch("codeSpans.after",e,n,a)}),t.subParser("completeHTMLDocument",function(e,t,n){"use strict";if(!t.completeHTMLDocument)return e;e=n.converter._dispatch("completeHTMLDocument.before",e,t,n);var a="html",i="\n",r="",o='\n',s="",l="";for(var u in void 0!==n.metadata.parsed.doctype&&(i="\n","html"!==(a=n.metadata.parsed.doctype.toString().toLowerCase())&&"html5"!==a||(o='')),n.metadata.parsed)if(n.metadata.parsed.hasOwnProperty(u))switch(u.toLowerCase()){case"doctype":break;case"title":r=""+n.metadata.parsed.title+"\n";break;case"charset":o="html"===a||"html5"===a?'\n':'\n';break;case"language":case"lang":s=' lang="'+n.metadata.parsed[u]+'"',l+='\n';break;default:l+='\n'}return e=i+"\n\n"+r+o+l+"\n\n"+e.trim()+"\n\n",e=n.converter._dispatch("completeHTMLDocument.after",e,t,n)}),t.subParser("detab",function(e,t,n){"use strict";return e=(e=(e=(e=(e=(e=n.converter._dispatch("detab.before",e,t,n)).replace(/\t(?=\t)/g," ")).replace(/\t/g,"¨A¨B")).replace(/¨B(.+?)¨A/g,function(e,t){for(var n=t,a=4-n.length%4,i=0;i/g,">"),e=n.converter._dispatch("encodeAmpsAndAngles.after",e,t,n)}),t.subParser("encodeBackslashEscapes",function(e,n,a){"use strict";return e=(e=(e=a.converter._dispatch("encodeBackslashEscapes.before",e,n,a)).replace(/\\(\\)/g,t.helper.escapeCharactersCallback)).replace(/\\([`*_{}\[\]()>#+.!~=|:-])/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("encodeBackslashEscapes.after",e,n,a)}),t.subParser("encodeCode",function(e,n,a){"use strict";return e=(e=a.converter._dispatch("encodeCode.before",e,n,a)).replace(/&/g,"&").replace(//g,">").replace(/([*_{}\[\]\\=~-])/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("encodeCode.after",e,n,a)}),t.subParser("escapeSpecialCharsWithinTagAttributes",function(e,n,a){"use strict";return e=(e=(e=a.converter._dispatch("escapeSpecialCharsWithinTagAttributes.before",e,n,a)).replace(/<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,function(e){return e.replace(/(.)<\/?code>(?=.)/g,"$1`").replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)})).replace(/-]|-[^>])(?:[^-]|-[^-])*)--)>/gi,function(e){return e.replace(/([\\`*_~=|])/g,t.helper.escapeCharactersCallback)}),e=a.converter._dispatch("escapeSpecialCharsWithinTagAttributes.after",e,n,a)}),t.subParser("githubCodeBlocks",function(e,n,a){"use strict";return n.ghCodeBlocks?(e=a.converter._dispatch("githubCodeBlocks.before",e,n,a),e=(e=(e+="¨0").replace(/(?:^|\n)(?: {0,3})(```+|~~~+)(?: *)([^\s`~]*)\n([\s\S]*?)\n(?: {0,3})\1/g,function(e,i,r,o){var s=n.omitExtraWLInCodeBlocks?"":"\n";return o=t.subParser("encodeCode")(o,n,a),o="
"+(o=(o=(o=t.subParser("detab")(o,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,""))+s+"
",o=t.subParser("hashBlock")(o,n,a),"\n\n¨G"+(a.ghCodeBlocks.push({text:e,codeblock:o})-1)+"G\n\n"})).replace(/¨0/,""),a.converter._dispatch("githubCodeBlocks.after",e,n,a)):e}),t.subParser("hashBlock",function(e,t,n){"use strict";return e=(e=n.converter._dispatch("hashBlock.before",e,t,n)).replace(/(^\n+|\n+$)/g,""),e="\n\n¨K"+(n.gHtmlBlocks.push(e)-1)+"K\n\n",e=n.converter._dispatch("hashBlock.after",e,t,n)}),t.subParser("hashCodeTags",function(e,n,a){"use strict";e=a.converter._dispatch("hashCodeTags.before",e,n,a);return e=t.helper.replaceRecursiveRegExp(e,function(e,i,r,o){var s=r+t.subParser("encodeCode")(i,n,a)+o;return"¨C"+(a.gHtmlSpans.push(s)-1)+"C"},"]*>","","gim"),e=a.converter._dispatch("hashCodeTags.after",e,n,a)}),t.subParser("hashElement",function(e,t,n){"use strict";return function(e,t){var a=t;return a=(a=(a=a.replace(/\n\n/g,"\n")).replace(/^\n/,"")).replace(/\n+$/g,""),a="\n\n¨K"+(n.gHtmlBlocks.push(a)-1)+"K\n\n"}}),t.subParser("hashHTMLBlocks",function(e,n,a){"use strict";e=a.converter._dispatch("hashHTMLBlocks.before",e,n,a);var i=["pre","div","h1","h2","h3","h4","h5","h6","blockquote","table","dl","ol","ul","script","noscript","form","fieldset","iframe","math","style","section","header","footer","nav","article","aside","address","audio","canvas","figure","hgroup","output","video","p"],r=function(e,t,n,i){var r=e;return-1!==n.search(/\bmarkdown\b/)&&(r=n+a.converter.makeHtml(t)+i),"\n\n¨K"+(a.gHtmlBlocks.push(r)-1)+"K\n\n"};n.backslashEscapesHTMLTags&&(e=e.replace(/\\<(\/?[^>]+?)>/g,function(e,t){return"<"+t+">"}));for(var o=0;o]*>)","im"),u="<"+i[o]+"\\b[^>]*>",c="";-1!==(s=t.helper.regexIndexOf(e,l));){var d=t.helper.splitAtIndex(e,s),h=t.helper.replaceRecursiveRegExp(d[1],r,u,c,"im");if(h===d[1])break;e=d[0].concat(h)}return e=e.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,n,a)),e=(e=t.helper.replaceRecursiveRegExp(e,function(e){return"\n\n¨K"+(a.gHtmlBlocks.push(e)-1)+"K\n\n"},"^ {0,3}\x3c!--","--\x3e","gm")).replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,t.subParser("hashElement")(e,n,a)),e=a.converter._dispatch("hashHTMLBlocks.after",e,n,a)}),t.subParser("hashHTMLSpans",function(e,t,n){"use strict";function a(e){return"¨C"+(n.gHtmlSpans.push(e)-1)+"C"}return e=(e=(e=(e=(e=n.converter._dispatch("hashHTMLSpans.before",e,t,n)).replace(/<[^>]+?\/>/gi,function(e){return a(e)})).replace(/<([^>]+?)>[\s\S]*?<\/\1>/g,function(e){return a(e)})).replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g,function(e){return a(e)})).replace(/<[^>]+?>/gi,function(e){return a(e)}),e=n.converter._dispatch("hashHTMLSpans.after",e,t,n)}),t.subParser("unhashHTMLSpans",function(e,t,n){"use strict";e=n.converter._dispatch("unhashHTMLSpans.before",e,t,n);for(var a=0;a]*>\\s*]*>","^ {0,3}\\s*
","gim"),e=a.converter._dispatch("hashPreCodeTags.after",e,n,a)}),t.subParser("headers",function(e,n,a){"use strict";e=a.converter._dispatch("headers.before",e,n,a);var i=isNaN(parseInt(n.headerLevelStart))?1:parseInt(n.headerLevelStart),r=n.smoothLivePreview?/^(.+)[ \t]*\n={2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n=+[ \t]*\n+/gm,o=n.smoothLivePreview?/^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm:/^(.+)[ \t]*\n-+[ \t]*\n+/gm;e=(e=e.replace(r,function(e,r){var o=t.subParser("spanGamut")(r,n,a),s=n.noHeaderId?"":' id="'+l(r)+'"',u=""+o+"";return t.subParser("hashBlock")(u,n,a)})).replace(o,function(e,r){var o=t.subParser("spanGamut")(r,n,a),s=n.noHeaderId?"":' id="'+l(r)+'"',u=i+1,c=""+o+"";return t.subParser("hashBlock")(c,n,a)});var s=n.requireSpaceBeforeHeadingText?/^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm:/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;function l(e){var i,r;if(n.customizedHeaderId){var o=e.match(/\{([^{]+?)}\s*$/);o&&o[1]&&(e=o[1])}return i=e,r=t.helper.isString(n.prefixHeaderId)?n.prefixHeaderId:!0===n.prefixHeaderId?"section-":"",n.rawPrefixHeaderId||(i=r+i),i=n.ghCompatibleHeaderId?i.replace(/ /g,"-").replace(/&/g,"").replace(/¨T/g,"").replace(/¨D/g,"").replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g,"").toLowerCase():n.rawHeaderId?i.replace(/ /g,"-").replace(/&/g,"&").replace(/¨T/g,"¨").replace(/¨D/g,"$").replace(/["']/g,"-").toLowerCase():i.replace(/[^\w]/g,"").toLowerCase(),n.rawPrefixHeaderId&&(i=r+i),a.hashLinkCounts[i]?i=i+"-"+a.hashLinkCounts[i]++:a.hashLinkCounts[i]=1,i}return e=e.replace(s,function(e,r,o){var s=o;n.customizedHeaderId&&(s=o.replace(/\s?\{([^{]+?)}\s*$/,""));var u=t.subParser("spanGamut")(s,n,a),c=n.noHeaderId?"":' id="'+l(o)+'"',d=i-1+r.length,h=""+u+"";return t.subParser("hashBlock")(h,n,a)}),e=a.converter._dispatch("headers.after",e,n,a)}),t.subParser("horizontalRule",function(e,n,a){"use strict";e=a.converter._dispatch("horizontalRule.before",e,n,a);var i=t.subParser("hashBlock")("
",n,a);return e=(e=(e=e.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm,i)).replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm,i)).replace(/^ {0,2}( ?_){3,}[ \t]*$/gm,i),e=a.converter._dispatch("horizontalRule.after",e,n,a)}),t.subParser("images",function(e,n,a){"use strict";function i(e,n,i,r,o,s,l,u){var c=a.gUrls,d=a.gTitles,h=a.gDimensions;if(i=i.toLowerCase(),u||(u=""),e.search(/\(? ?(['"].*['"])?\)$/m)>-1)r="";else if(""===r||null===r){if(""!==i&&null!==i||(i=n.toLowerCase().replace(/ ?\n/g," ")),r="#"+i,t.helper.isUndefined(c[i]))return e;r=c[i],t.helper.isUndefined(d[i])||(u=d[i]),t.helper.isUndefined(h[i])||(o=h[i].width,s=h[i].height)}n=n.replace(/"/g,""").replace(t.helper.regexes.asteriskDashAndColon,t.helper.escapeCharactersCallback);var p=''+n+'"}return e=(e=(e=(e=(e=(e=a.converter._dispatch("images.before",e,n,a)).replace(/!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,i)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,function(e,t,n,a,r,o,s,l){return i(e,t,n,a=a.replace(/\s/g,""),r,o,s,l)})).replace(/!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,i)).replace(/!\[([^\]]*?)][ \t]*()\([ \t]??(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,i)).replace(/!\[([^\[\]]+)]()()()()()/g,i),e=a.converter._dispatch("images.after",e,n,a)}),t.subParser("italicsAndBold",function(e,t,n){"use strict";function a(e,t,n){return t+e+n}return e=n.converter._dispatch("italicsAndBold.before",e,t,n),e=t.literalMidWordUnderscores?(e=(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,t){return a(t,"","")})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,t){return a(t,"","")})).replace(/\b_(\S[\s\S]*?)_\b/g,function(e,t){return a(t,"","")}):(e=(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/__(\S[\s\S]*?)__/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/_([^\s_][\s\S]*?)_/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e}),e=t.literalMidWordAsterisks?(e=(e=e.replace(/([^*]|^)\B\*\*\*(\S[\s\S]*?)\*\*\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")})).replace(/([^*]|^)\B\*\*(\S[\s\S]*?)\*\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")})).replace(/([^*]|^)\B\*(\S[\s\S]*?)\*\B(?!\*)/g,function(e,t,n){return a(n,t+"","")}):(e=(e=e.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/\*\*(\S[\s\S]*?)\*\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e})).replace(/\*([^\s*][\s\S]*?)\*/g,function(e,t){return/\S$/.test(t)?a(t,"",""):e}),e=n.converter._dispatch("italicsAndBold.after",e,t,n)}),t.subParser("lists",function(e,n,a){"use strict";function i(e,i){a.gListLevel++,e=e.replace(/\n{2,}$/,"\n");var r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,o=/\n[ \t]*\n(?!¨0)/.test(e+="¨0");return n.disableForced4SpacesIndentedSublists&&(r=/(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm),e=(e=e.replace(r,function(e,i,r,s,l,u,c){c=c&&""!==c.trim();var d=t.subParser("outdent")(l,n,a),h="";return u&&n.tasklists&&(h=' class="task-list-item" style="list-style-type: none;"',d=d.replace(/^[ \t]*\[(x|X| )?]/m,function(){var e='-1?(d=t.subParser("githubCodeBlocks")(d,n,a),d=t.subParser("blockGamut")(d,n,a)):(d=(d=t.subParser("lists")(d,n,a)).replace(/\n$/,""),d=(d=t.subParser("hashHTMLBlocks")(d,n,a)).replace(/\n\n+/g,"\n\n"),d=o?t.subParser("paragraphs")(d,n,a):t.subParser("spanGamut")(d,n,a)),d=""+(d=d.replace("¨A",""))+"\n"})).replace(/¨0/g,""),a.gListLevel--,i&&(e=e.replace(/\s+$/,"")),e}function r(e,t){if("ol"===t){var n=e.match(/^ *(\d+)\./);if(n&&"1"!==n[1])return' start="'+n[1]+'"'}return""}function o(e,t,a){var o=n.disableForced4SpacesIndentedSublists?/^ ?\d+\.[ \t]/gm:/^ {0,3}\d+\.[ \t]/gm,s=n.disableForced4SpacesIndentedSublists?/^ ?[*+-][ \t]/gm:/^ {0,3}[*+-][ \t]/gm,l="ul"===t?o:s,u="";if(-1!==e.search(l))!function n(c){var d=c.search(l),h=r(e,t);-1!==d?(u+="\n\n<"+t+h+">\n"+i(c.slice(0,d),!!a)+"\n",l="ul"===(t="ul"===t?"ol":"ul")?o:s,n(c.slice(d))):u+="\n\n<"+t+h+">\n"+i(c,!!a)+"\n"}(e);else{var c=r(e,t);u="\n\n<"+t+c+">\n"+i(e,!!a)+"\n"}return u}return e=a.converter._dispatch("lists.before",e,n,a),e+="¨0",e=(e=a.gListLevel?e.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,t,n){return o(t,n.search(/[*+-]/g)>-1?"ul":"ol",!0)}):e.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,function(e,t,n,a){return o(n,a.search(/[*+-]/g)>-1?"ul":"ol",!1)})).replace(/¨0/,""),e=a.converter._dispatch("lists.after",e,n,a)}),t.subParser("metadata",function(e,t,n){"use strict";if(!t.metadata)return e;function a(e){n.metadata.raw=e,(e=(e=e.replace(/&/g,"&").replace(/"/g,""")).replace(/\n {4}/g," ")).replace(/^([\S ]+): +([\s\S]+?)$/gm,function(e,t,a){return n.metadata.parsed[t]=a,""})}return e=(e=(e=(e=n.converter._dispatch("metadata.before",e,t,n)).replace(/^\s*«««+(\S*?)\n([\s\S]+?)\n»»»+\n/,function(e,t,n){return a(n),"¨M"})).replace(/^\s*---+(\S*?)\n([\s\S]+?)\n---+\n/,function(e,t,i){return t&&(n.metadata.format=t),a(i),"¨M"})).replace(/¨M/g,""),e=n.converter._dispatch("metadata.after",e,t,n)}),t.subParser("outdent",function(e,t,n){"use strict";return e=(e=(e=n.converter._dispatch("outdent.before",e,t,n)).replace(/^(\t|[ ]{1,4})/gm,"¨0")).replace(/¨0/g,""),e=n.converter._dispatch("outdent.after",e,t,n)}),t.subParser("paragraphs",function(e,n,a){"use strict";for(var i=(e=(e=(e=a.converter._dispatch("paragraphs.before",e,n,a)).replace(/^\n+/g,"")).replace(/\n+$/g,"")).split(/\n{2,}/g),r=[],o=i.length,s=0;s=0?r.push(l):l.search(/\S/)>=0&&(l=(l=t.subParser("spanGamut")(l,n,a)).replace(/^([ \t]*)/g,"

"),l+="

",r.push(l))}for(o=r.length,s=0;s]*>\s*]*>/.test(c)&&(d=!0)}r[s]=c}return e=(e=(e=r.join("\n")).replace(/^\n+/g,"")).replace(/\n+$/g,""),a.converter._dispatch("paragraphs.after",e,n,a)}),t.subParser("runExtension",function(e,t,n,a){"use strict";if(e.filter)t=e.filter(t,a.converter,n);else if(e.regex){var i=e.regex;i instanceof RegExp||(i=new RegExp(i,"g")),t=t.replace(i,e.replace)}return t}),t.subParser("spanGamut",function(e,n,a){"use strict";return e=a.converter._dispatch("spanGamut.before",e,n,a),e=t.subParser("codeSpans")(e,n,a),e=t.subParser("escapeSpecialCharsWithinTagAttributes")(e,n,a),e=t.subParser("encodeBackslashEscapes")(e,n,a),e=t.subParser("images")(e,n,a),e=t.subParser("anchors")(e,n,a),e=t.subParser("autoLinks")(e,n,a),e=t.subParser("simplifiedAutoLinks")(e,n,a),e=t.subParser("emoji")(e,n,a),e=t.subParser("underline")(e,n,a),e=t.subParser("italicsAndBold")(e,n,a),e=t.subParser("strikethrough")(e,n,a),e=t.subParser("ellipsis")(e,n,a),e=t.subParser("hashHTMLSpans")(e,n,a),e=t.subParser("encodeAmpsAndAngles")(e,n,a),n.simpleLineBreaks?/\n\n¨K/.test(e)||(e=e.replace(/\n+/g,"
\n")):e=e.replace(/ +\n/g,"
\n"),e=a.converter._dispatch("spanGamut.after",e,n,a)}),t.subParser("strikethrough",function(e,n,a){"use strict";return n.strikethrough&&(e=(e=a.converter._dispatch("strikethrough.before",e,n,a)).replace(/(?:~){2}([\s\S]+?)(?:~){2}/g,function(e,i){return function(e){return n.simplifiedAutoLink&&(e=t.subParser("simplifiedAutoLinks")(e,n,a)),""+e+""}(i)}),e=a.converter._dispatch("strikethrough.after",e,n,a)),e}),t.subParser("stripLinkDefinitions",function(e,n,a){"use strict";var i=function(i,r,o,s,l,u,c){return r=r.toLowerCase(),e.toLowerCase().split(r).length-1<2?i:(o.match(/^data:.+?\/.+?;base64,/)?a.gUrls[r]=o.replace(/\s/g,""):a.gUrls[r]=t.subParser("encodeAmpsAndAngles")(o,n,a),u?u+c:(c&&(a.gTitles[r]=c.replace(/"|'/g,""")),n.parseImgDimensions&&s&&l&&(a.gDimensions[r]={width:s,height:l}),""))};return e=(e=(e=(e+="¨0").replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm,i)).replace(/^ {0,3}\[([^\]]+)]:[ \t]*\n?[ \t]*\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,i)).replace(/¨0/,"")}),t.subParser("tables",function(e,n,a){"use strict";if(!n.tables)return e;function i(e){return/^:[ \t]*--*$/.test(e)?' style="text-align:left;"':/^--*[ \t]*:[ \t]*$/.test(e)?' style="text-align:right;"':/^:[ \t]*--*[ \t]*:$/.test(e)?' style="text-align:center;"':""}function r(e,i){var r="";return e=e.trim(),(n.tablesHeaderId||n.tableHeaderId)&&(r=' id="'+e.replace(/ /g,"_").toLowerCase()+'"'),""+(e=t.subParser("spanGamut")(e,n,a))+"\n"}function o(e,i){return""+t.subParser("spanGamut")(e,n,a)+"\n"}function s(e){var s,l=e.split("\n");for(s=0;s\n\n\n",i=0;i\n";for(var r=0;r\n"}return n+"\n\n"}(h,f)}return e=(e=(e=(e=a.converter._dispatch("tables.before",e,n,a)).replace(/\\(\|)/g,t.helper.escapeCharactersCallback)).replace(/^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|¨0)/gm,s)).replace(/^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|¨0)/gm,s),e=a.converter._dispatch("tables.after",e,n,a)}),t.subParser("underline",function(e,n,a){"use strict";return n.underline?(e=a.converter._dispatch("underline.before",e,n,a),e=(e=n.literalMidWordUnderscores?(e=e.replace(/\b___(\S[\s\S]*?)___\b/g,function(e,t){return""+t+""})).replace(/\b__(\S[\s\S]*?)__\b/g,function(e,t){return""+t+""}):(e=e.replace(/___(\S[\s\S]*?)___/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/__(\S[\s\S]*?)__/g,function(e,t){return/\S$/.test(t)?""+t+"":e})).replace(/(_)/g,t.helper.escapeCharactersCallback),e=a.converter._dispatch("underline.after",e,n,a)):e}),t.subParser("unescapeSpecialChars",function(e,t,n){"use strict";return e=(e=n.converter._dispatch("unescapeSpecialChars.before",e,t,n)).replace(/¨E(\d+)E/g,function(e,t){var n=parseInt(t);return String.fromCharCode(n)}),e=n.converter._dispatch("unescapeSpecialChars.after",e,t,n)}),t.subParser("makeMarkdown.blockquote",function(e,n){"use strict";var a="";if(e.hasChildNodes())for(var i=e.childNodes,r=i.length,o=0;o ")}),t.subParser("makeMarkdown.codeBlock",function(e,t){"use strict";var n=e.getAttribute("language"),a=e.getAttribute("precodenum");return"```"+n+"\n"+t.preList[a]+"\n```"}),t.subParser("makeMarkdown.codeSpan",function(e){"use strict";return"`"+e.innerHTML+"`"}),t.subParser("makeMarkdown.emphasis",function(e,n){"use strict";var a="";if(e.hasChildNodes()){a+="*";for(var i=e.childNodes,r=i.length,o=0;o",e.hasAttribute("width")&&e.hasAttribute("height")&&(t+=" ="+e.getAttribute("width")+"x"+e.getAttribute("height")),e.hasAttribute("title")&&(t+=' "'+e.getAttribute("title")+'"'),t+=")"),t}),t.subParser("makeMarkdown.links",function(e,n){"use strict";var a="";if(e.hasChildNodes()&&e.hasAttribute("href")){var i=e.childNodes,r=i.length;a="[";for(var o=0;o",e.hasAttribute("title")&&(a+=' "'+e.getAttribute("title")+'"'),a+=")"}return a}),t.subParser("makeMarkdown.list",function(e,n,a){"use strict";var i="";if(!e.hasChildNodes())return"";for(var r=e.childNodes,o=r.length,s=e.getAttribute("start")||1,l=0;l"+t.preList[n]+""}),t.subParser("makeMarkdown.strikethrough",function(e,n){"use strict";var a="";if(e.hasChildNodes()){a+="~~";for(var i=e.childNodes,r=i.length,o=0;otr>th"),l=e.querySelectorAll("tbody>tr");for(a=0;af&&(f=m)}for(a=0;a/g,"\\$1>")).replace(/^#/gm,"\\#")).replace(/^(\s*)([-=]{3,})(\s*)$/,"$1\\$2$3")).replace(/^( {0,3}\d+)\./gm,"$1\\.")).replace(/^( {0,3})([+-])/gm,"$1\\$2")).replace(/]([\s]*)\(/g,"\\]$1\\(")).replace(/^ {0,3}\[([\S \t]*?)]:/gm,"\\[$1]:")});"function"==typeof define&&define.amd?define(function(){"use strict";return t}):"undefined"!=typeof module&&module.exports?module.exports=t:this.showdown=t}.call(this);var NostrTools=(()=>{var e=Object.defineProperty,t=Object.getOwnPropertyDescriptor,n=Object.getOwnPropertyNames,a=Object.prototype.hasOwnProperty,i=(t,n)=>{for(var a in n)e(t,a,{get:n[a],enumerable:!0})},r={};function o(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&"Uint8Array"===e.constructor.name}function s(e,t=""){if(!Number.isSafeInteger(e)||e<0){throw new Error(`${t&&`"${t}" `}expected integer >= 0, got ${e}`)}}function l(e,t,n=""){const a=o(e),i=e?.length,r=void 0!==t;if(!a||r&&i!==t){throw new Error((n&&`"${n}" `)+"expected Uint8Array"+(r?` of length ${t}`:"")+", got "+(a?`length=${i}`:"type="+typeof e))}return e}function u(e){if("function"!=typeof e||"function"!=typeof e.create)throw new Error("Hash must wrapped by utils.createHasher");s(e.outputLen),s(e.blockLen)}function c(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function d(...e){for(let t=0;t>>t}i(r,{Relay:()=>Ya,SimplePool:()=>Ja,finalizeEvent:()=>jt,fj:()=>Na,generateSecretKey:()=>Nt,getEventHash:()=>zt,getFilterLimit:()=>Ia,getPublicKey:()=>Ot,kinds:()=>qt,matchFilter:()=>Ma,matchFilters:()=>Ra,mergeFilters:()=>za,nip04:()=>Ki,nip05:()=>Lr,nip10:()=>Dr,nip11:()=>Br,nip13:()=>Ur,nip17:()=>Gr,nip18:()=>Wo,nip19:()=>Xa,nip21:()=>Qo,nip25:()=>es,nip27:()=>as,nip28:()=>ls,nip30:()=>fs,nip39:()=>ys,nip42:()=>Va,nip44:()=>Yr,nip47:()=>xs,nip54:()=>Ts,nip57:()=>As,nip59:()=>Kr,nip77:()=>Os,nip98:()=>Zs,parseReferences:()=>Gi,serializeEvent:()=>Rt,sortEvents:()=>xt,utils:()=>St,validateEvent:()=>kt,verifiedSymbol:()=>yt,verifyEvent:()=>Dt});var f=(()=>"function"==typeof Uint8Array.from([]).toHex&&"function"==typeof Uint8Array.fromHex)(),m=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function _(e){if(l(e),f)return e.toHex();let t="";for(let n=0;n=g&&e<=v?e-g:e>=b&&e<=y?e-(b-10):e>=w&&e<=k?e-(w-10):void 0}function S(e){if("string"!=typeof e)throw new Error("hex string expected, got "+typeof e);if(f)return Uint8Array.fromHex(e);const t=e.length,n=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);const a=new Uint8Array(n);for(let t=0,i=0;te(n).update(t).digest(),a=e(void 0);return n.outputLen=a.outputLen,n.blockLen=a.blockLen,n.create=t=>e(t),Object.assign(n,t),Object.freeze(n)}function P(e=32){const t="object"==typeof globalThis?globalThis.crypto:null;if("function"!=typeof t?.getRandomValues)throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}var E=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});function A(e,t,n){return e&t^~e&n}function L(e,t,n){return e&t^e&n^t&n}var M=class{blockLen;outputLen;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(e,t,n,a){this.blockLen=e,this.outputLen=t,this.padOffset=n,this.isLE=a,this.buffer=new Uint8Array(e),this.view=h(this.buffer)}update(e){c(this),l(e);const{view:t,buffer:n,blockLen:a}=this,i=e.length;for(let r=0;r='+n)}(e,this),this.finished=!0;const{buffer:t,view:n,blockLen:a,isLE:i}=this;let{pos:r}=this;t[r++]=128,d(this.buffer.subarray(r)),this.padOffset>a-r&&(this.process(n,0),r=0);for(let e=r;ep.length)throw new Error("_sha2: outputLen bigger than state");for(let e=0;e>>3,i=p(n,17)^p(n,19)^n>>>10;I[e]=i+I[e-7]+a+I[e-16]|0}let{A:n,B:a,C:i,D:r,E:o,F:s,G:l,H:u}=this;for(let e=0;e<64;e++){const t=u+(p(o,6)^p(o,11)^p(o,25))+A(o,s,l)+z[e]+I[e]|0,c=(p(n,2)^p(n,13)^p(n,22))+L(n,a,i)|0;u=l,l=s,s=o,o=r+t|0,r=i,i=a,a=n,n=t+c|0}n=n+this.A|0,a=a+this.B|0,i=i+this.C|0,r=r+this.D|0,o=o+this.E|0,s=s+this.F|0,l=l+this.G|0,u=u+this.H|0,this.set(n,a,i,r,o,s,l,u)}roundClean(){d(I)}destroy(){this.set(0,0,0,0,0,0,0,0),d(this.buffer)}},O=class extends N{A=0|R[0];B=0|R[1];C=0|R[2];D=0|R[3];E=0|R[4];F=0|R[5];G=0|R[6];H=0|R[7];constructor(){super(32)}},j=T(()=>new O,E(1)),D=BigInt(0),q=BigInt(1);function B(e,t=""){if("boolean"!=typeof e){throw new Error((t&&`"${t}" `)+"expected boolean, got type="+typeof e)}return e}function F(e){if("bigint"==typeof e){if(!K(e))throw new Error("positive bigint expected, got "+e)}else s(e);return e}function V(e){const t=F(e).toString(16);return 1&t.length?"0"+t:t}function U(e){if("string"!=typeof e)throw new Error("hex string expected, got "+typeof e);return""===e?D:BigInt("0x"+e)}function $(e){return U(_(e))}function H(e){return U(_(function(e){return Uint8Array.from(e)}(l(e)).reverse()))}function W(e,t){s(t);const n=S((e=F(e)).toString(16).padStart(2*t,"0"));if(n.length!==t)throw new Error("number too large");return n}function G(e,t){return W(e,t).reverse()}var K=e=>"bigint"==typeof e&&D<=e;function Y(e,t,n,a){if(!function(e,t,n){return K(e)&&K(t)&&K(n)&&t<=e&&e(q<Object.entries(t).forEach(([t,a])=>function(t,n,a){const i=e[t];if(a&&void 0===i)return;const r=typeof i;if(r!==n||null===i)throw new Error(`param "${t}" is invalid: expected ${n}, got ${r}`)}(t,a,n));a(t,!1),a(n,!0)}function J(e){const t=new WeakMap;return(n,...a)=>{const i=t.get(n);if(void 0!==i)return i;const r=e(n,...a);return t.set(n,r),r}}var X=BigInt(0),ee=BigInt(1),te=BigInt(2),ne=BigInt(3),ae=BigInt(4),ie=BigInt(5),re=BigInt(7),oe=BigInt(8),se=BigInt(9),le=BigInt(16);function ue(e,t){const n=e%t;return n>=X?n:t+n}function ce(e,t,n){let a=e;for(;t-- >X;)a*=a,a%=n;return a}function de(e,t){if(e===X)throw new Error("invert: expected non-zero number");if(t<=X)throw new Error("invert: expected positive modulus, got "+t);let n=ue(e,t),a=t,i=X,r=ee,o=ee,s=X;for(;n!==X;){const e=a/n,t=a%n,l=i-o*e,u=r-s*e;a=n,n=t,i=o,r=s,o=l,s=u}if(a!==ee)throw new Error("invert: does not exist");return ue(i,t)}function he(e,t,n){if(!e.eql(e.sqr(t),n))throw new Error("Cannot find square root")}function pe(e,t){const n=(e.ORDER+ee)/ae,a=e.pow(t,n);return he(e,a,t),a}function fe(e,t){const n=(e.ORDER-ie)/oe,a=e.mul(t,te),i=e.pow(a,n),r=e.mul(t,i),o=e.mul(e.mul(r,te),i),s=e.mul(r,e.sub(o,e.ONE));return he(e,s,t),s}function me(e){if(e1e3)throw new Error("Cannot find square root: probably non-prime P");if(1===n)return pe;let r=i.pow(a,t);const o=(t+ee)/te;return function(e,a){if(e.is0(a))return a;if(1!==be(e,a))throw new Error("Cannot find square root");let i=n,s=e.mul(e.ONE,r),l=e.pow(a,t),u=e.pow(a,o);for(;!e.eql(l,e.ONE);){if(e.is0(l))return e.ZERO;let t=1,n=e.sqr(l);for(;!e.eql(n,e.ONE);)if(t++,n=e.sqr(n),t===i)throw new Error("Cannot find square root");const a=ee<{let n=e.pow(t,o),s=e.mul(n,a);const l=e.mul(n,i),u=e.mul(n,r),c=e.eql(e.sqr(s),t),d=e.eql(e.sqr(l),t);n=e.cmov(n,s,c),s=e.cmov(u,l,d);const h=e.eql(e.sqr(s),t),p=e.cmov(n,s,h);return he(e,p,t),p}}(e):me(e)}var ge=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function ve(e,t,n=!1){const a=new Array(t.length).fill(n?e.ZERO:void 0),i=t.reduce((t,n,i)=>e.is0(n)?t:(a[i]=t,e.mul(t,n)),e.ONE),r=e.inv(i);return t.reduceRight((t,n,i)=>e.is0(n)?t:(a[i]=e.mul(t,a[i]),e.mul(t,n)),r),a}function be(e,t){const n=(e.ORDER-ee)/te,a=e.pow(t,n),i=e.eql(a,e.ONE),r=e.eql(a,e.ZERO),o=e.eql(a,e.neg(e.ONE));if(!i&&!r&&!o)throw new Error("invalid Legendre symbol result");return i?1:r?0:-1}var ye=class{ORDER;BITS;BYTES;isLE;ZERO=X;ONE=ee;_lengths;_sqrt;_mod;constructor(e,t={}){if(e<=X)throw new Error("invalid field: expected ORDER > 0, got "+e);let n;this.isLE=!1,null!=t&&"object"==typeof t&&("number"==typeof t.BITS&&(n=t.BITS),"function"==typeof t.sqrt&&(this.sqrt=t.sqrt),"boolean"==typeof t.isLE&&(this.isLE=t.isLE),t.allowedLengths&&(this._lengths=t.allowedLengths?.slice()),"boolean"==typeof t.modFromBytes&&(this._mod=t.modFromBytes));const{nBitLength:a,nByteLength:i}=function(e,t){void 0!==t&&s(t);const n=void 0!==t?t:e.toString(2).length;return{nBitLength:n,nByteLength:Math.ceil(n/8)}}(e,n);if(i>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=e,this.BITS=a,this.BYTES=i,this._sqrt=void 0,Object.preventExtensions(this)}create(e){return ue(e,this.ORDER)}isValid(e){if("bigint"!=typeof e)throw new Error("invalid field element: expected bigint, got "+typeof e);return X<=e&&eX;)n&ee&&(a=e.mul(a,i)),i=e.sqr(i),n>>=ee;return a}(this,e,t)}div(e,t){return ue(e*de(t,this.ORDER),this.ORDER)}sqrN(e){return e*e}addN(e,t){return e+t}subN(e,t){return e-t}mulN(e,t){return e*t}inv(e){return de(e,this.ORDER)}sqrt(e){return this._sqrt||(this._sqrt=_e(this.ORDER)),this._sqrt(this,e)}toBytes(e){return this.isLE?G(e,this.BYTES):W(e,this.BYTES)}fromBytes(e,t=!1){l(e);const{_lengths:n,BYTES:a,isLE:i,ORDER:r,_mod:o}=this;if(n){if(!n.includes(e.length)||e.length>a)throw new Error("Field.fromBytes: expected "+n+" bytes, got "+e.length);const t=new Uint8Array(a);t.set(e,i?0:t.length-e.length),e=t}if(e.length!==a)throw new Error("Field.fromBytes: expected "+a+" bytes, got "+e.length);let s=i?H(e):$(e);if(o&&(s=ue(s,r)),!t&&!this.isValid(s))throw new Error("invalid field element: outside of range 0..ORDER");return s}invertBatch(e){return ve(this,e)}cmov(e,t,n){return n?t:e}};function we(e,t={}){return new ye(e,t)}function ke(e){if("bigint"!=typeof e)throw new Error("field order must be bigint");const t=e.toString(2).length;return Math.ceil(t/8)}function xe(e){const t=ke(e);return t+Math.ceil(t/2)}function Se(e,t,n=!1){l(e);const a=e.length,i=ke(t),r=xe(t);if(a<16||a1024)throw new Error("expected "+r+"-1024 bytes of input, got "+a);const o=ue(n?H(e):$(e),t-ee)+ee;return n?G(o,i):W(o,i)}var Ce=BigInt(0),Te=BigInt(1);function Pe(e,t){const n=t.negate();return e?n:t}function Ee(e,t){const n=ve(e.Fp,t.map(e=>e.Z));return t.map((t,a)=>e.fromAffine(t.toAffine(n[a])))}function Ae(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function Le(e,t){Ae(e,t);const n=2**e;return{windows:Math.ceil(t/e)+1,windowSize:2**(e-1),mask:Q(e),maxNumber:n,shiftBy:BigInt(e)}}function Me(e,t,n){const{windowSize:a,mask:i,maxNumber:r,shiftBy:o}=n;let s=Number(e&i),l=e>>o;s>a&&(s-=r,l+=Te);const u=t*a;return{nextN:l,offset:u+Math.abs(s)-1,isZero:0===s,isNeg:s<0,isNegF:t%2!=0,offsetF:u}}var Re=new WeakMap,ze=new WeakMap;function Ie(e){return ze.get(e)||1}function Ne(e){if(e!==Ce)throw new Error("invalid wNAF")}var Oe=class{BASE;ZERO;Fn;bits;constructor(e,t){this.BASE=e.BASE,this.ZERO=e.ZERO,this.Fn=e.Fn,this.bits=t}_unsafeLadder(e,t,n=this.ZERO){let a=e;for(;t>Ce;)t&Te&&(n=n.add(a)),a=a.double(),t>>=Te;return n}precomputeWindow(e,t){const{windows:n,windowSize:a}=Le(t,this.bits),i=[];let r=e,o=r;for(let e=0;e(e[t]="function",e),{ORDER:"bigint",BYTES:"number",BITS:"number"}))}(t),t}return we(e,{isLE:n})}function De(e,t){return function(n){const a=e(n);return{secretKey:a,publicKey:t(a)}}}var qe=class{oHash;iHash;blockLen;outputLen;finished=!1;destroyed=!1;constructor(e,t){if(u(e),l(t,void 0,"key"),this.iHash=e.create(),"function"!=typeof this.iHash.update)throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;const n=this.blockLen,a=new Uint8Array(n);a.set(t.length>n?e.create().update(t).digest():t);for(let e=0;enew qe(e,t).update(n).digest();Be.create=(e,t)=>new qe(e,t);var Fe=(e,t)=>(e+(e>=0?t:-t)/Ke)/t;function Ve(e,t,n){const[[a,i],[r,o]]=t,s=Fe(o*e,n),l=Fe(-i*e,n);let u=e-s*a-l*r,c=-s*i-l*o;const d=uD;e>>=q,t+=1);return t}(n)/2))+Ge;if(u=p||c=p)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:d,k1:u,k2neg:h,k2:c}}function Ue(e){if(!["compact","recovered","der"].includes(e))throw new Error('Signature format must be "compact", "recovered", or "der"');return e}function $e(e,t){const n={};for(let a of Object.keys(t))n[a]=void 0===e[a]?t[a]:e[a];return B(n.lowS,"lowS"),B(n.prehash,"prehash"),void 0!==n.format&&Ue(n.format),n}var He={Err:class extends Error{constructor(e=""){super(e)}},_tlv:{encode:(e,t)=>{const{Err:n}=He;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(1&t.length)throw new n("tlv.encode: unpadded data");const a=t.length/2,i=V(a);if(i.length/2&128)throw new n("tlv.encode: long form length too big");const r=a>127?V(i.length/2|128):"";return V(e)+r+i+t},decode(e,t){const{Err:n}=He;let a=0;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(t.length<2||t[a++]!==e)throw new n("tlv.decode: wrong tlv");const i=t[a++];let r=0;if(!!(128&i)){const e=127&i;if(!e)throw new n("tlv.decode(long): indefinite length not supported");if(e>4)throw new n("tlv.decode(long): byte length is too big");const o=t.subarray(a,a+e);if(o.length!==e)throw new n("tlv.decode: length bytes not complete");if(0===o[0])throw new n("tlv.decode(long): zero leftmost byte");for(const e of o)r=r<<8|e;if(a+=e,r<128)throw new n("tlv.decode(long): not minimal encoding")}else r=i;const o=t.subarray(a,a+r);if(o.length!==r)throw new n("tlv.decode: wrong value length");return{v:o,l:t.subarray(a+r)}}},_int:{encode(e){const{Err:t}=He;if(eCe))throw new Error(`CURVE.${e} must be positive bigint`)}const i=je(t.p,n.Fp,a),r=je(t.n,n.Fn,a),o=["Gx","Gy","a","weierstrass"===e?"b":"d"];for(const e of o)if(!i.isValid(t[e]))throw new Error(`CURVE.${e} must be valid field element of CURVE.Fp`);return{CURVE:t=Object.freeze(Object.assign({},t)),Fp:i,Fn:r}}("weierstrass",e,t),{Fp:a,Fn:i}=n;let r=n.CURVE;const{h:o,n:s}=r;Z(t,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object"});const{endo:u}=t;if(u&&(!a.is0(r.a)||"bigint"!=typeof u.beta||!Array.isArray(u.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');const c=Xe(a,i);function d(){if(!a.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}const h=t.toBytes||function(e,t,n){const{x:i,y:r}=t.toAffine(),o=a.toBytes(i);if(B(n,"isCompressed"),n){d();return C(Je(!a.isOdd(r)),o)}return C(Uint8Array.of(4),o,a.toBytes(r))},p=t.fromBytes||function(e){l(e,void 0,"Point");const{publicKey:t,publicKeyUncompressed:n}=c,i=e.length,r=e[0],o=e.subarray(1);if(i!==t||2!==r&&3!==r){if(i===n&&4===r){const e=a.BYTES,t=a.fromBytes(o.subarray(0,e)),n=a.fromBytes(o.subarray(e,2*e));if(!m(t,n))throw new Error("bad point: is not on curve");return{x:t,y:n}}throw new Error(`bad point: got length ${i}, expected compressed=${t} or uncompressed=${n}`)}{const e=a.fromBytes(o);if(!a.isValid(e))throw new Error("bad point: is not on curve, wrong x");const t=f(e);let n;try{n=a.sqrt(t)}catch(e){const t=e instanceof Error?": "+e.message:"";throw new Error("bad point: is not on curve, sqrt error"+t)}d();return!(1&~r)!==a.isOdd(n)&&(n=a.neg(n)),{x:e,y:n}}};function f(e){const t=a.sqr(e),n=a.mul(t,e);return a.add(a.add(n,a.mul(e,r.a)),r.b)}function m(e,t){const n=a.sqr(t),i=f(e);return a.eql(n,i)}if(!m(r.Gx,r.Gy))throw new Error("bad curve params: generator point");const g=a.mul(a.pow(r.a,Ye),Qe),v=a.mul(a.sqr(r.b),BigInt(27));if(a.is0(a.add(g,v)))throw new Error("bad curve params: a or b");function b(e,t,n=!1){if(!a.isValid(t)||n&&a.is0(t))throw new Error(`bad point coordinate ${e}`);return t}function y(e){if(!(e instanceof P))throw new Error("Weierstrass Point expected")}function w(e){if(!u||!u.basises)throw new Error("no endo");return Ve(e,u.basises,i.ORDER)}const k=J((e,t)=>{const{X:n,Y:i,Z:r}=e;if(a.eql(r,a.ONE))return{x:n,y:i};const o=e.is0();null==t&&(t=o?a.ONE:a.inv(r));const s=a.mul(n,t),l=a.mul(i,t),u=a.mul(r,t);if(o)return{x:a.ZERO,y:a.ZERO};if(!a.eql(u,a.ONE))throw new Error("invZ was invalid");return{x:s,y:l}}),x=J(e=>{if(e.is0()){if(t.allowInfinityPoint&&!a.is0(e.Y))return;throw new Error("bad point: ZERO")}const{x:n,y:i}=e.toAffine();if(!a.isValid(n)||!a.isValid(i))throw new Error("bad point: x or y not field elements");if(!m(n,i))throw new Error("bad point: equation left != right");if(!e.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function T(e,t,n,i,r){return n=new P(a.mul(n.X,e),n.Y,n.Z),t=Pe(i,t),n=Pe(r,n),t.add(n)}class P{static BASE=new P(r.Gx,r.Gy,a.ONE);static ZERO=new P(a.ZERO,a.ONE,a.ZERO);static Fp=a;static Fn=i;X;Y;Z;constructor(e,t,n){this.X=b("x",e),this.Y=b("y",t,!0),this.Z=b("z",n),Object.freeze(this)}static CURVE(){return r}static fromAffine(e){const{x:t,y:n}=e||{};if(!e||!a.isValid(t)||!a.isValid(n))throw new Error("invalid affine point");if(e instanceof P)throw new Error("projective point not allowed");return a.is0(t)&&a.is0(n)?P.ZERO:new P(t,n,a.ONE)}static fromBytes(e){const t=P.fromAffine(p(l(e,void 0,"point")));return t.assertValidity(),t}static fromHex(e){return P.fromBytes(S(e))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(e=8,t=!0){return A.createCache(this,e),t||this.multiply(Ye),this}assertValidity(){x(this)}hasEvenY(){const{y:e}=this.toAffine();if(!a.isOdd)throw new Error("Field doesn't support isOdd");return!a.isOdd(e)}equals(e){y(e);const{X:t,Y:n,Z:i}=this,{X:r,Y:o,Z:s}=e,l=a.eql(a.mul(t,s),a.mul(r,i)),u=a.eql(a.mul(n,s),a.mul(o,i));return l&&u}negate(){return new P(this.X,a.neg(this.Y),this.Z)}double(){const{a:e,b:t}=r,n=a.mul(t,Ye),{X:i,Y:o,Z:s}=this;let l=a.ZERO,u=a.ZERO,c=a.ZERO,d=a.mul(i,i),h=a.mul(o,o),p=a.mul(s,s),f=a.mul(i,o);return f=a.add(f,f),c=a.mul(i,s),c=a.add(c,c),l=a.mul(e,c),u=a.mul(n,p),u=a.add(l,u),l=a.sub(h,u),u=a.add(h,u),u=a.mul(l,u),l=a.mul(f,l),c=a.mul(n,c),p=a.mul(e,p),f=a.sub(d,p),f=a.mul(e,f),f=a.add(f,c),c=a.add(d,d),d=a.add(c,d),d=a.add(d,p),d=a.mul(d,f),u=a.add(u,d),p=a.mul(o,s),p=a.add(p,p),d=a.mul(p,f),l=a.sub(l,d),c=a.mul(p,h),c=a.add(c,c),c=a.add(c,c),new P(l,u,c)}add(e){y(e);const{X:t,Y:n,Z:i}=this,{X:o,Y:s,Z:l}=e;let u=a.ZERO,c=a.ZERO,d=a.ZERO;const h=r.a,p=a.mul(r.b,Ye);let f=a.mul(t,o),m=a.mul(n,s),_=a.mul(i,l),g=a.add(t,n),v=a.add(o,s);g=a.mul(g,v),v=a.add(f,m),g=a.sub(g,v),v=a.add(t,i);let b=a.add(o,l);return v=a.mul(v,b),b=a.add(f,_),v=a.sub(v,b),b=a.add(n,i),u=a.add(s,l),b=a.mul(b,u),u=a.add(m,_),b=a.sub(b,u),d=a.mul(h,v),u=a.mul(p,_),d=a.add(u,d),u=a.sub(m,d),d=a.add(m,d),c=a.mul(u,d),m=a.add(f,f),m=a.add(m,f),_=a.mul(h,_),v=a.mul(p,v),m=a.add(m,_),_=a.sub(f,_),_=a.mul(h,_),v=a.add(v,_),f=a.mul(m,v),c=a.add(c,f),f=a.mul(b,v),u=a.mul(g,u),u=a.sub(u,f),f=a.mul(g,m),d=a.mul(b,d),d=a.add(d,f),new P(u,c,d)}subtract(e){return this.add(e.negate())}is0(){return this.equals(P.ZERO)}multiply(e){const{endo:n}=t;if(!i.isValidNot0(e))throw new Error("invalid scalar: out of range");let a,r;const o=e=>A.cached(this,e,e=>Ee(P,e));if(n){const{k1neg:t,k1:i,k2neg:s,k2:l}=w(e),{p:u,f:c}=o(i),{p:d,f:h}=o(l);r=c.add(h),a=T(n.beta,u,d,t,s)}else{const{p:t,f:n}=o(e);a=t,r=n}return Ee(P,[a,r])[0]}multiplyUnsafe(e){const{endo:n}=t,a=this;if(!i.isValid(e))throw new Error("invalid scalar: out of range");if(e===We||a.is0())return P.ZERO;if(e===Ge)return a;if(A.hasCache(this))return this.multiply(e);if(n){const{k1neg:t,k1:i,k2neg:r,k2:o}=w(e),{p1:s,p2:l}=function(e,t,n,a){let i=t,r=e.ZERO,o=e.ZERO;for(;n>Ce||a>Ce;)n&Te&&(r=r.add(i)),a&Te&&(o=o.add(i)),i=i.double(),n>>=Te,a>>=Te;return{p1:r,p2:o}}(P,a,i,o);return T(n.beta,s,l,t,r)}return A.unsafe(a,e)}toAffine(e){return k(this,e)}isTorsionFree(){const{isTorsionFree:e}=t;return o===Ge||(e?e(P,this):A.unsafe(this,s).is0())}clearCofactor(){const{clearCofactor:e}=t;return o===Ge?this:e?e(P,this):this.multiplyUnsafe(o)}isSmallOrder(){return this.multiplyUnsafe(o).is0()}toBytes(e=!0){return B(e,"isCompressed"),this.assertValidity(),h(P,this,e)}toHex(e=!0){return _(this.toBytes(e))}toString(){return``}}const E=i.BITS,A=new Oe(P,t.endo?Math.ceil(E/2):E);return P.BASE.precompute(8),P}function Je(e){return Uint8Array.of(e?2:3)}function Xe(e,t){return{secretKey:t.BYTES,publicKey:1+e.BYTES,publicKeyUncompressed:1+2*e.BYTES,publicKeyHasPrefix:!0,signature:2*t.BYTES}}function et(e,t,n={}){u(t),Z(n,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"});const a=(n=Object.assign({},n)).randomBytes||P,i=n.hmac||((e,n)=>Be(t,e,n)),{Fp:r,Fn:c}=e,{ORDER:d,BITS:h}=c,{keygen:p,getPublicKey:f,getSharedSecret:m,utils:g,lengths:v}=function(e,t={}){const{Fn:n}=e,a=t.randomBytes||P,i=Object.assign(Xe(e.Fp,n),{seed:xe(n.ORDER)});function r(e=a(i.seed)){return Se(l(e,i.seed,"seed"),n.ORDER)}function s(t,a=!0){return e.BASE.multiply(n.fromBytes(t)).toBytes(a)}function u(e){const{secretKey:t,publicKey:a,publicKeyUncompressed:r}=i;if(!o(e))return;if("_lengths"in n&&n._lengths||t===a)return;const s=l(e,void 0,"key").length;return s===a||s===r}const c={isValidSecretKey:function(e){try{const t=n.fromBytes(e);return n.isValidNot0(t)}catch(e){return!1}},isValidPublicKey:function(t,n){const{publicKey:a,publicKeyUncompressed:r}=i;try{const i=t.length;return!(!0===n&&i!==a||!1===n&&i!==r||!e.fromBytes(t))}catch(e){return!1}},randomSecretKey:r},d=De(r,s);return Object.freeze({getPublicKey:s,getSharedSecret:function(t,a,i=!0){if(!0===u(t))throw new Error("first arg must be private key");if(!1===u(a))throw new Error("second arg must be public key");const r=n.fromBytes(t);return e.fromBytes(a).multiply(r).toBytes(i)},keygen:d,Point:e,utils:c,lengths:i})}(e,n),b={prehash:!0,lowS:"boolean"!=typeof n.lowS||n.lowS,format:"compact",extraEntropy:!1},y=d*Ked>>Ge}function k(e,t){if(!c.isValidNot0(t))throw new Error(`invalid signature ${e}: out of range 1..Point.Fn.ORDER`);return t}function x(){if(y)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function T(e,t){Ue(t);const n=v.signature;return l(e,"compact"===t?n:"recovered"===t?n+1:void 0)}class E{r;s;recovery;constructor(e,t,n){if(this.r=k("r",e),this.s=k("s",t),null!=n){if(x(),![0,1,2,3].includes(n))throw new Error("invalid recovery id");this.recovery=n}Object.freeze(this)}static fromBytes(e,t=b.format){let n;if(T(e,t),"der"===t){const{r:t,s:n}=He.toSig(l(e));return new E(t,n)}"recovered"===t&&(n=e[0],t="compact",e=e.subarray(1));const a=v.signature/2,i=e.subarray(0,a),r=e.subarray(a,2*a);return new E(c.fromBytes(i),c.fromBytes(r),n)}static fromHex(e,t){return this.fromBytes(S(e),t)}assertRecovery(){const{recovery:e}=this;if(null==e)throw new Error("invalid recovery id: must be present");return e}addRecoveryBit(e){return new E(this.r,this.s,e)}recoverPublicKey(t){const{r:n,s:a}=this,i=this.assertRecovery(),o=2===i||3===i?n+d:n;if(!r.isValid(o))throw new Error("invalid recovery id: sig.r+curve.n != R.x");const s=r.toBytes(o),u=e.fromBytes(C(Je(!(1&i)),s)),h=c.inv(o),p=L(l(t,void 0,"msgHash")),f=c.create(-p*h),m=c.create(a*h),_=e.BASE.multiplyUnsafe(f).add(u.multiplyUnsafe(m));if(_.is0())throw new Error("invalid recovery: point at infinify");return _.assertValidity(),_}hasHighS(){return w(this.s)}toBytes(e=b.format){if(Ue(e),"der"===e)return S(He.hexFromSig(this));const{r:t,s:n}=this,a=c.toBytes(t),i=c.toBytes(n);return"recovered"===e?(x(),C(Uint8Array.of(this.assertRecovery()),a,i)):C(a,i)}toHex(e){return _(this.toBytes(e))}}const A=n.bits2int||function(e){if(e.length>8192)throw new Error("input is too large");const t=$(e),n=8*e.length-h;return n>0?t>>BigInt(n):t},L=n.bits2int_modN||function(e){return c.create(A(e))},M=Q(h);function R(e){return Y("num < 2^"+h,e,We,M),c.toBytes(e)}function z(e,n){return l(e,void 0,"message"),n?l(t(e),void 0,"prehashed message"):e}return Object.freeze({keygen:p,getPublicKey:f,getSharedSecret:m,utils:g,lengths:v,Point:e,sign:function(n,r,o={}){const{seed:u,k2sig:d}=function(t,n,i){const{lowS:r,prehash:o,extraEntropy:s}=$e(i,b);t=z(t,o);const u=L(t),d=c.fromBytes(n);if(!c.isValidNot0(d))throw new Error("invalid private key");const h=[R(d),R(u)];if(null!=s&&!1!==s){const e=!0===s?a(v.secretKey):s;h.push(l(e,void 0,"extraEntropy"))}const p=C(...h),f=u;return{seed:p,k2sig:function(t){const n=A(t);if(!c.isValidNot0(n))return;const a=c.inv(n),i=e.BASE.multiply(n).toAffine(),o=c.create(i.x);if(o===We)return;const s=c.create(a*c.create(f+o*d));if(s===We)return;let l=(i.x===o?0:2)|Number(i.y&Ge),u=s;return r&&w(s)&&(u=c.neg(s),l^=1),new E(o,u,y?void 0:l)}}}(n,r,o);return function(e,t,n){if(s(e,"hashLen"),s(t,"qByteLen"),"function"!=typeof n)throw new Error("hmacFn must be a function");const a=e=>new Uint8Array(e),i=Uint8Array.of(),r=Uint8Array.of(0),o=Uint8Array.of(1);let l=a(e),u=a(e),c=0;const d=()=>{l.fill(1),u.fill(0),c=0},h=(...e)=>n(u,C(l,...e)),p=(e=i)=>{u=h(r,e),l=h(),0!==e.length&&(u=h(o,e),l=h())},f=()=>{if(c++>=1e3)throw new Error("drbg: tried max amount of iterations");let e=0;const n=[];for(;e{let n;for(d(),p(e);!(n=t(f()));)p();return d(),n}}(t.outputLen,c.BYTES,i)(u,d).toBytes(o.format)},verify:function(t,n,a,i={}){const{lowS:r,prehash:s,format:u}=$e(i,b);if(a=l(a,void 0,"publicKey"),n=z(n,s),!o(t)){throw new Error("verify expects Uint8Array signature"+(t instanceof E?", use sig.toBytes()":""))}T(t,u);try{const i=E.fromBytes(t,u),o=e.fromBytes(a);if(r&&i.hasHighS())return!1;const{r:s,s:l}=i,d=L(n),h=c.inv(l),p=c.create(d*h),f=c.create(s*h),m=e.BASE.multiplyUnsafe(p).add(o.multiplyUnsafe(f));if(m.is0())return!1;return c.create(m.x)===s}catch(e){return!1}},recoverPublicKey:function(e,t,n={}){const{prehash:a}=$e(n,b);return t=z(t,a),E.fromBytes(e,"recovered").recoverPublicKey(t).toBytes()},Signature:E,hash:t})}var tt={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},nt={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},at=BigInt(0),it=BigInt(2);var rt=we(tt.p,{sqrt:function(e){const t=tt.p,n=BigInt(3),a=BigInt(6),i=BigInt(11),r=BigInt(22),o=BigInt(23),s=BigInt(44),l=BigInt(88),u=e*e*e%t,c=u*u*e%t,d=ce(c,n,t)*c%t,h=ce(d,n,t)*c%t,p=ce(h,it,t)*u%t,f=ce(p,i,t)*p%t,m=ce(f,r,t)*f%t,_=ce(m,s,t)*m%t,g=ce(_,l,t)*_%t,v=ce(g,s,t)*m%t,b=ce(v,n,t)*c%t,y=ce(b,o,t)*f%t,w=ce(y,a,t)*u%t,k=ce(w,it,t);if(!rt.eql(rt.sqr(k),e))throw new Error("Cannot find square root");return k}}),ot=Ze(tt,{Fp:rt,endo:nt}),st=et(ot,j),lt={};function ut(e,...t){let n=lt[e];if(void 0===n){const t=j((a=e,Uint8Array.from(a,(e,t)=>{const n=e.charCodeAt(0);if(1!==e.length||n>127)throw new Error(`string contains non-ASCII character "${a[t]}" with code ${n} at position ${t}`);return n})));n=C(t,t),lt[e]=n}var a;return j(C(n,...t))}var ct=e=>e.toBytes(!0).slice(1),dt=e=>e%it===at;function ht(e){const{Fn:t,BASE:n}=ot,a=t.fromBytes(e),i=n.multiply(a);return{scalar:dt(i.y)?a:t.neg(a),bytes:ct(i)}}function pt(e){const t=rt;if(!t.isValidNot0(e))throw new Error("invalid x: Fail if x ≥ p");const n=t.create(e*e),a=t.create(n*e+BigInt(7));let i=t.sqrt(a);dt(i)||(i=t.neg(i));const r=ot.fromAffine({x:e,y:i});return r.assertValidity(),r}var ft=$;function mt(...e){return ot.Fn.create(ft(ut("BIP0340/challenge",...e)))}function _t(e){return ht(e).bytes}function gt(e,t,n=P(32)){const{Fn:a}=ot,i=l(e,void 0,"message"),{bytes:r,scalar:o}=ht(t),s=l(n,32,"auxRand"),u=a.toBytes(o^ft(ut("BIP0340/aux",s))),c=ut("BIP0340/nonce",u,r,i),{bytes:d,scalar:h}=ht(c),p=mt(d,r,i),f=new Uint8Array(64);if(f.set(d,0),f.set(a.toBytes(a.create(h+p*o)),32),!vt(f,i,r))throw new Error("sign: Invalid signature produced");return f}function vt(e,t,n){const{Fp:a,Fn:i,BASE:r}=ot,o=l(e,64,"signature"),s=l(t,void 0,"message"),u=l(n,32,"publicKey");try{const e=pt(ft(u)),t=ft(o.subarray(0,32));if(!a.isValidNot0(t))return!1;const n=ft(o.subarray(32,64));if(!i.isValidNot0(n))return!1;const l=mt(i.toBytes(t),ct(e),s),c=r.multiplyUnsafe(n).add(e.multiplyUnsafe(i.neg(l))),{x:d,y:h}=c.toAffine();return!(c.is0()||!dt(h)||d!==t)}catch(e){return!1}}var bt=(()=>{const e=(e=P(48))=>Se(e,tt.n);return{keygen:De(e,_t),getPublicKey:_t,sign:gt,verify:vt,Point:ot,utils:{randomSecretKey:e,taggedHash:ut,lift_x:pt,pointToBytes:ct},lengths:{secretKey:32,publicKey:32,publicKeyHasPrefix:!1,signature:64,seed:48}}})(),yt=Symbol("verified"),wt=e=>e instanceof Object;function kt(e){if(!wt(e))return!1;if("number"!=typeof e.kind)return!1;if("string"!=typeof e.content)return!1;if("number"!=typeof e.created_at)return!1;if("string"!=typeof e.pubkey)return!1;if(!e.pubkey.match(/^[a-f0-9]{64}$/))return!1;if(!Array.isArray(e.tags))return!1;for(let t=0;te.created_at!==t.created_at?t.created_at-e.created_at:e.id.localeCompare(t.id))}var St={};i(St,{binarySearch:()=>Lt,bytesToHex:()=>_,hexToBytes:()=>S,insertEventIntoAscendingList:()=>At,insertEventIntoDescendingList:()=>Et,mergeReverseSortedLists:()=>Mt,normalizeURL:()=>Pt,utf8Decoder:()=>Ct,utf8Encoder:()=>Tt});var Ct=new TextDecoder("utf-8"),Tt=new TextEncoder;function Pt(e){try{-1===e.indexOf("://")&&(e="wss://"+e);let t=new URL(e);return"http:"===t.protocol?t.protocol="ws:":"https:"===t.protocol&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),("80"===t.port&&"ws:"===t.protocol||"443"===t.port&&"wss:"===t.protocol)&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch(t){throw new Error(`Invalid URL: ${e}`)}}function Et(e,t){const[n,a]=Lt(e,e=>t.id===e.id?0:t.created_at===e.created_at?-1:e.created_at-t.created_at);return a||e.splice(n,0,t),e}function At(e,t){const[n,a]=Lt(e,e=>t.id===e.id?0:t.created_at===e.created_at?-1:t.created_at-e.created_at);return a||e.splice(n,0,t),e}function Lt(e,t){let n=0,a=e.length-1;for(;n<=a;){const i=Math.floor((n+a)/2),r=t(e[i]);if(0===r)return[i,!0];r<0?a=i-1:n=i+1}return[n,!1]}function Mt(e,t){const n=new Array(e.length+t.length);n.length=0;let a=0,i=0,r=[];for(;at[i]?.created_at?(o=e[a],a++):(o=t[i],i++),n.length>0&&n[n.length-1].created_at===o.created_at){if(r.includes(o.id))continue}else r.length=0;n.push(o),r.push(o.id)}for(;a0&&n[n.length-1].created_at===t.created_at){if(r.includes(t.id))continue}else r.length=0;n.push(t),r.push(t.id)}for(;i0&&n[n.length-1].created_at===e.created_at){if(r.includes(e.id))continue}else r.length=0;n.push(e),r.push(e.id)}return n}function Rt(e){if(!kt(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function zt(e){return _(j(Tt.encode(Rt(e))))}var It=new class{generateSecretKey(){return bt.utils.randomSecretKey()}getPublicKey(e){return _(bt.getPublicKey(e))}finalizeEvent(e,t){const n=e;return n.pubkey=_(bt.getPublicKey(t)),n.id=zt(n),n.sig=_(bt.sign(S(zt(n)),t)),n[yt]=!0,n}verifyEvent(e){if("boolean"==typeof e[yt])return e[yt];try{const t=zt(e);if(t!==e.id)return e[yt]=!1,!1;const n=bt.verify(S(e.sig),S(t),S(e.pubkey));return e[yt]=n,n}catch(t){return e[yt]=!1,!1}}},Nt=It.generateSecretKey,Ot=It.getPublicKey,jt=It.finalizeEvent,Dt=It.verifyEvent,qt={};function Bt(e){return e<1e4&&0!==e&&3!==e}function Ft(e){return 0===e||3===e||1e4<=e&&e<2e4}function Vt(e){return 2e4<=e&&e<3e4}function Ut(e){return 3e4<=e&&e<4e4}function $t(e){return Bt(e)?"regular":Ft(e)?"replaceable":Vt(e)?"ephemeral":Ut(e)?"parameterized":"unknown"}function Ht(e,t){const n=t instanceof Array?t:[t];return kt(e)&&n.includes(e.kind)||!1}i(qt,{Application:()=>ga,BadgeAward:()=>en,BadgeDefinition:()=>ca,BlockedRelaysList:()=>Un,BlossomServerList:()=>Qn,BookmarkList:()=>Bn,Bookmarksets:()=>sa,Calendar:()=>Sa,CalendarEventRSVP:()=>Ca,ChannelCreation:()=>dn,ChannelHideMessage:()=>fn,ChannelMessage:()=>pn,ChannelMetadata:()=>hn,ChannelMuteUser:()=>mn,ChatMessage:()=>tn,ClassifiedListing:()=>ya,ClientAuth:()=>Xn,Comment:()=>yn,CommunitiesList:()=>Fn,CommunityDefinition:()=>Aa,CommunityPostApproval:()=>En,Contacts:()=>Yt,CreateOrUpdateProduct:()=>pa,CreateOrUpdateStall:()=>ha,Curationsets:()=>la,Date:()=>ka,DirectMessageRelaysList:()=>Kn,DraftClassifiedListing:()=>wa,DraftLong:()=>ma,Emojisets:()=>_a,EncryptedDirectMessage:()=>Qt,EventDeletion:()=>Zt,FavoriteRelays:()=>Hn,FileMessage:()=>on,FileMetadata:()=>bn,FileServerPreference:()=>Yn,Followsets:()=>ia,ForumThread:()=>nn,GenericRepost:()=>sn,Genericlists:()=>ra,GiftWrap:()=>gn,GroupMetadata:()=>La,HTTPAuth:()=>aa,Handlerinformation:()=>Ea,Handlerrecommendation:()=>Pa,Highlights:()=>Nn,InterestsList:()=>Wn,Interestsets:()=>da,JobFeedback:()=>Mn,JobRequest:()=>An,JobResult:()=>Ln,Label:()=>Pn,LightningPubRPC:()=>Jn,LiveChatMessage:()=>wn,LiveEvent:()=>va,LongFormArticle:()=>fa,Metadata:()=>Wt,Mutelist:()=>jn,NWCWalletInfo:()=>Zn,NWCWalletRequest:()=>ea,NWCWalletResponse:()=>ta,NormalVideo:()=>un,NostrConnect:()=>na,OpenTimestamps:()=>_n,Photo:()=>ln,Pinlist:()=>Dn,Poll:()=>vn,PollResponse:()=>On,PrivateDirectMessage:()=>rn,ProblemTracker:()=>Sn,ProfileBadges:()=>ua,PublicChatsList:()=>Vn,Reaction:()=>Xt,RecommendRelay:()=>Kt,RelayList:()=>qn,RelayReview:()=>Ta,Relaysets:()=>oa,Report:()=>Cn,Reporting:()=>Tn,Repost:()=>Jt,Seal:()=>an,SearchRelaysList:()=>$n,ShortTextNote:()=>Gt,ShortVideo:()=>cn,Time:()=>xa,UserEmojiList:()=>Gn,UserStatuses:()=>ba,Voice:()=>kn,VoiceComment:()=>xn,Zap:()=>In,ZapGoal:()=>Rn,ZapRequest:()=>zn,classifyKind:()=>$t,isAddressableKind:()=>Ut,isEphemeralKind:()=>Vt,isKind:()=>Ht,isRegularKind:()=>Bt,isReplaceableKind:()=>Ft});var Wt=0,Gt=1,Kt=2,Yt=3,Qt=4,Zt=5,Jt=6,Xt=7,en=8,tn=9,nn=11,an=13,rn=14,on=15,sn=16,ln=20,un=21,cn=22,dn=40,hn=41,pn=42,fn=43,mn=44,_n=1040,gn=1059,vn=1068,bn=1063,yn=1111,wn=1311,kn=1222,xn=1244,Sn=1971,Cn=1984,Tn=1984,Pn=1985,En=4550,An=5999,Ln=6999,Mn=7e3,Rn=9041,zn=9734,In=9735,Nn=9802,On=1018,jn=1e4,Dn=10001,qn=10002,Bn=10003,Fn=10004,Vn=10005,Un=10006,$n=10007,Hn=10012,Wn=10015,Gn=10030,Kn=10050,Yn=10096,Qn=10063,Zn=13194,Jn=21e3,Xn=22242,ea=23194,ta=23195,na=24133,aa=27235,ia=3e4,ra=30001,oa=30002,sa=30003,la=30004,ua=30008,ca=30009,da=30015,ha=30017,pa=30018,fa=30023,ma=30024,_a=30030,ga=30078,va=30311,ba=30315,ya=30402,wa=30403,ka=31922,xa=31923,Sa=31924,Ca=31925,Ta=31987,Pa=31989,Ea=31990,Aa=34550,La=39e3;function Ma(e,t){if(e.ids&&-1===e.ids.indexOf(t.id))return!1;if(e.kinds&&-1===e.kinds.indexOf(t.kind))return!1;if(e.authors&&-1===e.authors.indexOf(t.pubkey))return!1;for(let n in e)if("#"===n[0]){let a=e[`#${n.slice(1)}`];if(a&&!t.tags.find(([e,t])=>e===n.slice(1)&&-1!==a.indexOf(t)))return!1}return!(e.since&&t.created_ate.until)}function Ra(e,t){for(let n=0;n{if("kinds"===e||"ids"===e||"authors"===e||"#"===e[0]){t[e]=t[e]||[];for(let a=0;at.limit)&&(t.limit=a.limit),a.until&&(!t.until||a.until>t.until)&&(t.until=a.until),a.since&&(!t.since||a.sinceFt(e))?e.authors.length*e.kinds.length:1/0,e.authors?.length&&e.kinds?.every(e=>Ut(e))&&e["#d"]?.length?e.authors.length*e.kinds.length*e["#d"].length:1/0)}var Na={};function Oa(e,t){let n=t.length+3,a=e.indexOf(`"${t}":`)+n,i=e.slice(a).indexOf('"')+a+1;return e.slice(i,i+64)}function ja(e,t){let n=t.length,a=e.indexOf(`"${t}":`)+n+3,i=e.slice(a),r=Math.min(i.indexOf(","),i.indexOf("}"));return parseInt(i.slice(0,r),10)}function Da(e){let t=e.slice(0,22).indexOf('"EVENT"');if(-1===t)return null;let n=e.slice(t+7+1).indexOf('"');if(-1===n)return null;let a=t+7+1+n,i=e.slice(a+1,80).indexOf('"');if(-1===i)return null;let r=a+1+i;return e.slice(a+1,r)}function qa(e,t){return t===Oa(e,"id")}function Ba(e,t){return t===Oa(e,"pubkey")}function Fa(e,t){return t===ja(e,"kind")}i(Na,{getHex64:()=>Oa,getInt:()=>ja,getSubscriptionId:()=>Da,matchEventId:()=>qa,matchEventKind:()=>Fa,matchEventPubkey:()=>Ba});var Va={};function Ua(e,t){return{kind:Xn,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}i(Va,{makeAuthEvent:()=>Ua});var $a,Ha=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},Wa=class{url;_connected=!1;onclose=null;onnotice=e=>console.debug(`NOTICE from ${this.url}: ${e}`);onauth;baseEoseTimeout=4400;publishTimeout=4400;pingFrequency=29e3;pingTimeout=2e4;resubscribeBackoff=[1e4,1e4,1e4,2e4,2e4,3e4,6e4];openSubs=new Map;enablePing;enableReconnect;idleSince=Date.now();ongoingOperations=0;reconnectTimeoutHandle;pingIntervalHandle;reconnectAttempts=0;skipReconnection=!1;connectionPromise;openCountRequests=new Map;openEventPublishes=new Map;ws;challenge;authPromise;serial=0;verifyEvent;_WebSocket;constructor(e,t){this.url=Pt(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1}static async connect(e,t){const n=new Wa(e,t);return await n.connect(t),n}closeAllSubscriptions(e){for(let[t,n]of this.openSubs)n.close(e);this.openSubs.clear();for(let[t,n]of this.openEventPublishes)n.reject(new Error(e));this.openEventPublishes.clear();for(let[t,n]of this.openCountRequests)n.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}async reconnect(){const e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch(e){}},e)}handleHardClose(e){this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.enableReconnect&&!this.skipReconnection?this.reconnect():(this.onclose?.(),this.closeAllSubscriptions(e))}async connect(e){let t;return this.connectionPromise||(this.challenge=void 0,this.authPromise=void 0,this.skipReconnection=!1,this.connectionPromise=new Promise((n,a)=>{e?.timeout&&(t=setTimeout(()=>{a("connection timed out"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection timed out")},e.timeout)),e?.abort&&(e.abort.onabort=a);try{this.ws=new this._WebSocket(this.url)}catch(e){return clearTimeout(t),void a(e)}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(t),this._connected=!0;const e=this.reconnectAttempts>0;this.reconnectAttempts=0;for(const t of this.openSubs.values()){if(t.eosed=!1,e)for(let e=0;ethis.pingpong(),this.pingFrequency)),n()},this.ws.onerror=()=>{clearTimeout(t),a("connection failed"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection failed")},this.ws.onclose=e=>{clearTimeout(t),a(e.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)})),this.connectionPromise}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}waitForDummyReq(){return new Promise((e,t)=>{if(!this.connectionPromise)return t(new Error(`no connection to ${this.url}, can't ping`));try{const t=this.subscribe([{ids:["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],limit:0}],{label:"",oneose:()=>{e(!0),t.close()},onclose(){e(!0)},eoseTimeout:this.pingTimeout+1e3})}catch(e){t(e)}})}async pingpong(){if(1===this.ws?.readyState){await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(e=>setTimeout(()=>e(!1),this.pingTimeout))])||this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}}async send(e){if(!this.connectionPromise)throw new Ha(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){const t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise||(this.authPromise=new Promise(async(n,a)=>{try{let i=await e(Ua(this.url,t)),r=setTimeout(()=>{let e=this.openEventPublishes.get(i.id);e&&(e.reject(new Error("auth timed out")),this.openEventPublishes.delete(i.id))},this.publishTimeout);this.openEventPublishes.set(i.id,{resolve:n,reject:a,timeout:r}),this.send('["AUTH",'+JSON.stringify(i)+"]")}catch(e){console.warn("subscribe auth function failed:",e)}})),this.authPromise}async publish(e){this.idleSince=void 0,this.ongoingOperations++;const t=new Promise((t,n)=>{const a=setTimeout(()=>{const t=this.openEventPublishes.get(e.id);t&&(t.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:t,reject:n,timeout:a})});return this.send('["EVENT",'+JSON.stringify(e)+"]"),this.ongoingOperations--,0===this.ongoingOperations&&(this.idleSince=Date.now()),t}async count(e,t){this.serial++;const n=t?.id||"count:"+this.serial,a=new Promise((e,t)=>{this.openCountRequests.set(n,{resolve:e,reject:t})});return this.send('["COUNT","'+n+'",'+JSON.stringify(e).substring(1)),a}subscribe(e,t){""!==t.label&&(this.idleSince=void 0,this.ongoingOperations++);const n=this.prepareSubscription(e,t);return n.fire(),t.abort&&(t.abort.onabort=()=>n.close(String(t.abort.reason||""))),n}prepareSubscription(e,t){this.serial++;const n=t.id||(t.label?t.label+":":"sub:")+this.serial,a=new Ga(this,n,e,t);return this.openSubs.set(n,a),a}close(){this.skipReconnection=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.idleSince=void 0,this.onclose?.(),this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}_onmessage(e){const t=e.data;if(!t)return;const n=Da(t);if(n){const e=this.openSubs.get(n);if(!e)return;const a=Oa(t,"id"),i=e.alreadyHaveEvent?.(a);if(e.receivedEvent?.(this,a),i)return}try{let e=JSON.parse(t);switch(e[0]){case"EVENT":{const t=this.openSubs.get(e[1]),n=e[2];return this.verifyEvent(n)&&Ra(t.filters,n)?t.onevent(n):t.oninvalidevent?.(n),void((!t.lastEmitted||t.lastEmitted{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,e)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(e){if(!(e instanceof Ha))throw e}this.closed=!0}this.relay.openSubs.delete(this.id),this.relay.ongoingOperations--,0===this.relay.ongoingOperations&&(this.relay.idleSince=Date.now()),this.onclose?.(e)}};try{$a=WebSocket}catch{}var Ka,Ya=class extends Wa{constructor(e,t){super(e,{verifyEvent:Dt,websocketImplementation:$a,...t})}static async connect(e,t){const n=new Ya(e,t);return await n.connect(),n}},Qa=e=>(e[yt]=!0,!0),Za=class{relays=new Map;seenOn=new Map;trackRelays=!1;verifyEvent;enablePing;enableReconnect;automaticallyAuth;trustedRelayURLs=new Set;onRelayConnectionFailure;onRelayConnectionSuccess;allowConnectingToRelay;maxWaitForConnection;_WebSocket;constructor(e){this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect||!1,this.automaticallyAuth=e.automaticallyAuth,this.onRelayConnectionFailure=e.onRelayConnectionFailure,this.onRelayConnectionSuccess=e.onRelayConnectionSuccess,this.allowConnectingToRelay=e.allowConnectingToRelay,this.maxWaitForConnection=e.maxWaitForConnection||3e3}async ensureRelay(e,t){e=Pt(e);let n=this.relays.get(e);if(n||(n=new Wa(e,{verifyEvent:this.trustedRelayURLs.has(e)?Qa:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect}),n.onclose=()=>{this.relays.delete(e)},this.relays.set(e,n)),this.automaticallyAuth){const t=this.automaticallyAuth(e);t&&(n.onauth=t)}try{await n.connect({timeout:t?.connectionTimeout,abort:t?.abort})}catch(t){throw this.relays.delete(e),t}return n}close(e){e.map(Pt).forEach(e=>{this.relays.get(e)?.close(),this.relays.delete(e)})}subscribe(e,t,n){const a=[],i=[];for(let n=0;ne.url===r)||-1===i.indexOf(r)&&(i.push(r),a.push({url:r,filter:t}))}return this.subscribeMap(a,n)}subscribeMany(e,t,n){return this.subscribe(e,t,n)}subscribeMap(e,t){const n=new Map;for(const t of e){const{url:e,filter:a}=t;n.has(e)||n.set(e,[]),n.get(e).push(a)}const a=Array.from(n.entries()).map(([e,t])=>({url:e,filters:t}));this.trackRelays&&(t.receivedEvent=(e,t)=>{let n=this.seenOn.get(t);n||(n=new Set,this.seenOn.set(t,n)),n.add(e)});const i=new Set,r=[],o=[];let s=e=>{o[e]||(o[e]=!0,o.filter(e=>e).length===a.length&&(t.oneose?.(),s=()=>{}))};const l=[];let u=(e,n)=>{l[e]||(s(e),l[e]=n,l.filter(e=>e).length===a.length&&(t.onclose?.(l),u=()=>{}))};const c=e=>{if(t.alreadyHaveEvent?.(e))return!0;const n=i.has(e);return i.add(e),n},d=Promise.all(a.map(async({url:e,filters:n},a)=>{if(!1===this.allowConnectingToRelay?.(e,["read",n]))return void u(a,"connection skipped by allowConnectingToRelay");let i;try{i=await this.ensureRelay(e,{connectionTimeout:this.maxWaitForConnection<(t.maxWait||0)?Math.max(.8*t.maxWait,t.maxWait-1e3):this.maxWaitForConnection,abort:t.abort})}catch(t){return this.onRelayConnectionFailure?.(e),void u(a,t?.message||String(t))}this.onRelayConnectionSuccess?.(e);let o=i.subscribe(n,{...t,oneose:()=>s(a),onclose:e=>{e.startsWith("auth-required: ")&&t.onauth?i.auth(t.onauth).then(()=>{i.subscribe(n,{...t,oneose:()=>s(a),onclose:e=>{u(a,e)},alreadyHaveEvent:c,eoseTimeout:t.maxWait,abort:t.abort})}).catch(e=>{u(a,`auth was required and attempted, but failed with: ${e}`)}):u(a,e)},alreadyHaveEvent:c,eoseTimeout:t.maxWait,abort:t.abort});r.push(o)}));return{async close(e){await d,r.forEach(t=>{t.close(e)})}}}subscribeEose(e,t,n){let a;return a=this.subscribe(e,t,{...n,oneose(){const t="closed automatically on eose";a?a.close(t):n.onclose?.(e.map(e=>t))}}),a}subscribeManyEose(e,t,n){return this.subscribeEose(e,t,n)}async querySync(e,t,n){return new Promise(async a=>{const i=[];this.subscribeEose(e,t,{...n,onevent(e){i.push(e)},onclose(e){a(i)}})})}async get(e,t,n){t.limit=1;const a=await this.querySync(e,t,n);return a.sort((e,t)=>t.created_at-e.created_at),a[0]||null}publish(e,t,n){return e.map(Pt).map(async(e,a,i)=>{if(i.indexOf(e)!==a)return Promise.reject("duplicate url");if(!1===this.allowConnectingToRelay?.(e,["write",t]))return Promise.reject("connection skipped by allowConnectingToRelay");let r;try{r=await this.ensureRelay(e,{connectionTimeout:this.maxWaitForConnection<(n?.maxWait||0)?Math.max(.8*n.maxWait,n.maxWait-1e3):this.maxWaitForConnection,abort:n?.abort})}catch(t){return this.onRelayConnectionFailure?.(e),String("connection failure: "+String(t))}return r.publish(t).catch(async e=>{if(e instanceof Error&&e.message.startsWith("auth-required: ")&&n?.onauth)return await r.auth(n.onauth),r.publish(t);throw e}).then(e=>{if(this.trackRelays){let e=this.seenOn.get(t.id);e||(e=new Set,this.seenOn.set(t.id,e)),e.add(r)}return e})})}listConnectionStatus(){const e=new Map;return this.relays.forEach((t,n)=>e.set(n,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}pruneIdleRelays(e=1e4){const t=[];for(const[n,a]of this.relays)a.idleSince&&Date.now()-a.idleSince>=e&&(this.relays.delete(n),t.push(n),a.close());return t}};try{Ka=WebSocket}catch{}var Ja=class extends Za{constructor(e){super({verifyEvent:Dt,websocketImplementation:Ka,maxWaitForConnection:3e3,...e})}},Xa={};function ei(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&"Uint8Array"===e.constructor.name}function ti(e){if(!ei(e))throw new Error("Uint8Array expected")}function ni(e,t){return!!Array.isArray(t)&&(0===t.length||(e?t.every(e=>"string"==typeof e):t.every(e=>Number.isSafeInteger(e))))}function ai(e){if("function"!=typeof e)throw new Error("function expected");return!0}function ii(e,t){if("string"!=typeof t)throw new Error(`${e}: string expected`);return!0}function ri(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function oi(e){if(!Array.isArray(e))throw new Error("array expected")}function si(e,t){if(!ni(!0,t))throw new Error(`${e}: array of strings expected`)}function li(e,t){if(!ni(!1,t))throw new Error(`${e}: array of numbers expected`)}function ui(...e){const t=e=>e,n=(e,t)=>n=>e(t(n));return{encode:e.map(e=>e.encode).reduceRight(n,t),decode:e.map(e=>e.decode).reduce(n,t)}}function ci(e){const t="string"==typeof e?e.split(""):e,n=t.length;si("alphabet",t);const a=new Map(t.map((e,t)=>[e,t]));return{encode:a=>(oi(a),a.map(a=>{if(!Number.isSafeInteger(a)||a<0||a>=n)throw new Error(`alphabet.encode: digit index outside alphabet "${a}". Allowed: ${e}`);return t[a]})),decode:t=>(oi(t),t.map(t=>{ii("alphabet.decode",t);const n=a.get(t);if(void 0===n)throw new Error(`Unknown letter: "${t}". Allowed: ${e}`);return n}))}}function di(e=""){return ii("join",e),{encode:t=>(si("join.decode",t),t.join(e)),decode:t=>(ii("join.decode",t),t.split(e))}}function hi(e,t="="){return ri(e),ii("padding",t),{encode(n){for(si("padding.encode",n);n.length*e%8;)n.push(t);return n},decode(n){si("padding.decode",n);let a=n.length;if(a*e%8)throw new Error("padding: invalid, string should have whole number of bytes");for(;a>0&&n[a-1]===t;a--){if((a-1)*e%8==0)throw new Error("padding: invalid, string has too much padding")}return n.slice(0,a)}}}function pi(e){return ai(e),{encode:e=>e,decode:t=>e(t)}}function fi(e,t,n){if(t<2)throw new Error(`convertRadix: invalid from=${t}, base cannot be less than 2`);if(n<2)throw new Error(`convertRadix: invalid to=${n}, base cannot be less than 2`);if(oi(e),!e.length)return[];let a=0;const i=[],r=Array.from(e,e=>{if(ri(e),e<0||e>=t)throw new Error(`invalid integer: ${e}`);return e}),o=r.length;for(;;){let e=0,s=!0;for(let i=a;izi,Bech32MaxSize:()=>Ri,NostrTypeGuard:()=>Mi,decode:()=>Ni,decodeNostrURI:()=>Ii,encodeBytes:()=>Fi,naddrEncode:()=>$i,neventEncode:()=>Ui,noteEncode:()=>qi,nprofileEncode:()=>Vi,npubEncode:()=>Di,nsecEncode:()=>ji});var mi=(e,t)=>0===t?e:mi(t,e%t),_i=(e,t)=>e+(t-mi(e,t)),gi=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function vi(e,t,n,a){if(oi(e),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(n<=0||n>32)throw new Error(`convertRadix2: wrong to=${n}`);if(_i(t,n)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${n} carryBits=${_i(t,n)}`);let i=0,r=0;const o=gi[t],s=gi[n]-1,l=[];for(const a of e){if(ri(a),a>=o)throw new Error(`convertRadix2: invalid data word=${a} from=${t}`);if(i=i<32)throw new Error(`convertRadix2: carry overflow pos=${r} from=${t}`);for(r+=t;r>=n;r-=n)l.push((i>>r-n&s)>>>0);const e=gi[r];if(void 0===e)throw new Error("invalid carry");i&=e-1}if(i=i<=t)throw new Error("Excess padding");if(!a&&i>0)throw new Error(`Non-zero padding: ${i}`);return a&&r>0&&l.push(i>>>0),l}function bi(e,t=!1){if(ri(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(_i(8,e)>32||_i(e,8)>32)throw new Error("radix2: carry overflow");return{encode:n=>{if(!ei(n))throw new Error("radix2.encode input should be Uint8Array");return vi(Array.from(n),8,e,!t)},decode:n=>(li("radix2.decode",n),Uint8Array.from(vi(n,e,8,t)))}}function yi(e){return ai(e),function(...t){try{return e.apply(null,t)}catch(e){}}}ui(bi(4),ci("0123456789ABCDEF"),di("")),ui(bi(5),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),hi(5),di("")),ui(bi(5),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),di("")),ui(bi(5),ci("0123456789ABCDEFGHIJKLMNOPQRSTUV"),hi(5),di("")),ui(bi(5),ci("0123456789ABCDEFGHIJKLMNOPQRSTUV"),di("")),ui(bi(5),ci("0123456789ABCDEFGHJKMNPQRSTVWXYZ"),di(""),pi(e=>e.toUpperCase().replace(/O/g,"0").replace(/[IL]/g,"1")));var wi=(()=>"function"==typeof Uint8Array.from([]).toBase64&&"function"==typeof Uint8Array.fromBase64)(),ki=(e,t)=>{ii("base64",e);const n=t?/^[A-Za-z0-9=_-]+$/:/^[A-Za-z0-9=+/]+$/,a=t?"base64url":"base64";if(e.length>0&&!n.test(e))throw new Error("invalid base64");return Uint8Array.fromBase64(e,{alphabet:a,lastChunkHandling:"strict"})},xi=wi?{encode:e=>(ti(e),e.toBase64()),decode:e=>ki(e,!1)}:ui(bi(6),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),hi(6),di("")),Si=(ui(bi(6),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),di("")),wi||ui(bi(6),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),hi(6),di("")),ui(bi(6),ci("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),di("")),e=>{return ui((ri(t=58),{encode:e=>{if(!ei(e))throw new Error("radix.encode input should be Uint8Array");return fi(Array.from(e),256,t)},decode:e=>(li("radix.decode",e),Uint8Array.from(fi(e,t,256)))}),ci(e),di(""));var t}),Ci=(Si("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),Si("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"),Si("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"),ui(ci("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),di(""))),Ti=[996825010,642813549,513874426,1027748829,705979059];function Pi(e){const t=e>>25;let n=(33554431&e)<<5;for(let e=0;e>e&1)&&(n^=Ti[e]);return n}function Ei(e,t,n=1){const a=e.length;let i=1;for(let t=0;t126)throw new Error(`Invalid prefix (${e})`);i=Pi(i)^n>>5}i=Pi(i);for(let t=0;ta)throw new TypeError(`Length ${r} exceeds limit ${a}`);const o=e.toLowerCase(),s=Ei(o,n,t);return`${o}1${Ci.encode(n)}${s}`}function s(e,n=90){ii("bech32.decode input",e);const a=e.length;if(a<8||!1!==n&&a>n)throw new TypeError(`invalid string length: ${a} (${e}). Expected (8..${n})`);const i=e.toLowerCase();if(e!==i&&e!==e.toUpperCase())throw new Error("String must be lowercase or uppercase");const r=i.lastIndexOf("1");if(0===r||-1===r)throw new Error('Letter "1" must be present between prefix and data only');const o=i.slice(0,r),s=i.slice(r+1);if(s.length<6)throw new Error("Data must be at least 6 characters long");const l=Ci.decode(s).slice(0,-6),u=Ei(o,l,t);if(!s.endsWith(u))throw new Error(`Invalid checksum in ${e}: expected "${u}"`);return{prefix:o,words:l}}return{encode:o,decode:s,encodeFromBytes:function(e,t){return o(e,i(t))},decodeToBytes:function(e){const{prefix:t,words:n}=s(e,!1);return{prefix:t,words:n,bytes:a(n)}},decodeUnsafe:yi(s),fromWords:a,fromWordsUnsafe:r,toWords:i}}var Li=Ai("bech32"),Mi=(Ai("bech32m"),(()=>"function"==typeof Uint8Array.from([]).toHex&&"function"==typeof Uint8Array.fromHex)()||ui(bi(4),ci("0123456789abcdef"),di(""),pi(e=>{if("string"!=typeof e||e.length%2!=0)throw new TypeError(`hex.decode: expected string, got ${typeof e} with length ${e.length}`);return e.toLowerCase()})),{isNProfile:e=>/^nprofile1[a-z\d]+$/.test(e||""),isNEvent:e=>/^nevent1[a-z\d]+$/.test(e||""),isNAddr:e=>/^naddr1[a-z\d]+$/.test(e||""),isNSec:e=>/^nsec1[a-z\d]{58}$/.test(e||""),isNPub:e=>/^npub1[a-z\d]{58}$/.test(e||""),isNote:e=>/^note1[a-z\d]+$/.test(e||""),isNcryptsec:e=>/^ncryptsec1[a-z\d]+$/.test(e||"")}),Ri=5e3,zi=/[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;function Ii(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),Ni(e)}catch(e){return{type:"invalid",data:null}}}function Ni(e){let{prefix:t,words:n}=Li.decode(e,Ri),a=new Uint8Array(Li.fromWords(n));switch(t){case"nprofile":{let e=Oi(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for nprofile");if(32!==e[0][0].length)throw new Error("TLV 0 should be 32 bytes");return{type:"nprofile",data:{pubkey:_(e[0][0]),relays:e[1]?e[1].map(e=>Ct.decode(e)):[]}}}case"nevent":{let e=Oi(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for nevent");if(32!==e[0][0].length)throw new Error("TLV 0 should be 32 bytes");if(e[2]&&32!==e[2][0].length)throw new Error("TLV 2 should be 32 bytes");if(e[3]&&4!==e[3][0].length)throw new Error("TLV 3 should be 4 bytes");return{type:"nevent",data:{id:_(e[0][0]),relays:e[1]?e[1].map(e=>Ct.decode(e)):[],author:e[2]?.[0]?_(e[2][0]):void 0,kind:e[3]?.[0]?parseInt(_(e[3][0]),16):void 0}}}case"naddr":{let e=Oi(a);if(!e[0]?.[0])throw new Error("missing TLV 0 for naddr");if(!e[2]?.[0])throw new Error("missing TLV 2 for naddr");if(32!==e[2][0].length)throw new Error("TLV 2 should be 32 bytes");if(!e[3]?.[0])throw new Error("missing TLV 3 for naddr");if(4!==e[3][0].length)throw new Error("TLV 3 should be 4 bytes");return{type:"naddr",data:{identifier:Ct.decode(e[0][0]),pubkey:_(e[2][0]),kind:parseInt(_(e[3][0]),16),relays:e[1]?e[1].map(e=>Ct.decode(e)):[]}}}case"nsec":return{type:t,data:a};case"npub":case"note":return{type:t,data:_(a)};default:throw new Error(`unknown prefix ${t}`)}}function Oi(e){let t={},n=e;for(;n.length>0;){let e=n[0],a=n[1],i=n.slice(2,2+a);if(n=n.slice(2+a),i.lengthTt.encode(e))}))}function Ui(e){let t;return void 0!==e.kind&&(t=function(e){const t=new Uint8Array(4);return t[0]=e>>24&255,t[1]=e>>16&255,t[2]=e>>8&255,t[3]=255&e,t}(e.kind)),Bi("nevent",Hi({0:[S(e.id)],1:(e.relays||[]).map(e=>Tt.encode(e)),2:e.author?[S(e.author)]:[],3:t?[new Uint8Array(t)]:[]}))}function $i(e){let t=new ArrayBuffer(4);return new DataView(t).setUint32(0,e.kind,!1),Bi("naddr",Hi({0:[Tt.encode(e.identifier)],1:(e.relays||[]).map(e=>Tt.encode(e)),2:[S(e.pubkey)],3:[new Uint8Array(t)]}))}function Hi(e){let t=[];return Object.entries(e).reverse().forEach(([e,n])=>{n.forEach(n=>{let a=new Uint8Array(n.length+2);a.set([parseInt(e)],0),a.set([n.length],1),a.set(n,2),t.push(a)})}),C(...t)}var Wi=/\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g;function Gi(e){let t=[];for(let n of e.content.matchAll(Wi))if(n[2])try{let{type:e,data:a}=Ni(n[1]);switch(e){case"npub":t.push({text:n[0],profile:{pubkey:a,relays:[]}});break;case"nprofile":t.push({text:n[0],profile:a});break;case"note":t.push({text:n[0],event:{id:a,relays:[]}});break;case"nevent":t.push({text:n[0],event:a});break;case"naddr":t.push({text:n[0],address:a})}}catch(e){}else if(n[3]){let a=parseInt(n[3],10),i=e.tags[a];if(!i)continue;switch(i[0]){case"p":t.push({text:n[0],profile:{pubkey:i[1],relays:i[2]?[i[2]]:[]}});break;case"e":t.push({text:n[0],event:{id:i[1],relays:i[2]?[i[2]]:[]}});break;case"a":try{let[e,a,r]=i[1].split(":");t.push({text:n[0],address:{identifier:r,pubkey:a,kind:parseInt(e,10),relays:i[2]?[i[2]]:[]}})}catch(e){}}}return t}var Ki={};function Yi(e){if("boolean"!=typeof e)throw new Error(`boolean expected, not ${e}`)}function Qi(e){if(!Number.isSafeInteger(e)||e<0)throw new Error("positive integer expected, got "+e)}function Zi(e,t,n=""){const a=(i=e)instanceof Uint8Array||ArrayBuffer.isView(i)&&"Uint8Array"===i.constructor.name;var i;const r=e?.length,o=void 0!==t;if(!a||o&&r!==t){throw new Error((n&&`"${n}" `)+"expected Uint8Array"+(o?` of length ${t}`:"")+", got "+(a?`length=${r}`:"type="+typeof e))}return e}function Ji(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Xi(e){return new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4))}function er(...e){for(let t=0;tEr,encrypt:()=>Pr});var tr=(()=>68===new Uint8Array(new Uint32Array([287454020]).buffer)[0])();function nr(e,t){if(a=t,(n=e).buffer===a.buffer&&n.byteOffset{function n(n,...a){if(Zi(n,void 0,"key"),!tr)throw new Error("Non little-endian hardware is not yet supported");if(void 0!==e.nonceLength){Zi(a[0],e.varSizeNonce?void 0:e.nonceLength,"nonce")}const i=e.tagLength;i&&void 0!==a[1]&&Zi(a[1],void 0,"AAD");const r=t(n,...a),o=(e,t)=>{if(void 0!==t){if(2!==e)throw new Error("cipher output not supported");Zi(t,void 0,"output")}};let s=!1;return{encrypt(e,t){if(s)throw new Error("cannot encrypt() twice with same key + nonce");return s=!0,Zi(e),o(r.encrypt.length,t),r.encrypt(e,t)},decrypt(e,t){if(Zi(e),i&&e.length"e"===e&&t);return a&&!a[1].match(/^[a-f0-9]{64}$/)?"Zap request 'e' tag is not valid hex.":t.tags.find(([e,t])=>"relays"===e&&t)?null:"Zap request doesn't have a 'relays' tag."}function Is({zapRequest:e,preimage:t,bolt11:n,paidAt:a}){let i=JSON.parse(e),r=i.tags.filter(([e])=>"e"===e||"p"===e||"a"===e),o={kind:9735,created_at:Math.round(a.getTime()/1e3),content:"",tags:[...r,["P",i.pubkey],["bolt11",n],["description",e]]};return t&&o.tags.push(["preimage",t]),o}function Ns(e){if(e.length<50)return 0;const t=(e=e.substring(0,50)).lastIndexOf("1");if(-1===t)return 0;const n=e.substring(0,t);if(!n.startsWith("lnbc"))return 0;const a=n.substring(4);if(a.length<1)return 0;const i=a[a.length-1],r=i.charCodeAt(0)-"0".charCodeAt(0),o=r>=0&&r<=9;let s=a.length-1;if(o&&s++,s<1)return 0;const l=parseInt(a.substring(0,s));switch(i){case"m":return 1e5*l;case"u":return 100*l;case"n":return l/10;case"p":return l/1e4;default:return 1e8*l}}var Os={};i(Os,{Negentropy:()=>Gs,NegentropyStorageVector:()=>Ws,NegentropySync:()=>Qs});var js=32,Ds=0,qs=1,Bs=2,Fs=class{_raw;length;constructor(e){"number"==typeof e?(this._raw=new Uint8Array(e),this.length=0):e instanceof Uint8Array?(this._raw=new Uint8Array(e),this.length=e.length):(this._raw=new Uint8Array(512),this.length=0)}unwrap(){return this._raw.subarray(0,this.length)}get capacity(){return this._raw.byteLength}extend(e){if(e instanceof Fs&&(e=e.unwrap()),"number"!=typeof e.length)throw Error("bad length");const t=e.length+this.length;if(this.capacity>>=7;t.reverse();for(let e=0;e4294967295&&(n=1),a.setUint32(r,4294967295&o,!0),t=n,n=0}}negate(){let e=new DataView(this.buf.buffer);for(let t=0;t<8;t++){let n=4*t;e.setUint32(n,~e.getUint32(n,!0))}let t=new Uint8Array(js);t[0]=1,this.add(t)}getFingerprint(e){let t=new Fs;return t.extend(this.buf),t.extend(Us(e)),j(t.unwrap()).subarray(0,16)}},Ws=class{items;sealed;constructor(){this.items=[],this.sealed=!1}insert(e,t){if(this.sealed)throw Error("already sealed");const n=S(t);if(n.byteLength!==js)throw Error("bad id size for added item");this.items.push({timestamp:e,id:n})}seal(){if(this.sealed)throw Error("already sealed");this.sealed=!0,this.items.sort(Ys);for(let e=1;e=this.items.length)throw Error("out of range");return this.items[e]}iterate(e,t,n){this._checkSealed(),this._checkBounds(e,t);for(let a=e;aYs(e,n)<0)}fingerprint(e,t){let n=new Hs;return n.setToZero(),this.iterate(e,t,e=>(n.add(e.id),!0)),n.getFingerprint(t-e)}_checkSealed(){if(!this.sealed)throw Error("not sealed")}_checkBounds(e,t){if(e>t||t>this.items.length)throw Error("bad range")}_binarySearch(e,t,n,a){let i=n-t;for(;i>0;){let n=t,r=Math.floor(i/2);n+=r,a(e[n])?(t=++n,i-=r+1):i=r}return t}},Gs=class{storage;frameSizeLimit;lastTimestampIn;lastTimestampOut;constructor(e,t=6e4){if(t<4096)throw Error("frameSizeLimit too small");this.storage=e,this.frameSizeLimit=t,this.lastTimestampIn=0,this.lastTimestampOut=0}_bound(e,t){return{timestamp:e,id:t||new Uint8Array(0)}}initiate(){let e=new Fs;return e.extend(new Uint8Array([97])),this.splitRange(0,this.storage.size(),this._bound(Number.MAX_VALUE),e),_(e.unwrap())}reconcile(e,t,n){const a=new Fs(S(e));this.lastTimestampIn=this.lastTimestampOut=0;let i=new Fs;i.extend(new Uint8Array([97]));let r=$s(a,1)[0];if(r<96||r>111)throw Error("invalid negentropy protocol version byte");if(97!==r)throw Error("unsupported negentropy protocol version requested: "+(r-96));let o=this.storage.size(),s=this._bound(0),l=0,u=!1;for(;0!==a.length;){let e=new Fs,r=()=>{u&&(u=!1,e.extend(this.encodeBound(s)),e.extend(Us(Ds)))},c=this.decodeBound(a),d=Vs(a),h=l,p=this.storage.findLowerBound(l,o,c);if(d===Ds)u=!0;else if(d===qs){0!==Ks($s(a,16),this.storage.fingerprint(h,p))?(r(),this.splitRange(h,p,c,e)):u=!0}else{if(d!==Bs)throw Error("unexpected mode");{let e=Vs(a),i={};for(let t=0;t{let n=e.id;const a=_(n);return i[a]?delete i[_(n)]:t?.(a),!0}),n)for(let e of Object.values(i))n(_(e))}}if(this.exceededFrameSizeLimit(i.length+e.length)){let e=this.storage.fingerprint(p,o);i.extend(this.encodeBound(this._bound(Number.MAX_VALUE))),i.extend(Us(qs)),i.extend(e);break}i.extend(e),l=p,s=c}return 1===i.length?null:_(i.unwrap())}splitRange(e,t,n,a){let i=t-e;if(i<32)a.extend(this.encodeBound(n)),a.extend(Us(Bs)),a.extend(Us(i)),this.storage.iterate(e,t,e=>(a.extend(e.id),!0));else{let r=Math.floor(i/16),o=i%16,s=e;for(let e=0;e<16;e++){let i,l=r+(e(a===s-1?e=n:t=n,!0)),i=this.getMinimalBound(e,t)}a.extend(this.encodeBound(i)),a.extend(Us(qs)),a.extend(u)}}}exceededFrameSizeLimit(e){return e>this.frameSizeLimit-200}decodeTimestampIn(e){let t=Vs(e);return t=0===t?Number.MAX_VALUE:t-1,this.lastTimestampIn===Number.MAX_VALUE||t===Number.MAX_VALUE?(this.lastTimestampIn=Number.MAX_VALUE,Number.MAX_VALUE):(t+=this.lastTimestampIn,this.lastTimestampIn=t,t)}decodeBound(e){let t=this.decodeTimestampIn(e),n=Vs(e);if(n>js)throw Error("bound key too long");return{timestamp:t,id:$s(e,n)}}encodeTimestampOut(e){if(e===Number.MAX_VALUE)return this.lastTimestampOut=Number.MAX_VALUE,Us(0);let t=e;return e-=this.lastTimestampOut,this.lastTimestampOut=t,Us(e+1)}encodeBound(e){let t=new Fs;return t.extend(this.encodeTimestampOut(e.timestamp)),t.extend(Us(e.id.length)),t.extend(e.id),t}getMinimalBound(e,t){if(t.timestamp!==e.timestamp)return this._bound(t.timestamp);{let n=0,a=t.id,i=e.id;for(let e=0;et[n])return 1}return e.byteLength>t.byteLength?1:e.byteLength{switch(e[0]){case"NEG-MSG":e.length<3&&console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${e}`);try{const t=this.neg.reconcile(e[2],this.onhave,this.onneed);t?this.relay.send(`["NEG-MSG", "${this.subscription.id}", "${t}"]`):(this.close(),a.onclose?.())}catch(e){console.error("negentropy reconcile error:",e),a?.onclose?.(`reconcile error: ${e}`)}break;case"NEG-CLOSE":{const t=e[2];console.warn("negentropy error:",t),a.onclose?.(t);break}case"NEG-ERR":a.onclose?.()}}}async start(){const e=this.neg.initiate();this.relay.send(`["NEG-OPEN","${this.subscription.id}",${JSON.stringify(this.filter)},"${e}"]`)}close(){this.relay.send(`["NEG-CLOSE","${this.subscription.id}"]`),this.subscription.close()}},Zs={};i(Zs,{getToken:()=>el,hashPayload:()=>sl,unpackEventFromToken:()=>nl,validateEvent:()=>ul,validateEventKind:()=>il,validateEventMethodTag:()=>ol,validateEventPayloadTag:()=>ll,validateEventTimestamp:()=>al,validateEventUrlTag:()=>rl,validateToken:()=>tl});var Js,Xs="Nostr ";async function el(e,t,n,a=!1,i){const r={kind:aa,tags:[["u",e],["method",t]],created_at:Math.round((new Date).getTime()/1e3),content:""};i&&r.tags.push(["payload",sl(i)]);const o=await n(r);return(a?Xs:"")+xi.encode(Tt.encode(JSON.stringify(o)))}async function tl(e,t,n){const a=await nl(e).catch(e=>{throw e});return await ul(a,t,n).catch(e=>{throw e})}async function nl(e){if(!e)throw new Error("Missing token");e=e.replace(Xs,"");const t=Ct.decode(xi.decode(e));if(!t||0===t.length||!t.startsWith("{"))throw new Error("Invalid token");return JSON.parse(t)}function al(e){return!!e.created_at&&Math.round((new Date).getTime()/1e3)-e.created_at<60}function il(e){return e.kind===aa}function rl(e,t){const n=e.tags.find(e=>"u"===e[0]);return!!n&&(n.length>0&&n[1]===t)}function ol(e,t){const n=e.tags.find(e=>"method"===e[0]);return!!n&&(n.length>0&&n[1].toLowerCase()===t.toLowerCase())}function sl(e){return _(j(Tt.encode(JSON.stringify(e))))}function ll(e,t){const n=e.tags.find(e=>"payload"===e[0]);if(!n)return!1;const a=sl(t);return n.length>0&&n[1]===a}async function ul(e,t,n,a){if(!Dt(e))throw new Error("Invalid nostr event, signature invalid");if(!il(e))throw new Error("Invalid nostr event, kind invalid");if(!al(e))throw new Error("Invalid nostr event, created_at timestamp invalid");if(!rl(e,t))throw new Error("Invalid nostr event, url tag invalid");if(!ol(e,n))throw new Error("Invalid nostr event, method tag invalid");if(Boolean(a)&&"object"==typeof a&&Object.keys(a).length>0&&!ll(e,a))throw new Error("Invalid nostr event, payload tag does not match request body hash");return!0}return Js=r,((i,r,o,s)=>{if(r&&"object"==typeof r||"function"==typeof r)for(let l of n(r))a.call(i,l)||l===o||e(i,l,{get:()=>r[l],enumerable:!(s=t(r,l))||s.enumerable});return i})(e({},"__esModule",{value:!0}),Js)})();window.localisation={},window.localisation.de={confirm:"Ja",server:"Server",theme:"Theme",site_customisation:"Website-Anpassung",funding:"Funding",users:"Benutzer",audit:"Prüfung",apps:"Apps",channels:"Kanäle",transactions:"Transaktionen",dashboard:"Armaturenbrett",node:"Knoten",export_users:"Benutzer exportieren",no_users:"Keine Benutzer gefunden",total_capacity:"Gesamtkapazität",avg_channel_size:"Durchschn. Kanalgröße",biggest_channel_size:"Größte Kanalgröße",smallest_channel_size:"Kleinste Kanalgröße",number_of_channels:"Anzahl der Kanäle",active_channels:"Aktive Kanäle",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Offener Kanal",open:"Öffnen",close_channel:"Kanal schließen",close:"Schließen",restart:"Server neu starten",save:"Speichern",save_tooltip:"Änderungen speichern",credit_debit:"Kredit / Debit",credit_hint:"Klicke Enter, um das Konto zu belasten",credit_label:"{denomination} zu belasten",credit_ok:"Erfolgreiches Gutschreiben/Abziehen von virtuellen Geldern ({amount} Sats). Zahlungen hängen von den tatsächlichen Mitteln der Finanzierungsquelle ab.",restart_tooltip:"Starte den Server neu, um die Änderungen zu übernehmen",add_funds_tooltip:"Füge Geld zu einer Wallet hinzu.",reset_defaults:"Zurücksetzen",reset_defaults_tooltip:"Alle Einstellungen auf die Standardeinstellungen zurücksetzen.",download_backup:"Datenbank-Backup herunterladen",name_your_wallet:"Vergib deiner {name} Wallet einen Namen",paste_invoice_label:"Füge eine Rechnung, Zahlungsanforderung oder LNURL ein *",lnbits_description:"Einfach zu installieren und kompakt, LNbits kann auf jeder Funding-Quelle im Lightning Netzwerk aufsetzen und sogar LNbits selbst! Du kannst LNbits für dich selbst betreiben oder anderen die Verwaltung durch dich anbieten. Jede Wallet hat ihre eigenen API-Schlüssel und die Anzahl der Wallets ist unbegrenzt. Die Möglichkeit, Gelder auf verschiedene Accounts mit unterschiedlicher Logik aufteilen zu können macht LNbits zu einem nützlichen Werkzeug für deine Buchhaltung - aber auch als Entwicklungswerkzeug. Erweiterungen bereichern LNbits Accounts um zusätzliche Funktionalität, so dass du mit einer Reihe von neuartigen Technologien auf dem Lightning-Netzwerk experimentieren kannst. Wir haben es so einfach wie möglich gemacht, Erweiterungen zu entwickeln, und als freies und Open-Source-Projekt möchten wir Menschen ermutigen, sich selbst hieran zu versuchen und gemeinsam mit uns neue Funktionalitäten zu entwickeln.",export_to_phone:"Auf dem Telefon öffnen",export_to_phone_desc:"Dieser QR-Code beinhaltet vollständige Rechte auf deine Wallet. Du kannst den QR-Code mit Deinem Telefon scannen, um deine Wallet dort zu öffnen.",wallet:"Brieftasche:",wallets:"Wallets",add_wallet:"Wallet hinzufügen",delete_wallet:"Wallet löschen",delete_wallet_desc:"Die Wallet wird gelöscht, die hierin beinhalteten Daten hierin oder innerhalb einer Erweiterung sind UNWIEDERBRINGLICH.",rename_wallet:"Wallet umbenennen",update_name:"Namen aktualisieren",fiat_tracking:"Fiat-Tracking",currency:"Währung",update_currency:"Währung aktualisieren",press_to_claim:"Klicken, um Bitcoin einzufordern.",donate:"Spenden",view_github:"Auf GitHub anzeigen",voidwallet_active:"VoidWallet ist aktiv! Zahlungen deaktiviert",use_with_caution:"BITTE MIT VORSICHT BENUTZEN - {name} Wallet ist noch BETA",service_fee:"Dienstleistungsgebühr: {amount} % pro Transaktion",service_fee_max:"Servicegebühr: {amount} % pro Transaktion (max {max} Sats)",service_fee_tooltip:"Bearbeitungsgebühr, die vom LNbits Server-Administrator pro ausgehender Transaktion berechnet wird",toggle_darkmode:"Auf Dark Mode umschalten",payment_reactions:"Zahlungsreaktionen",view_swagger_docs:"LNbits Swagger API-Dokumentation",api_docs:"API-Dokumentation",api_keys_api_docs:"Knoten-URL, API-Schlüssel und API-Dokumentation",api_keys_warning:"Diese Schlüssel sollten sicher aufbewahrt werden; ihre Weitergabe kann zum Verlust von Guthaben führen.",admin_key_warning:"Dein Admin-Schlüssel gewährt vollen Zugriff auf deine Wallet, einschließlich der Möglichkeit, Zahlungen zu senden. Teile ihn niemals, es sei denn, du vertraust dem Empfänger vollständig.",lnbits_version:"LNbits-Version",runs_on:"Läuft auf",paste:"Einfügen",paste_from_clipboard:"Einfügen aus der Zwischenablage",paste_request:"Anfrage einfügen",create_invoice:"Rechnung erstellen",camera_tooltip:"Verwende die Kamera, um eine Rechnung oder einen QR-Code zu scannen",export_csv:"Exportieren als CSV",chart_tooltip:"Diagramm anzeigen",pending:"Ausstehend",copy_invoice:"Rechnung kopieren",withdraw_from:"Abheben von",cancel:"Stornieren",scan:"Scannen",read:"Lesen",pay:"Zahlen",memo:"Memo",date:"Datum",payment_processing:"Zahlung wird verarbeitet ...",not_enough_funds:"Geldmittel sind erschöpft!",search_by_tag_memo_amount:"Suche nach Tag, Memo, Betrag",invoice_waiting:"Rechnung wartend auf Zahlung",payment_received:"Zahlung erhalten",payment_sent:"Zahlung gesendet",receive:"erhalten",send:"schicken",outgoing_payment_pending:"Ausgehende Zahlung wartend",drain_funds:"Sats abziehen",drain_funds_desc:"LNURL-withdraw QR-Code, der das Abziehen aller Geldmittel aus dieser Wallet erlaubt. Teile ihn mit niemandem! Kompatibel mit balanceCheck und balanceNotify, so dass dein Wallet die Sats nach dem ersten Abzug kontinuierlich von hier abziehen kann.",i_understand:"Ich verstehe",copy_wallet_url:"Wallet-URL kopieren",disclaimer_dialog_title:"Wichtig!",disclaimer_dialog:"Login-Funktionalität wird in einem zukünftigen Update veröffentlicht. Bis dahin ist die Speicherung der Wallet-URL als Lesezeichen absolut notwendig, um Zugriff auf die Wallet zu erhalten! Dieser Service ist in BETA und wir übernehmen keine Verantwortung für Verluste durch verlorene Zugriffe.",no_transactions:"Keine Transaktionen",manage:"Verwalten",exchanges:"Börsenplätze",extensions:"Erweiterungen",no_extensions:"Du hast noch keine Erweiterungen installiert :(",created:"Erstellt",search_extensions:"Sucherweiterungen",extension_sources:"Erweiterungsquellen",ext_sources_hint:"Repositorys, von denen die Erweiterungen heruntergeladen werden können.",ext_sources_label:"Quell-URL (verwenden Sie nur die offizielle LNbits-Erweiterungsquelle und vertrauenswürdige Quellen)",warning:"Warnung",repository:"Repository",confirm_continue:"Bist du sicher, dass du fortfahren möchtest?",manage_extension_details:"Erweiterung installieren/deinstallieren",install:"Installieren",uninstall:"Deinstallieren",drop_db:"Daten löschen",enable:"Aktivieren",pay_to_enable:"Zahlen Sie zum Aktivieren",enable_extension_details:"Erweiterung für aktuellen Benutzer aktivieren",disable:"Deaktivieren",delete:"Löschen",installed:"Installiert",activated:"Aktiviert",deactivated:"Deaktiviert",release_notes:"Versionshinweise",activate_extension_details:"Erweiterung für Benutzer verfügbar/nicht verfügbar machen",featured:"Vorgestellt",all:"Alle",only_admins_can_install:"(Nur Administratorkonten können Erweiterungen installieren)",admin_only:"Nur für Admins",new_version:"Neue Version",extension_depends_on:"Hängt ab von:",extension_rating_soon:"Bewertungen sind bald verfügbar",extension_installed_version:"Installierte Version",extension_uninstall_warning:"Sie sind dabei, die Erweiterung für alle Benutzer zu entfernen.",uninstall_confirm:"Ja, deinstallieren",extension_db_drop_info:"Alle Daten für die Erweiterung werden dauerhaft gelöscht. Es gibt keine Möglichkeit, diesen Vorgang rückgängig zu machen!",extension_db_drop_warning:"Sie sind dabei, alle Daten für die Erweiterung zu entfernen. Bitte geben Sie den Namen der Erweiterung ein, um fortzufahren:",extension_required_lnbits_version:"Diese Version erfordert mindestens die LNbits-Version",min_version:"Mindestwert (inklusive)",max_version:"Maximalwert (ausgeschlossen)",payment_hash:"Zahlungs-Hash",fee:"Gebühr",amount:"Menge",amount_sats:"Betrag (sats)",tag:"Tag",unit:"Einheit",description:"Beschreibung",expiry:"Ablauf",webhook:"Webhook",payment_proof:"Beleg",update:"Aktualisieren",update_available:"Aktualisierung {version} verfügbar!",latest_update:"Sie sind auf der neuesten Version {version}.",notifications:"Benachrichtigungen",no_notifications:"Keine Benachrichtigungen",notifications_disabled:"LNbits Statusbenachrichtigungen sind deaktiviert.",enable_notifications:"Aktiviere Benachrichtigungen",enable_notifications_desc:"Wenn aktiviert, werden die neuesten LNbits-Statusaktualisierungen, wie Sicherheitsvorfälle und Updates, abgerufen.",enable_watchdog:"Aktiviere Watchdog",enable_watchdog_desc:"Wenn aktiviert, wird Ihre Zahlungsquelle automatisch auf VoidWallet umgestellt, wenn Ihr Guthaben niedriger als das LNbits-Guthaben ist. Nach einem Update müssen Sie dies manuell aktivieren.",watchdog_interval:"Überwachungszeitintervall",watchdog_interval_desc:"Wie oft die Hintergrundaufgabe nach einem Abschaltsignal im Wachhund-Delta [node_balance - lnbits_balance] suchen soll (in Minuten).",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Limit, bevor der Notausschalter die Finanzierungsquelle auf VoidWallet ändert [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Benachrichtigungsquelle",notification_source_label:"Quell-URL (verwenden Sie nur die offizielle LNbits-Statusquelle und Quellen, denen Sie vertrauen können)",more:"mehr",less:"weniger",releases:"Veröffentlichungen",watchdog:"Wachhund",server_logs:"Serverprotokolle",ip_blocker:"IP-Sperre",security:"Sicherheit",security_tools:"Sicherheitstools",block_access_hint:"Zugriff per IP sperren",allow_access_hint:"Zugriff durch IP erlauben (überschreibt blockierte IPs)",enter_ip:"Geben Sie die IP ein und drücken Sie die Eingabetaste",rate_limiter:"Ratenbegrenzer",wallet_limiter:"Geldbeutel-Limiter",wallet_limit_max_withdraw_per_day:"Maximales tägliches Wallet-Auszahlungslimit in Sats (0 zum Deaktivieren)",wallet_max_ballance:"Maximales Guthaben der Wallet in Sats (0 zum Deaktivieren)",wallet_limit_secs_between_trans:"Mindestsekunden zwischen Transaktionen pro Wallet (0 zum Deaktivieren)",number_of_requests:"Anzahl der Anfragen",time_unit:"Zeiteinheit",minute:"Minute",second:"Sekunde",hour:"Stunde",disable_server_log:"Server-Log deaktivieren",enable_server_log:"Serverprotokollierung aktivieren",coming_soon:"Funktion demnächst verfügbar",session_has_expired:"Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.",instant_access_question:"Möchten Sie sofortigen Zugang?",login_with_user_id:"Mit Benutzer-ID anmelden",or:"oder",create_new_wallet:"Neue Geldbörse erstellen",login_to_account:"Melden Sie sich bei Ihrem Konto an",create_account:"Konto erstellen",account_settings:"Kontoeinstellungen",signin_with_nostr:"Mit Nostr fortfahren",signin_with_google:"Mit Google anmelden",signin_with_github:"Anmelden mit GitHub",signin_with_keycloak:"Mit Keycloak anmelden",username_or_email:"Benutzername oder E-Mail",password:"Passwort",password_config:"Passwortkonfiguration",password_repeat:"Passwortwiederholung",change_password:"Passwort ändern",update_credentials:"Anmeldeinformationen aktualisieren",update_pubkey:"Öffentlichen Schlüssel aktualisieren",set_password:"Passwort festlegen",invalid_password:"Das Passwort muss mindestens 8 Zeichen haben.",login:"Anmelden",register:"Registrieren",username:"Benutzername",pubkey:"Öffentlicher Schlüssel",user_id:"Benutzer-ID",email:"E-Mail",first_name:"Vorname",last_name:"Nachname",picture:"Bild",verify_email:"E-Mail verifizieren mit",account:"Konto",update_account:"Konto aktualisieren",invalid_username:"Ungültiger Benutzername",auth_provider:"Anbieter für Authentifizierung",my_account:"Mein Konto",back:"Zurück",logout:"Abmelden",look_and_feel:"Aussehen und Verhalten",toggle_gradient:"Verlauf umschalten",gradient_background:"Verlaufs-Hintergrund",language:"Sprache",color_scheme:"Farbschema",admin_settings:"Admin-Einstellungen",extension_cost:"Diese Version erfordert eine Zahlung von mindestens {cost} Sats.",extension_paid_sats:"Sie haben bereits {paid_sats} Sats bezahlt.",release_details_error:"Kann die Details zur Veröffentlichung nicht abrufen.",pay_from_wallet:"Zahlen aus dem Geldbeutel",wallet_required:"Wallet *",show_qr:"QR anzeigen",retry_install:"Installieren erneut versuchen",new_payment:"Neue Zahlung vornehmen",update_payment:"Zahlung aktualisieren",already_paid_question:"Haben Sie schon bezahlt?",sell:"Verkaufen",sell_require:"Zahlung anfordern, um die Erweiterung zu aktivieren",sell_info:"Die {name}-Erweiterung erfordert eine Zahlung von mindestens {amount} Satoshis, um aktiviert zu werden.",hide_empty_wallets:"Leere Geldbörsen verbergen",recheck:"Erneut überprüfen",contributors:"Mitwirkende",license:"Lizenz",reset_key:"Zurücksetzen-Schlüssel",reset_password:"Passwort zurücksetzen",border_choices:"Randoptionen",select_all:"Alles auswählen",nfc_supported:"NFC unterstützt",nfc_not_supported:"NFC wird nicht unterstützt",expire_date:"Ablaufdatum:",hash:"Hash:",welcome_lnbits:"Willkommen bei LNbits",setup_su_account:"Richten Sie das Superuser-Konto unten ein.",create_ticker_converter:"Währungsticker-Konverter erstellen",enable_audit:"Audit aktivieren",recommended:"Empfohlen",audit_desc:"HTTP-Anfragen entsprechend den angegebenen Filtern aufzeichnen",audit_record_req:"Anfragekörper aufzeichnen",audit_record_warning:"Warnung:",audit_record_req_warning_1:"Vertrauliche Daten (wie Passwörter) werden protokolliert.",audit_record_req_warning_2:"Der Anfragetext kann groß sein.",audit_record_use:"Verwenden Sie es mit Vorsicht.",audit_ip:"IP-Adresse aufzeichnen",audit_ip_desc:"Speichern Sie die IP-Adresse des Clients",audit_path_params:"Pfadparameter aufzeichnen",audit_query_params:"Abfrageparameter aufzeichnen",audit_http_methods:"HTTP-Methoden einschließen",audit_http_methods_hint:"Liste der HTTP-Methoden, die einbezogen werden sollen. Leere Listen bedeuten alle.",audit_http_methods_label:"HTTP-Methoden",audit_resp_codes:"HTTP-Antwortcodes einbeziehen",audit_resp_codes_hint:"Liste der einzuschließenden HTTP-Codes (regex-Match). Leere Liste bedeutet alle. Z.B.: 4.*, 5.*",audit_resp_codes_label:"HTTP-Antwortcode (Regex)",audit_paths:"Einfügepfade",audit_paths_hint:"Liste der aufzunehmenden Pfade (Regex-Übereinstimmung). Leere Liste bedeutet alle.",audit_paths_label:"HTTP-Pfad (Regex)",audit_paths_exclude:"Pfade ausschließen",audit_paths_exclude_hint:"Liste der auszuschließenden Pfade (regex-Match). Leere Liste bedeutet keine.",audit_paths_exclude_label:"HTTP-Pfad (Regex)",exchange_providers:"Austauschdienste",admin_extensions:"Admin-Erweiterungen",admin_extensions_label:"Admin-Erweiterungen",admin_extensions_hint:"Nur Benutzer mit Admin-Rechten können Erweiterungen verwenden.",user_default_extensions:"Standarderweiterungen des Benutzers",user_default_extensions_label:"Benutzererweiterungen",user_default_extensions_hint:"Erweiterungen, die standardmäßig für die Benutzer aktiviert werden.",miscellanous:"Verschiedenes",misc_disable_extensions:"Erweiterungen deaktivieren",misc_disable_extensions_label:"Alle Erweiterungen deaktivieren",misc_hide_api:"API ausblenden",misc_hide_api_label:"Verbirgt Wallet-API, Erweiterungen können es ehren",wallets_management:"Verwaltung von Geldbörsen",funding_source_info:"Finanzierungsquelleninformationen",funding_source:"Finanzierungsquelle: {wallet_class}",node_balance:"Kontostand: {balance} Sats",lnbits_balance:"LNbits-Guthaben: {balance} Sats",funding_reserve_percent:"Reservieren Prozent: {percent} %",node_management:"Knotenverwaltung",node_management_not_supported:"Knotenverwaltung wird von der aktiven Finanzierungsquelle nicht unterstützt",toggle_node_ui:"Node-Benutzeroberfläche",toggle_public_node_ui:"Öffentliche Knoten-Benutzeroberfläche",toggle_transactions_node_ui:"Transaktionen-Tab (Bei großen CLN-Knoten deaktivieren)",invoice_expiry:"Rechnungsablauf",invoice_expiry_label:"Rechnungsablauf (Sekunden)",fee_reserve:"Gebührenreserve",fee_reserve_msats:"Reservierungsgebühr in msats",fee_reserve_percent:"Reservierungsgebühr in Prozent",server_management:"Serververwaltung",base_url:"Basis-URL",base_url_label:"Statische/Basis-URL für den Server",authentication:"Authentifizierung",auth_token_expiry_label:"Token-Ablaufminuten",auth_token_expiry_hint:"Zeit in Minuten bis der Token abläuft",auth_allowed_methods_label:"Erlaubte Autorisierungsmethoden",auth_allowed_methods_hint:"Wählen Sie Autorisierungsmethoden aus",auth_nostr_label:"Nostr-Anforderungs-URL",auth_nostr_hint:"Absolute URL, die die Clients für die Anmeldung verwenden.",auth_google_ci_label:"Google-Client-ID",auth_google_ci_hint:"Stellen Sie sicher, dass die autorisierten Umleitungs-URIs https://{domain}/api/v1/auth/google/token enthalten",auth_google_cs_label:"Google-Client-Geheimnis",auth_gh_client_id_label:"GitHub-Client-ID",auth_gh_client_id_hint:"Stellen Sie sicher, dass die URL für den Autorisierungsrückruf auf https://{domain}/api/v1/auth/github/token gesetzt ist.",auth_gh_client_secret_label:"GitHub-Client-Geheimnis",auth_keycloak_label:"Keycloak Discovery-URL",auth_keycloak_ci_label:"Keycloak-Client-ID",auth_keycloak_ci_hint:"Stellen Sie sicher, dass die Autorisierungs-Callback-URL auf https://{domain}/api/v1/auth/keycloak/token eingestellt ist.",auth_keycloak_cs_label:"Keycloak-Client-Geheimnis",auth_keycloak_custom_org_label:"Keycloak Benutzerdefinierte Organisation",auth_keycloak_custom_icon_label:"Keycloak Benutzerdefiniertes Symbol (URL)",auth_oidc_label:"OIDC Discovery-URL",auth_oidc_ci_label:"OIDC-Client-ID",auth_oidc_ci_hint:"Stellen Sie sicher, dass die Autorisierungs-Callback-URL auf https://{domain}/api/v1/auth/oidc/token eingestellt ist.",auth_oidc_cs_label:"OIDC-Client-Geheimnis",auth_oidc_custom_org_label:"OIDC Benutzerdefinierter Organisationsname (z.B. Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC Benutzerdefiniertes Symbol (URL)",currency_settings:"Währungseinstellungen",allowed_currencies:"Erlaubte Währungen",allowed_currencies_hint:"Begrenzen Sie die Anzahl der verfügbaren Fiat-Währungen",default_account_currency:"Standardkontowährung",default_account_currency_hint:"Standardwährung für Buchhaltung",service_fee_label:"Servicegebühr (%)",service_fee_hint:"Gebühr pro Transaktion (%)",service_fee_max_label:"Servicegebühr max. (sats)",service_fee_max_hint:"Maximale Servicegebühr in (sats) berechnen.",fee_wallet:"Gebühren-Wallet",fee_wallet_label:"Gebühren-Wallet (Wallet-ID)",fee_wallet_hint:"Wallet-ID, an die Gelder gesendet werden sollen",disable_fee:"Gebühr deaktivieren",disable_fee_internal:"Dienstleistungsgebühr für interne Zahlungen deaktivieren",disable_fee_internal_desc:"Dienstleistungsgebühr für interne Lightning-Zahlungen deaktivieren",ui_management:"UI-Verwaltung",ui_site_title:"Seitentitel",ui_site_tagline:"Seitenslogan",ui_elements_enable:"Elemente auf der Startseite aktivieren",ui_elements_disable:"Elemente auf der Startseite deaktivieren",ui_toggle_elements_tip:"Entfernen Sie Homepage-Elemente wie 'läuft auf' usw.",ui_site_description:"Seitenbeschreibung",ui_site_description_hint:"Verwenden Sie einfachen Text, Markdown oder rohes HTML",ui_default_wallet_name:"Standard-Walletname",lnbits_wallet:"LNbits-Wallet",denomination:"Nomination",denomination_hint:"Der Name für das FakeWallet-Token",ui_qr_code_logo:"QR-Code-Logo",ui_qr_code_logo_hint:"URL zum Logo-Bild im QR-Code",ui_custom_badge:"Benutzerdefiniertes Abzeichen",ui_custom_badge_label:"Benutzerdefiniertes Abzeichen 'MIT VORSICHT VERWENDEN - LNbits-Wallet ist noch in der BETA-Phase'",ui_custom_badge_color_label:"Benutzerdefinierte Abzeichenfarbe",themes:"Themen",themes_hint:"Wählen Sie Themen, die für Benutzer verfügbar sind",custom_logo:"Benutzerdefiniertes Logo",custom_logo_hint:"URL zum Logobild",ad_space_title:"Anzeigentitel",ad_space_title_label:"Unterstützt von",ad_slots:"Werbeplätze",ad_slots_hint:"URL-Adressen und Bilddateipfade im CSV-Format, Erweiterungen können darauf achten",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anzeigen aktiviert",ads_disabled:"Anzeigen deaktiviert",user_management:"Benutzerverwaltung",admin_users:"Admin-Benutzer",admin_users_hint:"Benutzer mit Administratorrechten",admin_users_label:"Benutzer-ID",allowed_users:"Zugelassene Benutzer",allowed_users_hint:"Nur diese Benutzer können LNbits verwenden.",allowed_users_label:"Benutzer-ID",allow_creation_user:"Erlauben Sie die Erstellung neuer Benutzer",allow_creation_user_desc:"Erlauben Sie das Erstellen neuer Benutzer auf der Indexseite",components:"Komponenten",long_running_endpoints:"Top 5 lang laufende Endpunkte",http_request_methods:"HTTP-Anfragemethoden",http_response_codes:"HTTP-Antwortcodes",request_details:"Anfragedetails",http_request_details:"HTTP-Anfragedetails",block_explorer:"Block Explorer",enable_block_explorer:"Block Explorer aktivieren",block_explorer_desc:"Ermöglicht Nutzern das Durchsuchen von Bitcoin-Transaktionen und -Adressen über Electrum.",blockexplorer_public_api:"Öffentlicher API-Zugang",blockexplorer_public_api_desc:"Nicht-authentifizierten Zugriff auf die Block-Explorer-API-Endpunkte erlauben.",electrum_server_url:"Electrum-Server-URL",electrum_server_url_hint:"z.B. ssl://electrum.blockstream.info:50002 oder tcp://localhost:50001",blockexplorer_search_label:"Nach TXID oder Adresse suchen",blockexplorer_search_hint:"64-Zeichen-Hex = Transaktion · Alles andere = Bitcoin-Adresse",recent_blocks:"Aktuelle Blöcke",chain_tip:"Kettenspitze",block_height:"Blockhöhe",block_fee:"Blockgebühr",fee_estimates:"Gebührenschätzungen",confirmed_balance:"Bestätigtes Guthaben",unconfirmed_balance:"Unbestätigtes Guthaben",transaction_history:"Transaktionsverlauf",coinbase:"Coinbase",inputs:"Eingaben",outputs:"Ausgaben",confirmations:"Bestätigungen",confirmed:"Bestätigt",unconfirmed:"Unbestätigt",history_unavailable:"Transaktionsverlauf nicht verfügbar (Adresse hat zu viele Transaktionen)",address:"Adresse",block_number:"Block #{height}",block_diff:"Schw. {value}",block_hash:"Hash",previous_block:"Vorheriger Block",merkle_root:"Merkle-Wurzel",version:"Version",bits:"Bits",difficulty:"Schwierigkeit",nonce:"Nonce",txid:"TXID",vsize:"Virtuelle Größe",weight:"Gewicht",n_block_fee:"{n}-Block-Gebühr"},window.localisation.en={confirm:"Yes",server:"Server",theme:"Theme",site_customisation:"Site Customisation",funding:"Funding",users:"Users",audit:"Audit",api_watch:"API Watch",apps:"Apps",channels:"Channels",transactions:"Transactions",dashboard:"Dashboard",node:"Node",export_users:"Export Users",no_users:"No users found",total_capacity:"Total Capacity",avg_channel_size:"Avg. Channel Size",biggest_channel_size:"Biggest Channel Size",smallest_channel_size:"Smallest Channel Size",number_of_channels:"Number of Channels",active_channels:"Active Channels",connect_peer:"Connect Peer",connect:"Connect",reconnect:"Reconnect",open_channel:"Open Channel",open:"Open",clear:"Clear",close_channel:"Close Channel",close:"Close",restart:"Restart server",image_library:"Image Library",save:"Save",save_tooltip:"Save your changes",must_save:"You have unsaved changes",credit_debit:"Credit / Debit",credit_hint:"Press Enter to credit/debit wallet (negative values allowed)",credit_label:"{denomination} to credit/debit",credit_ok:"Success crediting/debiting virtual funds ({amount} sats). Payments depend on actual funds on funding source.",restart_tooltip:"Restart the server for changes to take effect",add_funds_tooltip:"Add funds to a wallet.",reset_defaults:"Reset to defaults",reset_defaults_tooltip:"Delete all settings and reset to defaults.",download_backup:"Download database backup",name_your_wallet:"Name your {name} wallet",paste_invoice_label:"Paste an invoice, payment request, Lightning Address or LNURL*",lnbits_description:"Easy to set up and lightweight, LNbits can run on any Lightning Network funding source and even LNbits itself! You can run LNbits for yourself, or easily offer a custodian solution for others. Each wallet has its own API keys and there is no limit to the number of wallets you can make. Being able to partition funds makes LNbits a useful tool for money management and as a development tool. Extensions add extra functionality to LNbits so you can experiment with a range of cutting-edge technologies on the lightning network. We have made developing extensions as easy as possible, and as a free and open-source project, we encourage people to develop and submit their own.",export_to_phone:"Export to Phone with QR Code",export_to_phone_desc:"This QR code contains your wallet URL with full access. You can scan it from your phone to open your wallet from there.",access_wallet_on_mobile:"Mobile Access",stored_paylinks:"Stored LNURL pay links",wallet:"Wallet: ",wallet_name:"Wallet name",wallet_type:"Wallet type",shared_wallet:"Shared Wallet",share_wallet:"Share Wallet",update_permissions:"Update Permissions",shared_wallet_id:"Shared Wallet ID",shared_wallet_desc:"You have been invited to have access to someone else's wallet.",wallets:"Wallets",exclude_wallets:"Exclude Wallets",add_wallet:"Add wallet",add_field:"Add field",reject_wallet:"Reject wallet",add_new_wallet:"Add a new wallet",pin_wallet:"Pin wallet",delete_wallet:"Delete wallet",delete_wallet_desc:"This whole wallet will be deleted, the funds will be UNRECOVERABLE.",rename_wallet:"Rename wallet",update_name:"Update name",fiat_tracking:"Fiat tracking",fiat_providers:"Fiat providers",fiat_warning_bitcoin:'Fiat providers can get twitchy about anything bitcoin, so avoid using word "bitcoin" in your memos!',currency:"Currency",update_currency:"Update currency",press_to_claim:"Press to claim bitcoin",claim_desc:"It seems you have a claimable amount of bitcoin but you don’t have a wallet yet. Press the button below to claim it. This will create a new wallet for you.",donate:"Donate",view_github:"View on GitHub",voidwallet_active:"VoidWallet is active! Payments disabled",voidwallet_active_user:"Funding source unavailable. Please contact your admin to configure.",voidwallet_active_admin:"Funding source unavailable. Click here to configure.",service_fee_badge:"Service fee: {amount} % per transaction",service_fee_max_badge:"Service fee: {amount} % per transaction (max {max} {denom})",service_fee_tooltip:"Service fee charged by the LNbits server admin per outgoing transaction",toggle_darkmode:"Toggle Dark Mode",payment_reactions:"Payment Reactions",view_swagger_docs:"View LNbits Swagger API docs",api_docs:"API docs",api_keys_api_docs:"Node URL, API keys and API docs",api_keys_warning:"These keys should be kept safe, sharing them could risk losing funds.",admin_key_warning:"Your admin key grants full access to your wallet, including the ability to send payments. Never share it unless you fully trust the recipient.",lnbits_version:"LNbits version",runs_on:"Runs on",paste:"Paste",paste_from_clipboard:"Paste from clipboard",paste_request:"Paste Request",create_invoice:"Create Invoice",camera_tooltip:"Use camera to scan an invoice/QR",export_csv:"Export to CSV",export_csv_details:"Export to CSV with details",chart_tooltip:"Show chart",pending:"Pending",copy_invoice:"Copy invoice",withdraw_from:"Withdraw from",cancel:"Cancel",scan:"Scan",read:"Read",write:"Write",pay:"Pay",sending:"Sending",memo:"Memo",date:"Date",path:"Path",internal_memo:"Internal memo (optional)",internal_memo_hint_receive:"This memo is not shown to the payer but it's stored in the invoice for your reference.",internal_memo_hint_pay:"This memo is not shown to the payee but it's stored in the payment for your reference.",payment_processing:"Processing payment...",payment_processing:"Processing payment...",payment_successful:"Payment successful!",payment_pending:"Payment pending...",payment_check:"Check payment",not_enough_funds:"Not enough funds!",search_by_tag_memo_amount:"Search by tag, memo, amount",search:"Search",invoice_waiting:"Invoice waiting to be paid",payment_received:"Payment Received",payment_sent:"Payment Sent",payment_failed:"Payment Failed",receive:"receive",send:"send",outgoing_payment_pending:"Outgoing payment pending",drain_funds:"Drain Funds",drain_funds_desc:"This is an LNURL-withdraw QR code for slurping everything from this wallet. Do not share with anyone. It is compatible with balanceCheck and balanceNotify so your wallet may keep pulling the funds continuously from here after the first withdraw.",i_understand:"I understand",copy_wallet_url:"Copy wallet URL",disclaimer_dialog_title:"Important!",disclaimer_dialog:"You *must* save your login credentials to be able to access your wallet again. If you lose them, you will lose access to your wallet and funds.\n\nFind your login credentials on your account settings page.\n\nLNbits holds no responsibility for loss of access to funds.",no_transactions:"No transactions made yet",manage:"Manage",exchanges:"Exchanges",extensions:"Extensions",no_extensions:"You don't have any extensions installed :(",created:"Created",created_at:"Created At",updated_at:"Updated At",search_extensions:"Search extensions",search_wallets:"Search wallets",extension_sources:"Extension Sources",ext_sources_hint:"Repositories from where the extensions can be downloaded",ext_sources_label:"Source URL (only use the official LNbits extension source, and sources you can trust)",wasm_sources_hint:"Repositories from where WASM extensions can be downloaded",wasm_sources_label:"WASM source URL (only use WASM extension sources you can trust)",warning:"Warning",repository:"Repository",confirm_continue:"Are you sure you want to continue?",manage_extension_details:"Install/uninstall extension",upload:"Upload",install:"Install",uninstall:"Uninstall",drop_db:"Remove Data",enable:"Enable",enabled:"Enabled",disabled:"Disabled",pay_to_enable:"Pay To Enable",enable_extension_details:"Enable extension for current user",disable:"Disable",delete:"Delete",installed:"Installed",activated:"Activated",deactivated:"Deactivated",activate:"Activate",deactivate:"Deactivate",release_notes:"Release Notes",activate_extension_details:"Make extension available/unavailable for users",featured:"Featured",categories:"Categories",all:"All",only_admins_can_install:"(Only admin accounts can install extensions)",only_admins_can_create_extensions:"Only admin accounts can create extensions",admin_only:"Admin Only",make_user_admin:"Make User Admin",revoke_admin:"Revoke Admin",new_version:"New Version",reviews_url:"Reviews URL",reviews_url_label:"Reviews server URL",reviews_url_hint:"Full PaidReviews URL including the settings id (e.g. https://example.com/paidreviews/SETTINGS_ID)",reviews_open:"View reviews",reviews_leave:"Leave a review",reviews_name:"Your name",reviews_comment:"Your review",reviews_rating:"Rating",reviews_submit:"Submit review",reviews_loading:"Loading reviews...",reviews_refresh:"Refresh reviews",reviews_error_load:"Could not load reviews",reviews_url_not_configured:"Reviews URL not configured",reviews_pay_invoice:"Pay invoice",reviews_invoice_paid:"Invoice paid",reviews_invoice_title:"Pay this invoice to submit your review",reviews_count:"Reviews",no_reviews:"No reviews yet",extension_has_free_release:"Has free releases",extension_has_paid_release:"Has paid releases",extension_depends_on:"Depends on:",extension_rating_soon:"Ratings coming soon",extension_installed_version:"Installed version",extension_uninstall_warning:"You are about to remove the extension for all users.",uninstall_confirm:"Yes, Uninstall",extension_db_drop_info:"All data for the extension will be permanently deleted. There is no way to undo this operation!",extension_db_drop_warning:"You are about to remove all data for the extension. Please type the extension name to continue:",extension_required_lnbits_version:"This release requires LNbits version",min_version:"Minimum (included)",max_version:"Maximum (excluded)",preimage:"Preimage",preimage_hint:"Preimage to settle the hold invoice",hold_invoice:"Hold Invoice",hold_invoice_description:"This invoice is on hold and requires a preimage to settle.",payment_hash:"Payment Hash",invoice_cancelled:"Invoice Cancelled",invoice_settled:"Invoice Settled",hold_invoice_payment_hash:"Payment hash for hold invoice (optional)",settle_invoice:"Settle Invoice",cancel_invoice:"Cancel Invoice",fee:"Fee",amount:"Amount",amount_limits:"Amount Limits",amount_sats:"Amount (sats)",faucest_wallet:"Faucet Wallet",faucest_wallet_desc_1:"Each time a payment is confirmed by the {provider} provider funds will be subtracted from this wallet.",faucest_wallet_desc_2:"This helps monitor all {provider} payments and their status.",faucest_wallet_desc_3:"This wallet must be topped up with the amount of sats that the admin is willing to offer in exchange for the fiat currency.",faucest_wallet_desc_4:"If this wallet is configured, but is empty, the {provider} payments will not be processed.",faucest_wallet_desc_5:"This wallet can eventually get to a negative balance if parallel fiat payments are made.",faucest_wallet_id:"Faucet Wallet ID (optional)",faucest_wallet_id_hint:"Wallet ID to use for the faucet. It will be used to send the funds to the user.",tag:"Tag",unit:"Unit",description:"Description",expiry:"Expiry",webhook:"Webhook",webhook_url:"Webhook URL",webhook_url_hint:"Webhook URL to send the payment details to. It will be called when the payment is completed.",copy_webhook_url:"Copy webhook URL",webhook_events_list:"The following events must be supported by the webhook:",webhook_stripe_description:"One the stripe side you must configure a webhook with a URL that points to your LNbits server.",webhook_square_description:"On the Square side configure a webhook pointing to this exact LNbits URL.",square_webhook_url_hint:"Must exactly match the Square notification URL. LNbits requires the /api/v1/callback/square path.",access_token:"Access Token",location_id:"Location ID",square_location_id_hint:"Square location ID to create payment links for. Use the endpoint to select sandbox or production.",api_version:"API Version",payment_proof:"Payment Proof",update:"Update",update_available:"Update {version} available!",funding_sources:"Funding Sources",funding_source:"Funding Source",requires_server_restart:"Changing these settings requires a server restart to take effect.",funding_source_info:"Select the active funding wallet",phoenixd_warning:"Phoenixd mnemonic is only available if phoenixd data-dir is specified and is readable by LNbits. It's not indicative of phoenixd not running. It just means LNbits cannot access the mnemonic to display it here.",latest_update:"You are on the latest version {version}.",notifications:"Notifications",notifications_configure:"Configure Notifications",notifications_nostr_config:"Nostr Configuration",notifications_enable_nostr:"Enable Nostr",notifications_enable_nostr_desc:"Send notifications over Nostr",notifications_nostr_private_key:"Nostr Private Key",notifications_nostr_private_key_desc:"Private key (hex or nsec) to sign the messages sent to Nostr",notifications_nostr_identifier:"Nostr Identifier",notifications_nostr_identifier_desc:"Nip5 identifier to send notifications to",notifications_nostr_identifiers:"Nostr Identifiers",notifications_nostr_identifiers_desc:"List of identifiers to send notifications to.",notifications_telegram_config:"Telegram Configuration",notifications_enable_telegram:"Enable Telegram",notifications_enable_telegram_desc:"Send notifications over Telegram",notifications_telegram_access_token:"Access Token",notifications_telegram_access_token_desc:"Access token for the bot",notifications_chat_id:"Telegram Chat ID",notifications_chat_id_desc:"Telegram Chat ID to send the notifications to",notifications_excluded_wallets_desc:"Do not send notifications for these wallets",notifications_email_config:"Email Configuration",notifications_enable_email:"Enable Email",notifications_enable_email_desc:"Send notifications over email",notifications_send_test_email:"Send test email",notifications_send_email:"Send email",notifications_send_email_desc:"Email you will send from",notifications_send_email_username:"Username",notifications_send_email_username_desc:"Username, will use the email if not set",notifications_send_email_password:"Send email password",notifications_send_email_password_desc:"Password for the email you will send from",notifications_send_email_server_port:"Send email SMTP port",notifications_send_email_server_port_desc:"Port for the SMTP server",notifications_send_email_server:"Send email SMTP server",notifications_send_email_server_desc:"SMTP server for the email you will send from",notifications_send_to_emails:"Emails to send to",notifications_send_to_emails_desc:"Emails notifications will be sent to",notification_settings_update:"Settings updated",notification_settings_update_desc:"Send a notification when server settings have been updated",notification_server_start_stop:"Server Start/Stop",notification_server_start_stop_desc:"Send a notification when the server has been started/stopped",notification_watchdog_limit:"Watchdog Limit Notification",notification_watchdog_limit_desc:"Send a notification when the watchdog limit has been reached (does not affect the funding source)",notification_server_status:"Server Status",notification_server_status_desc:"Send regular notifications about the server status (interval value in hours)",notification_incoming_payment:"Incoming Payments",notification_incoming_payment_desc:"Send a notification when a wallet has received a payment above the specified amount (sats)",notification_outgoing_payment:"Outgoing Payments",notification_outgoing_payment_desc:"Send a notification when a wallet has sent a payment above the specified amount (sats)",notification_credit_debit:"Credit / Debit",notification_credit_debit_desc:"Send a notification when a wallet has been credited/debited by the superuser",notification_balance_delta_changed:"Balance Delta Changed",notification_balance_delta_changed_desc:"Send a notification when the difference between the node balance and the LNbits balance has changed by more than the specified amount (in sats). Set to 0 to disable. This runs every minute.",watchdog_introduction:"Watchdog is a feature that allows you to automatically switch the LNbits funding source to VoidWallet if your node balance is lower than the LNbits balance by a certain threshold. This can help prevent overspending and keep your node's funds safe.",enable_watchdog:"Enable Watchdog",enable_watchdog_desc:"You will need to re-enable this manually after an update.",watchdog_interval:"Watchdog Check Interval",watchdog_interval_desc:"How often LNbits should check for a killswitch signal in the watchdog threshold delta value [node_balance - lnbits_balance] (in minutes).",watchdog_delta:"Watchdog Threshold Delta",watchdog_delta_desc:"The LNbit's > Node balance delta threshold. If this threshold is exceeded, the funding source is changed to VoidWallet.",status:"Status",notification_source:"Notification Source",notification_source_label:"Source URL (only use the official LNbits status source, and sources you can trust)",more:"more",more_count:"{count} more",less:"less",releases:"Releases",watchdog:"Watchdog",server_logs:"Server Logs",ip_blocker:"IP Blacklist/Whitelist",security:"Security",security_tools:"Security Tools",block_access_hint:"Block access by IP",allow_access_hint:"Allow access by IP (will override blocked IPs)",enter_ip:"Enter an IP address and press enter",rate_limiter:"Rate Limiter",callback_url_rules:"Callback URL Rules",enter_callback_url_rule:"Enter URL rule as regex and hit enter",callback_url_rule_hint:"Callback URLs (like LNURL one) will be validated against these rules. At leat one rule must match. No rule means all URLs are allowed.",wallet_limiter:"Wallet Limiter",wallet_config:"Wallet Config",wallet_charts:"Wallet Charts",wallet_limit_max_withdraw_per_day:"Max daily wallet withdrawal in sats (0 for no limit, -1 to block withdrawal)",wallet_max_ballance:"Wallet max balance in sats (0 to disable)",wallet_limit_secs_between_trans:"Min secs between transactions per wallet (0 to disable)",only_incoming_payments_allowed:"Allow incoming payments only",disable_outgoing_payments:"Disable outgoing payments",number_of_requests:"Number of requests to allow",number_of_requests_hint:'Number of requests to allow per "time unit" for the rate limiter. Set to 0 to disable.',time_unit:"Time unit",minute:"Minute",settings:"Settings",second:"Second",hour:"Hour",disable_server_log:"Disable Server Log",enable_server_log:"Enable Server Log",coming_soon:"Feature coming soon",session_has_expired:"Your session has expired. Please login again.",instant_access_question:"or instant access",login_with_user_id:"Login with user ID",or:"or",create_new_wallet:"Create New Wallet",delete_all_wallets:"Delete All Wallets",confirm_delete_all_wallets:"Are you sure you want to delete ALL wallets for this user?",login_to_account:"Login to your account",create_account:"Create account",account_settings:"Account Settings",signin_with_oauth:"Login with",signin_with_oauth_or:"or Login with",signin_with_nostr:"Continue with Nostr",signin_with_google:"Sign in with Google",signin_with_github:"Sign in with GitHub",signin_with_custom_org:"Sign in with {custom_org}",username_or_email:"Username or Email",password:"Password",password_config:"Password Config",password_repeat:"Password repeat",update_password:"Update Password",change_password:"Change Password",update_credentials:"Update Credentials",update_pubkey:"Update Public Key",nostr_pubkey_tooltip:"Enter this user's Nostr public key (hex value)",set_password:"Set Password",set_password_tooltip:"Set a password for this user",invalid_password:"Password must have at least 8 characters",invalid_password_repeat:"Passwords do not match",reset_key_generated:"A reset key has been generated.",reset_key_copy:"Click OK to copy the reset URL to your clipboard.",login:"Login",register:"Register",username:"Username",pubkey:"Public Key",user_id:"User ID",id:"ID",email:"Email",first_name:"First Name",last_name:"Last Name",picture:"Picture",user_picture_desc:"URL to an image to use as profile picture. You can upload it as an asset.",verify_email:"Verify email with",account:"Account",update_account:"Update Account",invalid_username:"Invalid Username",auth_provider:"Auth Provider",external_id:"External ID",my_account:"My Account",existing_account_question:"Already have an account?",background_image:"Background Image",back:"Back",logout:"Logout",look_and_feel:"Look and Feel",endpoint:"Endpoint",api:"API",api_stripe:"API",api_token:"API Token",api_tokens:"API Tokens",access_control_list:"Access Control List",access_control_list_admin_warning:"This is an admin account. The generated tokens will have admin privileges.",new_api_acl:"New Access Control List",acl_token_active:"Active",acl_token_expired:"Expired",api_token_id:"Token Id",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",rounded_ui:"Rounded Cards & Buttons",toggle_rounded_ui:"Toggle rounded corners for cards and buttons",card_gradient:"Card Gradient",toggle_card_gradient:"Toggle gradient on cards",card_shadow:"Card Shadow",toggle_card_shadow:"Toggle shadow on cards",burger_menu_background:"Burger Menu Background",toggle_burger_menu_background:"Toggle burger menu background",language:"Language",assets:"Assets",max_asset_size_mb:"Max Asset Size (MB)",max_asset_size_mb_desc:"The maximum allowed size for asset uploads in megabytes (can use decimal values).",assets_allowed_mime_types:"Allowed MIME Types",assets_allowed_mime_types_desc:"The MIME types that are allowed for asset uploads. No value means all uploads are allowed.",thumbnail_width:"Thumbnail Width",thumbnail_width_desc:"Width of the generated thumbnail in pixels.",thumbnail_height:"Thumbnail Height",thumbnail_height_desc:"Height of the generated thumbnail in pixels.",thumbnail_format:"Thumbnail Format",thumbnail_format_desc:"Image format of the generated thumbnail (PNG, JPEG, etc.).",max_assets_per_user:"Max Assets Per User",max_assets_per_user_desc:"The maximum number of assets a user can upload. Zero means upload forbidden.",assets_no_limit_users:"Users Without Asset Limits",assets_no_limit_users_desc:"These users can upload an unlimited number of assets (user id based).",color_scheme:"Color Scheme",visible_wallet_count:"Visible Wallet Count",admin_settings:"Admin Settings",extension_cost:"This release requires a payment of minimum {cost} sats.",extension_paid_sats:"You have already paid {paid_sats} sats.",extension_permissions_title:"Grant extension permissions",extension_permissions_tab:"Extension Permissions",user_permissions_tab:"My Grants",extension_permissions_none:"This extension has no install-time permissions.",user_permissions_none:"You have not granted any permissions for this extension.",user_permissions_max_amount:"Max payment amount",user_permissions_destination_policy:"Allowed destinations",user_permissions_no_editable_settings:"This grant has no editable settings.",extension_permissions_grant_install:"Grant and install",extension_permissions_high_risk_warning:"This extension requests permissions that can move funds.",extension_permission_risk_low:"Low risk",extension_permission_risk_medium:"Medium risk",extension_permission_risk_high:"High risk",extension_permission_warning_wallet_pay_invoice:"Can spend funds from wallets available to your account.",extension_permission_warning_wallet_pay_invoice_background:"Can spend funds later from approved wallets without an active click.",extension_permission_warning_wallet_payments_watch:"Can read payment metadata for approved wallets.",extension_permission_warning_extension_api_request_write:"Can write data or trigger actions in approved extensions.",extension_permission_ext_storage_read:"Read extension storage",extension_permission_ext_storage_append_public:"Append public extension storage",extension_permission_ext_storage_append_public_sources:"Allowed append targets",extension_permission_ext_storage_append_public_max_rows_per_source:"Max rows per source",extension_permission_ext_storage_read_public:"Read public extension storage",extension_permission_ext_storage_read_public_source_required:"required to read",extension_permission_ext_storage_write:"Write extension storage",extension_permission_ext_storage_read_write:"Read & Write extension storage",extension_permission_extension_api_request:"Use other extensions",extension_permission_extension_api_request_extensions:"Allowed extensions",extension_permission_access_read:"Read",extension_permission_access_write:"Write",extension_permission_http_request:"Connect to external websites",extension_permission_http_request_hosts:"Allowed hosts",extension_permission_utils_basic:"Use basic LNbits utilities",extension_permission_ui_camera_scan_qr:"Scan QR codes",extension_permission_websocket:"Use extension websockets",extension_permission_websocket_publish_limits:"Publish limits",extension_permission_websocket_publish_max_messages_per_second:"Max messages per second",extension_permission_websocket_publish:"Publish websocket messages",extension_permission_websocket_subscribe:"Subscribe to websocket messages",extension_permission_wallet_payments_watch:"Watch wallet payments",extension_permission_wallet_create_invoice:"Create invoices",extension_permission_wallet_create_invoice_public:"Create Lightning invoices from public pages",extension_permission_wallet_balance_read:"View wallet balances",extension_permission_wallet_list:"List wallets",extension_permission_wallet_pay_invoice:"Pay invoices",extension_permission_wallet_pay_invoice_background:"Make background payments",create_extension:"Create Extension",release_details_error:"Cannot get the release details.",pay_from_wallet:"Pay from Wallet",pay_with:"Pay with {provider}",select_payment_provider:"Select payment provider",wallet_required:"Wallet *",show_qr:"Show QR",retry_install:"Retry Install",new_payment:"Make New Payment",update_payment:"Update Payment",already_paid_question:"Have you already paid?",sell:"Sell",sell_require:"Ask payment to enable extension",sell_info:"The {name} extension requires a payment of minimum {amount} sats to enable.",hide_empty_wallets:"Hide empty wallets",recheck:"Recheck",check:"Check",check_connection:"Check Connection",check_webhook:"Check Webhook",contributors:"Contributors",license:"License",reset_key:"Reset Key",reset_password:"Reset Password",border_choices:"Border Choices",select_all:"Select All",nfc_supported:"NFC Supported",nfc_not_supported:"NFC not Supported",expire_date:"Expire Date: ",hash:"Hash: ",welcome_lnbits:"Welcome to LNbits",setup_su_account:"Set up the Superuser account below.",first_install_token:"First Install Token",create_ticker_converter:"Create Currency Ticker Converter",enable_audit:"Enable Audit",recommended:"Recommended",audit_desc:"Log HTTP requests according to the filters specified below.",audit_record_req:"Log Request Body",audit_record_warning:"Warning!",audit_record_req_warning_1:"Sensitive data (like passwords) will be logged.",audit_record_req_warning_2:"The request body can be large. This can fill up your logs quickly.",audit_record_use:"Use this with caution!",audit_ip:"Log IP Address",audit_ip_desc:"Log the IP address of users making requests to LNbits.",audit_path_params:"Log Path Parameters",audit_query_params:"Log Query Parameters",audit_http_methods:"Include HTTP Methods",audit_http_methods_hint:"List of HTTP methods to be logged. No value means all methods will be logged.",audit_http_methods_label:"HTTP Methods to Log",audit_resp_codes_hint:"List of HTTP codes to be included (regex match). Empty lists means all. Eg: 4.*, 5.*",audit_resp_codes_label:"HTTP Response Codes to Log (regex)",audit_paths_hint:"List of paths to be included (regex match). Empty list means all.",audit_paths_label:"HTTP Paths to Log (regex)",audit_paths_exclude_hint:"List of paths to be excluded (regex match). Empty list means none.",audit_paths_exclude_label:"HTTP Paths to Exclude from Logging (regex)",exchange_providers:"Exchange Providers",admin_extensions:"Admin Extensions",admin_extensions_label:"Admin extensions",admin_extensions_hint:"Extensions only user with admin privileges can use",user_default_extensions:"User Default Extensions",user_default_extensions_label:"User extensions",user_default_extensions_hint:"Extensions that will be enabled by default for the users.",extension_builder:"Extension Builder",extension_builder_manifest_url:"Extension Builder Manifest URL",extension_builder_manifest_url_hint:"URL to a JSON manifest file with extension builder details",miscellanous:"Miscellanous",misc_disable_extensions:"Disable Extensions",misc_disable_extensions_label:"Disable all extensions",misc_disable_extensions_builder:"Enable Extensions Builder",misc_disable_extensions_builder_label:"Enable Extensions Builder for non admin users.",misc_hide_api:"Hide API",misc_hide_api_label:"Hides wallet API, extensions can choose to honor",wallets_management:"Wallets Management",funding_source_info:"Funding Source Information",funding_source:"Funding source: {wallet_class}",node_balance:"Node balance: {balance} sats",lnbits_balance:"LNbits balance: {balance} sats",funding_reserve_percent:"Funding reserve percentage: {percent} %",node_management:"Node Management",node_management_not_supported:"Node management is not supported by the active funding source",toggle_node_ui:"Node UI",toggle_public_node_ui:"Public Node UI",toggle_transactions_node_ui:"Transactions Tab (Disable on large CLN nodes)",invoice_expiry:"Invoice Expiry",routing_fee_reserve_calculations:"Routing Fee Reserve Calculations",routing_fee_reserve_calculations_desc:"LNbits sets aside a “reserve amount” for each payment to cover routing fees. The maximum routing fee passed to the funding source is whichever is higher: the minimum routing fee reserve or the routing fee reserve percentage.",millisats:"millisats",fee_reserve:"Minimum Routing Fee Reserve",fee_reserve_percent:"Routing Fee Reserve Percentage",fee_reserve_min_hint:"The minimum fee reserved per payment.
This acts as a floor - the maximum allowed routing fee will never be lower than this value regardless of payment size.",fee_reserve_percent_hint:"The percentage of the payment amount to reserve for routing fees.",payment_timeouts:"Payment Timeouts",payment_wait_time:"Payment Wait Time",seconds:"seconds",payment_pending_interval:"Check payment interval (sec)",payment_pending_interval_desc:"Interval to check pending payments",payment_pending_interval_tooltip:"Controls how often LNbits checks for pending payments to update their status. Higher values can reduce the load on the node and speed up the payment process, but it will take longer for pending payments to be updated.",payment_wait_time_desc:"Wait time before marking an outgoing payment as pending. Default: 5s; raise for slow-settling invoices.",payment_wait_time_tooltip:"Controls how long LNbits waits for an outgoing payment attempt to confirm before marking it as pending. Higher values help when paying slow-settling invoices (e.g., HODL invoices, Boltz). The payment will be rechecked later and updated automatically or manually.",server_management:"Server Management",base_url_label:"Base URL of the server",authentication:"Authentication",auth_token_expiry_label:"Token expiry (minutes)",auth_token_expiry_hint:"Time in minutes until the token expires",auth_authentication_cache_label:"Cache time (minutes)",auth_authentication_cache_hint:"Time in minutes to cache successful authentication (0 to disable)",auth_allowed_methods_label:"Allowed authorization methods",auth_allowed_methods_hint:"Select allowed authorization methods",auth_nostr_label:"Nostr Request URL",auth_nostr_hint:"Absolute URL that the clients will use to login.",auth_google_ci_label:"Google Client ID",auth_google_ci_hint:"Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub Client ID",auth_gh_client_id_hint:"Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Keycloak Discovery URL",auth_keycloak_ci_label:"Keycloak Client ID",auth_keycloak_ci_hint:"Make sure thant the authorization callback URL is set to https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",auth_keycloak_custom_org_label:"Keycloak Custom Organization",auth_keycloak_custom_icon_label:"Keycloak Custom Icon (URL)",auth_oidc_label:"OIDC Discovery URL",auth_oidc_ci_label:"OIDC Client ID",auth_oidc_ci_hint:"Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC Client Secret",auth_oidc_custom_org_label:"OIDC Custom Organization Name (e.g., Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC Custom Icon (URL)",currency_settings:"Currency Settings",allowed_currencies:"Allowed Currencies",allowed_currencies_hint:"Set the allowed fiat currencies for the exchange features",default_account_currency:"Default Accounting Currency",default_account_currency_hint:"The default currency to use for accounting features.",min_incoming_payment_amount:"Min Incoming Payment Amount",min_incoming_payment_amount_desc:"Minimum amount allowed for generating an invoice",max_incoming_payment_amount:"Maximum Incoming Payment Amount",max_incoming_payment_amount_desc:"Maximum amount allowed when generating an invoice",max_outgoing_payment_amount:"Maximum Outgoing Payment Amount",max_outgoing_payment_amount_desc:"Maximum amount allowed when making a payment",service_fees:"Service Fees",service_fee:"Service Fee",service_fee_label:"Service Fee Charged Per Transaction",service_fee_hint:"Fee charged per transaction (%)",service_fee_max:"Maximum Service Fee (sats)",service_fee_max_label:"Maximum Service Fee Limit",service_fee_max_hint:"Maximum service fee to charge in (sats)",fee_wallet_label:"Service Fee Wallet ID",fee_wallet_hint:"The ID of the wallet to which to send service funds",disable_fee:"Disable Service Fees for Internal Payments",ui_management:"UI Management",ui_site_title:"Site Title",ui_changing_remove_lnbits_elements:" (changing will remove LNbits elements on the homepage and footer)",ui_site_tagline:"Site Tagline",ui_elements_enable:"Enable elements on homepage/footer",ui_elements_disable:"Disable elements on homepage/footer",ui_toggle_elements_tip:"Remove homepage elements like 'runs on' etc",ui_site_description:"Site Description",ui_site_description_hint:"Use plain text, Markdown, or raw HTML",ui_default_wallet_name:"Default Wallet Name",ui_default_theme:"Default Theme",wallet_featured_button_title:"Wallet - Featured Button",wallet_featured_button_label:"Wallet Featured Button Label",wallet_featured_button_label_hint:"Show featured button on the wallet homepage",wallet_featured_button_url:"Featured Button URL",wallet_featured_button_url_hint:"On click the button will open this URL. Leave empty to hide the button.",wallet_featured_button_icon:"Featured Button Icon",wallet_featured_button_icon_hint:'Icon shown on the featured button (Quasar icon name e.g. "bolt")',lnbits_wallet:"LNbits wallet",denomination:"Denomination",denomination_hint:"The name for the FakeWallet token",denomination_error:"Denomination must be 3 characters, or `sats`",ui_qr_code_logo:"QR Code/Favicon Logo",ui_qr_code_logo_hint:"QR code icon and favicon logo URL",ui_apple_touch_icon:"Apple Touch Icon",ui_apple_touch_icon_hint:"Apple touch icon URL",ui_custom_image:"Custom Image",ui_custom_image_label:"URL to custom image",ui_custom_image_hint:"This image is shown on the LNbits homepage and login screen.",ui_custom_badge_title:"Custom Badge Settings",ui_custom_badge_desc:"Show a custom badge in the header of LNbits",ui_custom_badge:"Custom Badge Text",ui_custom_badge_label:"Custom Badge 'USE WITH CAUTION'",ui_custom_badge_color_label:"Custom Badge Color",themes:"Themes",themes_hint:"Choose themes available for users",custom_logo:"Custom Logo",custom_logo_hint:"URL to logo image",ad_space_section_title:"Advertisement Space",ad_space_section_desc:"Configure the advertisement space on the wallet sidebar.",ad_space_title:"Advertisement Space Title",ad_space_title_hint:"Title shown above the advertisement space",ad_slots:"Advertisement Slots",ad_slots_hint:"Advertisement image filepaths in CSV format, extensions can choose to honor. Format: url;img_light_url;img_dark_url, url..",ads_enabled:"Enable Advertisement",ads_disabled:"Disabled Advertisement",user_management:"User Management",admin_users:"Admin Users",admin_users_hint:"Users with admin privileges",admin_users_label:"User ID",allowed_users:"Allowed Users",allowed_users_hint:"Only these users can use LNbits",allowed_users_hint_feature:"Only these users can use {feature}",allowed_users_label:"User ID",allow_creation_user:"Allow creation of new users",allow_creation_user_desc:"Allow creation of new users on the index page",require_user_activation:"Require user activation",require_user_activation_desc:"New users will be activated only after they pass one of the confirmation methods. Admins can activate users manually from the admin panel.",reusable_activation_code:"Reusable activation code",reusable_activation_code_label:"Reusable activation code",reusable_activation_code_hint:"This activation code can be used multiple times by different users.",one_time_activation_code:"One-time activation codes",one_time_activation_code_label:"Add activation code",one_time_activation_code_hint:"List of one-time activation codes. Each code can be used only once, then will be reomved from the list.",invitation_code:"Invitation Code",invitation_code_hint:"The invitation code that you have received.",email:"Email",email_confirmation_hint:"Email address to send the confirmation code to.",nostr_identifier:"Nostr Identifier",nostr_identifier_hint:"Nostr nip5 identifier or to send the confirmation code to.",new_user_not_allowed:"Registration is disabled.",start_user_impersonation:"Impersonate this user",stop_user_impersonation:"Stop User Impersonation",components:"Components",long_running_endpoints:"Top 5 Long Running Endpoints",http_request_methods:"HTTP Request Methods",http_response_codes:"HTTP Response Codes",request_details:"Request Details",http_request_details:"HTTP Request Details",payment_details:"Payment Details",payment_details_desc:"Detailed information about the payment",payments:"Payments",payment_show_internal:"Show Internal Payments",payment_chart_flow:"Monthly Payment Flow",payment_chart_status:"Payment Status",payment_chart_tx_per_wallet:"Transactions per Wallet (balance/count)",payment_details_back:"Back to Payments",payment_chart_tags:"Payments by Tags",payments_balance_in_out:"Balance In/Out",payments_count_in_out:"Count In/Out",payments_status_chart:"Status Chart",payments_tag_chart:"Tag Chart",payments_balance_chart:"Balance Chart",payments_wallets_chart:"Wallets Chart",payments_balance_in_out_chart:"Balance In/Out Chart",payments_count_in_out_chart:"Count In/Out Chart",reset_wallet_keys:"Reset Keys",reset_wallet_keys_desc:"Reset the API keys for this wallet. This will invalidate the current keys and generate new ones.",view_list:"View wallets as list",view_column:"View wallets as rows",filter_payments:"Filter payments",filter_labels:"Filter labels",filter_date:"Filter by date",websocket_example:"Websocket example",client_id:"Client ID",secret_key:"Secret Key",signing_secret:"Signing Secret",signing_secret_hint:"Signing secret for the webhook. Messages will be signed with this secret.",webhook_id:"Webhook ID",webhook_id_hint:"PayPal webhook ID used to verify incoming events.",webhook_paypal_description:"On the PayPal side configure a webhook pointing to your LNbits server.",square_webhook_signature_key_hint:"Square webhook signature key used to verify incoming events.",callback_success_url:"Callback Success URL",callback_success_url_hint:"The user will be redirected to this URL after the payment is successful",connected:"Connected",not_connected:"Not Connected",free:"Free",paid:"Paid",funding_source_retries:"Max Retries",funding_source_retries_desc:"Maximum number of retries for funding sources, before it falls back to VoidWallet.",add_label:"Add Label",label:"Label",labels:"Labels",label_filter:"Label Filter",no_labels_defined:"No labels defined yet",manage_labels:"Manage Labels",update_label:"Update Label",delete_label:"Delete Label",add_remove_labels:"Add or Remove Labels",payment_labels_updated:"Payment labels updated",color:"Color",sort:"Sort",sort_by:"Sort by",lightning_address:"Lightning Address",lightning_addresses:"Lightning Addresses",lightning_address_price:"Lightning Address price",enable_lightning_address:"Enable Lightning Addresses",ln_address_mode:"Lightning Address Resolution Mode",ln_address_core_first:"Resolve from LNbits Core first",ln_address_extension_first:"Resolve from Pay Links extension first",ln_address_extension_only:"Resolve from Pay Links extension only",ln_address_mode_hint:"Choose how LNbits should resolve Lightning Addresses. Using both LNbits Core and the Pay Links extension will have a small impact on performance.",enable_lightning_address_for_all_wallets:"Enable Lightning Addresses for all LNbits wallets",allow_users_specify_lightning_addresses:"Allow users to specify Lightning Addresses",allow_wallet_owners_set_custom_lightning_addresses:"Allow wallet owners to set custom Lightning Addresses",charge_for_lightning_addresses:"Charge for Lightning Addresses",charge_users_set_change_lightning_address:"Charge users when they set or change a Lightning Address.",service_fee_wallet_id_must_be_set:"Service Fee Wallet ID must be set in the Service Fees section below for this to work.",lightning_address_blacklist:"Lightning Address blacklist",lightning_address_blacklist_instructions:"Newline separated reserved words. Users cannot choose a Lightning Address that matches any of these words.",set_lightning_address:"Set Lightning Address",block_explorer:"Block Explorer",enable_block_explorer:"Enable Block Explorer",block_explorer_desc:"Allow users to explore Bitcoin transactions and addresses via Electrum.",blockexplorer_public_api:"Public API Access",blockexplorer_public_api_desc:"Allow unauthenticated access to the block explorer API endpoints.",electrum_compatible_server:"Electrum compatible server",electrum_server_url:"Electrum Server URL",electrum_server_url_hint:"Choose a public Electrum server or enter your own.",electrum_server_url_custom:"Custom Electrum Server URL",view_public_electrum_servers:"View public Electrum servers",blockexplorer_network:"Bitcoin Network",blockexplorer_network_hint:"The network the Electrum server is connected to, used to render addresses correctly.",blockexplorer_search_label:"Search by TXID or Address",blockexplorer_search_hint:"64-char hex = transaction · anything else = Bitcoin address",recent_blocks:"Recent Blocks",chain_tip:"Chain Tip",block_height:"Block Height",block_fee:"block fee",fee_estimates:"Fee Estimates",confirmed_balance:"Confirmed Balance",unconfirmed_balance:"Unconfirmed Balance",transaction_history:"Transaction History",coinbase:"Coinbase",inputs:"Inputs",outputs:"Outputs",confirmations:"Confirmations",confirmed:"Confirmed",unconfirmed:"Unconfirmed",no_transactions:"No transactions found",history_unavailable:"Transaction history unavailable (address has too many transactions)",address:"Address",block_number:"Block #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Previous Block",merkle_root:"Merkle Root",version:"Version",bits:"Bits",difficulty:"Difficulty",nonce:"Nonce",txid:"TXID",vsize:"Virtual Size",weight:"Weight",n_block_fee:"{n}-block fee"},window.localisation.es={confirm:"Sí",server:"Servidor",theme:"Tema",site_customisation:"Personalización del sitio",funding:"Financiación",users:"Usuarios",audit:"Auditoría",apps:"Aplicaciones",channels:"Canales",transactions:"Transacciones",dashboard:"Tablero de instrumentos",node:"Nodo",export_users:"Exportar Usuarios",no_users:"No se encontraron usuarios",total_capacity:"Capacidad Total",avg_channel_size:"Tamaño Medio del Canal",biggest_channel_size:"Tamaño del Canal Más Grande",smallest_channel_size:"Tamaño de canal más pequeño",number_of_channels:"Número de canales",active_channels:"Canales activos",connect_peer:"Conectar Par",connect:"Conectar",open_channel:"Canal Abierto",open:"Abrir",close_channel:"Cerrar canal",close:"Cerrar",restart:"Reiniciar el servidor",save:"Guardar",save_tooltip:"Guardar cambios",credit_debit:"Crédito / Débito",credit_hint:"Presione Enter para cargar la cuenta",credit_label:"Cargar {denomination}",credit_ok:"Éxito al acreditar/debitar fondos virtuales ({amount} sats). Los pagos dependen de los fondos reales en la fuente de financiación.",restart_tooltip:"Reinicie el servidor para aplicar los cambios",add_funds_tooltip:"Agregue fondos a una billetera.",reset_defaults:"Restablecer",reset_defaults_tooltip:"Borrar todas las configuraciones y restablecer a los valores predeterminados.",download_backup:"Descargar copia de seguridad de la base de datos",name_your_wallet:"Nombre de su billetera {name}",paste_invoice_label:"Pegue la factura aquí",lnbits_description:"Fácil de instalar y liviano, LNbits puede ejecutarse en cualquier fuente de financiación de la red Lightning y hasta LNbits mismo! Puede ejecutar LNbits para usted mismo o ofrecer una solución competente a otros. Cada billetera tiene su propia clave API y no hay límite para la cantidad de billeteras que puede crear. La capacidad de particionar fondos hace de LNbits una herramienta útil para la administración de fondos y como herramienta de desarrollo. Las extensiones agregan funcionalidad adicional a LNbits, por lo que puede experimentar con una variedad de tecnologías de vanguardia en la red Lightning. Lo hemos hecho lo más simple posible para desarrollar extensiones y, como un proyecto gratuito y de código abierto, animamos a las personas a que se desarrollen a sí mismas y envíen sus propios contribuciones.",export_to_phone:"Exportar a teléfono con código QR",export_to_phone_desc:"Este código QR contiene su URL de billetera con acceso completo. Puede escanearlo desde su teléfono para abrir su billetera allí.",wallet:"Billetera:",wallets:"Billeteras",add_wallet:"Agregar nueva billetera",delete_wallet:"Eliminar billetera",delete_wallet_desc:"Esta billetera completa se eliminará, los fondos son IRREVERSIBLES.",rename_wallet:"Cambiar el nombre de la billetera",update_name:"Actualizar nombre",fiat_tracking:"Seguimiento Fiat",currency:"Moneda",update_currency:"Actualizar moneda",press_to_claim:"Presione para reclamar Bitcoin",donate:"Donar",view_github:"Ver en GitHub",voidwallet_active:"¡VoidWallet está activo! Pagos desactivados",use_with_caution:"USAR CON CUIDADO - {name} Wallet aún está en BETA",service_fee:"Tarifa de servicio: {amount} % por transacción",service_fee_max:"Tarifa de servicio: {amount} % por transacción (máx {max} sats)",service_fee_tooltip:"Comisión de servicio cobrada por el administrador del servidor LNbits por cada transacción saliente",toggle_darkmode:"Cambiar modo oscuro",payment_reactions:"Reacciones de Pago",view_swagger_docs:"Ver documentación de API de LNbits Swagger",api_docs:"Documentación de API",api_keys_api_docs:"URL del nodo, claves de API y documentación de API",api_keys_warning:"Estas claves deben mantenerse seguras; compartirlas podría provocar la pérdida de fondos.",admin_key_warning:"Tu clave de administrador otorga acceso total a tu billetera, incluida la posibilidad de enviar pagos. Nunca la compartas a menos que confíes plenamente en el destinatario.",lnbits_version:"Versión de LNbits",runs_on:"Corre en",paste:"Pegar",paste_from_clipboard:"Pegar desde el portapapeles",paste_request:"Pegar solicitud",create_invoice:"Crear factura",camera_tooltip:"Utilice la cámara para escanear una factura / código QR",export_csv:"Exportar a CSV",chart_tooltip:"Mostrar gráfico",pending:"Pendiente",copy_invoice:"Copiar factura",withdraw_from:"Retirar de",cancel:"Cancelar",scan:"Escanear",read:"Leer",pay:"Pagar",memo:"Memo",date:"Fecha",payment_processing:"Procesando pago ...",not_enough_funds:"¡No hay suficientes fondos!",search_by_tag_memo_amount:"Buscar por etiqueta, memo, cantidad",invoice_waiting:"Factura esperando pago",payment_received:"Pago recibido",payment_sent:"Pago enviado",receive:"recibir",send:"enviar",outgoing_payment_pending:"Pago saliente pendiente",drain_funds:"Drenar fondos",drain_funds_desc:"Este es un código QR LNURL-withdraw para drenar todos los fondos de esta billetera. No lo comparta con nadie. Es compatible con balanceCheck y balanceNotify, por lo que su billetera puede continuar drenando los fondos de aquí después del primer drenaje.",i_understand:"Lo entiendo",copy_wallet_url:"Copiar URL de billetera",disclaimer_dialog_title:"¡Importante!",disclaimer_dialog:"La funcionalidad de inicio de sesión se lanzará en una actualización futura, por ahora, asegúrese de guardar esta página como marcador para acceder a su billetera en el futuro. Este servicio está en BETA y no asumimos ninguna responsabilidad por personas que pierdan el acceso a sus fondos.",no_transactions:"No hay transacciones todavía",manage:"Administrar",exchanges:"Intercambios",extensions:"Extensiones",no_extensions:"No tienes extensiones instaladas :(",created:"Creado",search_extensions:"Extensiones de búsqueda",extension_sources:"Fuentes de extensión",ext_sources_hint:"Repositorios desde donde se pueden descargar las extensiones",ext_sources_label:"URL de origen (utilice solo la fuente oficial de la extensión LNbits y fuentes en las que pueda confiar)",warning:"Advertencia",repository:"Repositorio",confirm_continue:"¿Está seguro de que desea continuar?",manage_extension_details:"Instalar/desinstalar extensión",install:"Instalar",uninstall:"Desinstalar",drop_db:"Eliminar datos",enable:"Habilitar",pay_to_enable:"Pagar para habilitar",enable_extension_details:"Habilitar extensión para el usuario actual",disable:"Deshabilitar",delete:"Eliminar",installed:"Instalado",activated:"Activado",deactivated:"Desactivado",release_notes:"Notas de la versión",activate_extension_details:"Hacer que la extensión esté disponible/no disponible para los usuarios",featured:"Destacado",all:"Todos",only_admins_can_install:"(Solo las cuentas de administrador pueden instalar extensiones)",admin_only:"Solo administradores",new_version:"Nueva Versión",extension_depends_on:"Depende de:",extension_rating_soon:"Calificaciones próximamente",extension_installed_version:"Versión instalada",extension_uninstall_warning:"Está a punto de eliminar la extensión para todos los usuarios.",uninstall_confirm:"Sí, desinstalar",extension_db_drop_info:"Todos los datos para la extensión se eliminarán permanentemente. ¡No hay manera de deshacer esta operación!",extension_db_drop_warning:"Está a punto de eliminar todos los datos para la extensión. Por favor, escriba el nombre de la extensión para continuar:",extension_required_lnbits_version:"Esta versión requiere al menos una versión de LNbits",min_version:"Mínimo (incluido)",max_version:"Máximo (excluido)",payment_hash:"Hash de pago",fee:"Cuota",amount:"Cantidad",amount_sats:"Cantidad (sats)",tag:"Etiqueta",unit:"Unidad",description:"Descripción",expiry:"Expiración",webhook:"Webhook",payment_proof:"Prueba de pago",update:"Actualizar",update_available:"¡Actualización {version} disponible!",latest_update:"Usted está en la última versión {version}.",notifications:"Notificaciones",no_notifications:"No hay notificaciones",notifications_disabled:"Las notificaciones de estado de LNbits están desactivadas.",enable_notifications:"Activar notificaciones",enable_notifications_desc:"Si está activado, buscará las últimas actualizaciones del estado de LNbits, como incidentes de seguridad y actualizaciones.",enable_watchdog_desc:"Si está activado, cambiará automáticamente su fuente de financiamiento a VoidWallet si su saldo es inferior al saldo de LNbits. Tendrá que activarlo manualmente después de una actualización.",watchdog_interval:"Intervalo de vigilancia",watchdog_interval_desc:"Con qué frecuencia la tarea de fondo debe verificar la señal de killswitch en el delta del watchdog [node_balance - lnbits_balance] (en minutos).",watchdog_delta:"Vigilante Delta",watchdog_delta_desc:"Límite antes de que el interruptor de apagado cambie la fuente de financiamiento a VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fuente de notificación",notification_source_label:"URL de origen (solo use la fuente oficial de estado de LNbits y fuentes en las que confíe)",more:"más",less:"menos",releases:"Lanzamientos",watchdog:"Perro guardián",server_logs:"Registros del Servidor",ip_blocker:"Bloqueador de IP",security:"Seguridad",security_tools:"Herramientas de seguridad",block_access_hint:"Bloquear acceso por IP",allow_access_hint:"Permitir acceso por IP (anulará las IPs bloqueadas)",enter_ip:"Ingrese la IP y presione enter",rate_limiter:"Limitador de tasa",wallet_limiter:"Limitador de Cartera",wallet_limit_max_withdraw_per_day:"Límite diario de retiro de la cartera en sats (0 para deshabilitar)",wallet_max_ballance:"Saldo máximo de la billetera en sats (0 para desactivar)",wallet_limit_secs_between_trans:"Mín. segs entre transacciones por cartera (0 para desactivar)",number_of_requests:"Número de solicitudes",time_unit:"Unidad de tiempo",minute:"minuto",second:"segundo",hour:"hora",disable_server_log:"Desactivar registro del servidor",enable_server_log:"Activar registro del servidor",coming_soon:"Función próximamente disponible",session_has_expired:"Tu sesión ha expirado. Por favor, inicia sesión de nuevo.",instant_access_question:"¿Quieres acceso instantáneo?",login_with_user_id:"Iniciar sesión con ID de usuario",or:"o",create_new_wallet:"Crear Nueva Cartera",login_to_account:"Inicie sesión en su cuenta",create_account:"Crear cuenta",account_settings:"Configuración de la cuenta",signin_with_nostr:"Continuar con Nostr",signin_with_google:"Inicia sesión con Google",signin_with_github:"Inicia sesión con GitHub",signin_with_keycloak:"Iniciar sesión con Keycloak",username_or_email:"Nombre de usuario o correo electrónico",password:"Contraseña",password_config:"Configuración de Contraseña",password_repeat:"Repetición de contraseña",change_password:"Cambiar contraseña",update_credentials:"Actualizar credenciales",update_pubkey:"Actualizar clave pública",set_password:"Establecer contraseña",invalid_password:"La contraseña debe tener al menos 8 caracteres.",login:"Iniciar sesión",register:"Registrarse",username:"Nombre de usuario",pubkey:"Clave pública",user_id:"Identificación de usuario",email:"Correo electrónico",first_name:"Nombre de pila",last_name:"Apellido",picture:"Imagen",verify_email:"Verifique el correo electrónico con",account:"Cuenta",update_account:"Actualizar cuenta",invalid_username:"Nombre de usuario inválido",auth_provider:"Proveedor de Autenticación",my_account:"Mi cuenta",back:"Atrás",logout:"Cerrar sesión",look_and_feel:"Apariencia",toggle_gradient:"Alternar degradado",gradient_background:"Fondo de gradiente",language:"Idioma",color_scheme:"Esquema de colores",admin_settings:"Configuración del administrador",extension_cost:"Esta versión requiere un pago mínimo de {cost} sats.",extension_paid_sats:"Ya has pagado {paid_sats} sats.",release_details_error:"No se pueden obtener los detalles de la versión.",pay_from_wallet:"Pagar desde la billetera",wallet_required:"Billetera *",show_qr:"Mostrar QR",retry_install:"Reintentar Instalación",new_payment:"Realizar nuevo pago",update_payment:"Actualizar Pago",already_paid_question:"¿Ya has pagado?",sell:"Vender",sell_require:"Solicitar pago para habilitar la extensión",sell_info:"La extensión {name} requiere un pago mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar billeteras vacías",recheck:"Revisar de nuevo",contributors:"Colaboradores",license:"Licencia",reset_key:"Restablecer clave",reset_password:"Restablecer contraseña",border_choices:"Opciones de Borde",select_all:"Seleccionar todo",nfc_supported:"Compatible con NFC",nfc_not_supported:"NFC no compatible",expire_date:"Fecha de vencimiento:",hash:"Hash:",welcome_lnbits:"Bienvenido a LNbits",setup_su_account:"Configura la cuenta de Superusuario a continuación.",create_ticker_converter:"Crear Convertidor de Ticker de Moneda",enable_audit:"Habilitar auditoría",recommended:"Recomendado",audit_desc:"Registrar solicitudes HTTP de acuerdo con los filtros especificados",audit_record_req:"Registrar cuerpo de solicitud",audit_record_warning:"Advertencia:",audit_record_req_warning_1:"los datos confidenciales (como las contraseñas) serán registrados.",audit_record_req_warning_2:"el cuerpo de la solicitud puede tener un tamaño grande.",audit_record_use:"Úsalo con precaución.",audit_ip:"Registrar Dirección IP",audit_ip_desc:"Registra la dirección IP del cliente",audit_path_params:"Registrar parámetros de ruta",audit_query_params:"Registrar parámetros de consulta",audit_http_methods:"Incluye métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a incluir. Las listas vacías significan todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Respuesta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a incluir (coincidencia regex). Listas vacías significan todos. Ej: 4.*, 5.*",audit_resp_codes_label:"Código de respuesta HTTP (regex)",audit_paths:"Incluir rutas",audit_paths_hint:"Lista de rutas a incluir (coincidencia de expresión regular). Lista vacía significa todas.",audit_paths_label:"Ruta HTTP (regex)",audit_paths_exclude:"Excluir rutas",audit_paths_exclude_hint:"Lista de rutas a excluir (coincidencia de expresiones regulares). Lista vacía significa ninguna.",audit_paths_exclude_label:"Ruta HTTP (regex)",exchange_providers:"Proveedores de intercambio",admin_extensions:"Extensiones de Administración",admin_extensions_label:"Extensiones de administración",admin_extensions_hint:"Solo los usuarios con privilegios de administrador pueden usar extensiones.",user_default_extensions:"Extensiones predeterminadas del usuario",user_default_extensions_label:"Extensiones de usuario",user_default_extensions_hint:"Extensiones que estarán habilitadas de forma predeterminada para los usuarios.",miscellanous:"Misceláneo",misc_disable_extensions:"Desactivar extensiones",misc_disable_extensions_label:"Desactivar todas las extensiones",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta la API de la billetera, las extensiones pueden optar por respetar",wallets_management:"Gestión de Carteras",funding_source_info:"Información sobre la Fuente de Financiamiento",funding_source:"Fuente de financiamiento: {wallet_class}",node_balance:"Balance de Nodo: {balance} sats",lnbits_balance:"Saldo de LNbits: {balance} sats",funding_reserve_percent:"Reserve Porcentaje: {percent} %",node_management:"Gestión de nodos",node_management_not_supported:"La gestión de nodos no es compatible con la fuente de financiación activa",toggle_node_ui:"Interfaz de usuario de nodo",toggle_public_node_ui:"Interfaz Pública de Nodo",toggle_transactions_node_ui:"Pestaña de transacciones (desactivar en nodos CLN grandes)",invoice_expiry:"Vencimiento de la Factura",invoice_expiry_label:"Expiración de la factura (segundos)",fee_reserve:"Reserva de tarifa",fee_reserve_msats:"Cuota de reserva en msats",fee_reserve_percent:"Tasa de reserva en porcentaje",server_management:"Gestión del Servidor",base_url:"URL base",base_url_label:"URL base estática para el servidor",authentication:"Autenticación",auth_token_expiry_label:"Minutos de vencimiento del token",auth_token_expiry_hint:"Tiempo en minutos hasta que el token expire",auth_allowed_methods_label:"Métodos de autorización permitidos",auth_allowed_methods_hint:"Seleccione métodos de autorización",auth_nostr_label:"URL de solicitud Nostr",auth_nostr_hint:"URL absoluto que los clientes utilizarán para iniciar sesión.",auth_google_ci_label:"ID de cliente de Google",auth_google_ci_hint:"Asegúrate de que los URIs de redirección autorizados contengan https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secreto del Cliente de Google",auth_gh_client_id_label:"ID de cliente de GitHub",auth_gh_client_id_hint:"Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secreto del cliente de GitHub",auth_keycloak_label:"URL de descubrimiento de Keycloak",auth_keycloak_ci_label:"ID de cliente de Keycloak",auth_keycloak_ci_hint:"Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secreto del Cliente de Keycloak",auth_keycloak_custom_org_label:"Organización personalizada de Keycloak",auth_keycloak_custom_icon_label:"Icono personalizado de Keycloak (URL)",auth_oidc_label:"URL de descubrimiento de OIDC",auth_oidc_ci_label:"ID de cliente de OIDC",auth_oidc_ci_hint:"Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Secreto del Cliente de OIDC",auth_oidc_custom_org_label:"Nombre de organización personalizada OIDC (ej. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Icono personalizado de OIDC (URL)",currency_settings:"Configuración de moneda",allowed_currencies:"Monedas permitidas",allowed_currencies_hint:"Limite el número de monedas fiduciarias disponibles",default_account_currency:"Moneda predeterminada de la cuenta",default_account_currency_hint:"Moneda predeterminada para contabilidad",service_fee_label:"Tarifa de servicio (%)",service_fee_hint:"Tarifa cobrada por tx (%)",service_fee_max_label:"Tarifa de servicio máx (sats)",service_fee_max_hint:"Tarifa máxima por servicio a cobrar en (sats)",fee_wallet:"Billetera de Tarifas",fee_wallet_label:"Billetera de tarifas (ID de billetera)",fee_wallet_hint:"ID de la billetera a la que enviar fondos",disable_fee:"Desactivar tarifa",disable_fee_internal:"Desactivar tarifa de servicio para pagos internos",disable_fee_internal_desc:"Desactivar tarifa de servicio para pagos internos Lightning",ui_management:"Gestión de la interfaz de usuario",ui_site_title:"Título del Sitio",ui_site_tagline:"Lema del sitio",ui_elements_enable:"Habilitar elementos en la página de inicio",ui_elements_disable:"Desactivar elementos en la página de inicio",ui_toggle_elements_tip:"Eliminar elementos de la página de inicio como 'funciona en', etc.",ui_site_description:"Descripción del sitio",ui_site_description_hint:"Usa texto sin formato, Markdown o HTML sin procesar",ui_default_wallet_name:"Nombre predeterminado de la billetera",lnbits_wallet:"Cartera LNbits",denomination:"Denominación",denomination_hint:"El nombre para el token FakeWallet",ui_qr_code_logo:"Logo de código QR",ui_qr_code_logo_hint:"URL a la imagen del logo en el código QR",ui_custom_badge:"Insignia personalizada",ui_custom_badge_label:"Insignia personalizada 'USAR CON PRECAUCIÓN - La billetera LNbits aún está en BETA'",ui_custom_badge_color_label:"Color personalizado de insignia",themes:"Temas",themes_hint:"Elige los temas disponibles para los usuarios",custom_logo:"Logotipo personalizado",custom_logo_hint:"URL a la imagen del logo",ad_space_title:"Título del Espacio Publicitario",ad_space_title_label:"Respaldado por",ad_slots:"Espacios publicitarios",ad_slots_hint:"URL de anuncio y rutas de archivo de imagen en formato CSV, las extensiones pueden optar por respetar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anuncios habilitados",ads_disabled:"Anuncios desactivados",user_management:"Gestión de Usuarios",admin_users:"Usuarios Administradores",admin_users_hint:"Usuarios con privilegios de administrador",admin_users_label:"ID de usuario",allowed_users:"Usuarios Permitidos",allowed_users_hint:"Solo estos usuarios pueden usar LNbits",allowed_users_label:"ID de usuario",allow_creation_user:"Permitir la creación de nuevos usuarios",allow_creation_user_desc:"Permitir la creación de nuevos usuarios en la página de índice",components:"Componentes",long_running_endpoints:"Principales 5 puntos de conexión de larga duración",http_request_methods:"Métodos de solicitud HTTP",http_response_codes:"Códigos de Respuesta HTTP",request_details:"Detalles de la solicitud",http_request_details:"Detalles de la Solicitud HTTP",block_explorer:"Block Explorer",enable_block_explorer:"Activar Block Explorer",block_explorer_desc:"Permite a los usuarios explorar transacciones y direcciones de Bitcoin a través de Electrum.",blockexplorer_public_api:"Acceso a la API pública",blockexplorer_public_api_desc:"Permitir acceso no autenticado a los endpoints de la API del explorador de bloques.",electrum_server_url:"URL del servidor Electrum",electrum_server_url_hint:"p.ej. ssl://electrum.blockstream.info:50002 o tcp://localhost:50001",blockexplorer_search_label:"Buscar por TXID o dirección",blockexplorer_search_hint:"Hex de 64 caracteres = transacción · cualquier otra cosa = dirección Bitcoin",recent_blocks:"Bloques recientes",chain_tip:"Punta de cadena",block_height:"Altura de bloque",block_fee:"tarifa de bloque",fee_estimates:"Estimaciones de tarifa",confirmed_balance:"Saldo confirmado",unconfirmed_balance:"Saldo no confirmado",transaction_history:"Historial de transacciones",coinbase:"Coinbase",inputs:"Entradas",outputs:"Salidas",confirmations:"Confirmaciones",confirmed:"Confirmado",unconfirmed:"No confirmado",history_unavailable:"Historial de transacciones no disponible (la dirección tiene demasiadas transacciones)",address:"Dirección",block_number:"Bloque #{height}",block_diff:"dif {value}",block_hash:"Hash",previous_block:"Bloque anterior",merkle_root:"Raíz de Merkle",version:"Versión",bits:"Bits",difficulty:"Dificultad",nonce:"Nonce",txid:"TXID",vsize:"Tamaño virtual",weight:"Peso",n_block_fee:"tarifa {n} bloques"},window.localisation.fr={confirm:"Oui",server:"Serveur",theme:"Thème",site_customisation:"Personnalisation du site",funding:"Financement",users:"Utilisateurs",audit:"Audit",apps:"Applications",channels:"Canaux",transactions:"Transactions",dashboard:"Tableau de bord",node:"Noeud",export_users:"Exporter les utilisateurs",no_users:"Aucun utilisateur trouvé",total_capacity:"Capacité totale",avg_channel_size:"Taille moyenne du canal",biggest_channel_size:"Taille de canal maximale",smallest_channel_size:"Taille de canal la plus petite",number_of_channels:"Nombre de canaux",active_channels:"Canaux actifs",connect_peer:"Connecter un pair",connect:"Connecter",open_channel:"Ouvrir le canal",open:"Ouvrir",close_channel:"Fermer le canal",close:"Fermer",restart:"Redémarrer le serveur",save:"Enregistrer",save_tooltip:"Enregistrer vos modifications",credit_debit:"Crédit / Débit",credit_hint:"Appuyez sur Entrée pour créditer le compte",credit_label:"{denomination} à créditer",credit_ok:"Succès du crédit/débit des fonds virtuels ({amount} sats). Les paiements dépendent des fonds réels sur la source de financement.",restart_tooltip:"Redémarrez le serveur pour que les changements prennent effet",add_funds_tooltip:"Ajouter des fonds à un portefeuille.",reset_defaults:"Réinitialiser aux valeurs par défaut",reset_defaults_tooltip:"Supprimer tous les paramètres et les réinitialiser aux valeurs par défaut.",download_backup:"Télécharger la sauvegarde de la base de données",name_your_wallet:"Nommez votre portefeuille {name}",paste_invoice_label:"Coller une facture, une demande de paiement ou un code lnurl *",lnbits_description:"Facile à installer et léger, LNbits peut fonctionner sur n'importe quelle source de financement du réseau Lightning et même LNbits lui-même! Vous pouvez exécuter LNbits pour vous-même ou offrir facilement une solution de gardien pour les autres. Chaque portefeuille a ses propres clés API et il n'y a pas de limite au nombre de portefeuilles que vous pouvez créer. La capacité de partitionner les fonds rend LNbits un outil utile pour la gestion de l'argent et comme outil de développement. Les extensions ajoutent une fonctionnalité supplémentaire à LNbits afin que vous puissiez expérimenter une gamme de technologies de pointe sur le réseau Lightning. Nous avons rendu le développement d'extensions aussi simple que possible et, en tant que projet gratuit et open source, nous encourageons les gens à développer et à soumettre les leurs.",export_to_phone:"Exporter vers le téléphone avec un code QR",export_to_phone_desc:"Ce code QR contient l'URL de votre portefeuille avec un accès complet. Vous pouvez le scanner depuis votre téléphone pour ouvrir votre portefeuille depuis là-bas.",wallet:"Portefeuille :",wallets:"Portefeuilles",add_wallet:"Ajouter un nouveau portefeuille",delete_wallet:"Supprimer le portefeuille",delete_wallet_desc:"Ce portefeuille entier sera supprimé et les fonds seront IRRECUPERABLES.",rename_wallet:"Renommer le portefeuille",update_name:"Mettre à jour le nom",fiat_tracking:"Suivi Fiat",currency:"Devise",update_currency:"Mettre à jour la devise",press_to_claim:"Appuyez pour demander du Bitcoin",donate:"Donner",view_github:"Voir sur GitHub",voidwallet_active:"VoidWallet est actif! Paiements désactivés",use_with_caution:"UTILISER AVEC PRUDENCE - Le portefeuille {name} est toujours en version BETA",service_fee:"Frais de service : {amount} % par transaction",service_fee_max:"Frais de service : {amount} % par transaction (max {max} sats)",service_fee_tooltip:"Frais de service facturés par l'administrateur du serveur LNbits pour chaque transaction sortante",toggle_darkmode:"Basculer le mode sombre",payment_reactions:"Réactions de paiement",view_swagger_docs:"Voir les documentation de l'API Swagger de LNbits",api_docs:"Documentation de l'API",api_keys_api_docs:"URL du nœud, clés API et documentation API",api_keys_warning:"Ces clés doivent être conservées en lieu sûr ; les partager pourrait entraîner la perte de fonds.",admin_key_warning:"Votre clé d'administrateur donne un accès complet à votre portefeuille, y compris la possibilité d'envoyer des paiements. Ne la partagez jamais, sauf si vous faites entièrement confiance au destinataire.",lnbits_version:"Version de LNbits",runs_on:"Fonctionne sur",paste:"Coller",paste_from_clipboard:"Coller depuis le presse-papiers",paste_request:"Coller la requête",create_invoice:"Créer une facture",camera_tooltip:"Utiliser la caméra pour scanner une facture / un code QR",export_csv:"Exporter vers CSV",chart_tooltip:"Afficher le graphique",pending:"En attente",copy_invoice:"Copier la facture",withdraw_from:"Retirer de",cancel:"Annuler",scan:"Scanner",read:"Lire",pay:"Payer",memo:"Mémo",date:"Date",payment_processing:"Traitement du paiement...",not_enough_funds:"Fonds insuffisants !",search_by_tag_memo_amount:"Rechercher par tag, mémo, montant",invoice_waiting:"Facture en attente de paiement",payment_received:"Paiement reçu",payment_sent:"Paiement envoyé",receive:"recevoir",send:"envoyer",outgoing_payment_pending:"Paiement sortant en attente",drain_funds:"Vider les fonds",drain_funds_desc:"Il s'agit d'un code QR LNURL-withdraw pour tout aspirer de ce portefeuille. Ne le partagez avec personne. Il est compatible avec balanceCheck et balanceNotify, de sorte que votre portefeuille peut continuer à retirer les fonds continuellement à partir d'ici après le premier retrait.",i_understand:"J'ai compris",copy_wallet_url:"Copier l'URL du portefeuille",disclaimer_dialog_title:"Important !",disclaimer_dialog:"La fonctionnalité de connexion sera publiée dans une future mise à jour, pour l'instant, assurez-vous de mettre cette page en favori pour accéder à votre portefeuille ultérieurement ! Ce service est en BETA, et nous ne sommes pas responsables des personnes qui perdent l'accès à leurs fonds.",no_transactions:"Aucune transaction effectuée pour le moment",manage:"Gérer",exchanges:"Échanges",extensions:"Extensions",no_extensions:"Vous n'avez installé aucune extension :(",created:"Créé",search_extensions:"Rechercher des extensions",extension_sources:"Sources d'extension",ext_sources_hint:"Dépôts à partir desquels les extensions peuvent être téléchargées",ext_sources_label:"URL source (utilisez uniquement la source officielle de l'extension LNbits et des sources fiables)",warning:"Avertissement",repository:"Référentiel",confirm_continue:"Êtes-vous sûr de vouloir continuer ?",manage_extension_details:"Installer/désinstaller l'extension",install:"Installer",uninstall:"Désinstaller",drop_db:"Supprimer les données",enable:"Activer",pay_to_enable:"Payer pour activer",enable_extension_details:"Activer l'extension pour l'utilisateur actuel",disable:"Désactiver",delete:"Supprimer",installed:"Installé",activated:"Activé",deactivated:"Désactivé",release_notes:"Notes de version",activate_extension_details:"Rendre l'extension disponible/indisponible pour les utilisateurs",featured:"Mis en avant",all:"Tout",only_admins_can_install:"Seuls les comptes administrateurs peuvent installer des extensions",admin_only:"Réservé aux administrateurs",new_version:"Nouvelle version",extension_depends_on:"Dépend de :",extension_rating_soon:"Notes des utilisateurs à venir bientôt",extension_installed_version:"Version installée",extension_uninstall_warning:"Vous êtes sur le point de supprimer l'extension pour tous les utilisateurs.",uninstall_confirm:"Oui, Désinstaller",extension_db_drop_info:"Toutes les données pour l'extension seront supprimées de manière permanente. Il n'est pas possible d'annuler cette opération !",extension_db_drop_warning:"Vous êtes sur le point de supprimer toutes les données de l'extension. Veuillez taper le nom de l'extension pour continuer :",extension_required_lnbits_version:"Cette version nécessite au moins LNbits version",min_version:"Minimum (inclus)",max_version:"Maximum (exclu)",payment_hash:"Hash de paiement",fee:"Frais",amount:"Montant",amount_sats:"Montant (sats)",tag:"Étiqueter",unit:"Unité",description:"Description",expiry:"Expiration",webhook:"Webhook",payment_proof:"Preuve de paiement",update:"Mettre à jour",update_available:"Mise à jour {version} disponible !",latest_update:"Vous êtes sur la dernière version {version}.",notifications:"Notifications",no_notifications:"Aucune notification",notifications_disabled:"Les notifications de statut LNbits sont désactivées.",enable_notifications:"Activer les notifications",enable_notifications_desc:"Si activé, il récupérera les dernières mises à jour du statut LNbits, telles que les incidents de sécurité et les mises à jour.",enable_watchdog:"Activer le Watchdog",enable_watchdog_desc:"Si elle est activée, elle changera automatiquement votre source de financement en VoidWallet si votre solde est inférieur au solde LNbits. Vous devrez activer manuellement après une mise à jour.",watchdog_interval:"Intervalle du gardien",watchdog_interval_desc:"À quelle fréquence la tâche en arrière-plan doit-elle vérifier la présence d'un signal d'arrêt d'urgence dans le delta du gardien [node_balance - lnbits_balance] (en minutes).",watchdog_delta:"Chien de garde Delta",watchdog_delta_desc:"Limite avant que l'interrupteur d'arrêt ne change la source de financement pour VoidWallet [lnbits_balance - node_balance > delta]",status:"Statut",notification_source:"Source de notification",notification_source_label:"URL source (utilisez uniquement la source officielle de statut LNbits et des sources de confiance)",more:"plus",less:"moins",releases:"Versions",watchdog:"Chien de garde",server_logs:"Journaux du serveur",ip_blocker:"Bloqueur d'IP",security:"Sécurité",security_tools:"Outils de sécurité",block_access_hint:"Bloquer l'accès par IP",allow_access_hint:"Autoriser l'accès par IP (cela passera outre les IP bloquées)",enter_ip:"Entrez l'adresse IP et appuyez sur Entrée",rate_limiter:"Limiteur de débit",wallet_limiter:"Limiteur de portefeuille",wallet_limit_max_withdraw_per_day:"Retrait quotidien maximum du portefeuille en sats (0 pour désactiver)",wallet_max_ballance:"Solde maximum du portefeuille en sats (0 pour désactiver)",wallet_limit_secs_between_trans:"Minutes et secondes entre les transactions par portefeuille (0 pour désactiver)",number_of_requests:"Nombre de requêtes",time_unit:"Unité de temps",minute:"minute",second:"seconde",hour:"heure",disable_server_log:"Désactiver le journal du serveur",enable_server_log:"Activer le journal du serveur",coming_soon:"Fonctionnalité à venir bientôt",session_has_expired:"Votre session a expiré. Veuillez vous reconnecter.",instant_access_question:"Voulez-vous un accès instantané ?",login_with_user_id:"Connexion avec l'identifiant utilisateur",or:"ou",create_new_wallet:"Créer un nouveau portefeuille",login_to_account:"Connectez-vous à votre compte",create_account:"Créer un compte",account_settings:"Paramètres du compte",signin_with_nostr:"Continuer avec Nostr",signin_with_google:"Connectez-vous avec Google",signin_with_github:"Connectez-vous avec GitHub",signin_with_keycloak:"Connectez-vous avec Keycloak",username_or_email:"Nom d'utilisateur ou e-mail",password:"Mot de passe",password_config:"Configuration du mot de passe",password_repeat:"Répétition du mot de passe",change_password:"Changer le mot de passe",update_credentials:"Mettre à jour les informations d'identification",update_pubkey:"Mettre à jour la clé publique",set_password:"Définir le mot de passe",invalid_password:"Le mot de passe doit comporter au moins 8 caractères",login:"Connexion",register:"Inscrire",username:"Nom d'utilisateur",pubkey:"Clé publique",user_id:"Identifiant utilisateur",email:"E-mail",first_name:"Prénom",last_name:"Nom de famille",picture:"Image",verify_email:"Vérifiez l'e-mail avec",account:"Compte",update_account:"Mettre à jour le compte",invalid_username:"Nom d'utilisateur invalide",auth_provider:"Fournisseur d'authentification",my_account:"Mon compte",back:"Retour",logout:"Déconnexion",look_and_feel:"Apparence",toggle_gradient:"Basculer le dégradé",gradient_background:"Fond en dégradé",language:"Langue",color_scheme:"Schéma de couleurs",admin_settings:"Paramètres administrateur",extension_cost:"Cette version nécessite un paiement minimum de {cost} sats.",extension_paid_sats:"Vous avez déjà payé {paid_sats} sats.",release_details_error:"Impossible d'obtenir les détails de la version.",pay_from_wallet:"Payer depuis le portefeuille",wallet_required:"Portefeuille *",show_qr:"Afficher le QR",retry_install:"Réessayer l'installation",new_payment:"Effectuer un nouveau paiement",update_payment:"Mettre à jour le paiement",already_paid_question:"Avez-vous déjà payé ?",sell:"Vendre",sell_require:"Demander un paiement pour activer l'extension",sell_info:"L'extension {name} nécessite un paiement minimum de {amount} sats pour être activée.",hide_empty_wallets:"Masquer les portefeuilles vides",recheck:"Revérifier",contributors:"Contributeurs",license:"Licence",reset_key:"Réinitialiser la clé",reset_password:"Réinitialiser le mot de passe",border_choices:"Choix de bordure",select_all:"Sélectionner tout",nfc_supported:"NFC pris en charge",nfc_not_supported:"NFC non pris en charge",expire_date:"Date d'expiration :",hash:"Hash :",welcome_lnbits:"Bienvenue à LNbits",setup_su_account:"Configurez le compte Superuser ci-dessous.",create_ticker_converter:"Créer un convertisseur de code de devise",enable_audit:"Activer l'audit",recommended:"Recommandé",audit_desc:"Enregistrer les requêtes HTTP selon les filtres spécifiés",audit_record_req:"Enregistrer le corps de la demande",audit_record_warning:"Avertissement :",audit_record_req_warning_1:"les données confidentielles (comme les mots de passe) seront enregistrées.",audit_record_req_warning_2:"le corps de la requête peut être de grande taille.",audit_record_use:"Utilisez-le avec précaution.",audit_ip:"Enregistrer l'adresse IP",audit_ip_desc:"Enregistrer l'adresse IP du client",audit_path_params:"Enregistrer les paramètres de chemin",audit_query_params:"Enregistrer les paramètres de la requête",audit_http_methods:"Inclure les méthodes HTTP",audit_http_methods_hint:"Liste des méthodes HTTP à inclure. Listes vides signifie toutes.",audit_http_methods_label:"Méthodes HTTP",audit_resp_codes:"Inclure les codes de réponse HTTP",audit_resp_codes_hint:"Liste des codes HTTP à inclure (correspondance regex). Les listes vides signifient tout. Ex : 4.*, 5.*",audit_resp_codes_label:"Code de réponse HTTP (regex)",audit_paths:"Inclure des chemins",audit_paths_hint:"Liste des chemins à inclure (correspondance regex). Liste vide signifie tout.",audit_paths_label:"Chemin HTTP (regex)",audit_paths_exclude:"Exclure les chemins",audit_paths_exclude_hint:"Liste des chemins à exclure (correspondance regex). Liste vide signifie aucun.",audit_paths_exclude_label:"Chemin HTTP (regex)",exchange_providers:"Fournisseurs d'échange",admin_extensions:"Extensions d'administration",admin_extensions_label:"Extensions d'administration",admin_extensions_hint:"Seuls les utilisateurs avec des privilèges d'administrateur peuvent utiliser les extensions.",user_default_extensions:"Extensions par défaut de l'utilisateur",user_default_extensions_label:"Extensions utilisateur",user_default_extensions_hint:"Extensions qui seront activées par défaut pour les utilisateurs.",miscellanous:"Divers",misc_disable_extensions:"Désactiver les extensions",misc_disable_extensions_label:"Désactiver toutes les extensions",misc_hide_api:"Masquer l'API",misc_hide_api_label:"Masque l'API du portefeuille, les extensions peuvent choisir de respecter",wallets_management:"Gestion des portefeuilles",funding_source_info:"Informations sur la source de financement",funding_source:"Source de financement : {wallet_class}",node_balance:"Solde du nœud : {balance} sats",lnbits_balance:"Solde LNbits : {balance} sats",funding_reserve_percent:"Pourcentage de Réserve : {percent} %",node_management:"Gestion des nœuds",node_management_not_supported:"La gestion des nœuds n'est pas prise en charge par la source de financement active",toggle_node_ui:"Interface utilisateur de nœud",toggle_public_node_ui:"Interface utilisateur du nœud public",toggle_transactions_node_ui:"Onglet des transactions (Désactiver sur les grands nœuds CLN)",invoice_expiry:"Expiration de la facture",invoice_expiry_label:"Expiration de la facture (secondes)",fee_reserve:"Réserve de frais",fee_reserve_msats:"Frais de réservation en msats",fee_reserve_percent:"Frais de réservation en pourcentage",server_management:"Gestion de serveur",base_url:"URL de base",base_url_label:"URL statique/de base pour le serveur",authentication:"Authentification",auth_token_expiry_label:"Durée d'expiration du jeton (en minutes)",auth_token_expiry_hint:"Durée en minutes avant l'expiration du jeton",auth_allowed_methods_label:"Méthodes d'autorisation autorisées",auth_allowed_methods_hint:"Sélectionnez les méthodes d'autorisation",auth_nostr_label:"URL de requête Nostr",auth_nostr_hint:"URL absolue que les clients utiliseront pour se connecter.",auth_google_ci_label:"ID Client Google",auth_google_ci_hint:"Assurez-vous que les URIs de redirection autorisées contiennent https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secret client Google",auth_gh_client_id_label:"Identifiant client GitHub",auth_gh_client_id_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secret Client GitHub",auth_keycloak_label:"URL de découverte Keycloak",auth_keycloak_ci_label:"ID Client Keycloak",auth_keycloak_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secret client Keycloak",auth_keycloak_custom_org_label:"Organisation personnalisée Keycloak",auth_keycloak_custom_icon_label:"Icône personnalisée Keycloak (URL)",auth_oidc_label:"URL de découverte OIDC",auth_oidc_ci_label:"ID Client OIDC",auth_oidc_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Secret client OIDC",auth_oidc_custom_org_label:"Nom de l'organisation personnalisée OIDC (par ex. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Icône personnalisée OIDC (URL)",currency_settings:"Paramètres de devise",allowed_currencies:"Devises autorisées",allowed_currencies_hint:"Limiter le nombre de devises fiduciaires disponibles",default_account_currency:"Devise par défaut du compte",default_account_currency_hint:"Devise par défaut pour la comptabilité",service_fee_label:"Frais de service (%)",service_fee_hint:"Frais facturés par tx (%)",service_fee_max_label:"Frais de service max (sats)",service_fee_max_hint:"Frais de service maximum à facturer en (sats)",fee_wallet:"Portefeuille de frais",fee_wallet_label:"Portefeuille de frais (ID de portefeuille)",fee_wallet_hint:"Identifiant de portefeuille pour envoyer des fonds à",disable_fee:"Désactiver les frais",disable_fee_internal:"Désactiver les frais de service pour les paiements internes",disable_fee_internal_desc:"Désactiver les frais de service pour les paiements Lightning internes",ui_management:"Gestion de l'interface utilisateur",ui_site_title:"Titre du site",ui_site_tagline:"Slogan du site",ui_elements_enable:"Activer les éléments sur la page d'accueil",ui_elements_disable:"Désactiver les éléments sur la page d'accueil",ui_toggle_elements_tip:"Supprimer les éléments de la page d'accueil comme 'fonctionne avec', etc.",ui_site_description:"Description du site",ui_site_description_hint:"Utilisez du texte brut, du Markdown ou du HTML brut",ui_default_wallet_name:"Nom par Défaut du Portefeuille",lnbits_wallet:"Portefeuille LNbits",denomination:"Dénomination",denomination_hint:"Le nom du jeton FakeWallet",ui_qr_code_logo:"Logo de code QR",ui_qr_code_logo_hint:"URL de l'image du logo dans le code QR",ui_custom_badge:"Badge personnalisé",ui_custom_badge_label:"Badge personnalisé 'À UTILISER AVEC PRÉCAUTION - Le portefeuille LNbits est encore en BÊTA'",ui_custom_badge_color_label:"Couleur de badge personnalisée",themes:"Thèmes",themes_hint:"Choisissez des thèmes disponibles pour les utilisateurs",custom_logo:"Logo personnalisé",custom_logo_hint:"URL de l'image du logo",ad_space_title:"Titre de l'espace publicitaire",ad_space_title_label:"Soutenu par",ad_slots:"Emplacements publicitaires",ad_slots_hint:"URL de l'annonce et chemins des fichiers image au format CSV, les extensions peuvent choisir de respecter",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annonces activées",ads_disabled:"Publicités désactivées",user_management:"Gestion des utilisateurs",admin_users:"Utilisateurs administrateurs",admin_users_hint:"Utilisateurs avec des privilèges d'administration",admin_users_label:"Identifiant utilisateur",allowed_users:"Utilisateurs autorisés",allowed_users_hint:"Seuls ces utilisateurs peuvent utiliser LNbits",allowed_users_label:"ID utilisateur",allow_creation_user:"Autoriser la création de nouveaux utilisateurs",allow_creation_user_desc:"Permettre la création de nouveaux utilisateurs sur la page d’index",components:"Composants",long_running_endpoints:"Top 5 points de terminaison longue durée",http_request_methods:"Méthodes de requête HTTP",http_response_codes:"Codes de réponse HTTP",request_details:"Détails de la demande",http_request_details:"Détails de la requête HTTP",block_explorer:"Block Explorer",enable_block_explorer:"Activer le Block Explorer",block_explorer_desc:"Permet aux utilisateurs d'explorer les transactions et adresses Bitcoin via Electrum.",blockexplorer_public_api:"Accès API public",blockexplorer_public_api_desc:"Autoriser l'accès non authentifié aux endpoints de l'API de l'explorateur de blocs.",electrum_server_url:"URL du serveur Electrum",electrum_server_url_hint:"p.ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001",blockexplorer_search_label:"Rechercher par TXID ou adresse",blockexplorer_search_hint:"Hex 64 caractères = transaction · autre chose = adresse Bitcoin",recent_blocks:"Blocs récents",chain_tip:"Sommet de chaîne",block_height:"Hauteur de bloc",block_fee:"frais de bloc",fee_estimates:"Estimations de frais",confirmed_balance:"Solde confirmé",unconfirmed_balance:"Solde non confirmé",transaction_history:"Historique des transactions",coinbase:"Coinbase",inputs:"Entrées",outputs:"Sorties",confirmations:"Confirmations",confirmed:"Confirmé",unconfirmed:"Non confirmé",history_unavailable:"Historique des transactions indisponible (adresse avec trop de transactions)",address:"Adresse",block_number:"Bloc #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Bloc précédent",merkle_root:"Racine de Merkle",version:"Version",bits:"Bits",difficulty:"Difficulté",nonce:"Nonce",txid:"TXID",vsize:"Taille virtuelle",weight:"Poids",n_block_fee:"frais {n} blocs"},window.localisation.it={confirm:"Sì",server:"Server",theme:"Tema",site_customisation:"Personalizzazione del sito",funding:"Funding",users:"Utenti",audit:"Verifica",apps:"Applicazioni",channels:"Canali",transactions:"Transazioni",dashboard:"Pannello di controllo",node:"Interruttore",export_users:"Esporta utenti",no_users:"Nessun utente trovato",total_capacity:"Capacità Totale",avg_channel_size:"Dimensione media del canale",biggest_channel_size:"Dimensione del canale più grande",smallest_channel_size:"Dimensione Più Piccola del Canale",number_of_channels:"Numero di Canali",active_channels:"Canali Attivi",connect_peer:"Connetti Peer",connect:"Connetti",open_channel:"Canale aperto",open:"Apri",close_channel:"Chiudi Canale",close:"Chiudi",restart:"Riavvia il server",save:"Salva",save_tooltip:"Salva le modifiche",credit_debit:"Credito / Debito",credit_hint:"Premere Invio per accreditare i fondi",credit_label:"{denomination} da accreditare",credit_ok:"Credito/addebito riuscito di fondi virtuali ({amount} sats). I pagamenti dipendono dai fondi effettivi sulla fonte di finanziamento.",restart_tooltip:"Riavvia il server affinché le modifiche abbiano effetto",add_funds_tooltip:"Aggiungere fondi a un portafoglio",reset_defaults:"Ripristina le impostazioni predefinite",reset_defaults_tooltip:"Cancella tutte le impostazioni e ripristina i valori predefiniti",download_backup:"Scarica il backup del database",name_your_wallet:"Dai un nome al tuo portafoglio {name}",paste_invoice_label:"Incolla una fattura, una richiesta di pagamento o un codice lnurl *",lnbits_description:"Leggero e facile da configurare, LNbits può funzionare su qualsiasi fonte di finanziamento Lightning Network e persino LNbits stesso! Potete gestire LNbits per conto vostro o offrire facilmente una soluzione di custodia per altri. Ogni portafoglio ha le proprie chiavi API e non c'è limite al numero di portafogli che si possono creare. La possibilità di suddividere i fondi rende LNbits uno strumento utile per la gestione del denaro e come strumento di sviluppo. Le estensioni aggiungono ulteriori funzionalità a LNbits, consentendo di sperimentare una serie di tecnologie all'avanguardia sulla rete Lightning. Abbiamo reso lo sviluppo delle estensioni il più semplice possibile e, in quanto progetto libero e open-source, incoraggiamo le persone a sviluppare e inviare le proprie",export_to_phone:"Esportazione su telefono con codice QR",export_to_phone_desc:"Questo codice QR contiene l'URL del portafoglio con accesso da amministratore. È possibile scansionarlo dal telefono per aprire il portafoglio da lì.",wallet:"Portafoglio:",wallets:"Portafogli",add_wallet:"Aggiungi un nuovo portafoglio",delete_wallet:"Elimina il portafoglio",delete_wallet_desc:"L'intero portafoglio sarà cancellato, i fondi saranno irrecuperabili",rename_wallet:"Rinomina il portafoglio",update_name:"Aggiorna il nome",fiat_tracking:"Tracciamento Fiat",currency:"Valuta",update_currency:"Aggiorna valuta",press_to_claim:"Premi per richiedere bitcoin",donate:"Donazioni",view_github:"Visualizza su GitHub",voidwallet_active:"VoidWallet è attivo! Pagamenti disabilitati",use_with_caution:"USARE CON CAUTELA - {name} portafoglio è ancora in BETA",service_fee:"Commissione di servizio: {amount} % per transazione",service_fee_max:"Commissione di servizio: {amount} % per transazione (max {max} sats)",service_fee_tooltip:"Commissione di servizio addebitata dall'amministratore del server LNbits per ogni transazione in uscita",toggle_darkmode:"Attiva la modalità notturna",payment_reactions:"Reazioni al Pagamento",view_swagger_docs:"Visualizza i documentazione dell'API Swagger di LNbits",api_docs:"Documentazione dell'API",api_keys_api_docs:"URL del nodo, chiavi API e documentazione API",api_keys_warning:"Queste chiavi devono essere conservate al sicuro; condividerle potrebbe causare la perdita di fondi.",admin_key_warning:"La tua chiave di amministratore concede accesso completo al tuo portafoglio, inclusa la possibilità di inviare pagamenti. Non condividerla mai, a meno che tu non ti fidi completamente del destinatario.",lnbits_version:"Versione di LNbits",runs_on:"Esegue su",paste:"Incolla",paste_from_clipboard:"Incolla dagli appunti",paste_request:"Richiesta di pagamento",create_invoice:"Crea fattura",camera_tooltip:"Usa la fotocamera per scansionare la fattura/QR",export_csv:"Esporta CSV",chart_tooltip:"Mostra grafico",pending:"In attesa",copy_invoice:"Copia fattura",withdraw_from:"Prelevare da",cancel:"Annulla",scan:"Scansiona",read:"Leggi",pay:"Paga",memo:"Memo",date:"Dati",payment_processing:"Elaborazione pagamento...",not_enough_funds:"Non ci sono abbastanza fondi!",search_by_tag_memo_amount:"Cerca per tag, memo, importo...",invoice_waiting:"Fattura in attesa di pagamento",payment_received:"Pagamento ricevuto",payment_sent:"Pagamento inviato",receive:"ricevere",send:"inviare",outgoing_payment_pending:"Pagamento in uscita in attesa",drain_funds:"Fondi di drenaggio",drain_funds_desc:"Questo è un codice QR LNURL-withdraw per prelevare tutti i fondi da questo portafoglio. Non condividerlo con nessuno. È compatibile con balanceCheck e balanceNotify, di conseguenza il vostro portafoglio può continuare a prelevare continuamente i fondi da qui dopo il primo prelievo",i_understand:"Ho capito",copy_wallet_url:"Copia URL portafoglio",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"La funzionalità di login sarà rilasciata in un futuro aggiornamento; per ora, assicuratevi di salvare tra i preferiti questa pagina per accedere nuovamente in futuro a questo portafoglio! Questo servizio è in fase BETA e non ci assumiamo alcuna responsabilità per la perdita all'accesso dei fondi",no_transactions:"Nessuna transazione effettuata",manage:"Gestisci",exchanges:"Scambi",extensions:"Estensioni",no_extensions:"Non ci sono estensioni installate :(",created:"Creato",search_extensions:"Estensioni di ricerca",extension_sources:"Fonti di estensione",ext_sources_hint:"Repository da cui è possibile scaricare le estensioni",ext_sources_label:"URL di origine (utilizzare solo la fonte ufficiale dell'estensione LNbits e fonti affidabili)",warning:"Attenzione",repository:"Deposito",confirm_continue:"Sei sicuro di voler continuare?",manage_extension_details:"Installa/disinstalla estensione",install:"Installare",uninstall:"Disinstalla",drop_db:"Rimuovi Dati",enable:"Abilita",pay_to_enable:"Paga per abilitare",enable_extension_details:"Attiva l'estensione per l'utente corrente",disable:"Disabilita",delete:"Elimina",installed:"Installato",activated:"Attivato",deactivated:"Disattivato",release_notes:"Note di Rilascio",activate_extension_details:"Rendi l'estensione disponibile/non disponibile per gli utenti",featured:"In primo piano",all:"Tutto",only_admins_can_install:"Solo gli account amministratore possono installare estensioni.",admin_only:"Solo amministratore",new_version:"Nuova Versione",extension_depends_on:"Dipende da:",extension_rating_soon:"Valutazioni in arrivo",extension_installed_version:"Versione installata",extension_uninstall_warning:"Stai per rimuovere l'estensione per tutti gli utenti.",uninstall_confirm:"Sì, Disinstalla",extension_db_drop_info:"Tutti i dati relativi all'estensione saranno cancellati permanentemente. Non c'è modo di annullare questa operazione!",extension_db_drop_warning:"Stai per rimuovere tutti i dati per l'estensione. Digita il nome dell'estensione per continuare:",extension_required_lnbits_version:"Questa versione richiede almeno la versione LNbits",min_version:"Minimo (incluso)",max_version:"Massimo (escluso)",payment_hash:"Hash del pagamento",fee:"Tariffa",amount:"Importo",amount_sats:"Importo (sats)",tag:"Etichetta",unit:"Unità",description:"Descrizione",expiry:"Scadenza",webhook:"Webhook",payment_proof:"Prova di pagamento",update:"Aggiorna",update_available:"Aggiornamento {version} disponibile!",latest_update:"Sei sulla versione più recente {version}.",notifications:"Notifiche",no_notifications:"Nessuna notifica",notifications_disabled:"Le notifiche di stato di LNbits sono disattivate.",enable_notifications:"Attiva le notifiche",enable_notifications_desc:"Se attivato, recupererà gli ultimi aggiornamenti sullo stato di LNbits, come incidenti di sicurezza e aggiornamenti.",enable_watchdog:"Attiva Watchdog",enable_watchdog_desc:"Se abilitato, cambierà automaticamente la tua fonte di finanziamento in VoidWallet se il tuo saldo è inferiore al saldo LNbits. Dovrai abilitarlo manualmente dopo un aggiornamento.",watchdog_interval:"Intervallo Watchdog",watchdog_interval_desc:"Quanto spesso il task in background dovrebbe controllare un segnale di killswitch nel delta del watchdog [node_balance - lnbits_balance] (in minuti).",watchdog_delta:"Guardiano Delta",watchdog_delta_desc:"Limite prima che l'interruttore di sicurezza modifichi la fonte di finanziamento in VoidWallet [lnbits_balance - node_balance > delta]",status:"Stato",notification_source:"Sorgente di notifica",notification_source_label:"URL sorgente (utilizzare solo la fonte ufficiale di stato LNbits e fonti di cui ti puoi fidare)",more:"più",less:"meno",releases:"Pubblicazioni",watchdog:"Cane da guardia",server_logs:"Registri del server",ip_blocker:"Blocco IP",security:"Sicurezza",security_tools:"Strumenti di sicurezza",block_access_hint:"Blocca l'accesso per IP",allow_access_hint:"Consenti l'accesso per IP (sovrascriverà gli IP bloccati)",enter_ip:"Inserisci l'IP e premi invio",rate_limiter:"Limitatore di frequenza",wallet_limiter:"Limitatore del Portafoglio",wallet_limit_max_withdraw_per_day:"Prelievo massimo giornaliero dal portafoglio in sats (0 per disabilitare)",wallet_max_ballance:"Saldo massimo del portafoglio in sats (0 per disabilitare)",wallet_limit_secs_between_trans:"Minuti e secondi tra transazioni per portafoglio (0 per disabilitare)",number_of_requests:"Numero di richieste",time_unit:"Unità di tempo",minute:"minuto",second:"secondo",hour:"ora",disable_server_log:"Disabilita Registro Server",enable_server_log:"Attiva Registro Server",coming_soon:"Caratteristica in arrivo prossimamente",session_has_expired:"La tua sessione è scaduta. Per favore, effettua nuovamente il login.",instant_access_question:"Vuoi accesso immediato?",login_with_user_id:"Accedi con ID utente",or:"oppure",create_new_wallet:"Crea nuovo portafoglio",login_to_account:"Accedi al tuo account",create_account:"Crea un account",account_settings:"Impostazioni dell'account",signin_with_nostr:"Continua con Nostr",signin_with_google:"Accedi con Google",signin_with_github:"Accedi con GitHub",signin_with_keycloak:"Accedi con Keycloak",username_or_email:"Nome utente o Email",password:"Password",password_config:"Configurazione della password",password_repeat:"Ripeti la password",change_password:"Cambia Password",update_credentials:"Aggiorna credenziali",update_pubkey:"Aggiorna chiave pubblica",set_password:"Imposta password",invalid_password:"La password deve contenere almeno 8 caratteri",login:"Accesso",register:"Registrati",username:"Nome utente",pubkey:"Chiave pubblica",user_id:"ID utente",email:"Email",first_name:"Nome",last_name:"Cognome",picture:"Immagine",verify_email:"Verifica email con",account:"Conto",update_account:"Aggiorna Account",invalid_username:"Nome utente non valido",auth_provider:"Provider di Autenticazione",my_account:"Il mio account",back:"Indietro",logout:"Esci",look_and_feel:"Aspetto e Comportamento",toggle_gradient:"Attiva/disattiva gradiente",gradient_background:"Sfondo sfumato",language:"Lingua",color_scheme:"Schema dei colori",admin_settings:"Impostazioni di amministrazione",extension_cost:"Questa versione richiede un pagamento minimo di {cost} satoshi.",extension_paid_sats:"Hai già pagato {paid_sats} sats.",release_details_error:"Impossibile ottenere i dettagli della versione.",pay_from_wallet:"Paga dal Portafoglio",wallet_required:"Portafoglio *",show_qr:"Mostra QR",retry_install:"Riprova Installazione",new_payment:"Effettua Nuovo Pagamento",update_payment:"Aggiorna Pagamento",already_paid_question:"Hai già pagato?",sell:"Vendi",sell_require:"Chiedi il pagamento per abilitare l'estensione",sell_info:"L'estensione {name} richiede un pagamento minimo di {amount} sats per essere abilitata.",hide_empty_wallets:"Nascondi portafogli vuoti",recheck:"Ricontrolla",contributors:"Contributori",license:"Licenza",reset_key:"Reimposta Chiave",reset_password:"Reimposta password",border_choices:"Scelte del bordo",select_all:"Seleziona tutto",nfc_supported:"Supportato NFC",nfc_not_supported:"NFC non supportato",expire_date:"Data di scadenza:",hash:"Hash:",welcome_lnbits:"Benvenuto in LNbits",setup_su_account:"Configura l'account Superuser qui sotto.",create_ticker_converter:"Crea Convertitore di Simboli di Valuta",enable_audit:"Abilita controllo",recommended:"Consigliato",audit_desc:"Registrare le richieste HTTP secondo i filtri specificati",audit_record_req:"Registra il corpo della richiesta",audit_record_warning:"Avvertimento:",audit_record_req_warning_1:"I dati riservati (come le password) verranno registrati.",audit_record_req_warning_2:"il corpo della richiesta può avere grandi dimensioni.",audit_record_use:"Usalo con cautela.",audit_ip:"Registrare l'indirizzo IP",audit_ip_desc:"Registra l'indirizzo IP del cliente",audit_path_params:"Registra i parametri del percorso",audit_query_params:"Registrare i parametri di query",audit_http_methods:"Includi i metodi HTTP",audit_http_methods_hint:"Elenco di metodi HTTP da includere. Liste vuote significano tutti.",audit_http_methods_label:"Metodi HTTP",audit_resp_codes:"Includere codici di risposta HTTP",audit_resp_codes_hint:"Elenco dei codici HTTP da includere (corrispondenza regex). Liste vuote significano tutto. Ad esempio: 4.*, 5.*",audit_resp_codes_label:"Codice di risposta HTTP (regex)",audit_paths:"Includi percorsi",audit_paths_hint:"Elenco dei percorsi da includere (corrispondenza regex). Elenco vuoto significa tutto.",audit_paths_label:"Percorso HTTP (regex)",audit_paths_exclude:"Escludi percorsi",audit_paths_exclude_hint:"Elenco dei percorsi da escludere (corrispondenza regex). Un elenco vuoto significa nessuno.",audit_paths_exclude_label:"Percorso HTTP (regex)",exchange_providers:"Fornitori di scambio",admin_extensions:"Estensioni Admin",admin_extensions_label:"Estensioni amministrative",admin_extensions_hint:"Solo un utente con privilegi di amministratore può utilizzare le estensioni.",user_default_extensions:"Estensioni predefinite dell'utente",user_default_extensions_label:"Estensioni utente",user_default_extensions_hint:"Estensioni che saranno abilitate di default per gli utenti.",miscellanous:"Varie",misc_disable_extensions:"Disabilita estensioni",misc_disable_extensions_label:"Disabilita tutte le estensioni",misc_hide_api:"Nascondi API",misc_hide_api_label:"Nasconde l'api del portafoglio, le estensioni possono scegliere di onorare",wallets_management:"Gestione dei portafogli",funding_source_info:"Informazioni sulla fonte di finanziamento",funding_source:"Fonte di finanziamento: {wallet_class}",node_balance:"Saldo Nodo: {balance} sats",lnbits_balance:"Saldo LNbits: {balance} sats",funding_reserve_percent:"Riserva Percentuale: {percent} %",node_management:"Gestione dei nodi",node_management_not_supported:"La gestione dei nodi non è supportata dalla fonte di finanziamento attiva.",toggle_node_ui:"Interfaccia utente del nodo",toggle_public_node_ui:"Interfaccia Utente Nodo Pubblico",toggle_transactions_node_ui:"Scheda Transazioni (Disabilita su nodi CLN grandi)",invoice_expiry:"Scadenza fattura",invoice_expiry_label:"Scadenza fattura (secondi)",fee_reserve:"Riserva delle commissioni",fee_reserve_msats:"Tariffa di prenotazione in msats",fee_reserve_percent:"Commissione di riserva in percentuale",server_management:"Gestione server",base_url:"URL di base",base_url_label:"URL statica/base per il server",authentication:"Autenticazione",auth_token_expiry_label:"Minuti di scadenza del token",auth_token_expiry_hint:"Tempo in minuti fino alla scadenza del token",auth_allowed_methods_label:"Metodi di autorizzazione consentiti",auth_allowed_methods_hint:"Seleziona i metodi di autorizzazione",auth_nostr_label:"URL richiesta Nostr",auth_nostr_hint:"URL assoluto che i clienti utilizzeranno per accedere.",auth_google_ci_label:"ID client di Google",auth_google_ci_hint:"Assicurati che gli URI di reindirizzamento autorizzati contengano https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"ID client di GitHub",auth_gh_client_id_hint:"Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Segreto Client GitHub",auth_keycloak_label:"URL di individuazione di Keycloak",auth_keycloak_ci_label:"ID client di Keycloak",auth_keycloak_ci_hint:"Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",auth_keycloak_custom_org_label:"Organizzazione personalizzata di Keycloak",auth_keycloak_custom_icon_label:"Icona personalizzata di Keycloak (URL)",auth_oidc_label:"URL di individuazione di OIDC",auth_oidc_ci_label:"ID client di OIDC",auth_oidc_ci_hint:"Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC Client Secret",auth_oidc_custom_org_label:"Nome organizzazione personalizzata OIDC (es. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Icona personalizzata di OIDC (URL)",currency_settings:"Impostazioni valuta",allowed_currencies:"Valute consentite",allowed_currencies_hint:"Limita il numero di valute fiat disponibili",default_account_currency:"Valuta predefinita del conto",default_account_currency_hint:"Valuta predefinita per la contabilità",service_fee_label:"Tassa di servizio (%)",service_fee_hint:"Tariffa addebitata per transazione (%)",service_fee_max_label:"Commissione di servizio max (sats)",service_fee_max_hint:"Commissione massima da addebitare in (sats)",fee_wallet:"Portafoglio delle commissioni",fee_wallet_label:"Portafoglio delle commissioni (ID portafoglio)",fee_wallet_hint:"ID portafoglio a cui inviare fondi",disable_fee:"Disabilita Commissione",disable_fee_internal:"Disabilita la commissione di servizio per i pagamenti interni",disable_fee_internal_desc:"Disabilita la commissione di servizio per i pagamenti Lightning interni",ui_management:"Gestione dell'interfaccia utente",ui_site_title:"Titolo del sito",ui_site_tagline:"Slogan del sito",ui_elements_enable:"Abilita elementi sulla homepage",ui_elements_disable:"Disabilita elementi sulla homepage",ui_toggle_elements_tip:"Rimuovi elementi della homepage come 'runs on' ecc.",ui_site_description:"Descrizione del sito",ui_site_description_hint:"Usa testo normale, Markdown o HTML grezzo",ui_default_wallet_name:"Nome predefinito del portafoglio",lnbits_wallet:"Portafoglio LNbits",denomination:"Denominazione",denomination_hint:"Il nome per il token FakeWallet",ui_qr_code_logo:"Logo del codice QR",ui_qr_code_logo_hint:"URL all'immagine del logo nel codice QR",ui_custom_badge:"Badge personalizzato",ui_custom_badge_label:"Badge personalizzato 'USARE CON CAUTELA - Il portafoglio LNbits è ancora in BETA'",ui_custom_badge_color_label:"Colore distintivo personalizzato",themes:"Temi",themes_hint:"Scegli i temi disponibili per gli utenti",custom_logo:"Logo personalizzato",custom_logo_hint:"URL all'immagine del logo",ad_space_title:"Titolo Spazio Pubblicitario",ad_space_title_label:"Supportato da",ad_slots:"Spazi pubblicitari",ad_slots_hint:"Percorso dell'URL e dell'immagine in formato CSV, le estensioni possono scegliere di rispettare",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annunci abilitati",ads_disabled:"Annunci disabilitati",user_management:"Gestione utenti",admin_users:"Utenti amministratori",admin_users_hint:"Utenti con privilegi di amministratore",admin_users_label:"ID utente",allowed_users:"Utenti consentiti",allowed_users_hint:"Solo questi utenti possono usare LNbits",allowed_users_label:"ID utente",allow_creation_user:"Consenti la creazione di nuovi utenti",allow_creation_user_desc:"Consenti la creazione di nuovi utenti nella pagina indice",components:"Componenti",long_running_endpoints:"I primi 5 endpoint a lunga esecuzione",http_request_methods:"Metodi di richiesta HTTP",http_response_codes:"Codici di risposta HTTP",request_details:"Dettagli della richiesta",http_request_details:"Dettagli della richiesta HTTP",block_explorer:"Block Explorer",enable_block_explorer:"Abilita Block Explorer",block_explorer_desc:"Consenti agli utenti di esplorare transazioni e indirizzi Bitcoin tramite Electrum.",blockexplorer_public_api:"Accesso API pubblico",blockexplorer_public_api_desc:"Consenti accesso non autenticato agli endpoint API dell'esploratore di blocchi.",electrum_server_url:"URL server Electrum",electrum_server_url_hint:"es. ssl://electrum.blockstream.info:50002 o tcp://localhost:50001",blockexplorer_search_label:"Cerca per TXID o indirizzo",blockexplorer_search_hint:"Hex 64 caratteri = transazione · altro = indirizzo Bitcoin",recent_blocks:"Blocchi recenti",chain_tip:"Punta della catena",block_height:"Altezza blocco",block_fee:"commissione blocco",fee_estimates:"Stime delle commissioni",confirmed_balance:"Saldo confermato",unconfirmed_balance:"Saldo non confermato",transaction_history:"Storico transazioni",coinbase:"Coinbase",inputs:"Input",outputs:"Output",confirmations:"Conferme",confirmed:"Confermato",unconfirmed:"Non confermato",history_unavailable:"Storico transazioni non disponibile (l'indirizzo ha troppe transazioni)",address:"Indirizzo",block_number:"Blocco #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Blocco precedente",merkle_root:"Radice di Merkle",version:"Versione",bits:"Bit",difficulty:"Difficoltà",nonce:"Nonce",txid:"TXID",vsize:"Dimensione virtuale",weight:"Peso",n_block_fee:"commissione {n} blocchi"},window.localisation.jp={confirm:"はい",server:"サーバー",theme:"テーマ",site_customisation:"サイトカスタマイズ",funding:"資金調達",users:"ユーザー",audit:"監査",apps:"アプリ",channels:"チャンネル",transactions:"トランザクション",dashboard:"ダッシュボード",node:"ノード",export_users:"ユーザーのエクスポート",no_users:"ユーザーが見つかりません",total_capacity:"合計容量",avg_channel_size:"平均チャンネルサイズ",biggest_channel_size:"最大チャネルサイズ",smallest_channel_size:"最小チャンネルサイズ",number_of_channels:"チャンネル数",active_channels:"アクティブチャンネル",connect_peer:"ピアを接続",connect:"接続",open_channel:"オープンチャンネル",open:"開く",close_channel:"チャンネルを閉じる",close:"閉じる",restart:"サーバーを再起動する",save:"保存",save_tooltip:"変更を保存する",credit_debit:"クレジット / デビット",credit_hint:"クレジットカードを使用して資金を追加するには、LNbitsを使用してください。",credit_label:"{denomination} をクレジットに",restart_tooltip:"サーバーを再起動して変更を適用します",add_funds_tooltip:"ウォレットに資金を追加します。",reset_defaults:"リセット",reset_defaults_tooltip:"すべての設定を削除してデフォルトに戻します。",download_backup:"データベースのバックアップをダウンロードする",name_your_wallet:"あなたのウォレットの名前 {name}",paste_invoice_label:"請求書を貼り付けてください",lnbits_description:"簡単にインストールでき、軽量なLNbitsは、あらゆるライトニングネットワークの資金源と、LNbits自身でさえも実行できます!LNbitsを個人で実行することも、他人に対してカストディアンソリューションをで実行できます! LNbitsを自分で実行することも、他の人に優れたソリューションを提供することもできます。各ウォレットには独自のAPIキーがあり、作成できるウォレットの数に制限はありません。資金を分割する機能は、LNbitsを資金管理ツールとして使用したり、開発ツールとして使用したりするための便利なツールです。拡張機能は、LNbitsに追加の機能を追加します。そのため、LNbitsは最先端の技術をネットワークLightningで試すことができます。拡張機能を開発するのは簡単で、無料でオープンソースのプロジェクトであるため、人々が自分で開発し、自分の貢献を送信することを奨励しています。",export_to_phone:"電話にエクスポート",export_to_phone_desc:"ウォレットを電話にエクスポートすると、ウォレットを削除する前にウォレットを復元できます。ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。",wallet:"ウォレット:",wallets:"ウォレット",add_wallet:"ウォレットを追加",delete_wallet:"ウォレットを削除",delete_wallet_desc:"ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。",rename_wallet:"ウォレットの名前を変更",update_name:"名前を更新",fiat_tracking:"フィアット追跡",currency:"通貨",update_currency:"通貨を更新する",press_to_claim:"クレームするには押してください",donate:"寄付",view_github:"GitHubで表示",voidwallet_active:"Voidwalletアクティブ",use_with_caution:"注意して使用してください - {name} ウォレットはまだベータ版です",service_fee:"取引ごとのサービス手数料: {amount} %",service_fee_max:"取引手数料:{amount}%(最大{max}サトシ)",service_fee_tooltip:"LNbitsサーバー管理者が発生する送金ごとの手数料",toggle_darkmode:"ダークモードを切り替える",payment_reactions:"支払いの反応",view_swagger_docs:"Swaggerドキュメントを表示",api_docs:"APIドキュメント",api_keys_api_docs:"ノードURL、APIキー、APIドキュメント",api_keys_warning:"これらのキーは安全に保管してください。共有すると資金を失うおそれがあります。",admin_key_warning:"管理者キーは、支払いの送信を含むウォレットへの完全なアクセスを許可します。受取人を完全に信頼している場合を除き、決して共有しないでください。",lnbits_version:"LNbits バージョン",runs_on:"で実行",paste:"貼り付け",paste_from_clipboard:"クリップボードから貼り付け",paste_request:"リクエストを貼り付ける",create_invoice:"請求書を作成する",camera_tooltip:"QRコードを読み取る",export_csv:"CSVでエクスポート",chart_tooltip:"チャートを表示するには、グラフの上にカーソルを合わせます",pending:"保留中",copy_invoice:"請求書をコピー",withdraw_from:"出金",cancel:"キャンセル",scan:"スキャン",read:"読む",pay:"支払う",memo:"メモ",date:"日付",payment_processing:"支払い処理中",not_enough_funds:"資金が不足しています",search_by_tag_memo_amount:"タグ、メモ、金額で検索",invoice_waiting:"請求書を待っています",payment_received:"お支払いありがとうございます",payment_sent:"支払いが完了しました",receive:"受け取る",send:"送信",outgoing_payment_pending:"支払い保留中",drain_funds:"資金を排出する",drain_funds_desc:"ウォレットの残高をすべて他のウォレットに送金します",i_understand:"理解した",copy_wallet_url:"ウォレットURLをコピー",disclaimer_dialog_title:"重要!",disclaimer_dialog:"ウォレットを削除すると、ウォレットの秘密鍵が削除され、ウォレットを復元することはできません。ウォレットを削除する前に、ウォレットをエクスポートしてください。",no_transactions:"トランザクションはありません",manage:"管理",exchanges:"取引所",extensions:"拡張機能",no_extensions:"拡張機能はありません",created:"作成済み",search_extensions:"検索拡張機能",extension_sources:"拡張ソース",ext_sources_hint:"拡張機能をダウンロードできるリポジトリ",ext_sources_label:"ソースURL(公式のLNbits拡張ソースおよび信頼できるソースのみを使用してください)",warning:"警告",repository:"リポジトリ",confirm_continue:"続行してもよろしいですか?",manage_extension_details:"拡張機能のインストール/アンインストール",install:"インストール",uninstall:"アンインストール",drop_db:"データを削除",enable:"有効",pay_to_enable:"有効にするために支払う",enable_extension_details:"現在のユーザーの拡張機能を有効にする",disable:"無効",delete:"削除",installed:"インストール済み",activated:"有効化",deactivated:"無効化",release_notes:"リリースノート",activate_extension_details:"拡張機能をユーザーが利用できるようにする/利用できないようにする",featured:"特集",all:"すべて",only_admins_can_install:"(管理者アカウントのみが拡張機能をインストールできます)",admin_only:"管理者のみ",new_version:"新しいバージョン",extension_depends_on:"依存先:",extension_rating_soon:"評価は近日公開",extension_installed_version:"インストール済みバージョン",extension_uninstall_warning:"すべてのユーザーの拡張機能を削除しようとしています.",uninstall_confirm:"はい、アンインストールします",extension_db_drop_info:"エクステンションのすべてのデータが完全に削除されます。この操作を元に戻す方法はありません!",extension_db_drop_warning:"エクステンションのすべてのデータを削除しようとしています。続行するには、エクステンションの名前を入力してください:",extension_required_lnbits_version:"このリリースには少なくとも LNbits バージョンが必要です",min_version:"最小値(含む)",max_version:"最大(除外)",payment_hash:"支払いハッシュ",fee:"料金",amount:"量",amount_sats:"金額 (サッツ)",tag:"タグ",unit:"単位",description:"説明",expiry:"有効期限",webhook:"ウェブフック",payment_proof:"支払い証明",update:"更新",update_available:"アップデート{version}が利用可能です!",latest_update:"あなたは最新バージョン{version}を使用しています。",notifications:"通知",no_notifications:"通知はありません",notifications_disabled:"LNbitsステータス通知は無効です。",enable_notifications:"通知を有効にする",enable_notifications_desc:"有効にすると、セキュリティインシデントやアップデートのような最新のLNbitsステータス更新を取得します。",enable_watchdog:"ウォッチドッグを有効にする",enable_watchdog_desc:"有効にすると、残高がLNbitsの残高より少ない場合に、資金源を自動的にVoidWalletに変更します。アップデート後は手動で有効にする必要があります。",watchdog_interval:"ウォッチドッグ・インターバル",watchdog_interval_desc:"バックグラウンドタスクがウォッチドッグデルタ[node_balance - lnbits_balance]でキルスイッチシグナルを確認する頻度(分単位)。",watchdog_delta:"ウォッチドッグデルタ",watchdog_delta_desc:"キルスイッチが資金源をVoidWalletに変更する前の限界 [lnbits_balance - node_balance > delta]",status:"ステータス",notification_source:"通知ソース",notification_source_label:"ソースURL(公式のLNbitsステータスソースのみを使用し、信頼できるソースのみを利用してください)",more:"より多くの",less:"少ない",releases:"リリース",watchdog:"ウォッチドッグ",server_logs:"サーバーログ",ip_blocker:"IPブロッカー",security:"セキュリティ",security_tools:"セキュリティツール",block_access_hint:"IPによるアクセスをブロック",allow_access_hint:"IPによるアクセスを許可する(ブロックされたIPを上書きします)",enter_ip:"IPを入力してエンターキーを押してください",rate_limiter:"レートリミッター",wallet_limiter:"ウォレットリミッター",wallet_limit_max_withdraw_per_day:"1日あたりの最大ウォレット出金額をsatsで入力してください(0 で無効)。",wallet_max_ballance:"ウォレットの最大残高(sats)(0は無効)",wallet_limit_secs_between_trans:"トランザクション間の最小秒数(ウォレットごと)(0は無効)",number_of_requests:"リクエストの数",time_unit:"時間単位",minute:"分",second:"秒",hour:"時間",disable_server_log:"サーバーログを無効にする",enable_server_log:"サーバーログを有効にする",coming_soon:"機能は間もなく登場します",session_has_expired:"あなたのセッションは期限切れです。もう一度ログインしてください。",instant_access_question:"即時アクセスをご希望ですか?",login_with_user_id:"ユーザーIDでログイン",or:"または",create_new_wallet:"新しいウォレットを作成",login_to_account:"アカウントにログインしてください",create_account:"アカウントを作成",account_settings:"アカウント設定",signin_with_nostr:"Nostrで続行",signin_with_google:"Googleでサインイン",signin_with_github:"GitHubでサインイン",signin_with_keycloak:"Keycloakでサインイン",username_or_email:"ユーザー名またはメールアドレス",password:"パスワード",password_config:"パスワード設定",password_repeat:"パスワードの再入力",change_password:"パスワードを変更",update_credentials:"資格情報を更新する",update_pubkey:"公開鍵を更新",set_password:"パスワードを設定",invalid_password:"パスワードは少なくとも8文字必要です",login:"ログイン",register:"登録",username:"ユーザー名",pubkey:"公開鍵",user_id:"ユーザーID",email:"メール",first_name:"名",last_name:"姓",picture:"写真",verify_email:"メールアドレスの確認を行ってください",account:"アカウント",update_account:"アカウントを更新",invalid_username:"無効なユーザー名",auth_provider:"認証プロバイダ",my_account:"マイアカウント",back:"戻る",logout:"ログアウト",look_and_feel:"ルック・アンド・フィール",toggle_gradient:"グラデーションを切り替える",gradient_background:"グラデーション背景",language:"言語",color_scheme:"カラースキーム",admin_settings:"管理設定",extension_cost:"このリリースには最低 {cost} サトシの支払いが必要です。",extension_paid_sats:"すでに{paid_sats} satsを支払いました。",release_details_error:"リリースの詳細を取得できません。",pay_from_wallet:"ウォレットから支払う",wallet_required:"ウォレット *",show_qr:"QRを表示",retry_install:"再試行インストール",new_payment:"新しい支払いを作成する",update_payment:"支払いを更新する",already_paid_question:"すでに支払いましたか?",sell:"販売する",sell_require:"拡張を有効にするために支払いを求める",sell_info:"{name}拡張機能を有効にするには、最小{amount}サツの支払いが必要です。",hide_empty_wallets:"空のウォレットを非表示にする",recheck:"再確認",contributors:"貢献者",license:"ライセンス",reset_key:"リセットキー",reset_password:"パスワードをリセットする",border_choices:"境界の選択肢",select_all:"すべて選択",nfc_supported:"NFC対応",nfc_not_supported:"NFCがサポートされていません",expire_date:"有効期限日:",hash:"ハッシュ:",welcome_lnbits:"LNbitsへようこそ",setup_su_account:"スーパーアカウントを以下に設定してください。",create_ticker_converter:"通貨ティッカーコンバーターを作成",enable_audit:"監査を有効にする",recommended:"推奨",audit_desc:"指定されたフィルターに従ってHTTPリクエストを記録する",audit_record_req:"リクエストボディの記録",audit_record_warning:"警告:",audit_record_req_warning_1:"パスワードなどの機密データが記録されます。",audit_record_req_warning_2:"リクエストボディは大きなサイズになる可能性があります。",audit_record_use:"注意して使用してください。",audit_ip:"IPアドレスを記録する",audit_ip_desc:"クライアントのIPアドレスを記録する",audit_path_params:"パスパラメータを記録",audit_query_params:"クエリパラメータを記録する",audit_http_methods:"HTTPメソッドを含める",audit_http_methods_hint:"含めるHTTPメソッドのリスト。空のリストはすべてを意味します。",audit_http_methods_label:"HTTPメソッド",audit_resp_codes:"HTTPレスポンスコードを含める",audit_resp_codes_hint:"含めるHTTPコードの一覧(正規表現で一致)。空のリストはすべてを意味します。例: 4.*, 5.*",audit_resp_codes_label:"HTTPレスポンスコード(正規表現)",audit_paths:"パスを含める",audit_paths_hint:"含めるパスのリスト(正規表現マッチ)。空のリストはすべてを意味します。",audit_paths_label:"HTTP パス (正規表現)",audit_paths_exclude:"パスを除外",audit_paths_exclude_hint:"除外するパスの一覧(正規表現の一致)。空のリストは対象がないことを意味します。",audit_paths_exclude_label:"HTTP パス (正規表現)",exchange_providers:"取引所プロバイダー",admin_extensions:"管理拡張機能",admin_extensions_label:"管理者拡張機能",admin_extensions_hint:"拡張機能は管理者権限を持つユーザーのみが使用できます",user_default_extensions:"ユーザーデフォルト拡張機能",user_default_extensions_label:"ユーザー拡張機能",user_default_extensions_hint:"ユーザーに対してデフォルトで有効化される拡張機能。",miscellanous:"その他",misc_disable_extensions:"拡張機能を無効にする",misc_disable_extensions_label:"すべての拡張機能を無効にする",misc_hide_api:"APIを非表示",misc_hide_api_label:"ウォレットAPIを隠すことができ、拡張機能は尊重することを選ぶことができます。",wallets_management:"ウォレット管理",funding_source_info:"資金源情報",funding_source:"資金源: {wallet_class}",node_balance:"ノード残高: {balance} サッツ",lnbits_balance:"LNbits残高: {balance} sats",funding_reserve_percent:"予約パーセント: {percent} %",node_management:"ノード管理",node_management_not_supported:"アクティブな資金源ではノード管理がサポートされていません",toggle_node_ui:"ノードUI",toggle_public_node_ui:"パブリックノードUI",toggle_transactions_node_ui:"トランザクションタブ(大規模なCLNノードで無効化)",invoice_expiry:"インボイスの有効期限",invoice_expiry_label:"インボイスの有効期限(秒)",fee_reserve:"料金予約",fee_reserve_msats:"ミリサトシでの予約手数料",fee_reserve_percent:"パーセンテージの予約料",server_management:"サーバー管理",base_url:"ベースURL",base_url_label:"サーバーの静的/基本URL",authentication:"認証",auth_token_expiry_label:"トークン有効期限(分)",auth_token_expiry_hint:"トークンが失効するまでの時間(分)",auth_allowed_methods_label:"許可された認証方法",auth_allowed_methods_hint:"認証方法を選択",auth_nostr_label:"Nostr リクエスト URL",auth_nostr_hint:"クライアントがログインするために使用する絶対URL。",auth_google_ci_label:"Google クライアントID",auth_google_ci_hint:"認可されたリダイレクトURIにhttps://{domain}/api/v1/auth/google/tokenが含まれていることを確認してください",auth_google_cs_label:"Google クライアントシークレット",auth_gh_client_id_label:"GitHub クライアントID",auth_gh_client_id_hint:"認証コールバックURLがhttps://{domain}/api/v1/auth/github/tokenに設定されていることを確認してください。",auth_gh_client_secret_label:"GitHub クライアントシークレット",auth_keycloak_label:"キーコーク ディスカバリー URL",auth_keycloak_ci_label:"Keycloak クライアント ID",auth_keycloak_ci_hint:"認証コールバックURLが https://{domain}/api/v1/auth/keycloak/token に設定されていることを確認してください。",auth_keycloak_cs_label:"キークローククライアントシークレット",auth_keycloak_custom_org_label:"Keycloak カスタム組織",auth_keycloak_custom_icon_label:"Keycloak カスタムアイコン (URL)",auth_oidc_label:"OIDC ディスカバリー URL",auth_oidc_ci_label:"OIDC クライアント ID",auth_oidc_ci_hint:"認証コールバックURLが https://{domain}/api/v1/auth/oidc/token に設定されていることを確認してください。",auth_oidc_cs_label:"OIDC クライアントシークレット",auth_oidc_custom_org_label:"OIDC カスタム組織名(例:Zitadel、Authentik)",auth_oidc_custom_icon_label:"OIDC カスタムアイコン (URL)",currency_settings:"通貨設定",allowed_currencies:"許可されている通貨",allowed_currencies_hint:"利用可能な法定通貨の数を制限する",default_account_currency:"デフォルト口座通貨",default_account_currency_hint:"会計のデフォルト通貨",service_fee_label:"サービス料 (%)",service_fee_hint:"1 取引あたりの手数料 (%)",service_fee_max_label:"サービス料最大 (sats)",service_fee_max_hint:"(サット)での最大サービス料金",fee_wallet:"手数料ウォレット",fee_wallet_label:"手数料ウォレット (ウォレットID)",fee_wallet_hint:"送金先のウォレットID",disable_fee:"手数料を無効にする",disable_fee_internal:"内部支払に対するサービス手数料を無効にする",disable_fee_internal_desc:"内部のライトニングペイメントのサービス料金を無効にする",ui_management:"UI管理",ui_site_title:"サイトのタイトル",ui_site_tagline:"サイトのタグライン",ui_elements_enable:"ホームページの要素を有効にする",ui_elements_disable:"ホームページの要素を無効にする",ui_toggle_elements_tip:"「runs on」などのホームページ要素を削除します。",ui_site_description:"サイトの説明",ui_site_description_hint:"プレーンテキスト、Markdown、または生のHTMLを使用してください。",ui_default_wallet_name:"デフォルトウォレット名",lnbits_wallet:"LNbitsウォレット",denomination:"額面",denomination_hint:"FakeWalletトークンの名前",ui_qr_code_logo:"QRコードロゴ",ui_qr_code_logo_hint:"QRコードのロゴ画像のURL",ui_custom_badge:"カスタムバッジ",ui_custom_badge_label:"カスタムバッジ「使用に注意 - LNbitsウォレットはまだベータ版です」",ui_custom_badge_color_label:"カスタムバッジカラー",themes:"テーマ",themes_hint:"ユーザーが利用可能なテーマを選択してください",custom_logo:"カスタムロゴ",custom_logo_hint:"ロゴ画像へのURL",ad_space_title:"広告スペースのタイトル",ad_space_title_label:"サポートされています",ad_slots:"広告スロット",ad_slots_hint:"CSV形式の広告URLと画像ファイルパス、拡張機能は遵守することを選択できます",ad_slots_label:"URL;img_light_url;img_dark_url、URL...",ads_enabled:"広告が有効になっています",ads_disabled:"広告が無効になっています",user_management:"ユーザー管理",admin_users:"管理者ユーザー",admin_users_hint:"管理者権限を持つユーザー",admin_users_label:"ユーザーID",allowed_users:"許可されたユーザー",allowed_users_hint:"これらのユーザーのみがLNbitsを使用できます。",allowed_users_label:"ユーザーID",allow_creation_user:"新しいユーザーの作成を許可",allow_creation_user_desc:"インデックスページで新しいユーザーの作成を許可する",components:"コンポーネント",long_running_endpoints:"トップ5の長時間実行エンドポイント",http_request_methods:"HTTPリクエストメソッド",http_response_codes:"HTTPレスポンスコード",request_details:"リクエストの詳細",http_request_details:"HTTPリクエストの詳細",block_explorer:"ブロックエクスプローラー",enable_block_explorer:"ブロックエクスプローラーを有効化",block_explorer_desc:"Electrumを介してビットコインのトランザクションとアドレスを探索できます。",blockexplorer_public_api:"パブリックAPIアクセス",blockexplorer_public_api_desc:"ブロックエクスプローラーAPIエンドポイントへの非認証アクセスを許可します。",electrum_server_url:"ElectrumサーバーURL",electrum_server_url_hint:"例: ssl://electrum.blockstream.info:50002 または tcp://localhost:50001",blockexplorer_search_label:"TXIDまたはアドレスで検索",blockexplorer_search_hint:"64文字の16進数 = トランザクション · それ以外 = ビットコインアドレス",recent_blocks:"最新ブロック",chain_tip:"チェーン先端",block_height:"ブロック高さ",block_fee:"ブロック手数料",fee_estimates:"手数料見積もり",confirmed_balance:"確認済み残高",unconfirmed_balance:"未確認残高",transaction_history:"トランザクション履歴",coinbase:"コインベース",inputs:"インプット",outputs:"アウトプット",confirmations:"確認数",confirmed:"確認済み",unconfirmed:"未確認",history_unavailable:"トランザクション履歴が取得できません(アドレスのトランザクションが多すぎます)",address:"アドレス",block_number:"ブロック #{height}",block_diff:"diff {value}",block_hash:"ハッシュ",previous_block:"前のブロック",merkle_root:"マークルルート",version:"バージョン",bits:"Bits",difficulty:"難易度",nonce:"Nonce",txid:"TXID",vsize:"仮想サイズ",weight:"重量",n_block_fee:"{n}ブロック手数料"},window.localisation.cn={confirm:"确定",server:"服务器",theme:"主题",site_customisation:"网站定制",funding:"资金",users:"用户",audit:"审计",apps:"应用程序",channels:"频道",transactions:"交易记录",dashboard:"控制面板",node:"节点",export_users:"导出用户",no_users:"未找到用户",total_capacity:"总容量",avg_channel_size:"平均频道大小",biggest_channel_size:"最大通道大小",smallest_channel_size:"最小频道尺寸",number_of_channels:"频道数量",active_channels:"活跃频道",connect_peer:"连接对等",connect:"连接",open_channel:"打开频道",open:"打开",close_channel:"关闭频道",close:"关闭",restart:"重新启动服务器",save:"保存",save_tooltip:"保存更改",credit_debit:"信用卡 / 借记卡",credit_hint:"按 Enter 键充值账户",credit_label:"{denomination} 充值",credit_ok:"成功记入/扣除虚拟资金 ({amount} sats)。付款取决于资金来源的实际资金。",restart_tooltip:"重新启动服务器以使更改生效",add_funds_tooltip:"为钱包添加资金",reset_defaults:"重置为默认设置",reset_defaults_tooltip:"删除所有设置并重置为默认设置",download_backup:"下载数据库备份",name_your_wallet:"给你的 {name}钱包起个名字",paste_invoice_label:"粘贴发票,付款请求或lnurl*",lnbits_description:"LNbits 设置简单、轻量级,可以在任何闪电网络的资金来源上运行,甚至可以在LNbits自身上运行!您可以为自己运行LNbits,或者轻松为他人提供托管解决方案。每个钱包都有自己的 API 密钥,你可以创建的钱包数量没有限制。能够把资金分开管理使 LNbits 成为一款有用的资金管理和开发工具。扩展程序增加了 LNbits 的额外功能,所以你可以在闪电网络上尝试各种尖端技术。我们已经尽可能简化了开发扩展程序的过程,作为一个免费和开源的项目,我们鼓励人们开发并提交自己的扩展程序。",export_to_phone:"通过二维码导出到手机",export_to_phone_desc:"这个二维码包含您钱包的URL。您可以使用手机扫描的方式打开您的钱包。",wallet:"钱包:",wallets:"钱包",add_wallet:"添加新钱包",delete_wallet:"删除钱包",delete_wallet_desc:"整个钱包将被删除,资金将无法恢复",rename_wallet:"重命名钱包",update_name:"更新名称",fiat_tracking:"菲亚特追踪",currency:"货币",update_currency:"更新货币",press_to_claim:"点击领取比特币",donate:"捐献",view_github:"在GitHub上查看",voidwallet_active:"VoidWallet 已激活!付款功能已禁用。",use_with_caution:"请谨慎使用 - {name}钱包还处于测试版阶段",service_fee:"服务费:{amount}% 每笔交易",service_fee_max:"服务费:{amount}% 每笔交易(最高 {max} sats)",service_fee_tooltip:"LNbits服务器管理员每笔外发交易收取的服务费",toggle_darkmode:"切换暗黑模式",payment_reactions:"支付反应",view_swagger_docs:"查看 LNbits Swagger API 文档",api_docs:"API文档",api_keys_api_docs:"节点URL、API密钥和API文档",api_keys_warning:"请妥善保管这些密钥,分享它们可能导致资金损失。",admin_key_warning:"您的管理员密钥可完全访问您的钱包,包括发送付款的权限。除非您完全信任接收者,否则切勿分享。",lnbits_version:"LNbits版本",runs_on:"可运行在",paste:"粘贴",paste_from_clipboard:"从剪贴板粘贴",paste_request:"粘贴请求",create_invoice:"创建发票",camera_tooltip:"用相机扫描发票/二维码",export_csv:"导出为CSV",chart_tooltip:"显示图表",pending:"待处理",copy_invoice:"复制发票",withdraw_from:"从",cancel:"取消",scan:"扫描",read:"读取",pay:"付款",memo:"备注",date:"日期",payment_processing:"正在处理支付...",not_enough_funds:"资金不足!",search_by_tag_memo_amount:"按标签、备注、金额搜索",invoice_waiting:"待支付的发票",payment_received:"收到付款",payment_sent:"付款已发送",receive:"收款",send:"付款",outgoing_payment_pending:"付款正在等待处理",drain_funds:"清空资金",drain_funds_desc:"这是一个 LNURL-取款的二维码,用于从该钱包中提取全部资金。请不要与他人分享。它与 balanceCheck 和 balanceNotify 兼容,因此在第一次取款后,您的钱包还可能会持续从这里提取资金",i_understand:"我明白",copy_wallet_url:"复制钱包URL",disclaimer_dialog_title:"重要!",disclaimer_dialog:"登录功能将在以后的更新中发布,请将此页面加为书签,以便将来访问您的钱包!此服务处于测试阶段,我们不对资金的丢失承担任何责任。",no_transactions:"尚未进行任何交易",manage:"管理",exchanges:"交易所",extensions:"扩展程序",no_extensions:"你没有安装任何扩展程序 :(",created:"已创建",search_extensions:"搜索扩展程序",extension_sources:"扩展源",ext_sources_hint:"可以下载扩展的存储库",ext_sources_label:"来源网址(仅使用官方LNbits扩展程序来源和您可以信任的来源)",warning:"警告",repository:"代码库",confirm_continue:"你确定要继续吗?",manage_extension_details:"安装/卸载扩展程序",install:"安装",uninstall:"卸载",drop_db:"删除数据",enable:"启用",pay_to_enable:"支付以启用",enable_extension_details:"为当前用户启用扩展程序",disable:"禁用",delete:"删除",installed:"已安装",activated:"已激活",deactivated:"已停用",release_notes:"发布说明",activate_extension_details:"对用户开放或禁用扩展程序",featured:"精选",all:"全部",only_admins_can_install:"(只有管理员账户可以安装扩展)",admin_only:"仅限管理员",new_version:"新版本",extension_depends_on:"依赖于:",extension_rating_soon:"即将推出评分",extension_installed_version:"已安装的版本",extension_uninstall_warning:"您即将对所有用户删除该扩展程序。",uninstall_confirm:"是的,卸载",extension_db_drop_info:"该扩展程序的所有数据将被永久删除。此操作无法撤销!",extension_db_drop_warning:"您即将删除该扩展的所有数据。请继续输入扩展程序名称以确认操作:",extension_required_lnbits_version:"此版本要求最低的 LNbits 版本为",min_version:"最小值(包含)",max_version:"最大值(不含)",payment_hash:"付款哈希",fee:"费",amount:"金额",amount_sats:"金额(聪)",tag:"标签",unit:"单位",description:"详情",expiry:"过期时间",webhook:"Webhook",payment_proof:"付款证明",update:"更新",update_available:"更新{version}可用!",latest_update:"您当前使用的是最新版本{version}。",notifications:"通知",no_notifications:"没有通知",notifications_disabled:"LNbits状态通知已禁用。",enable_notifications:"启用通知",enable_notifications_desc:"如果启用,它将获取最新的LNbits状态更新,如安全事件和更新。",enable_watchdog:"启用看门狗",enable_watchdog_desc:"如果启用,当您的余额低于LNbits余额时,系统将自动将您的资金来源更改为VoidWallet。更新后您将需要手动启用。",watchdog_interval:"看门狗间隔",watchdog_interval_desc:"后台任务应该多久检查一次看门狗增量中的 killswitch 信号 [node_balance - lnbits_balance](以分钟计)。",watchdog_delta:"看门狗德尔塔",watchdog_delta_desc:"在触发紧急停止前切换资金来源至VoidWallet的限制 [lnbits_balance - node_balance > delta]",status:"状态",notification_source:"通知来源",notification_source_label:"来源 URL(仅使用官方LNbits状态源和您信任的源)",more:"更多",less:"少",releases:"版本",watchdog:"监控程序",server_logs:"服务器日志",ip_blocker:"IP 阻止器",security:"安全",security_tools:"安全工具",block_access_hint:"屏蔽IP访问",allow_access_hint:"允许通过IP访问(将覆盖被屏蔽的IP)",enter_ip:"输入IP地址并按回车键",rate_limiter:"速率限制器",wallet_limiter:"钱包限制器",wallet_limit_max_withdraw_per_day:"每日钱包最大提现额度(单位:sats)(设为0则禁用)",wallet_max_ballance:"钱包最大余额(以sats计)(设为0则禁用)",wallet_limit_secs_between_trans:"每个钱包交易间最少秒数(设为0则禁用)",number_of_requests:"请求次数",time_unit:"时间单位",minute:"分钟",second:"秒",hour:"小时",disable_server_log:"禁用服务器日志",enable_server_log:"启用服务器日志",coming_soon:"功能即将推出",session_has_expired:"您的会话已过期。请重新登录。",instant_access_question:"想要即时访问吗?",login_with_user_id:"使用用户ID登录",or:"或",create_new_wallet:"创建新钱包",login_to_account:"登录您的账户",create_account:"创建账户",account_settings:"账户设置",signin_with_nostr:"继续使用 Nostr",signin_with_google:"使用谷歌账号登录",signin_with_github:"使用GitHub登录",signin_with_keycloak:"使用Keycloak登录",username_or_email:"用户名或电子邮箱",password:"密码",password_config:"密码配置",password_repeat:"密码重复",change_password:"修改密码",update_credentials:"更新凭证",update_pubkey:"更新公钥",set_password:"设置密码",invalid_password:"密码至少需要有8个字符",login:"登录",register:"注册",username:"用户名",pubkey:"公钥",user_id:"用户ID",email:"电子邮件",first_name:"名字",last_name:"姓氏",picture:"图片",verify_email:"验证电子邮件与",account:"账户",update_account:"更新帐户",invalid_username:"无效用户名",auth_provider:"认证提供者",my_account:"我的账户",back:"返回",logout:"注销",look_and_feel:"外观和感觉",toggle_gradient:"切换渐变",gradient_background:"渐变背景",language:"语言",color_scheme:"配色方案",admin_settings:"管理员设置",extension_cost:"此版本需要支付最低 {cost} sats。",extension_paid_sats:"您已经支付了{paid_sats} sats。",release_details_error:"无法获取发布详情。",pay_from_wallet:"从钱包支付",wallet_required:"钱包 *",show_qr:"显示QR码",retry_install:"重试安装",new_payment:"创建新支付",update_payment:"更新付款",already_paid_question:"你已经付款了吗?",sell:"出售",sell_require:"请求付款以启用扩展",sell_info:"{name} 扩展需要支付至少 {amount} sat 才能启用。",hide_empty_wallets:"隐藏空钱包",recheck:"重新检查",contributors:"贡献者们",license:"许可证",reset_key:"重置密钥",reset_password:"重置密码",border_choices:"边框选项",select_all:"全选",nfc_supported:"支持NFC",nfc_not_supported:"不支持NFC",expire_date:"有效期:",hash:"哈希:",welcome_lnbits:"欢迎来到LNbits",setup_su_account:"设置超级用户账户如下。",create_ticker_converter:"创建货币代码转换器",enable_audit:"启用审核",recommended:"推荐",audit_desc:"根据指定的过滤器记录HTTP请求",audit_record_req:"记录请求主体",audit_record_warning:"警告:",audit_record_req_warning_1:"机密数据(如密码)将被记录。",audit_record_req_warning_2:"请求主体可能会有较大尺寸。",audit_record_use:"请谨慎使用。",audit_ip:"记录 IP 地址",audit_ip_desc:"记录客户端的IP地址",audit_path_params:"记录路径参数",audit_query_params:"记录查询参数",audit_http_methods:"包括 HTTP 方法",audit_http_methods_hint:"要包含的 HTTP 方法列表。空列表表示全部。",audit_http_methods_label:"HTTP 方法",audit_resp_codes:"包括 HTTP 响应代码",audit_resp_codes_hint:"要包含的 HTTP 代码列表(正则表达式匹配)。空列表表示全部。例如:4.*,5.*",audit_resp_codes_label:"HTTP响应代码(正则表达式)",audit_paths:"包含路径",audit_paths_hint:"要包含的路径列表(正则表达式匹配)。空列表意味着全部。",audit_paths_label:"HTTP 路径(正则表达式)",audit_paths_exclude:"排除路径",audit_paths_exclude_hint:"要排除的路径列表(正则表达式匹配)。空列表表示没有。",audit_paths_exclude_label:"HTTP 路径(正则表达式)",exchange_providers:"兑换提供商",admin_extensions:"管理员扩展",admin_extensions_label:"管理员扩展件",admin_extensions_hint:"只有具有管理员权限的用户才能使用扩展程序",user_default_extensions:"用户默认扩展",user_default_extensions_label:"用户扩展",user_default_extensions_hint:"对用户默认启用的扩展。",miscellanous:"杂项",misc_disable_extensions:"禁用扩展程序",misc_disable_extensions_label:"禁用所有扩展程序",misc_hide_api:"隐藏 API",misc_hide_api_label:"隐藏钱包 api,扩展程序可以选择遵守",wallets_management:"钱包管理",funding_source_info:"资金来源信息",funding_source:"资金来源:{wallet_class}",node_balance:"节点余额:{balance} sats",lnbits_balance:"LNbits 余额:{balance} sats",funding_reserve_percent:"保留百分比: {percent} %",node_management:"节点管理",node_management_not_supported:"活动资金来源不支持节点管理",toggle_node_ui:"节点用户界面",toggle_public_node_ui:"公共节点用户界面",toggle_transactions_node_ui:"交易选项卡(在大型 CLN 节点上禁用)",invoice_expiry:"发票到期",invoice_expiry_label:"发票到期(秒)",fee_reserve:"费用储备",fee_reserve_msats:"以msats计的保留费",fee_reserve_percent:"以百分比计的保留费用",server_management:"服务器管理",base_url:"基本URL",base_url_label:"服务器的静态/基本网址",authentication:"认证",auth_token_expiry_label:"令牌过期分钟数",auth_token_expiry_hint:"令牌过期的剩余时间(分钟)",auth_allowed_methods_label:"允许的授权方法",auth_allowed_methods_hint:"选择授权方法",auth_nostr_label:"Nostr请求URL",auth_nostr_hint:"客户端将用于登录的绝对URL。",auth_google_ci_label:"谷歌客户ID",auth_google_ci_hint:"确保授权重定向URI包含https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google客户端密钥",auth_gh_client_id_label:"GitHub 客户端 ID",auth_gh_client_id_hint:"确保授权回调 URL 设置为 https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub客户端密码",auth_keycloak_label:"Keycloak 发现 URL",auth_keycloak_ci_label:"Keycloak 客户端 ID",auth_keycloak_ci_hint:"确保授权回调URL设置为https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak客户端密钥",auth_keycloak_custom_org_label:"Keycloak 自定义组织",auth_keycloak_custom_icon_label:"Keycloak 自定义图标 (URL)",auth_oidc_label:"OIDC 发现 URL",auth_oidc_ci_label:"OIDC 客户端 ID",auth_oidc_ci_hint:"确保授权回调URL设置为https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC客户端密钥",auth_oidc_custom_org_label:"OIDC 自定义组织名称(例如 Zitadel、Authentik)",auth_oidc_custom_icon_label:"OIDC 自定义图标 (URL)",currency_settings:"货币设置",allowed_currencies:"允许的货币",allowed_currencies_hint:"限制可用法定货币的数量",default_account_currency:"默认账户货币",default_account_currency_hint:"默认的会计货币",service_fee_label:"服务费 (%)",service_fee_hint:"每笔交易收取的费用 (%)",service_fee_max_label:"服务费最大值(聪)",service_fee_max_hint:"最大服务费以 (sats) 收取",fee_wallet:"费用钱包",fee_wallet_label:"费用钱包(钱包 ID)",fee_wallet_hint:"用于接收资金的钱包 ID",disable_fee:"禁用费用",disable_fee_internal:"禁用内部付款服务费",disable_fee_internal_desc:"禁用内部闪电支付的服务费",ui_management:"用户界面管理",ui_site_title:"网站标题",ui_site_tagline:"网站标语",ui_elements_enable:"在主页上启用元素",ui_elements_disable:"禁用主页上的元素",ui_toggle_elements_tip:"移除主页元素,例如“运行于”等。",ui_site_description:"网站描述",ui_site_description_hint:"使用纯文本、Markdown或原始HTML",ui_default_wallet_name:"默认钱包名称",lnbits_wallet:"LNbits 钱包",denomination:"面额",denomination_hint:"FakeWallet 代币的名称",ui_qr_code_logo:"二维码标志",ui_qr_code_logo_hint:"二维码中标志图像的 URL",ui_custom_badge:"自定义徽章",ui_custom_badge_label:"自定义徽章“慎用 - LNbits 钱包仍在测试阶段”",ui_custom_badge_color_label:"自定义徽章颜色",themes:"主题",themes_hint:"选择可供用户使用的主题",custom_logo:"自定义徽标",custom_logo_hint:"徽标图像的URL",ad_space_title:"广告位标题",ad_space_title_label:"由...支持",ad_slots:"广告位",ad_slots_hint:"广告网址和图像文件路径以CSV格式存储,扩展可以选择遵循。",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"启用广告",ads_disabled:"广告已禁用",user_management:"用户管理",admin_users:"管理员用户",admin_users_hint:"具有管理员权限的用户",admin_users_label:"用户ID",allowed_users:"允许的用户",allowed_users_hint:"仅这些用户可以使用LNbits",allowed_users_label:"用户 ID",allow_creation_user:"允许创建新用户",allow_creation_user_desc:"允许在索引页面上创建新用户",components:"组件",long_running_endpoints:"前五个长时间运行的端点",http_request_methods:"HTTP请求方法",http_response_codes:"HTTP响应代码",request_details:"请求详情",http_request_details:"HTTP请求详细信息",block_explorer:"区块浏览器",enable_block_explorer:"启用区块浏览器",block_explorer_desc:"允许用户通过 Electrum 浏览比特币交易和地址。",blockexplorer_public_api:"公开 API 访问",blockexplorer_public_api_desc:"允许对区块浏览器 API 端点的未认证访问。",electrum_server_url:"Electrum 服务器 URL",electrum_server_url_hint:"例如 ssl://electrum.blockstream.info:50002 或 tcp://localhost:50001",blockexplorer_search_label:"按 TXID 或地址搜索",blockexplorer_search_hint:"64位十六进制 = 交易 · 其他 = 比特币地址",recent_blocks:"最新区块",chain_tip:"链尖",block_height:"区块高度",block_fee:"区块手续费",fee_estimates:"手续费估算",confirmed_balance:"已确认余额",unconfirmed_balance:"未确认余额",transaction_history:"交易历史",coinbase:"Coinbase",inputs:"输入",outputs:"输出",confirmations:"确认数",confirmed:"已确认",unconfirmed:"未确认",history_unavailable:"交易历史不可用(地址交易过多)",address:"地址",block_number:"区块 #{height}",block_diff:"难度 {value}",block_hash:"哈希",previous_block:"上一区块",merkle_root:"Merkle 根",version:"版本",bits:"Bits",difficulty:"难度",nonce:"Nonce",txid:"TXID",vsize:"虚拟大小",weight:"权重",n_block_fee:"{n} 区块手续费"},window.localisation.nl={confirm:"Ja",server:"Server",theme:"Thema",site_customisation:"Site-aanpassing",funding:"Financiering",users:"Gebruikers",audit:"Controle",apps:"Apps",channels:"Kanalen",transactions:"Transacties",dashboard:"Dashboard",node:"Knooppunt",export_users:"Gebruikers exporteren",no_users:"Geen gebruikers gevonden",total_capacity:"Totale capaciteit",avg_channel_size:"Gem. Kanaalgrootte",biggest_channel_size:"Grootste Kanaalgrootte",smallest_channel_size:"Kleinste Kanaalgrootte",number_of_channels:"Aantal kanalen",active_channels:"Actieve Kanalen",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Open Kanaal",open:"Open",close_channel:"Kanaal Sluiten",close:"Sluiten",restart:"Server opnieuw opstarten",save:"Opslaan",save_tooltip:"Sla uw wijzigingen op",credit_debit:"Credit / Debet",credit_hint:"Druk op Enter om de rekening te crediteren",credit_label:"{denomination} te crediteren",credit_ok:"Succesvol crediteren/debiteren van virtuele gelden ({amount} sats). Betalingen zijn afhankelijk van de werkelijke fondsen op de financieringsbron.",restart_tooltip:"Start de server opnieuw op zodat wijzigingen van kracht worden",add_funds_tooltip:"Voeg geld toe aan een portemonnee.",reset_defaults:"Standaardinstellingen herstellen",reset_defaults_tooltip:"Wis alle instellingen en herstel de standaardinstellingen.",download_backup:"Databaseback-up downloaden",name_your_wallet:"Geef je {name} portemonnee een naam",paste_invoice_label:"Plak een factuur, betalingsverzoek of lnurl-code*",lnbits_description:"Gemakkelijk in te stellen en lichtgewicht, LNbits kan op elke lightning-netwerkfinancieringsbron draaien en zelfs LNbits zelf! U kunt LNbits voor uzelf laten draaien of gemakkelijk een bewaardersoplossing voor anderen bieden. Elke portemonnee heeft zijn eigen API-sleutels en er is geen limiet aan het aantal portemonnees dat u kunt maken. Het kunnen partitioneren van fondsen maakt LNbits een nuttige tool voor geldbeheer en als ontwikkelingstool. Extensies voegen extra functionaliteit toe aan LNbits, zodat u kunt experimenteren met een reeks toonaangevende technologieën op het bliksemschichtnetwerk. We hebben het ontwikkelen van extensies zo eenvoudig mogelijk gemaakt en als een gratis en opensource-project moedigen we mensen aan om hun eigen ontwikkelingen in te dienen.",export_to_phone:"Exporteren naar telefoon met QR-code",export_to_phone_desc:"Deze QR-code bevat uw portemonnee-URL met volledige toegang. U kunt het vanaf uw telefoon scannen om uw portemonnee van daaruit te openen.",wallet:"Wallet:",wallets:"Portemonnees",add_wallet:"Een nieuwe portemonnee toevoegen",delete_wallet:"Portemonnee verwijderen",delete_wallet_desc:"Deze hele portemonnee wordt verwijderd, de fondsen worden NIET TERUGGEVONDEN.",rename_wallet:"Portemonnee hernoemen",update_name:"Naam bijwerken",fiat_tracking:"Volgfunctie voor fiat-valuata",currency:"Valuta",update_currency:"Valuta bijwerken",press_to_claim:"Druk om bitcoin te claimen",donate:"Doneren",view_github:"Bekijken op GitHub",voidwallet_active:"VoidWallet is actief! Betalingen uitgeschakeld",use_with_caution:"GEBRUIK MET VOORZICHTIGHEID - {name} portemonnee is nog in BETA",service_fee:"Servicekosten: {amount} % per transactie",service_fee_max:"Servicekosten: {amount} % per transactie (max {max} sats)",service_fee_tooltip:"Transactiekosten in rekening gebracht door de LNbits serverbeheerder per uitgaande transactie",toggle_darkmode:"Donkere modus aan/uit",payment_reactions:"Betalingsreacties",view_swagger_docs:"Bekijk LNbits Swagger API-documentatie",api_docs:"API-documentatie",api_keys_api_docs:"Node URL, API-sleutels en API-documentatie",api_keys_warning:"Bewaar deze sleutels veilig; het delen ervan kan leiden tot verlies van tegoeden.",admin_key_warning:"Je beheerderssleutel geeft volledige toegang tot je wallet, inclusief de mogelijkheid om betalingen te versturen. Deel deze nooit, tenzij je de ontvanger volledig vertrouwt.",lnbits_version:"LNbits-versie",runs_on:"Draait op",paste:"Plakken",paste_from_clipboard:"Plakken van klembord",paste_request:"Verzoek plakken",create_invoice:"Factuur aanmaken",camera_tooltip:"Gebruik de camera om een factuur/QR-code te scannen",export_csv:"Exporteer naar CSV",chart_tooltip:"Toon grafiek",pending:"In behandeling",copy_invoice:"Kopieer factuur",withdraw_from:"Opnemen van",cancel:"Annuleren",scan:"Scannen",read:"Lezen",pay:"Betalen",memo:"Memo",date:"Datum",payment_processing:"Verwerking betaling...",not_enough_funds:"Onvoldoende saldo!",search_by_tag_memo_amount:"Zoeken op tag, memo, bedrag",invoice_waiting:"Factuur wachtend op betaling",payment_received:"Betaling ontvangen",payment_sent:"Betaling verzonden",receive:"ontvangen",send:"versturen",outgoing_payment_pending:"Uitgaande betaling in behandeling",drain_funds:"Geld opnemen",drain_funds_desc:"Dit is een LNURL-withdraw QR-code om alles uit deze portemonnee te halen. Deel deze code niet met anderen. Het is compatibel met balanceCheck en balanceNotify zodat jouw portemonnee continu geld kan blijven opnemen vanaf hier na de eerste opname.",i_understand:"Ik begrijp het",copy_wallet_url:"Kopieer portemonnee-URL",disclaimer_dialog_title:"Belangrijk!",disclaimer_dialog:"Inlogfunctionaliteit wordt uitgebracht in een toekomstige update. Zorg er nu voor dat je deze pagina als favoriet markeert om in de toekomst toegang te krijgen tot je portemonnee! Deze service is in BETA en we zijn niet verantwoordelijk voor mensen die de toegang tot hun fondsen verliezen.",no_transactions:"Er zijn nog geen transacties gedaan",manage:"Beheer",exchanges:"Beurzen",extensions:"Extensies",no_extensions:"Je hebt geen extensies geïnstalleerd :(",created:"Aangemaakt",search_extensions:"Zoekextensies",extension_sources:"Extensiebronnen",ext_sources_hint:"Repositories van waar de extensies kunnen worden gedownload",ext_sources_label:"Bron-URL (gebruik alleen de officiële LNbits-extensiebron en bronnen die je kunt vertrouwen)",warning:"Waarschuwing",repository:"Repository",confirm_continue:"Weet je zeker dat je wilt doorgaan?",manage_extension_details:"Installeren/verwijderen van extensie",install:"Installeren",uninstall:"Deïnstalleren",drop_db:"Gegevens verwijderen",enable:"Inschakelen",pay_to_enable:"Betalen om te activeren",enable_extension_details:"Schakel extensie in voor huidige gebruiker",disable:"Uitschakelen",delete:"Verwijderen",installed:"Geïnstalleerd",activated:"Geactiveerd",deactivated:"Gedeactiveerd",release_notes:"Release-opmerkingen",activate_extension_details:"Maak extensie beschikbaar/niet beschikbaar voor gebruikers",featured:"Uitgelicht",all:"Alles",only_admins_can_install:"Alleen beheerdersaccounts kunnen extensies installeren",admin_only:"Alleen beheerder",new_version:"Nieuwe Versie",extension_depends_on:"Afhankelijk van:",extension_rating_soon:"Beoordelingen binnenkort beschikbaar",extension_installed_version:"Geïnstalleerde versie",extension_uninstall_warning:"U staat op het punt de extensie voor alle gebruikers te verwijderen.",uninstall_confirm:"Ja, de-installeren",extension_db_drop_info:"Alle gegevens voor de extensie zullen permanent worden verwijderd. Er is geen manier om deze bewerking ongedaan te maken!",extension_db_drop_warning:"U staat op het punt alle gegevens voor de extensie te verwijderen. Typ de naam van de extensie om door te gaan:",extension_required_lnbits_version:"Deze release vereist ten minste LNbits-versie",min_version:"Minimum (inbegrepen)",max_version:"Maximum (uitgesloten)",payment_hash:"Betalings-hash",fee:"Kosten",amount:"Bedrag",amount_sats:"Bedrag (sats)",tag:"Label",unit:"Eenheid",description:"Beschrijving",expiry:"Vervaldatum",webhook:"Webhook",payment_proof:"Betalingsbewijs",update:"Bijwerken",update_available:"Update {version} beschikbaar!",latest_update:"U bent op de nieuwste versie {version}.",notifications:"Meldingen",no_notifications:"Geen meldingen",notifications_disabled:"LNbits-statusmeldingen zijn uitgeschakeld.",enable_notifications:"Schakel meldingen in",enable_notifications_desc:"Indien ingeschakeld zal het de laatste LNbits Status updates ophalen, zoals veiligheidsincidenten en updates.",enable_watchdog:"Inschakelen Watchdog",enable_watchdog_desc:"Indien ingeschakeld, wordt uw betaalbron automatisch gewijzigd naar VoidWallet als uw saldo lager is dan het saldo van LNbits. U zult dit na een update handmatig moeten inschakelen.",watchdog_interval:"Watchdog-interval",watchdog_interval_desc:"Hoe vaak de achtergrondtaak moet controleren op een killswitch signaal in het watchdog verschil [node_balance - lnbits_balance] (in minuten).",watchdog_delta:"Waakhond Delta",watchdog_delta_desc:"Limiet voordat de killswitch de financieringsbron verandert naar VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notificatiebron",notification_source_label:"Bron-URL (gebruik alleen de officiële LNbits-statusbron en bronnen die u vertrouwt)",more:"meer",less:"minder",releases:"Uitgaven",watchdog:"Waakhond",server_logs:"Serverlogboeken",ip_blocker:"IP-blokkering",security:"Beveiliging",security_tools:"Beveiligingstools",block_access_hint:"Toegang blokkeren per IP",allow_access_hint:"Toegang verlenen op basis van IP (zal geblokkeerde IP's overschrijven)",enter_ip:"Voer IP in en druk op enter",rate_limiter:"Snelheidsbegrenzer",wallet_limiter:"Portemonnee Limietsteller",wallet_limit_max_withdraw_per_day:"Maximale dagelijkse opname van wallet in sats (0 om uit te schakelen)",wallet_max_ballance:"Maximale portefeuillesaldo in sats (0 om uit te schakelen)",wallet_limit_secs_between_trans:"Min seconden tussen transacties per portemonnee (0 om uit te schakelen)",number_of_requests:"Aantal verzoeken",time_unit:"Tijdeenheid",minute:"minuut",second:"seconde",hour:"uur",disable_server_log:"Serverlog uitschakelen",enable_server_log:"Activeer Serverlog",coming_soon:"Functie binnenkort beschikbaar",session_has_expired:"Uw sessie is verlopen. Log alstublieft opnieuw in.",instant_access_question:"Wil je directe toegang?",login_with_user_id:"Inloggen met gebruikers-ID",or:"of",create_new_wallet:"Nieuwe portemonnee aanmaken",login_to_account:"Log in op je account",create_account:"Account aanmaken",account_settings:"Accountinstellingen",signin_with_nostr:"Doorgaan met Nostr",signin_with_google:"Inloggen met Google",signin_with_github:"Inloggen met GitHub",signin_with_keycloak:"Inloggen met Keycloak",username_or_email:"Gebruikersnaam of e-mail",password:"Wachtwoord",password_config:"Wachtwoordconfiguratie",password_repeat:"Wachtwoord herhalen",change_password:"Wachtwoord wijzigen",update_credentials:"Referenties bijwerken",update_pubkey:"Openbare Sleutel Bijwerken",set_password:"Wachtwoord instellen",invalid_password:"Wachtwoord moet ten minste 8 tekens bevatten",login:"Inloggen",register:"Registreren",username:"Gebruikersnaam",pubkey:"Publieke Sleutel",user_id:"Gebruikers-ID",email:"E-mail",first_name:"Voornaam",last_name:"Achternaam",picture:"Foto",verify_email:"E-mail verifiëren met",account:"Account",update_account:"Account bijwerken",invalid_username:"Ongeldige gebruikersnaam",auth_provider:"Auth Provider",my_account:"Mijn Account",back:"Terug",logout:"Afmelden",look_and_feel:"Uiterlijk en gedrag",toggle_gradient:"Gradiënt Schakelen",gradient_background:"Verloopachtergrond",language:"Taal",color_scheme:"Kleurenschema",admin_settings:"Beheerdersinstellingen",extension_cost:"Deze release vereist een betaling van minimaal {cost} sats.",extension_paid_sats:"U heeft al {paid_sats} sats betaald.",release_details_error:"Kan de gegevens van de release niet ophalen.",pay_from_wallet:"Betalen vanuit Portemonnee",wallet_required:"Wallet *",show_qr:"Toon QR",retry_install:"Opnieuw installeren",new_payment:"Nieuwe betaling maken",update_payment:"Betaling bijwerken",already_paid_question:"Heb je al betaald?",sell:"Verkopen",sell_require:"Vraag betaling om de extensie te activeren.",sell_info:"De {name} extensie vereist een betaling van minimaal {amount} sats om in te schakelen.",hide_empty_wallets:"Verberg lege portemonnees",recheck:"Opnieuw controleren",contributors:"Bijdragers",license:"Licentie",reset_key:"Hersteltoets",reset_password:"Wachtwoord Resetten",border_choices:"Randkeuzes",select_all:"Alles selecteren",nfc_supported:"NFC Ondersteund",nfc_not_supported:"NFC niet ondersteund",expire_date:"Vervaldatum:",hash:"Hash:",welcome_lnbits:"Welkom bij LNbits",setup_su_account:"Stel het Superuser-account hieronder in.",create_ticker_converter:"Maak Valuta Ticker Converter",enable_audit:"Audit inschakelen",recommended:"Aanbevolen",audit_desc:"HTTP-verzoeken vastleggen volgens de opgegeven filters",audit_record_req:"Verzoeklichaam registreren",audit_record_warning:"Waarschuwing:",audit_record_req_warning_1:"vertrouwelijke gegevens (zoals wachtwoorden) worden gelogd.",audit_record_req_warning_2:"de aanvraagbody kan een grote omvang hebben.",audit_record_use:"Gebruik het met voorzichtigheid.",audit_ip:"IP-adres vastleggen",audit_ip_desc:"Leg het IP-adres van de klant vast",audit_path_params:"Parameters van het pad opnemen",audit_query_params:"Queryparameters vastleggen",audit_http_methods:"Inclusief HTTP-methoden",audit_http_methods_hint:"Lijst van HTTP-methoden die moeten worden opgenomen. Lege lijsten betekenen alles.",audit_http_methods_label:"HTTP-methoden",audit_resp_codes:"Inclusief HTTP-responscodes",audit_resp_codes_hint:"Lijst van op te nemen HTTP-codes (regex-overeenkomst). Lege lijst betekent alles. Bijvoorbeeld: 4.*, 5.*",audit_resp_codes_label:"HTTP-responscode (regex)",audit_paths:"Inclusiepad",audit_paths_hint:"Lijst met paden die moeten worden opgenomen (regex match). Lege lijst betekent alles.",audit_paths_label:"HTTP-pad (regex)",audit_paths_exclude:"Paden uitsluiten",audit_paths_exclude_hint:"Lijst met paden die moeten worden uitgesloten (regex-overeenkomst). Een lege lijst betekent geen.",audit_paths_exclude_label:"HTTP-pad (regex)",exchange_providers:"Wisselaanbieders",admin_extensions:"Beheeruitbreidingen",admin_extensions_label:"Beheerdersuitbreidingen",admin_extensions_hint:"Alleen gebruikers met beheerdersrechten kunnen extensies gebruiken.",user_default_extensions:"Standaardextensies voor gebruikers",user_default_extensions_label:"Gebruikersuitbreidingen",user_default_extensions_hint:"Extensies die standaard voor de gebruikers worden ingeschakeld.",miscellanous:"Diversen",misc_disable_extensions:"Extensies uitschakelen",misc_disable_extensions_label:"Alle extensies uitschakelen",misc_hide_api:"API verbergen",misc_hide_api_label:"Verbergt de wallet-API, extensies kunnen ervoor kiezen dit te respecteren",wallets_management:"Beheer van portemonnees",funding_source_info:"Financieringsbroninfo",funding_source:"Financieringsbron: {wallet_class}",node_balance:"Node Balans: {balance} sats",lnbits_balance:"LNbits Saldo: {balance} sats",funding_reserve_percent:"Reservepercentage: {percent} %",node_management:"Nodebeheer",node_management_not_supported:"Nodebeheer wordt niet ondersteund door de actieve financieringsbron",toggle_node_ui:"Node UI",toggle_public_node_ui:"Openbare Node UI",toggle_transactions_node_ui:"Transacties Tabblad (Uitschakelen op grote CLN-nodes)",invoice_expiry:"Factuurvervaldatum",invoice_expiry_label:"Factuurverloop (seconden)",fee_reserve:"Toegangsvergoeding Reserve",fee_reserve_msats:"Reserveringskosten in msats",fee_reserve_percent:"Reserveringskosten in procent",server_management:"Serverbeheer",base_url:"Basis-URL",base_url_label:"Statisch/Basis-URL voor de server",authentication:"Authenticatie",auth_token_expiry_label:"Token vervalt over minuten",auth_token_expiry_hint:"Tijd in minuten totdat de token verloopt",auth_allowed_methods_label:"Toegestane autorisatiemethoden",auth_allowed_methods_hint:"Selecteer autorisatiemethoden",auth_nostr_label:"Nostr Aanvraag-URL",auth_nostr_hint:"Absolute URL die de klanten zullen gebruiken om in te loggen.",auth_google_ci_label:"Google Client-ID",auth_google_ci_hint:"Zorg ervoor dat de geautoriseerde omleidings-URL's https://{domain}/api/v1/auth/google/token bevatten.",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub client-ID",auth_gh_client_id_hint:"Zorg ervoor dat de autorisatie-callback-URL is ingesteld op https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Clientgeheim",auth_keycloak_label:"Keycloak Ontdekking URL",auth_keycloak_ci_label:"Keycloak-client-ID",auth_keycloak_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Clientgeheim",auth_keycloak_custom_org_label:"Keycloak Aangepaste Organisatie",auth_keycloak_custom_icon_label:"Keycloak Aangepast Pictogram (URL)",auth_oidc_label:"OIDC Ontdekking URL",auth_oidc_ci_label:"OIDC-client-ID",auth_oidc_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC Clientgeheim",auth_oidc_custom_org_label:"OIDC Aangepaste Organisatienaam (bijv. Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC Aangepast Pictogram (URL)",currency_settings:"Valuta-instellingen",allowed_currencies:"Toegestane valuta's",allowed_currencies_hint:"Beperk het aantal beschikbare fiatvaluta's",default_account_currency:"Standaardrekeningvaluta",default_account_currency_hint:"Standaardvaluta voor boekhouding",service_fee_label:"Servicekosten (%)",service_fee_hint:"Toeslag per transactie (%)",service_fee_max_label:"Servicekosten max (sats)",service_fee_max_hint:"Maximale servicekosten om in rekening te brengen in (sats)",fee_wallet:"Kosten Portemonnee",fee_wallet_label:"Kosten portemonnee (wallet ID)",fee_wallet_hint:"Wallet-ID om geld naar over te maken",disable_fee:"Kosten uitschakelen",disable_fee_internal:"Servicekosten uitschakelen voor interne betalingen",disable_fee_internal_desc:"Dienstenkosten uitschakelen voor interne Lightning-betalingen",ui_management:"UI-beheer",ui_site_title:"Site titel",ui_site_tagline:"Site-slogan",ui_elements_enable:"Elementen op de homepage inschakelen",ui_elements_disable:"Elementen op de homepage uitschakelen",ui_toggle_elements_tip:"Verwijder startpagina-elementen zoals 'werkt op' enz.",ui_site_description:"Sitebeschrijving",ui_site_description_hint:"Gebruik platte tekst, Markdown, of ruwe HTML",ui_default_wallet_name:"Standaard Wallet Naam",lnbits_wallet:"LNbits-portemonnee",denomination:"Denominatie",denomination_hint:"De naam voor de FakeWallet token",ui_qr_code_logo:"QR-code-logo",ui_qr_code_logo_hint:"URL naar logo-afbeelding in QR-code",ui_custom_badge:"Aangepaste badge",ui_custom_badge_label:"Aangepaste Badge 'GEBRUIK MET VOORZICHTIGHEID - LNbits-portemonnee is nog in BÈTA'",ui_custom_badge_color_label:"Aangepaste Badge Kleur",themes:"Thema's",themes_hint:"Kies thema's beschikbaar voor gebruikers",custom_logo:"Aangepast logo",custom_logo_hint:"URL naar logo-afbeelding",ad_space_title:"Advertentieruimte Titel",ad_space_title_label:"Ondersteund door",ad_slots:"Advertentieblokken",ad_slots_hint:"Ad URL en afbeeldingspad in CSV-formaat, extensies kunnen ervoor kiezen te honoreren",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Advertenties ingeschakeld",ads_disabled:"Advertenties uitgeschakeld",user_management:"Gebruikersbeheer",admin_users:"Beheerdersgebruikers",admin_users_hint:"Gebruikers met beheerdersrechten",admin_users_label:"Gebruikers-ID",allowed_users:"Toegestane gebruikers",allowed_users_hint:"Alleen deze gebruikers kunnen LNbits gebruiken",allowed_users_label:"Gebruikers-ID",allow_creation_user:"Sta het aanmaken van nieuwe gebruikers toe",allow_creation_user_desc:"Sta de aanmaak van nieuwe gebruikers op de indexpagina toe",components:"Componenten",long_running_endpoints:"Top 5 langlopende eindpunten",http_request_methods:"HTTP-aanvraagmethoden",http_response_codes:"HTTP-responscodes",request_details:"Aanvraagdetails",http_request_details:"HTTP-verzoekdetails",block_explorer:"Block Explorer",enable_block_explorer:"Block Explorer inschakelen",block_explorer_desc:"Laat gebruikers Bitcoin-transacties en -adressen verkennen via Electrum.",blockexplorer_public_api:"Publieke API-toegang",blockexplorer_public_api_desc:"Niet-geauthenticeerde toegang tot de block explorer API-eindpunten toestaan.",electrum_server_url:"Electrum-server-URL",electrum_server_url_hint:"bijv. ssl://electrum.blockstream.info:50002 of tcp://localhost:50001",blockexplorer_search_label:"Zoeken op TXID of adres",blockexplorer_search_hint:"64-karakter hex = transactie · alles anders = Bitcoin-adres",recent_blocks:"Recente blokken",chain_tip:"Kettingtop",block_height:"Blokhoogte",block_fee:"blokvergoeding",fee_estimates:"Vergoedingsschattingen",confirmed_balance:"Bevestigd saldo",unconfirmed_balance:"Onbevestigd saldo",transaction_history:"Transactiegeschiedenis",coinbase:"Coinbase",inputs:"Invoer",outputs:"Uitvoer",confirmations:"Bevestigingen",confirmed:"Bevestigd",unconfirmed:"Onbevestigd",history_unavailable:"Transactiegeschiedenis niet beschikbaar (adres heeft te veel transacties)",address:"Adres",block_number:"Blok #{height}",block_diff:"moeil. {value}",block_hash:"Hash",previous_block:"Vorig blok",merkle_root:"Merkle-wortel",version:"Versie",bits:"Bits",difficulty:"Moeilijkheid",nonce:"Nonce",txid:"TXID",vsize:"Virtuele grootte",weight:"Gewicht",n_block_fee:"{n}-blok vergoeding"},window.localisation.pi={confirm:"Aye",server:"Cap`n",theme:"Theme",site_customisation:"Site Customisation",funding:"Funding",users:"Buccaneers",audit:"Arrr-dit",apps:"Arrrrplications",channels:"Channels",transactions:"Pirate Transactions and loot",dashboard:"Arrr-board",node:"Node",export_users:"Export Mateys",no_users:"No swabbies found",total_capacity:"Total Capacity",avg_channel_size:"Avg. Channel Size",biggest_channel_size:"Largest Bilge Size",smallest_channel_size:"Smallest Channel Size",number_of_channels:"Nummer o' Channels",active_channels:"Active Channels",connect_peer:"Connect Peer",connect:"Connect",open_channel:"Open Channel",open:"Open yer hatches",close_channel:"Shut Yer Gob Channel",close:"Batten down the hatches, we be closin",restart:"Arr, restart Cap`n",save:"Bury Treasure",save_tooltip:"Bury yer changes, matey",credit_debit:"Credit / Debit",credit_hint:"Press Enter to credit account and make it richer",credit_label:"{denomination} to credit, arr!",credit_ok:"Success creditin'/debitin' virtual funds ({amount} sats). Payments depend on actual funds on fundin' source.",restart_tooltip:"Restart the Cap`n for changes to take effect, arr!",add_funds_tooltip:"Add doubloons to a chest and make it heavier",reset_defaults:"Reset to Davy Jones Locker",reset_defaults_tooltip:"Scuttle all settings and reset to Davy Jones Locker. Aye, start anew!",download_backup:"Download database booty",name_your_wallet:"Name yer {name} treasure chest",paste_invoice_label:"Paste a booty, payment request or lnurl code, matey!",lnbits_description:"Arr, easy to set up and lightweight, LNbits can run on any Lightning Network funding source and even LNbits itself! Ye can run LNbits for yourself, or easily offer a custodian solution for others. Each chest has its own API keys and there be no limit to the number of chests ye can make. Being able to partition booty makes LNbits a useful tool for money management and as a development tool. Arr, extensions add extra functionality to LNbits so ye can experiment with a range of cutting-edge technologies on the lightning network. We have made developing extensions as easy as possible, and as a free and open-source project, we encourage scallywags to develop and submit their own.",export_to_phone:"Export to Phone with QR Code, me hearties",export_to_phone_desc:"This QR code contains yer chest URL with full access. Ye can scan it from yer phone to open yer chest from there, arr!",wallet:"Booty Chest:",wallets:"Treasure Chests",add_wallet:"Add a new chest and fill it with doubloons!",delete_wallet:"Scuttle the Chest",delete_wallet_desc:"This whole chest will be scuttled, the booty will be UNRECOVERABLE. Aye, be warned!",rename_wallet:"Rename the Chest, me hearty",update_name:"Update name like a captain",fiat_tracking:"Trackin' o' the treasure",currency:"Curr'nsey",update_currency:"Update doubloons",press_to_claim:"Press to claim gold doubloons, matey!",donate:"Donate like a true pirate!",view_github:"View on GitHub and find treasures",voidwallet_active:"VoidWallet be active! Payments disabled",use_with_caution:"USE WITH CAUTION - {name} chest be still in BETA. Aye, be careful!",service_fee:"Service fee: {amount} % per transaction",service_fee_max:"Service fee: {amount} % per transaction (max {max} sats)",service_fee_tooltip:"Service fee charged by the LNbits server admin per goin' transaction",toggle_darkmode:"Toggle Dark Mode, arr!",payment_reactions:"Payment Reactions",view_swagger_docs:"View LNbits Swagger API docs and learn the secrets",api_docs:"API docs for the scallywags",api_keys_api_docs:"Node URL, API keys and API docs",api_keys_warning:"Keep these keys safe, matey; sharing them could lose ye yer doubloons.",admin_key_warning:"Yer admin key gives full access to yer wallet, including sending payments. Never share it unless ye trust the recipient completely.",lnbits_version:"LNbits version, arr!",runs_on:"Runs on, matey",paste:"Stow",paste_from_clipboard:"Paste from clipboard",paste_request:"Paste Request and find treasures",create_invoice:"Create Booty Request and get rich, me hearties!",camera_tooltip:"Use spyglass to scan a booty/QR, arr!",export_csv:"Export to CSV and keep track of the booty",chart_tooltip:"Show ye chart, me hearty",pending:"Pendin like a ship at anchor",copy_invoice:"Copy booty request, arrr",withdraw_from:"Withdraw from",cancel:"Abandon ship! We be retreatin",scan:"Avast! Scan me beauty, arrr",read:"Read it, if ye dare",pay:"Pay up or walk the plank, ye scallywag",memo:"Message in a bottle, argh",date:"Date of the map, me matey",payment_processing:"Processing yer payment... don´t make me say it again",not_enough_funds:"Arrr, ye don´t have enough doubloons! Walk the plank!",search_by_tag_memo_amount:"Search by tag, message, or booty amount, savvy",invoice_waiting:"Invoice waiting to be plundered, arrr",payment_received:"Payment Received like a treasure, argh",payment_sent:"Payment Sent, hoist the colors! We´ve got some doubloons!",receive:"booty",send:"hoist",outgoing_payment_pending:"Outgoing payment pending in the port, ye scurvy dog",drain_funds:"Plunder all the doubloons, ye buccaneer",drain_funds_desc:"This be an LNURL-withdraw QR code for slurpin everything from this wallet. Don`t share with anyone. It be compatible with balanceCheck and balanceNotify so yer wallet may keep pullin` the funds continuously from here after the first withdraw.",i_understand:"I understand, yo ho ho and a bottle of rum!",copy_wallet_url:"Copy wallet URL like a map, savvy",disclaimer_dialog_title:"Avast!",disclaimer_dialog:"Login functionality to be released in a future update, for now, make sure ye bookmark this page for future access to your booty! This service be in BETA, and we hold no responsibility for people losing access to doubloons.",no_transactions:"No transactions made yet, me hearties. Belay that!",manage:"Manage, me hearty",exchanges:"Exchanges",extensions:"Yer Extensions, ye scurvy dog",no_extensions:"Ye don't have any extensions installed, ye scallywag :(. Where be yer loot?",created:"Created like a legend, savvy",search_extensions:"Search fer extensions",extension_sources:"Extension Sources",ext_sources_hint:"Repositories from wharrr the extensions can be downloaded",ext_sources_label:"Source URL (only use th' official LNbits extension source, and sources ye can trust)",warning:"Avast",repository:"Repository",confirm_continue:"Be ye sure ye want t' proceed?",manage_extension_details:"Install/uninstall extension",install:"Set sail",uninstall:"Avaast",drop_db:"Scuttle Data",enable:"Enable",pay_to_enable:"Pay To Hoist",enable_extension_details:"Enable extension fer th' current user",disable:"Disablin'",delete:"Blow down",installed:"Installed",activated:"Activated",deactivated:"Deactivated",release_notes:"Release Notes",activate_extension_details:"Make extension available/unavailable fer users",featured:"Featured",all:"Arr",only_admins_can_install:"(Only admin accounts can install extensions)",admin_only:"Cap'n Only",new_version:"New Version",extension_depends_on:"Depends on:",extension_rating_soon:"Ratings a'comin' soon",extension_installed_version:"Installed version",extension_uninstall_warning:"Ye be about t' remove th' extension fer all hands.",uninstall_confirm:"Aye, Uninstall",extension_db_drop_info:"All data fer th' extension will be permanently deleted. There be no way to undo this operation!",extension_db_drop_warning:"Ye be about to scuttle all data fer th' extension. Please scribble th' extension name to continue:",extension_required_lnbits_version:"This release be needin' at least LNbits version",min_version:"Minimum (inclooded)",max_version:"Maximum (excluded)",payment_hash:"Payment Hash like a treasure map, arrr",fee:"Fee like a toll to cross a strait, matey",amount:"Amount of doubloons, arrr",amount_sats:"Amount (sats)",tag:"Tag",unit:"Unit of measurement like a fathom, ye buccaneer",description:"Description like a tale of adventure, arrr",expiry:"Expiry like the food on a ship, ye landlubber",webhook:"Webhook like a fishing line, arrr",payment_proof:"Payment Proof like a seal of authenticity, argh",update:"Updatin'",update_available:"Update {version} available, me matey!",latest_update:"Ye be on th' latest version {version}.",notifications:"Notificashuns",no_notifications:"No noticin's",notifications_disabled:"LNbits status notifications be disabled, arr!",enable_notifications:"Enable Notifications",enable_notifications_desc:"If ye be allowin' it, it'll be fetchin' the latest LNbits Status updates, like security incidents and updates.",enable_watchdog:"Enable Seadog",enable_watchdog_desc:"If enabled, it will swap yer treasure source t' VoidWallet on its own if yer balance be lower than th' LNbits balance. Ye'll need t' enable by hand after an update.",watchdog_interval:"Seadog Interval",watchdog_interval_desc:"How oft th' background task should be checkin' fer a killswitch signal in th' seadog delta [node_balance - lnbits_balance] (in minutes), arr.",watchdog_delta:"Seadog Delta",watchdog_delta_desc:"Limit afore killswitch changes fundin' source to VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notification Source",notification_source_label:"Source URL (only use th' official LNbits status source, and sources ye can trust)",more:"Arr, 'tis more.",less:"Arr, 'tis more fewer.",releases:"Releases",watchdog:"Seadog",server_logs:"Server Logs",ip_blocker:"IP Blockar",security:"Securrrity",security_tools:"Securrrity tools",block_access_hint:"Block access by IP",allow_access_hint:"Grant permission by IP (will override barred IPs)",enter_ip:"Enter IP and hit enter",rate_limiter:"Rate Limiter",wallet_limiter:"Pouch Limitar",wallet_limit_max_withdraw_per_day:"Max daily wallet withdrawal in sats (0 for no limit, -1 to block withdrawal)",wallet_max_ballance:"Purse max heaviness in sats (0 fer scuttle)",wallet_limit_secs_between_trans:"Min secs 'tween transactions per wallet (0 to disable)",number_of_requests:"Number o' requests",time_unit:"time bein'",minute:"minnit",second:"second",hour:"hour",disable_server_log:"Disabl' {Server} Log",enable_server_log:"Enable Server Log",coming_soon:"Feature comin' soon",session_has_expired:"Yer session has expired. Please login again.",instant_access_question:"Be wantin' quick entry, aye?",login_with_user_id:"Login with user ID",or:"arr",create_new_wallet:"Create New Wallet",login_to_account:"Log in to yer account",create_account:"Create account",account_settings:"Account Settin's",signin_with_nostr:"Continue with Nostr",signin_with_google:"Sign in wit' Google",signin_with_github:"Sign in wit' GitHub",signin_with_keycloak:"Sign in wit' Keycloak",username_or_email:"Usarrrname or Email",password:"Passwarrd",password_config:"Passwarrd Config",password_repeat:"Passwarrd repeat",change_password:"Change Passwarrd",update_credentials:"Hoist New Credentials",update_pubkey:"Swab Public Key",set_password:"Set yer Secret Code",invalid_password:"Passwarrd must be havin' at leest 8 charrracters",login:"Log in",register:"Sign on",username:"Username",pubkey:"Public Key",user_id:"User ID",email:"Email",first_name:"Firrrst Name",last_name:"Surname",picture:"pictur'",verify_email:"Verify email with",account:"Arrrccount",update_account:"Updatin' Arrrccount",invalid_username:"Username be not valid, matey!",auth_provider:"Auth Provider becometh Auth Provider, ye see?",my_account:"Me Arrrccount",back:"Return",logout:"Log out yer session",look_and_feel:"Look and Feel",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",language:"Langwidge",color_scheme:"Colour Scheme",admin_settings:"Admin Settin's",extension_cost:"This release be needin' a payment o' minimum {cost} sats, arr.",extension_paid_sats:"Ye have already paid {paid_sats} sats.",release_details_error:"Cannot get th' release details.",pay_from_wallet:"Pay from ye Wallet",wallet_required:"Doubloon Locker *",show_qr:"Show QR",retry_install:"Try 'nstallin' Again",new_payment:"Make New Payment",update_payment:"Be Updatin' Payment",already_paid_question:"Have ye already paid?",sell:"Sell",sell_require:"Ask fer payment to enable extension",sell_info:"The {name} extension requires a payment of minimum {amount} sats to enable.",hide_empty_wallets:"Stow empty wallets",recheck:"Recheck",contributors:"Contributors",license:"License",reset_key:"Reset Key",reset_password:"Reset Password",border_choices:"Border Choices",select_all:"Select All",nfc_supported:"NFC Supported",nfc_not_supported:"NFC not Supported",expire_date:"Expire Date:",hash:"Mizzenmast:",welcome_lnbits:"Welcome t' LNbits",setup_su_account:"Set up the Superuser account below.",create_ticker_converter:"Create Currency Ticker Converter",enable_audit:"Set Sail Fer Auditin'",recommended:"Recommended",audit_desc:"Record HTTP requests accordin' with the specified filters",audit_record_req:"Record Request Body",audit_record_warning:"Arrrning:",audit_record_req_warning_1:"confidential data (like passwords) will be logged.",audit_record_req_warning_2:"th' request body can have large size.",audit_record_use:"Use it with caution.",audit_ip:"Log IP Address",audit_ip_desc:"Record the IP address o' the client",audit_path_params:"Record Path Parameters",audit_query_params:"Rransack th' Query Parameters",audit_http_methods:"Include HTTP Methods",audit_http_methods_hint:"List o' HTTP methods to be included. Empty lists means all.",audit_http_methods_label:"HTTP Methods",audit_resp_codes:"Include HTTP Response Codes",audit_resp_codes_hint:"List o' HTTP codes t' be included (regex match). Empty lists means all. Eg: 4.*, 5.*",audit_resp_codes_label:"HTTP Response code (regex)",audit_paths:"Include Paths",audit_paths_hint:"List o' paths t' be included (regex match). Empty list means all.",audit_paths_label:"HTTP Path (regex)",audit_paths_exclude:"Exclude Paths",audit_paths_exclude_hint:"List o' paths t' be excluded (regex match). Empty list means none.",audit_paths_exclude_label:"HTTP Path (regex)",exchange_providers:"Trade Buccaneers",admin_extensions:"Admin Extensions",admin_extensions_label:"Admin extensions",admin_extensions_hint:"Extensions only user with admin privileges can use",user_default_extensions:"Crew Mate Default Extensions",user_default_extensions_label:"User extensions",user_default_extensions_hint:"Extensions that will be enabled by default fer the users.",miscellanous:"Miscelaneous",misc_disable_extensions:"Belay Extensions",misc_disable_extensions_label:"Disable all extensions",misc_hide_api:"Stow API",misc_hide_api_label:"Burieds wallet api, extensions be able t' choose t' honor",wallets_management:"Wallets Management",funding_source_info:"Loot Source Info",funding_source:"Loot Source: {wallet_class}",node_balance:"Node Balance: {balance} doubloons",lnbits_balance:"LNbits Balance: {balance} pieces o' eight",funding_reserve_percent:"Reserve Percent: {percent} %",node_management:"Node Management",node_management_not_supported:"Node Management not be supported by active funding source",toggle_node_ui:"Node Main Deck",toggle_public_node_ui:"Public Node UI",toggle_transactions_node_ui:"Transactions Tab (Disable on large CLN nodes)",invoice_expiry:"Invoice Expiry",invoice_expiry_label:"Invoice expiry (seconds)",fee_reserve:"Plunder Reserve",fee_reserve_msats:"Reserve fee in msats",fee_reserve_percent:"Reserve fee in percent",server_management:"Server Management",base_url:"Base URL",base_url_label:"Static/Base url fer the server",authentication:"Authent Mateys!",auth_token_expiry_label:"Token expire minutes",auth_token_expiry_hint:"Time in minutes until th' token expires",auth_allowed_methods_label:"Allowed authorizashun methods",auth_allowed_methods_hint:"Select arrrrthorization methods",auth_nostr_label:"Nostr Request URL",auth_nostr_hint:"Absolute URL that th' clients will use t' login.",auth_google_ci_label:"Google Client ID",auth_google_ci_hint:"Make sure that the authorized redirect URIs contain https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub Client ID",auth_gh_client_id_hint:"Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Keycloak Discovery URL",auth_keycloak_ci_label:"Keycloak Client ID",auth_keycloak_ci_hint:"Make sure thant th' authorization callback URL be set t' https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Client Secret",auth_keycloak_custom_org_label:"Keycloak Custom Organization",auth_keycloak_custom_icon_label:"Keycloak Custom Icon (URL)",auth_oidc_label:"OIDC Discovery URL",auth_oidc_ci_label:"OIDC Client ID",auth_oidc_ci_hint:"Make sure thant th' authorization callback URL be set t' https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC Client Secret",auth_oidc_custom_org_label:"OIDC Custom Organization Name (e.g., Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC Custom Icon (URL)",currency_settings:"Doubloon Settin's",allowed_currencies:"Allo'ed Doubloons",allowed_currencies_hint:"Limit the number of available fiat doubloons",default_account_currency:"Default Account Currency",default_account_currency_hint:"Default dubloon fer accountin'",service_fee_label:"Service fee (%).",service_fee_hint:"Fee charged per tx (%)",service_fee_max_label:"Service fee max (sats)",service_fee_max_hint:"Max service fee to charge in (sats)",fee_wallet:"Fee Wallet",fee_wallet_label:"Tariff wallet (wallet ID)",fee_wallet_hint:"Wallett ID t' send funds t'",disable_fee:"Disable Fee",disable_fee_internal:"Disable Service Fee for Internal Payments",disable_fee_internal_desc:"Disable Service Fee fer Internal Lightning Payments",ui_management:"UI Management",ui_site_title:"Site Title",ui_site_tagline:"Site Tagline",ui_elements_enable:"Set course for the homepage elements!",ui_elements_disable:"Disarm elements on homepage",ui_toggle_elements_tip:"Be rid of homepage elements like 'runs on' etc",ui_site_description:"Site Description",ui_site_description_hint:"Use plain text, Markdown, or raw HTML",ui_default_wallet_name:"Default Wallet Name",lnbits_wallet:"LNbits wallet",denomination:"Denomination",denomination_hint:"The name fer the FakeWallet doubloon",ui_qr_code_logo:"QR Code Logo",ui_qr_code_logo_hint:"URL t' logo image in QR code",ui_custom_badge:"Custom Badge",ui_custom_badge_label:"Custom Badge 'USE WITH CAUTION - LNbits wallet be still in BETA'",ui_custom_badge_color_label:"Custom Bauble Color",themes:"Themes",themes_hint:"Choose themes available for users",custom_logo:"Custom Logo",custom_logo_hint:"URL to logo image",ad_space_title:"Ad Space Title",ad_space_title_label:"Supported by",ad_slots:"Adversment Sprogs",ad_slots_hint:"Ad url an' image filepaths in CSV format, extensions can choose t' honor",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Ads Enabled",ads_disabled:"Ads Keelhauled",user_management:"User Matey-handlin'",admin_users:"Admin Scurvy Dogs",admin_users_hint:"Scallywags with cap'n privileges",admin_users_label:"User ID",allowed_users:"Allowed Users",allowed_users_hint:"Only these scallywags can use LNbits",allowed_users_label:"User ID",allow_creation_user:"Permit creation of new scallywags",allow_creation_user_desc:"Allow creation o' new users on th' index page",components:"Components",long_running_endpoints:"Top 5 Long Runnin' Endpoints",http_request_methods:"HTTP Request Methods",http_response_codes:"HTTP Response Codes",request_details:"Request Details",http_request_details:"HTTP Request Details",block_explorer:"Treasure Map",enable_block_explorer:"Hoist the Treasure Map",block_explorer_desc:"Let scallywags spy on Bitcoin doubloons an' addresses via Electrum.",blockexplorer_public_api:"Open Seas API",blockexplorer_public_api_desc:"Allow any landlubber access to the block explorer API ports.",electrum_server_url:"Electrum Port URL",electrum_server_url_hint:"e.g. ssl://electrum.blockstream.info:50002 or tcp://localhost:50001",blockexplorer_search_label:"Search by TXID or Port",blockexplorer_search_hint:"64-char hex = plunder · anything else = Bitcoin port",recent_blocks:"Recent Plunder",chain_tip:"Tip o' the Anchor Chain",block_height:"Plunder Height",block_fee:"plunder fee",fee_estimates:"Booty Estimates",confirmed_balance:"Confirmed Booty",unconfirmed_balance:"Unconfirmed Booty",transaction_history:"Plunder History",coinbase:"Coinbase",inputs:"Inbound Plunder",outputs:"Outbound Plunder",confirmations:"Confirmations, arr",confirmed:"Confirmed, arr",unconfirmed:"Unconfirmed, arr",history_unavailable:"Plunder history lost at sea (too many transactions, matey!)",address:"Port",block_number:"Block #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Previous Plunder Block",merkle_root:"Merkle Root",version:"Version",bits:"Bits",difficulty:"Difficulty",nonce:"Nonce",txid:"TXID",vsize:"Virtual Size",weight:"Weight",n_block_fee:"{n}-block booty"},window.localisation.pl={confirm:"Tak",server:"Serwer",theme:"Motyw",site_customisation:"Dostosowanie witryny",funding:"Finansowanie",users:"Użytkownicy",audit:"Audyt",apps:"Aplikacje",channels:"Kanały",transactions:"Transakcje",dashboard:"Panel kontrolny",node:"Węzeł",export_users:"Eksportuj użytkowników",no_users:"Nie znaleziono użytkowników",total_capacity:"Całkowita Pojemność",avg_channel_size:"Średni rozmiar kanału",biggest_channel_size:"Największy Rozmiar Kanału",smallest_channel_size:"Najmniejszy Rozmiar Kanału",number_of_channels:"Ilość kanałów",active_channels:"Aktywne kanały",connect_peer:"Połącz z węzłem równorzędnym",connect:"Połącz",open_channel:"Otwarty Kanał",open:"Otwórz",close_channel:"Zamknij kanał",close:"Zamknij",restart:"Restart serwera",save:"Zapisz",save_tooltip:"Zapisz zmiany",credit_debit:"Kredyt / Debet",credit_hint:"Naciśnij Enter aby doładować konto",credit_label:"{denomination} doładowanie",credit_ok:"Pomyślne zaksięgowanie/obciążenie wirtualnych środków ({amount} sats). Płatności zależą od rzeczywistych środków na źródle finansowania.",restart_tooltip:"Zrestartuj serwer aby aktywować zmiany",add_funds_tooltip:"Dodaj środki do portfela.",reset_defaults:"Powrót do ustawień domyślnych",reset_defaults_tooltip:"Wymaż wszystkie ustawienia i ustaw domyślne.",download_backup:"Pobierz kopię zapasową bazy danych",name_your_wallet:"Nazwij swój portfel {name}",paste_invoice_label:"Wklej fakturę, żądanie zapłaty lub kod lnurl *",lnbits_description:"Łatwy i lekki w konfiguracji, LNbits może działać w oparciu o dowolne źródło finansowania w sieci lightning czy nawet inną instancję LNbits! Możesz uruchomić instancję LNbits dla siebie lub dla innych. Każdy portfel ma swoje klucze API i nie ma ograniczeń jeśli chodzi o ilość portfeli. LNbits umożliwia dzielenie środków w celu zarządzania nimi, jest również dobrym narzędziem deweloperskim. Rozszerzenia zwiększają funkcjonalność LNbits co umożliwia eksperymentowanie z nowym technologiami w sieci lightning. Tworzenie rozszerzeń jest proste dlatego zachęcamy innych deweloperów do tworzenia dodatkowych funkcjonalności i wysyłanie do nas PR",export_to_phone:"Eksport kodu QR na telefon",export_to_phone_desc:"Ten kod QR zawiera adres URL Twojego portfela z pełnym dostępem do niego. Możesz go zeskanować na swoim telefonie aby otworzyć na nim ten portfel.",wallet:"Portfel:",wallets:"Portfele",add_wallet:"Dodaj portfel",delete_wallet:"Usuń portfel",delete_wallet_desc:"Ten portfel zostanie usunięty, środków na nim zgromadzonych NIE BĘDZIE MOŻNA ODZYSKAĆ.",rename_wallet:"Zmień nazwę portfela",update_name:"Zaktualizuj nazwę",fiat_tracking:"Śledzenie Fiata",currency:"Waluta",update_currency:"Aktualizuj walutę",press_to_claim:"Naciśnij aby odebrać Bitcoiny",donate:"Podaruj",view_github:"Otwórz GitHub",voidwallet_active:"VoidWallet jest aktywny! Płatności są niemożliwe",use_with_caution:"KORZYSTAJ Z ROZWAGĄ - portfel {name} jest w wersji BETA",service_fee:"Opłata serwisowa: {amount} % za transakcję",service_fee_max:"Opłata serwisowa: {amount} % za transakcję (maks {max} sat)",service_fee_tooltip:"Opłata serwisowa pobierana przez administratora serwera LNbits za każdą wychodzącą transakcję",toggle_darkmode:"Tryb nocny",payment_reactions:"Reakcje na płatność",view_swagger_docs:"Dokumentacja Swagger API",api_docs:"Dokumentacja API",api_keys_api_docs:"Adres URL węzła, klucze API i dokumentacja API",api_keys_warning:"Te klucze należy przechowywać bezpiecznie; ich udostępnienie może grozić utratą środków.",admin_key_warning:"Twój klucz administratora zapewnia pełny dostęp do portfela, w tym możliwość wysyłania płatności. Nigdy go nie udostępniaj, chyba że całkowicie ufasz odbiorcy.",lnbits_version:"Wersja LNbits",runs_on:"Działa na",paste:"Wklej",paste_from_clipboard:"Wklej ze schowka",paste_request:"Wklej żądanie",create_invoice:"Utwórz fakturę",camera_tooltip:"Użyj kamery aby zeskanować fakturę lub kod QR",export_csv:"Eksport do CSV",chart_tooltip:"Wykres",pending:"W toku",copy_invoice:"Skopiuj fakturę",withdraw_from:"Wypłać z",cancel:"Anuluj",scan:"Skanuj",read:"Odczytaj",pay:"Zapłać",memo:"Memo",date:"Data",payment_processing:"Przetwarzam płatność...",not_enough_funds:"Brak wystarczających środków!",search_by_tag_memo_amount:"Szukaj po tagu, memo czy wartości",invoice_waiting:"Faktura oczekuje na zapłatę",payment_received:"Otrzymano płatność",payment_sent:"Wysłano płatność",receive:"odbierać",send:"wysłać",outgoing_payment_pending:"Płatność wychodząca w toku",drain_funds:"Opróżnij środki",drain_funds_desc:"To jest kod QR służący do opróżnienia portfela (LNURL-withdraw). Nie udostępniaj go nikomu. Ten kod jest kompatybilny z funkcjami, które umożliwiają wielokrotne żądania aż do zupełnego opróżnienia portfela.",i_understand:"Rozumiem",copy_wallet_url:"Skopiuj URL portfela",disclaimer_dialog_title:"Ważne!",disclaimer_dialog:"Funkcja logowania zostanie uruchomiona w przyszłości. Póki co upewnij się, że zapisałeś adres URL tej strony aby mieć dostęp do tego portfela. Nie udostępniaj adresu tej strony nikomu, kto nie ma mieć do tego portfela dostępu! Ta usługa działa w wersji BETA, nie odpowiadamy za utratę dostępu do środków przez osoby używające LNbits.",no_transactions:"Brak transakcji",manage:"Zarządzaj",exchanges:"Giełdy",extensions:"Rozszerzenia",no_extensions:"Nie masz zainstalowanych żadnych rozszerzeń :(",created:"Utworzono",search_extensions:"Szukaj rozszerzeń",extension_sources:"Źródła rozszerzeń",ext_sources_hint:"Repozytoria, z których można pobrać rozszerzenia",ext_sources_label:"URL źródłowy (używaj tylko oficjalnego źródła rozszerzenia LNbits oraz źródeł, którym możesz zaufać)",warning:"Ostrzeżenie",repository:"Repozytorium",confirm_continue:"Czy na pewno chcesz kontynuować?",manage_extension_details:"Instaluj/odinstaluj rozszerzenie",install:"Zainstaluj",uninstall:"Odinstaluj",drop_db:"Usuń dane",enable:"Włącz",pay_to_enable:"Zapłać, aby włączyć",enable_extension_details:"Włącz rozszerzenie dla aktualnego użytkownika",disable:"Wyłącz",delete:"Usuń",installed:"Zainstalowano",activated:"Aktywowany",deactivated:"Dezaktywowany",release_notes:"Informacje o wydaniu",activate_extension_details:"Udostępnij/nie udostępniaj rozszerzenia użytkownikom",featured:"Polecane",all:"Wszystko",only_admins_can_install:"Tylko konta administratorów mogą instalować rozszerzenia",admin_only:"Tylko dla administratora",new_version:"Nowa wersja",extension_depends_on:"Zależy od:",extension_rating_soon:"Oceny będą dostępne wkrótce",extension_installed_version:"Zainstalowana wersja",extension_uninstall_warning:"Za chwilę usuniesz rozszerzenie dla wszystkich użytkowników.",uninstall_confirm:"Tak, Odinstaluj",extension_db_drop_info:"Wszystkie dane dla rozszerzenia zostaną trwale usunięte. Nie ma sposobu, aby cofnąć tę operację!",extension_db_drop_warning:"Za chwilę usuniesz wszystkie dane dla rozszerzenia. Proszę wpisz nazwę rozszerzenia, aby kontynuować:",extension_required_lnbits_version:"To wymaga przynajmniej wersji LNbits",min_version:"Minimum (włącznie)",max_version:"Maksymalna (wyłączona)",payment_hash:"Hash Płatności",fee:"Opłata",amount:"Wartość",amount_sats:"Kwota (sats)",tag:"Etykieta",unit:"Jednostka",description:"Opis",expiry:"Wygasa",webhook:"Webhook",payment_proof:"Potwierdzenie płatności",update:"Aktualizuj",update_available:"Aktualizacja {version} dostępna!",latest_update:"Korzystasz z najnowszej wersji {version}.",notifications:"Powiadomienia",no_notifications:"Brak powiadomień",notifications_disabled:"Powiadomienia o statusie LNbits są wyłączone.",enable_notifications:"Włącz powiadomienia",enable_notifications_desc:"Jeśli ta opcja zostanie włączona, będzie pobierać najnowsze informacje o statusie LNbits, takie jak incydenty bezpieczeństwa i aktualizacje.",enable_watchdog:"Włącz Watchdog",enable_watchdog_desc:"Jeśli zostanie włączone, automatycznie zmieni źródło finansowania na VoidWallet, jeśli saldo jest niższe niż saldo LNbits. Po aktualizacji trzeba będzie włączyć ręcznie.",watchdog_interval:"Interwał Watchdog",watchdog_interval_desc:"Jak często zadanie w tle powinno sprawdzać sygnał wyłącznika awaryjnego w delcie strażnika [node_balance - lnbits_balance] (w minutach).",watchdog_delta:"Strażnik Delta",watchdog_delta_desc:"Limit przed aktywacją wyłącznika zmienia źródło finansowania na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stan",notification_source:"Źródło powiadomień",notification_source_label:"Adres URL źródła (używaj tylko oficjalnego źródła statusu LNbits oraz źródeł, którym możesz zaufać)",more:"więcej",less:"mniej",releases:"Wydania",watchdog:"Pies gończy",server_logs:"Dzienniki serwera",ip_blocker:"Blokada IP",security:"Bezpieczeństwo",security_tools:"Narzędzia bezpieczeństwa",block_access_hint:"Zablokuj dostęp przez IP",allow_access_hint:"Zezwól na dostęp przez IP (zignoruje zablokowane adresy IP)",enter_ip:"Wpisz adres IP i naciśnij enter",rate_limiter:"Ogranicznik Częstotliwości",wallet_limiter:"Ogranicznik Portfela",wallet_limit_max_withdraw_per_day:"Maksymalna dzienna wypłata z portfela w satoshi (0 aby wyłączyć)",wallet_max_ballance:"Maksymalny stan portfela w satoshi (0 aby wyłączyć)",wallet_limit_secs_between_trans:"Min sekund pomiędzy transakcjami na portfel (0 aby wyłączyć)",number_of_requests:"Liczba żądań",time_unit:"Jednostka czasu",minute:"minuta",second:"sekunda",hour:"godzina",disable_server_log:"Wyłącz log serwera",enable_server_log:"Włącz dziennik serwera",coming_soon:"Funkcja wkrótce będzie dostępna",session_has_expired:"Twoja sesja wygasła. Proszę zaloguj się ponownie.",instant_access_question:"Chcesz mieć natychmiastowy dostęp?",login_with_user_id:"Zaloguj się za pomocą identyfikatora użytkownika",or:"lub",create_new_wallet:"Utwórz nowy portfel",login_to_account:"Zaloguj się do swojego konta",create_account:"Załóż konto",account_settings:"Ustawienia konta",signin_with_nostr:"Kontynuuj z Nostr",signin_with_google:"Zaloguj się przez Google",signin_with_github:"Zaloguj się przez GitHub",signin_with_keycloak:"Zaloguj się przez Keycloak",username_or_email:"Nazwa użytkownika lub Email",password:"Hasło",password_config:"Konfiguracja Hasła",password_repeat:"Powtórz hasło",change_password:"Zmień hasło",update_credentials:"Aktualizuj dane logowania",update_pubkey:"Zaktualizuj klucz publiczny",set_password:"Ustaw hasło",invalid_password:"Hasło musi zawierać co najmniej 8 znaków",login:"Logowanie",register:"Zarejestruj",username:"Nazwa użytkownika",pubkey:"Klucz publiczny",user_id:"Identyfikator użytkownika",email:"Email",first_name:"Imię",last_name:"Nazwisko",picture:"Zdjęcie",verify_email:"Zweryfikuj email za pomocą",account:"Konto",update_account:"Aktualizuj konto",invalid_username:"Nieprawidłowa nazwa użytkownika",auth_provider:"Dostawca uwierzytelniania",my_account:"Moje Konto",back:"Wstecz",logout:"Wyloguj",look_and_feel:"Wygląd i zachowanie",toggle_gradient:"Przełącz gradient",gradient_background:"Tło gradientowe",language:"Język",color_scheme:"Schemat kolorów",admin_settings:"Ustawienia administratora",extension_cost:"To niniejsze wydanie wymaga zapłaty minimalnej {cost} satów.",extension_paid_sats:"Już zapłaciłeś {paid_sats} satów.",release_details_error:"Nie można uzyskać szczegółów wydania.",pay_from_wallet:"Zapłać z portfela",wallet_required:"Portfel *",show_qr:"Pokaż kod QR",retry_install:"Ponów instalację",new_payment:"Dokonaj nowej płatności",update_payment:"Zaktualizuj płatność",already_paid_question:"Czy już zapłaciłeś?",sell:"Sprzedaj",sell_require:"Poproś o płatność, aby włączyć rozszerzenie",sell_info:"Rozszerzenie {name} wymaga płatności w wysokości minimum {amount} sats, aby je włączyć.",hide_empty_wallets:"Ukryj puste portfele",recheck:"Sprawdź ponownie",contributors:"Współpracownicy",license:"Licencja",reset_key:"Resetuj klucz",reset_password:"Zresetuj hasło",border_choices:"Wybory granicy",select_all:"Zaznacz wszystko",nfc_supported:"Obsługa NFC",nfc_not_supported:"NFC nieobsługiwane",expire_date:"Data wygaśnięcia:",hash:"Hash:",welcome_lnbits:"Witamy w LNbits",setup_su_account:"Skonfiguruj konto Superuser poniżej.",create_ticker_converter:"Stwórz Konwerter Kursu Walutowego",enable_audit:"Włącz Audyt",recommended:"Zalecane",audit_desc:"Rejestruj żądania HTTP zgodnie z określonymi filtrami",audit_record_req:"Zarejestruj treść żądania",audit_record_warning:"Ostrzeżenie:",audit_record_req_warning_1:"dane poufne (takie jak hasła) będą rejestrowane.",audit_record_req_warning_2:"treść żądania może mieć duży rozmiar.",audit_record_use:"Używaj tego ostrożnie.",audit_ip:"Zapisz adres IP",audit_ip_desc:"Zarejestruj adres IP klienta",audit_path_params:"Zarejestruj parametry ścieżki",audit_query_params:"Zarejestruj parametry zapytania",audit_http_methods:"Uwzględnij metody HTTP",audit_http_methods_hint:"Lista metod HTTP do uwzględnienia. Pusta lista oznacza wszystkie.",audit_http_methods_label:"Metody HTTP",audit_resp_codes:"Uwzględnij kody odpowiedzi HTTP",audit_resp_codes_hint:"Lista kodów HTTP do uwzględnienia (dopasowanie do wyrażenia regularnego). Puste listy oznaczają wszystkie. Np: 4.*, 5.*",audit_resp_codes_label:"Kod odpowiedzi HTTP (wyrażenie regularne)",audit_paths:"Ścieżki dołączania",audit_paths_hint:"Lista ścieżek do uwzględnienia (dopasowanie regex). Pusta lista oznacza wszystkie.",audit_paths_label:"Ścieżka HTTP (regex)",audit_paths_exclude:"Wyklucz ścieżki",audit_paths_exclude_hint:"Lista ścieżek do wykluczenia (dopasowanie do wyrażenia regularnego). Pusta lista oznacza brak.",audit_paths_exclude_label:"Ścieżka HTTP (wyrażenie regularne)",exchange_providers:"Dostawcy wymiany",admin_extensions:"Rozszerzenia administracyjne",admin_extensions_label:"Rozszerzenia administracyjne",admin_extensions_hint:"Tylko użytkownik rozszerzeń z uprawnieniami administratora może używać",user_default_extensions:"Domyślne Rozszerzenia Użytkownika",user_default_extensions_label:"Rozszerzenia użytkownika",user_default_extensions_hint:"Rozszerzenia, które będą domyślnie włączone dla użytkowników.",miscellanous:"Różne",misc_disable_extensions:"Wyłącz rozszerzenia",misc_disable_extensions_label:"Wyłącz wszystkie rozszerzenia",misc_hide_api:"Ukryj API",misc_hide_api_label:"Ukrywa interfejs API portfela, rozszerzenia mogą zdecydować się na honorowanie",wallets_management:"Zarządzanie portfelami",funding_source_info:"Informacje o źródle finansowania",funding_source:"Źródło finansowania: {wallet_class}",node_balance:"Saldo węzła: {balance} sats",lnbits_balance:"Saldo LNbits: {balance} sats",funding_reserve_percent:"Rezerwa procentowa: {percent} %",node_management:"Zarządzanie węzłami",node_management_not_supported:"Zarządzanie węzłami nie jest obsługiwane przez aktywne źródło finansowania.",toggle_node_ui:"Interfejs użytkownika węzła",toggle_public_node_ui:"Interfejs węzła publicznego",toggle_transactions_node_ui:"Karta transakcji (wyłącz na dużych węzłach CLN)",invoice_expiry:"Wygaśnięcie faktury",invoice_expiry_label:"Termin wygaśnięcia faktury (sekundy)",fee_reserve:"Rezerwa Opłat",fee_reserve_msats:"Opłata rezerwowa w msats",fee_reserve_percent:"Opłata rezerwacyjna w procentach",server_management:"Zarządzanie serwerem",base_url:"Podstawowy adres URL",base_url_label:"Adres URL statyczny/bazowy dla serwera",authentication:"Uwierzytelnianie",auth_token_expiry_label:"Minuty wygaśnięcia tokenu",auth_token_expiry_hint:"Czas w minutach do wygaśnięcia tokenu",auth_allowed_methods_label:"Dopuszczalne metody autoryzacji",auth_allowed_methods_hint:"Wybierz metody autoryzacji",auth_nostr_label:"Żądanie URL Nostr",auth_nostr_hint:"Absolutny URL, którego klienci będą używać do logowania.",auth_google_ci_label:"Identyfikator klienta Google",auth_google_ci_hint:"Upewnij się, że autoryzowane URI przekierowania zawierają https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Hasło tajne klienta Google",auth_gh_client_id_label:"Identyfikator klienta GitHub",auth_gh_client_id_hint:"Upewnij się, że adres URL wywołania zwrotnego autoryzacji jest ustawiony na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"Adres URL Discovery Keycloak",auth_keycloak_ci_label:"Identyfikator klienta Keycloak",auth_keycloak_ci_hint:"Upewnij się, że URL zwrotu autoryzacji jest ustawiony na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Hasło klienta Keycloak",auth_keycloak_custom_org_label:"Własna organizacja Keycloak",auth_keycloak_custom_icon_label:"Własna ikona Keycloak (URL)",auth_oidc_label:"Adres URL Discovery OIDC",auth_oidc_ci_label:"Identyfikator klienta OIDC",auth_oidc_ci_hint:"Upewnij się, że URL zwrotu autoryzacji jest ustawiony na https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Hasło klienta OIDC",auth_oidc_custom_org_label:"Nazwa własnej organizacji OIDC (np. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Własna ikona OIDC (URL)",currency_settings:"Ustawienia waluty",allowed_currencies:"Dozwolone waluty",allowed_currencies_hint:"Ogranicz liczbę dostępnych walut fiducjarnych",default_account_currency:"Domyślna waluta konta",default_account_currency_hint:"Domyślna waluta dla księgowości",service_fee_label:"Opłata serwisowa (%)",service_fee_hint:"Opłata pobierana za transakcję (%)",service_fee_max_label:"Opłata za usługę max (sats)",service_fee_max_hint:"Maksymalna opłata serwisowa do pobrania w (sats)",fee_wallet:"Portfel opłat",fee_wallet_label:"Portfel opłat (ID portfela)",fee_wallet_hint:"Identyfikator portfela, do którego wysłać środki",disable_fee:"Wyłącz opłatę",disable_fee_internal:"Wyłącz opłatę za usługę dla płatności wewnętrznych",disable_fee_internal_desc:"Wyłącz opłatę serwisową dla wewnętrznych płatności Lightning",ui_management:"Zarządzanie interfejsem użytkownika",ui_site_title:"Tytuł strony",ui_site_tagline:"Podpis strony",ui_elements_enable:"Włącz elementy na stronie głównej",ui_elements_disable:"Wyłącz elementy na stronie głównej",ui_toggle_elements_tip:"Usuń elementy strony głównej takie jak 'runs on' itp.",ui_site_description:"Opis strony",ui_site_description_hint:"Użyj zwykłego tekstu, Markdown lub surowego HTML",ui_default_wallet_name:"Domyślna nazwa portfela",lnbits_wallet:"Portfel LNbits",denomination:"Nominacja",denomination_hint:"Nazwa dla tokena FakeWallet",ui_qr_code_logo:"Logo kodu QR",ui_qr_code_logo_hint:"Adres URL do obrazu logo w kodzie QR",ui_custom_badge:"Niestandardowa odznaka",ui_custom_badge_label:"Znak niestandardowy 'UŻYWAJ OSTROŻNIE - portfel LNbits wciąż jest w WERSJI BETA'",ui_custom_badge_color_label:"Niestandardowy kolor odznaki",themes:"Motywy",themes_hint:"Wybierz motywy dostępne dla użytkowników",custom_logo:"Logo niestandardowe",custom_logo_hint:"URL do obrazu logo",ad_space_title:"Tytuł reklamy",ad_space_title_label:"Wspierane przez",ad_slots:"Sloty reklamowe",ad_slots_hint:"Adres URL i ścieżki plików obrazów w formacie CSV, rozszerzenia mogą zdecydować się na honorowanie",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy włączone",ads_disabled:"Reklamy wyłączone",user_management:"Zarządzanie użytkownikami",admin_users:"Użytkownicy administratorzy",admin_users_hint:"Użytkownicy z uprawnieniami administratora",admin_users_label:"Identyfikator użytkownika",allowed_users:"Dozwoleni użytkownicy",allowed_users_hint:"Tylko ci użytkownicy mogą używać LNbits",allowed_users_label:"Identyfikator użytkownika",allow_creation_user:"Zezwól na tworzenie nowych użytkowników",allow_creation_user_desc:"Zezwól na tworzenie nowych użytkowników na stronie głównej indeksu",components:"Komponenty",long_running_endpoints:"5 najdłużej działających punktów końcowych",http_request_methods:"Metody żądań HTTP",http_response_codes:"Kody Odpowiedzi HTTP",request_details:"Szczegóły żądania",http_request_details:"Szczegóły żądania HTTP",block_explorer:"Przeglądarka bloków",enable_block_explorer:"Włącz przeglądarkę bloków",block_explorer_desc:"Umożliwia użytkownikom przeglądanie transakcji i adresów Bitcoin przez Electrum.",blockexplorer_public_api:"Publiczny dostęp do API",blockexplorer_public_api_desc:"Zezwól na nieuwierzytelniony dostęp do punktów końcowych API przeglądarki bloków.",electrum_server_url:"URL serwera Electrum",electrum_server_url_hint:"np. ssl://electrum.blockstream.info:50002 lub tcp://localhost:50001",blockexplorer_search_label:"Szukaj po TXID lub adresie",blockexplorer_search_hint:"64-znakowy hex = transakcja · cokolwiek innego = adres Bitcoin",recent_blocks:"Ostatnie bloki",chain_tip:"Wierzchołek łańcucha",block_height:"Wysokość bloku",block_fee:"opłata bloku",fee_estimates:"Szacunki opłat",confirmed_balance:"Potwierdzony saldo",unconfirmed_balance:"Niepotwierdzony saldo",transaction_history:"Historia transakcji",coinbase:"Coinbase",inputs:"Wejścia",outputs:"Wyjścia",confirmations:"Potwierdzenia",confirmed:"Potwierdzone",unconfirmed:"Niepotwierdzone",history_unavailable:"Historia transakcji niedostępna (adres ma zbyt wiele transakcji)",address:"Adres",block_number:"Blok #{height}",block_diff:"trud. {value}",block_hash:"Hash",previous_block:"Poprzedni blok",merkle_root:"Korzeń Merkle",version:"Wersja",bits:"Bity",difficulty:"Trudność",nonce:"Nonce",txid:"TXID",vsize:"Rozmiar wirtualny",weight:"Waga",n_block_fee:"opłata {n} bloków"},window.localisation.fr={confirm:"Oui",server:"Serveur",theme:"Thème",site_customisation:"Personnalisation du site",funding:"Financement",users:"Utilisateurs",audit:"Audit",apps:"Applications",channels:"Canaux",transactions:"Transactions",dashboard:"Tableau de bord",node:"Noeud",export_users:"Exporter les utilisateurs",no_users:"Aucun utilisateur trouvé",total_capacity:"Capacité totale",avg_channel_size:"Taille moyenne du canal",biggest_channel_size:"Taille de canal maximale",smallest_channel_size:"Taille de canal la plus petite",number_of_channels:"Nombre de canaux",active_channels:"Canaux actifs",connect_peer:"Connecter un pair",connect:"Connecter",open_channel:"Ouvrir le canal",open:"Ouvrir",close_channel:"Fermer le canal",close:"Fermer",restart:"Redémarrer le serveur",save:"Enregistrer",save_tooltip:"Enregistrer vos modifications",credit_debit:"Crédit / Débit",credit_hint:"Appuyez sur Entrée pour créditer le compte",credit_label:"{denomination} à créditer",credit_ok:"Succès du crédit/débit des fonds virtuels ({amount} sats). Les paiements dépendent des fonds réels sur la source de financement.",restart_tooltip:"Redémarrez le serveur pour que les changements prennent effet",add_funds_tooltip:"Ajouter des fonds à un portefeuille.",reset_defaults:"Réinitialiser aux valeurs par défaut",reset_defaults_tooltip:"Supprimer tous les paramètres et les réinitialiser aux valeurs par défaut.",download_backup:"Télécharger la sauvegarde de la base de données",name_your_wallet:"Nommez votre portefeuille {name}",paste_invoice_label:"Coller une facture, une demande de paiement ou un code lnurl *",lnbits_description:"Facile à installer et léger, LNbits peut fonctionner sur n'importe quelle source de financement du réseau Lightning et même LNbits lui-même! Vous pouvez exécuter LNbits pour vous-même ou offrir facilement une solution de gardien pour les autres. Chaque portefeuille a ses propres clés API et il n'y a pas de limite au nombre de portefeuilles que vous pouvez créer. La capacité de partitionner les fonds rend LNbits un outil utile pour la gestion de l'argent et comme outil de développement. Les extensions ajoutent une fonctionnalité supplémentaire à LNbits afin que vous puissiez expérimenter une gamme de technologies de pointe sur le réseau Lightning. Nous avons rendu le développement d'extensions aussi simple que possible et, en tant que projet gratuit et open source, nous encourageons les gens à développer et à soumettre les leurs.",export_to_phone:"Exporter vers le téléphone avec un code QR",export_to_phone_desc:"Ce code QR contient l'URL de votre portefeuille avec un accès complet. Vous pouvez le scanner depuis votre téléphone pour ouvrir votre portefeuille depuis là-bas.",wallet:"Portefeuille :",wallets:"Portefeuilles",add_wallet:"Ajouter un nouveau portefeuille",delete_wallet:"Supprimer le portefeuille",delete_wallet_desc:"Ce portefeuille entier sera supprimé et les fonds seront IRRECUPERABLES.",rename_wallet:"Renommer le portefeuille",update_name:"Mettre à jour le nom",fiat_tracking:"Suivi Fiat",currency:"Devise",update_currency:"Mettre à jour la devise",press_to_claim:"Appuyez pour demander du Bitcoin",donate:"Donner",view_github:"Voir sur GitHub",voidwallet_active:"VoidWallet est actif! Paiements désactivés",use_with_caution:"UTILISER AVEC PRUDENCE - Le portefeuille {name} est toujours en version BETA",service_fee:"Frais de service : {amount} % par transaction",service_fee_max:"Frais de service : {amount} % par transaction (max {max} sats)",service_fee_tooltip:"Frais de service facturés par l'administrateur du serveur LNbits pour chaque transaction sortante",toggle_darkmode:"Basculer le mode sombre",payment_reactions:"Réactions de paiement",view_swagger_docs:"Voir les documentation de l'API Swagger de LNbits",api_docs:"Documentation de l'API",api_keys_api_docs:"URL du nœud, clés API et documentation API",api_keys_warning:"Ces clés doivent être conservées en lieu sûr ; les partager pourrait entraîner la perte de fonds.",admin_key_warning:"Votre clé d'administrateur donne un accès complet à votre portefeuille, y compris la possibilité d'envoyer des paiements. Ne la partagez jamais, sauf si vous faites entièrement confiance au destinataire.",lnbits_version:"Version de LNbits",runs_on:"Fonctionne sur",paste:"Coller",paste_from_clipboard:"Coller depuis le presse-papiers",paste_request:"Coller la requête",create_invoice:"Créer une facture",camera_tooltip:"Utiliser la caméra pour scanner une facture / un code QR",export_csv:"Exporter vers CSV",chart_tooltip:"Afficher le graphique",pending:"En attente",copy_invoice:"Copier la facture",withdraw_from:"Retirer de",cancel:"Annuler",scan:"Scanner",read:"Lire",pay:"Payer",memo:"Mémo",date:"Date",payment_processing:"Traitement du paiement...",not_enough_funds:"Fonds insuffisants !",search_by_tag_memo_amount:"Rechercher par tag, mémo, montant",invoice_waiting:"Facture en attente de paiement",payment_received:"Paiement reçu",payment_sent:"Paiement envoyé",receive:"recevoir",send:"envoyer",outgoing_payment_pending:"Paiement sortant en attente",drain_funds:"Vider les fonds",drain_funds_desc:"Il s'agit d'un code QR LNURL-withdraw pour tout aspirer de ce portefeuille. Ne le partagez avec personne. Il est compatible avec balanceCheck et balanceNotify, de sorte que votre portefeuille peut continuer à retirer les fonds continuellement à partir d'ici après le premier retrait.",i_understand:"J'ai compris",copy_wallet_url:"Copier l'URL du portefeuille",disclaimer_dialog_title:"Important !",disclaimer_dialog:"La fonctionnalité de connexion sera publiée dans une future mise à jour, pour l'instant, assurez-vous de mettre cette page en favori pour accéder à votre portefeuille ultérieurement ! Ce service est en BETA, et nous ne sommes pas responsables des personnes qui perdent l'accès à leurs fonds.",no_transactions:"Aucune transaction effectuée pour le moment",manage:"Gérer",exchanges:"Échanges",extensions:"Extensions",no_extensions:"Vous n'avez installé aucune extension :(",created:"Créé",search_extensions:"Rechercher des extensions",extension_sources:"Sources d'extension",ext_sources_hint:"Dépôts à partir desquels les extensions peuvent être téléchargées",ext_sources_label:"URL source (utilisez uniquement la source officielle de l'extension LNbits et des sources fiables)",warning:"Avertissement",repository:"Référentiel",confirm_continue:"Êtes-vous sûr de vouloir continuer ?",manage_extension_details:"Installer/désinstaller l'extension",install:"Installer",uninstall:"Désinstaller",drop_db:"Supprimer les données",enable:"Activer",pay_to_enable:"Payer pour activer",enable_extension_details:"Activer l'extension pour l'utilisateur actuel",disable:"Désactiver",delete:"Supprimer",installed:"Installé",activated:"Activé",deactivated:"Désactivé",release_notes:"Notes de version",activate_extension_details:"Rendre l'extension disponible/indisponible pour les utilisateurs",featured:"Mis en avant",all:"Tout",only_admins_can_install:"Seuls les comptes administrateurs peuvent installer des extensions",admin_only:"Réservé aux administrateurs",new_version:"Nouvelle version",extension_depends_on:"Dépend de :",extension_rating_soon:"Notes des utilisateurs à venir bientôt",extension_installed_version:"Version installée",extension_uninstall_warning:"Vous êtes sur le point de supprimer l'extension pour tous les utilisateurs.",uninstall_confirm:"Oui, Désinstaller",extension_db_drop_info:"Toutes les données pour l'extension seront supprimées de manière permanente. Il n'est pas possible d'annuler cette opération !",extension_db_drop_warning:"Vous êtes sur le point de supprimer toutes les données de l'extension. Veuillez taper le nom de l'extension pour continuer :",extension_required_lnbits_version:"Cette version nécessite au moins LNbits version",min_version:"Minimum (inclus)",max_version:"Maximum (exclu)",payment_hash:"Hash de paiement",fee:"Frais",amount:"Montant",amount_sats:"Montant (sats)",tag:"Étiqueter",unit:"Unité",description:"Description",expiry:"Expiration",webhook:"Webhook",payment_proof:"Preuve de paiement",update:"Mettre à jour",update_available:"Mise à jour {version} disponible !",latest_update:"Vous êtes sur la dernière version {version}.",notifications:"Notifications",no_notifications:"Aucune notification",notifications_disabled:"Les notifications de statut LNbits sont désactivées.",enable_notifications:"Activer les notifications",enable_notifications_desc:"Si activé, il récupérera les dernières mises à jour du statut LNbits, telles que les incidents de sécurité et les mises à jour.",enable_watchdog:"Activer le Watchdog",enable_watchdog_desc:"Si elle est activée, elle changera automatiquement votre source de financement en VoidWallet si votre solde est inférieur au solde LNbits. Vous devrez activer manuellement après une mise à jour.",watchdog_interval:"Intervalle du gardien",watchdog_interval_desc:"À quelle fréquence la tâche en arrière-plan doit-elle vérifier la présence d'un signal d'arrêt d'urgence dans le delta du gardien [node_balance - lnbits_balance] (en minutes).",watchdog_delta:"Chien de garde Delta",watchdog_delta_desc:"Limite avant que l'interrupteur d'arrêt ne change la source de financement pour VoidWallet [lnbits_balance - node_balance > delta]",status:"Statut",notification_source:"Source de notification",notification_source_label:"URL source (utilisez uniquement la source officielle de statut LNbits et des sources de confiance)",more:"plus",less:"moins",releases:"Versions",watchdog:"Chien de garde",server_logs:"Journaux du serveur",ip_blocker:"Bloqueur d'IP",security:"Sécurité",security_tools:"Outils de sécurité",block_access_hint:"Bloquer l'accès par IP",allow_access_hint:"Autoriser l'accès par IP (cela passera outre les IP bloquées)",enter_ip:"Entrez l'adresse IP et appuyez sur Entrée",rate_limiter:"Limiteur de débit",wallet_limiter:"Limiteur de portefeuille",wallet_limit_max_withdraw_per_day:"Retrait quotidien maximum du portefeuille en sats (0 pour désactiver)",wallet_max_ballance:"Solde maximum du portefeuille en sats (0 pour désactiver)",wallet_limit_secs_between_trans:"Minutes et secondes entre les transactions par portefeuille (0 pour désactiver)",number_of_requests:"Nombre de requêtes",time_unit:"Unité de temps",minute:"minute",second:"seconde",hour:"heure",disable_server_log:"Désactiver le journal du serveur",enable_server_log:"Activer le journal du serveur",coming_soon:"Fonctionnalité à venir bientôt",session_has_expired:"Votre session a expiré. Veuillez vous reconnecter.",instant_access_question:"Voulez-vous un accès instantané ?",login_with_user_id:"Connexion avec l'identifiant utilisateur",or:"ou",create_new_wallet:"Créer un nouveau portefeuille",login_to_account:"Connectez-vous à votre compte",create_account:"Créer un compte",account_settings:"Paramètres du compte",signin_with_nostr:"Continuer avec Nostr",signin_with_google:"Connectez-vous avec Google",signin_with_github:"Connectez-vous avec GitHub",signin_with_keycloak:"Connectez-vous avec Keycloak",username_or_email:"Nom d'utilisateur ou e-mail",password:"Mot de passe",password_config:"Configuration du mot de passe",password_repeat:"Répétition du mot de passe",change_password:"Changer le mot de passe",update_credentials:"Mettre à jour les informations d'identification",update_pubkey:"Mettre à jour la clé publique",set_password:"Définir le mot de passe",invalid_password:"Le mot de passe doit comporter au moins 8 caractères",login:"Connexion",register:"Inscrire",username:"Nom d'utilisateur",pubkey:"Clé publique",user_id:"Identifiant utilisateur",email:"E-mail",first_name:"Prénom",last_name:"Nom de famille",picture:"Image",verify_email:"Vérifiez l'e-mail avec",account:"Compte",update_account:"Mettre à jour le compte",invalid_username:"Nom d'utilisateur invalide",auth_provider:"Fournisseur d'authentification",my_account:"Mon compte",back:"Retour",logout:"Déconnexion",look_and_feel:"Apparence",toggle_gradient:"Basculer le dégradé",gradient_background:"Fond en dégradé",language:"Langue",color_scheme:"Schéma de couleurs",admin_settings:"Paramètres administrateur",extension_cost:"Cette version nécessite un paiement minimum de {cost} sats.",extension_paid_sats:"Vous avez déjà payé {paid_sats} sats.",release_details_error:"Impossible d'obtenir les détails de la version.",pay_from_wallet:"Payer depuis le portefeuille",wallet_required:"Portefeuille *",show_qr:"Afficher le QR",retry_install:"Réessayer l'installation",new_payment:"Effectuer un nouveau paiement",update_payment:"Mettre à jour le paiement",already_paid_question:"Avez-vous déjà payé ?",sell:"Vendre",sell_require:"Demander un paiement pour activer l'extension",sell_info:"L'extension {name} nécessite un paiement minimum de {amount} sats pour être activée.",hide_empty_wallets:"Masquer les portefeuilles vides",recheck:"Revérifier",contributors:"Contributeurs",license:"Licence",reset_key:"Réinitialiser la clé",reset_password:"Réinitialiser le mot de passe",border_choices:"Choix de bordure",select_all:"Sélectionner tout",nfc_supported:"NFC pris en charge",nfc_not_supported:"NFC non pris en charge",expire_date:"Date d'expiration :",hash:"Hash :",welcome_lnbits:"Bienvenue à LNbits",setup_su_account:"Configurez le compte Superuser ci-dessous.",create_ticker_converter:"Créer un convertisseur de code de devise",enable_audit:"Activer l'audit",recommended:"Recommandé",audit_desc:"Enregistrer les requêtes HTTP selon les filtres spécifiés",audit_record_req:"Enregistrer le corps de la demande",audit_record_warning:"Avertissement :",audit_record_req_warning_1:"les données confidentielles (comme les mots de passe) seront enregistrées.",audit_record_req_warning_2:"le corps de la requête peut être de grande taille.",audit_record_use:"Utilisez-le avec précaution.",audit_ip:"Enregistrer l'adresse IP",audit_ip_desc:"Enregistrer l'adresse IP du client",audit_path_params:"Enregistrer les paramètres de chemin",audit_query_params:"Enregistrer les paramètres de la requête",audit_http_methods:"Inclure les méthodes HTTP",audit_http_methods_hint:"Liste des méthodes HTTP à inclure. Listes vides signifie toutes.",audit_http_methods_label:"Méthodes HTTP",audit_resp_codes:"Inclure les codes de réponse HTTP",audit_resp_codes_hint:"Liste des codes HTTP à inclure (correspondance regex). Les listes vides signifient tout. Ex : 4.*, 5.*",audit_resp_codes_label:"Code de réponse HTTP (regex)",audit_paths:"Inclure des chemins",audit_paths_hint:"Liste des chemins à inclure (correspondance regex). Liste vide signifie tout.",audit_paths_label:"Chemin HTTP (regex)",audit_paths_exclude:"Exclure les chemins",audit_paths_exclude_hint:"Liste des chemins à exclure (correspondance regex). Liste vide signifie aucun.",audit_paths_exclude_label:"Chemin HTTP (regex)",exchange_providers:"Fournisseurs d'échange",admin_extensions:"Extensions d'administration",admin_extensions_label:"Extensions d'administration",admin_extensions_hint:"Seuls les utilisateurs avec des privilèges d'administrateur peuvent utiliser les extensions.",user_default_extensions:"Extensions par défaut de l'utilisateur",user_default_extensions_label:"Extensions utilisateur",user_default_extensions_hint:"Extensions qui seront activées par défaut pour les utilisateurs.",miscellanous:"Divers",misc_disable_extensions:"Désactiver les extensions",misc_disable_extensions_label:"Désactiver toutes les extensions",misc_hide_api:"Masquer l'API",misc_hide_api_label:"Masque l'API du portefeuille, les extensions peuvent choisir de respecter",wallets_management:"Gestion des portefeuilles",funding_source_info:"Informations sur la source de financement",funding_source:"Source de financement : {wallet_class}",node_balance:"Solde du nœud : {balance} sats",lnbits_balance:"Solde LNbits : {balance} sats",funding_reserve_percent:"Pourcentage de Réserve : {percent} %",node_management:"Gestion des nœuds",node_management_not_supported:"La gestion des nœuds n'est pas prise en charge par la source de financement active",toggle_node_ui:"Interface utilisateur de nœud",toggle_public_node_ui:"Interface utilisateur du nœud public",toggle_transactions_node_ui:"Onglet des transactions (Désactiver sur les grands nœuds CLN)",invoice_expiry:"Expiration de la facture",invoice_expiry_label:"Expiration de la facture (secondes)",fee_reserve:"Réserve de frais",fee_reserve_msats:"Frais de réservation en msats",fee_reserve_percent:"Frais de réservation en pourcentage",server_management:"Gestion de serveur",base_url:"URL de base",base_url_label:"URL statique/de base pour le serveur",authentication:"Authentification",auth_token_expiry_label:"Durée d'expiration du jeton (en minutes)",auth_token_expiry_hint:"Durée en minutes avant l'expiration du jeton",auth_allowed_methods_label:"Méthodes d'autorisation autorisées",auth_allowed_methods_hint:"Sélectionnez les méthodes d'autorisation",auth_nostr_label:"URL de requête Nostr",auth_nostr_hint:"URL absolue que les clients utiliseront pour se connecter.",auth_google_ci_label:"ID Client Google",auth_google_ci_hint:"Assurez-vous que les URIs de redirection autorisées contiennent https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Secret client Google",auth_gh_client_id_label:"Identifiant client GitHub",auth_gh_client_id_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Secret Client GitHub",auth_keycloak_label:"URL de découverte Keycloak",auth_keycloak_ci_label:"ID Client Keycloak",auth_keycloak_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Secret client Keycloak",auth_keycloak_custom_org_label:"Organisation personnalisée Keycloak",auth_keycloak_custom_icon_label:"Icône personnalisée Keycloak (URL)",auth_oidc_label:"URL de découverte OIDC",auth_oidc_ci_label:"ID Client OIDC",auth_oidc_ci_hint:"Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Secret client OIDC",auth_oidc_custom_org_label:"Nom de l'organisation personnalisée OIDC (par ex. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Icône personnalisée OIDC (URL)",currency_settings:"Paramètres de devise",allowed_currencies:"Devises autorisées",allowed_currencies_hint:"Limiter le nombre de devises fiduciaires disponibles",default_account_currency:"Devise par défaut du compte",default_account_currency_hint:"Devise par défaut pour la comptabilité",service_fee_label:"Frais de service (%)",service_fee_hint:"Frais facturés par tx (%)",service_fee_max_label:"Frais de service max (sats)",service_fee_max_hint:"Frais de service maximum à facturer en (sats)",fee_wallet:"Portefeuille de frais",fee_wallet_label:"Portefeuille de frais (ID de portefeuille)",fee_wallet_hint:"Identifiant de portefeuille pour envoyer des fonds à",disable_fee:"Désactiver les frais",disable_fee_internal:"Désactiver les frais de service pour les paiements internes",disable_fee_internal_desc:"Désactiver les frais de service pour les paiements Lightning internes",ui_management:"Gestion de l'interface utilisateur",ui_site_title:"Titre du site",ui_site_tagline:"Slogan du site",ui_elements_enable:"Activer les éléments sur la page d'accueil",ui_elements_disable:"Désactiver les éléments sur la page d'accueil",ui_toggle_elements_tip:"Supprimer les éléments de la page d'accueil comme 'fonctionne avec', etc.",ui_site_description:"Description du site",ui_site_description_hint:"Utilisez du texte brut, du Markdown ou du HTML brut",ui_default_wallet_name:"Nom par Défaut du Portefeuille",lnbits_wallet:"Portefeuille LNbits",denomination:"Dénomination",denomination_hint:"Le nom du jeton FakeWallet",ui_qr_code_logo:"Logo de code QR",ui_qr_code_logo_hint:"URL de l'image du logo dans le code QR",ui_custom_badge:"Badge personnalisé",ui_custom_badge_label:"Badge personnalisé 'À UTILISER AVEC PRÉCAUTION - Le portefeuille LNbits est encore en BÊTA'",ui_custom_badge_color_label:"Couleur de badge personnalisée",themes:"Thèmes",themes_hint:"Choisissez des thèmes disponibles pour les utilisateurs",custom_logo:"Logo personnalisé",custom_logo_hint:"URL de l'image du logo",ad_space_title:"Titre de l'espace publicitaire",ad_space_title_label:"Soutenu par",ad_slots:"Emplacements publicitaires",ad_slots_hint:"URL de l'annonce et chemins des fichiers image au format CSV, les extensions peuvent choisir de respecter",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Annonces activées",ads_disabled:"Publicités désactivées",user_management:"Gestion des utilisateurs",admin_users:"Utilisateurs administrateurs",admin_users_hint:"Utilisateurs avec des privilèges d'administration",admin_users_label:"Identifiant utilisateur",allowed_users:"Utilisateurs autorisés",allowed_users_hint:"Seuls ces utilisateurs peuvent utiliser LNbits",allowed_users_label:"ID utilisateur",allow_creation_user:"Autoriser la création de nouveaux utilisateurs",allow_creation_user_desc:"Permettre la création de nouveaux utilisateurs sur la page d’index",components:"Composants",long_running_endpoints:"Top 5 points de terminaison longue durée",http_request_methods:"Méthodes de requête HTTP",http_response_codes:"Codes de réponse HTTP",request_details:"Détails de la demande",http_request_details:"Détails de la requête HTTP",block_explorer:"Block Explorer",enable_block_explorer:"Activer le Block Explorer",block_explorer_desc:"Permet aux utilisateurs d'explorer les transactions et adresses Bitcoin via Electrum.",blockexplorer_public_api:"Accès API public",blockexplorer_public_api_desc:"Autoriser l'accès non authentifié aux endpoints de l'API de l'explorateur de blocs.",electrum_server_url:"URL du serveur Electrum",electrum_server_url_hint:"p.ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001",blockexplorer_search_label:"Rechercher par TXID ou adresse",blockexplorer_search_hint:"Hex 64 caractères = transaction · autre chose = adresse Bitcoin",recent_blocks:"Blocs récents",chain_tip:"Sommet de chaîne",block_height:"Hauteur de bloc",block_fee:"frais de bloc",fee_estimates:"Estimations de frais",confirmed_balance:"Solde confirmé",unconfirmed_balance:"Solde non confirmé",transaction_history:"Historique des transactions",coinbase:"Coinbase",inputs:"Entrées",outputs:"Sorties",confirmations:"Confirmations",confirmed:"Confirmé",unconfirmed:"Non confirmé",history_unavailable:"Historique des transactions indisponible (adresse avec trop de transactions)",address:"Adresse",block_number:"Bloc #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Bloc précédent",merkle_root:"Racine de Merkle",version:"Version",bits:"Bits",difficulty:"Difficulté",nonce:"Nonce",txid:"TXID",vsize:"Taille virtuelle",weight:"Poids",n_block_fee:"frais {n} blocs"},window.localisation.nl={confirm:"Ja",server:"Server",theme:"Thema",site_customisation:"Site-aanpassing",funding:"Financiering",users:"Gebruikers",audit:"Controle",apps:"Apps",channels:"Kanalen",transactions:"Transacties",dashboard:"Dashboard",node:"Knooppunt",export_users:"Gebruikers exporteren",no_users:"Geen gebruikers gevonden",total_capacity:"Totale capaciteit",avg_channel_size:"Gem. Kanaalgrootte",biggest_channel_size:"Grootste Kanaalgrootte",smallest_channel_size:"Kleinste Kanaalgrootte",number_of_channels:"Aantal kanalen",active_channels:"Actieve Kanalen",connect_peer:"Peer verbinden",connect:"Verbinden",open_channel:"Open Kanaal",open:"Open",close_channel:"Kanaal Sluiten",close:"Sluiten",restart:"Server opnieuw opstarten",save:"Opslaan",save_tooltip:"Sla uw wijzigingen op",credit_debit:"Credit / Debet",credit_hint:"Druk op Enter om de rekening te crediteren",credit_label:"{denomination} te crediteren",credit_ok:"Succesvol crediteren/debiteren van virtuele gelden ({amount} sats). Betalingen zijn afhankelijk van de werkelijke fondsen op de financieringsbron.",restart_tooltip:"Start de server opnieuw op zodat wijzigingen van kracht worden",add_funds_tooltip:"Voeg geld toe aan een portemonnee.",reset_defaults:"Standaardinstellingen herstellen",reset_defaults_tooltip:"Wis alle instellingen en herstel de standaardinstellingen.",download_backup:"Databaseback-up downloaden",name_your_wallet:"Geef je {name} portemonnee een naam",paste_invoice_label:"Plak een factuur, betalingsverzoek of lnurl-code*",lnbits_description:"Gemakkelijk in te stellen en lichtgewicht, LNbits kan op elke lightning-netwerkfinancieringsbron draaien en zelfs LNbits zelf! U kunt LNbits voor uzelf laten draaien of gemakkelijk een bewaardersoplossing voor anderen bieden. Elke portemonnee heeft zijn eigen API-sleutels en er is geen limiet aan het aantal portemonnees dat u kunt maken. Het kunnen partitioneren van fondsen maakt LNbits een nuttige tool voor geldbeheer en als ontwikkelingstool. Extensies voegen extra functionaliteit toe aan LNbits, zodat u kunt experimenteren met een reeks toonaangevende technologieën op het bliksemschichtnetwerk. We hebben het ontwikkelen van extensies zo eenvoudig mogelijk gemaakt en als een gratis en opensource-project moedigen we mensen aan om hun eigen ontwikkelingen in te dienen.",export_to_phone:"Exporteren naar telefoon met QR-code",export_to_phone_desc:"Deze QR-code bevat uw portemonnee-URL met volledige toegang. U kunt het vanaf uw telefoon scannen om uw portemonnee van daaruit te openen.",wallet:"Wallet:",wallets:"Portemonnees",add_wallet:"Een nieuwe portemonnee toevoegen",delete_wallet:"Portemonnee verwijderen",delete_wallet_desc:"Deze hele portemonnee wordt verwijderd, de fondsen worden NIET TERUGGEVONDEN.",rename_wallet:"Portemonnee hernoemen",update_name:"Naam bijwerken",fiat_tracking:"Volgfunctie voor fiat-valuata",currency:"Valuta",update_currency:"Valuta bijwerken",press_to_claim:"Druk om bitcoin te claimen",donate:"Doneren",view_github:"Bekijken op GitHub",voidwallet_active:"VoidWallet is actief! Betalingen uitgeschakeld",use_with_caution:"GEBRUIK MET VOORZICHTIGHEID - {name} portemonnee is nog in BETA",service_fee:"Servicekosten: {amount} % per transactie",service_fee_max:"Servicekosten: {amount} % per transactie (max {max} sats)",service_fee_tooltip:"Transactiekosten in rekening gebracht door de LNbits serverbeheerder per uitgaande transactie",toggle_darkmode:"Donkere modus aan/uit",payment_reactions:"Betalingsreacties",view_swagger_docs:"Bekijk LNbits Swagger API-documentatie",api_docs:"API-documentatie",api_keys_api_docs:"Node URL, API-sleutels en API-documentatie",api_keys_warning:"Bewaar deze sleutels veilig; het delen ervan kan leiden tot verlies van tegoeden.",admin_key_warning:"Je beheerderssleutel geeft volledige toegang tot je wallet, inclusief de mogelijkheid om betalingen te versturen. Deel deze nooit, tenzij je de ontvanger volledig vertrouwt.",lnbits_version:"LNbits-versie",runs_on:"Draait op",paste:"Plakken",paste_from_clipboard:"Plakken van klembord",paste_request:"Verzoek plakken",create_invoice:"Factuur aanmaken",camera_tooltip:"Gebruik de camera om een factuur/QR-code te scannen",export_csv:"Exporteer naar CSV",chart_tooltip:"Toon grafiek",pending:"In behandeling",copy_invoice:"Kopieer factuur",withdraw_from:"Opnemen van",cancel:"Annuleren",scan:"Scannen",read:"Lezen",pay:"Betalen",memo:"Memo",date:"Datum",payment_processing:"Verwerking betaling...",not_enough_funds:"Onvoldoende saldo!",search_by_tag_memo_amount:"Zoeken op tag, memo, bedrag",invoice_waiting:"Factuur wachtend op betaling",payment_received:"Betaling ontvangen",payment_sent:"Betaling verzonden",receive:"ontvangen",send:"versturen",outgoing_payment_pending:"Uitgaande betaling in behandeling",drain_funds:"Geld opnemen",drain_funds_desc:"Dit is een LNURL-withdraw QR-code om alles uit deze portemonnee te halen. Deel deze code niet met anderen. Het is compatibel met balanceCheck en balanceNotify zodat jouw portemonnee continu geld kan blijven opnemen vanaf hier na de eerste opname.",i_understand:"Ik begrijp het",copy_wallet_url:"Kopieer portemonnee-URL",disclaimer_dialog_title:"Belangrijk!",disclaimer_dialog:"Inlogfunctionaliteit wordt uitgebracht in een toekomstige update. Zorg er nu voor dat je deze pagina als favoriet markeert om in de toekomst toegang te krijgen tot je portemonnee! Deze service is in BETA en we zijn niet verantwoordelijk voor mensen die de toegang tot hun fondsen verliezen.",no_transactions:"Er zijn nog geen transacties gedaan",manage:"Beheer",exchanges:"Beurzen",extensions:"Extensies",no_extensions:"Je hebt geen extensies geïnstalleerd :(",created:"Aangemaakt",search_extensions:"Zoekextensies",extension_sources:"Extensiebronnen",ext_sources_hint:"Repositories van waar de extensies kunnen worden gedownload",ext_sources_label:"Bron-URL (gebruik alleen de officiële LNbits-extensiebron en bronnen die je kunt vertrouwen)",warning:"Waarschuwing",repository:"Repository",confirm_continue:"Weet je zeker dat je wilt doorgaan?",manage_extension_details:"Installeren/verwijderen van extensie",install:"Installeren",uninstall:"Deïnstalleren",drop_db:"Gegevens verwijderen",enable:"Inschakelen",pay_to_enable:"Betalen om te activeren",enable_extension_details:"Schakel extensie in voor huidige gebruiker",disable:"Uitschakelen",delete:"Verwijderen",installed:"Geïnstalleerd",activated:"Geactiveerd",deactivated:"Gedeactiveerd",release_notes:"Release-opmerkingen",activate_extension_details:"Maak extensie beschikbaar/niet beschikbaar voor gebruikers",featured:"Uitgelicht",all:"Alles",only_admins_can_install:"Alleen beheerdersaccounts kunnen extensies installeren",admin_only:"Alleen beheerder",new_version:"Nieuwe Versie",extension_depends_on:"Afhankelijk van:",extension_rating_soon:"Beoordelingen binnenkort beschikbaar",extension_installed_version:"Geïnstalleerde versie",extension_uninstall_warning:"U staat op het punt de extensie voor alle gebruikers te verwijderen.",uninstall_confirm:"Ja, de-installeren",extension_db_drop_info:"Alle gegevens voor de extensie zullen permanent worden verwijderd. Er is geen manier om deze bewerking ongedaan te maken!",extension_db_drop_warning:"U staat op het punt alle gegevens voor de extensie te verwijderen. Typ de naam van de extensie om door te gaan:",extension_required_lnbits_version:"Deze release vereist ten minste LNbits-versie",min_version:"Minimum (inbegrepen)",max_version:"Maximum (uitgesloten)",payment_hash:"Betalings-hash",fee:"Kosten",amount:"Bedrag",amount_sats:"Bedrag (sats)",tag:"Label",unit:"Eenheid",description:"Beschrijving",expiry:"Vervaldatum",webhook:"Webhook",payment_proof:"Betalingsbewijs",update:"Bijwerken",update_available:"Update {version} beschikbaar!",latest_update:"U bent op de nieuwste versie {version}.",notifications:"Meldingen",no_notifications:"Geen meldingen",notifications_disabled:"LNbits-statusmeldingen zijn uitgeschakeld.",enable_notifications:"Schakel meldingen in",enable_notifications_desc:"Indien ingeschakeld zal het de laatste LNbits Status updates ophalen, zoals veiligheidsincidenten en updates.",enable_watchdog:"Inschakelen Watchdog",enable_watchdog_desc:"Indien ingeschakeld, wordt uw betaalbron automatisch gewijzigd naar VoidWallet als uw saldo lager is dan het saldo van LNbits. U zult dit na een update handmatig moeten inschakelen.",watchdog_interval:"Watchdog-interval",watchdog_interval_desc:"Hoe vaak de achtergrondtaak moet controleren op een killswitch signaal in het watchdog verschil [node_balance - lnbits_balance] (in minuten).",watchdog_delta:"Waakhond Delta",watchdog_delta_desc:"Limiet voordat de killswitch de financieringsbron verandert naar VoidWallet [lnbits_balance - node_balance > delta]",status:"Status",notification_source:"Notificatiebron",notification_source_label:"Bron-URL (gebruik alleen de officiële LNbits-statusbron en bronnen die u vertrouwt)",more:"meer",less:"minder",releases:"Uitgaven",watchdog:"Waakhond",server_logs:"Serverlogboeken",ip_blocker:"IP-blokkering",security:"Beveiliging",security_tools:"Beveiligingstools",block_access_hint:"Toegang blokkeren per IP",allow_access_hint:"Toegang verlenen op basis van IP (zal geblokkeerde IP's overschrijven)",enter_ip:"Voer IP in en druk op enter",rate_limiter:"Snelheidsbegrenzer",wallet_limiter:"Portemonnee Limietsteller",wallet_limit_max_withdraw_per_day:"Maximale dagelijkse opname van wallet in sats (0 om uit te schakelen)",wallet_max_ballance:"Maximale portefeuillesaldo in sats (0 om uit te schakelen)",wallet_limit_secs_between_trans:"Min seconden tussen transacties per portemonnee (0 om uit te schakelen)",number_of_requests:"Aantal verzoeken",time_unit:"Tijdeenheid",minute:"minuut",second:"seconde",hour:"uur",disable_server_log:"Serverlog uitschakelen",enable_server_log:"Activeer Serverlog",coming_soon:"Functie binnenkort beschikbaar",session_has_expired:"Uw sessie is verlopen. Log alstublieft opnieuw in.",instant_access_question:"Wil je directe toegang?",login_with_user_id:"Inloggen met gebruikers-ID",or:"of",create_new_wallet:"Nieuwe portemonnee aanmaken",login_to_account:"Log in op je account",create_account:"Account aanmaken",account_settings:"Accountinstellingen",signin_with_nostr:"Doorgaan met Nostr",signin_with_google:"Inloggen met Google",signin_with_github:"Inloggen met GitHub",signin_with_keycloak:"Inloggen met Keycloak",username_or_email:"Gebruikersnaam of e-mail",password:"Wachtwoord",password_config:"Wachtwoordconfiguratie",password_repeat:"Wachtwoord herhalen",change_password:"Wachtwoord wijzigen",update_credentials:"Referenties bijwerken",update_pubkey:"Openbare Sleutel Bijwerken",set_password:"Wachtwoord instellen",invalid_password:"Wachtwoord moet ten minste 8 tekens bevatten",login:"Inloggen",register:"Registreren",username:"Gebruikersnaam",pubkey:"Publieke Sleutel",user_id:"Gebruikers-ID",email:"E-mail",first_name:"Voornaam",last_name:"Achternaam",picture:"Foto",verify_email:"E-mail verifiëren met",account:"Account",update_account:"Account bijwerken",invalid_username:"Ongeldige gebruikersnaam",auth_provider:"Auth Provider",my_account:"Mijn Account",back:"Terug",logout:"Afmelden",look_and_feel:"Uiterlijk en gedrag",toggle_gradient:"Gradiënt Schakelen",gradient_background:"Verloopachtergrond",language:"Taal",color_scheme:"Kleurenschema",admin_settings:"Beheerdersinstellingen",extension_cost:"Deze release vereist een betaling van minimaal {cost} sats.",extension_paid_sats:"U heeft al {paid_sats} sats betaald.",release_details_error:"Kan de gegevens van de release niet ophalen.",pay_from_wallet:"Betalen vanuit Portemonnee",wallet_required:"Wallet *",show_qr:"Toon QR",retry_install:"Opnieuw installeren",new_payment:"Nieuwe betaling maken",update_payment:"Betaling bijwerken",already_paid_question:"Heb je al betaald?",sell:"Verkopen",sell_require:"Vraag betaling om de extensie te activeren.",sell_info:"De {name} extensie vereist een betaling van minimaal {amount} sats om in te schakelen.",hide_empty_wallets:"Verberg lege portemonnees",recheck:"Opnieuw controleren",contributors:"Bijdragers",license:"Licentie",reset_key:"Hersteltoets",reset_password:"Wachtwoord Resetten",border_choices:"Randkeuzes",select_all:"Alles selecteren",nfc_supported:"NFC Ondersteund",nfc_not_supported:"NFC niet ondersteund",expire_date:"Vervaldatum:",hash:"Hash:",welcome_lnbits:"Welkom bij LNbits",setup_su_account:"Stel het Superuser-account hieronder in.",create_ticker_converter:"Maak Valuta Ticker Converter",enable_audit:"Audit inschakelen",recommended:"Aanbevolen",audit_desc:"HTTP-verzoeken vastleggen volgens de opgegeven filters",audit_record_req:"Verzoeklichaam registreren",audit_record_warning:"Waarschuwing:",audit_record_req_warning_1:"vertrouwelijke gegevens (zoals wachtwoorden) worden gelogd.",audit_record_req_warning_2:"de aanvraagbody kan een grote omvang hebben.",audit_record_use:"Gebruik het met voorzichtigheid.",audit_ip:"IP-adres vastleggen",audit_ip_desc:"Leg het IP-adres van de klant vast",audit_path_params:"Parameters van het pad opnemen",audit_query_params:"Queryparameters vastleggen",audit_http_methods:"Inclusief HTTP-methoden",audit_http_methods_hint:"Lijst van HTTP-methoden die moeten worden opgenomen. Lege lijsten betekenen alles.",audit_http_methods_label:"HTTP-methoden",audit_resp_codes:"Inclusief HTTP-responscodes",audit_resp_codes_hint:"Lijst van op te nemen HTTP-codes (regex-overeenkomst). Lege lijst betekent alles. Bijvoorbeeld: 4.*, 5.*",audit_resp_codes_label:"HTTP-responscode (regex)",audit_paths:"Inclusiepad",audit_paths_hint:"Lijst met paden die moeten worden opgenomen (regex match). Lege lijst betekent alles.",audit_paths_label:"HTTP-pad (regex)",audit_paths_exclude:"Paden uitsluiten",audit_paths_exclude_hint:"Lijst met paden die moeten worden uitgesloten (regex-overeenkomst). Een lege lijst betekent geen.",audit_paths_exclude_label:"HTTP-pad (regex)",exchange_providers:"Wisselaanbieders",admin_extensions:"Beheeruitbreidingen",admin_extensions_label:"Beheerdersuitbreidingen",admin_extensions_hint:"Alleen gebruikers met beheerdersrechten kunnen extensies gebruiken.",user_default_extensions:"Standaardextensies voor gebruikers",user_default_extensions_label:"Gebruikersuitbreidingen",user_default_extensions_hint:"Extensies die standaard voor de gebruikers worden ingeschakeld.",miscellanous:"Diversen",misc_disable_extensions:"Extensies uitschakelen",misc_disable_extensions_label:"Alle extensies uitschakelen",misc_hide_api:"API verbergen",misc_hide_api_label:"Verbergt de wallet-API, extensies kunnen ervoor kiezen dit te respecteren",wallets_management:"Beheer van portemonnees",funding_source_info:"Financieringsbroninfo",funding_source:"Financieringsbron: {wallet_class}",node_balance:"Node Balans: {balance} sats",lnbits_balance:"LNbits Saldo: {balance} sats",funding_reserve_percent:"Reservepercentage: {percent} %",node_management:"Nodebeheer",node_management_not_supported:"Nodebeheer wordt niet ondersteund door de actieve financieringsbron",toggle_node_ui:"Node UI",toggle_public_node_ui:"Openbare Node UI",toggle_transactions_node_ui:"Transacties Tabblad (Uitschakelen op grote CLN-nodes)",invoice_expiry:"Factuurvervaldatum",invoice_expiry_label:"Factuurverloop (seconden)",fee_reserve:"Toegangsvergoeding Reserve",fee_reserve_msats:"Reserveringskosten in msats",fee_reserve_percent:"Reserveringskosten in procent",server_management:"Serverbeheer",base_url:"Basis-URL",base_url_label:"Statisch/Basis-URL voor de server",authentication:"Authenticatie",auth_token_expiry_label:"Token vervalt over minuten",auth_token_expiry_hint:"Tijd in minuten totdat de token verloopt",auth_allowed_methods_label:"Toegestane autorisatiemethoden",auth_allowed_methods_hint:"Selecteer autorisatiemethoden",auth_nostr_label:"Nostr Aanvraag-URL",auth_nostr_hint:"Absolute URL die de klanten zullen gebruiken om in te loggen.",auth_google_ci_label:"Google Client-ID",auth_google_ci_hint:"Zorg ervoor dat de geautoriseerde omleidings-URL's https://{domain}/api/v1/auth/google/token bevatten.",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"GitHub client-ID",auth_gh_client_id_hint:"Zorg ervoor dat de autorisatie-callback-URL is ingesteld op https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Clientgeheim",auth_keycloak_label:"Keycloak Ontdekking URL",auth_keycloak_ci_label:"Keycloak-client-ID",auth_keycloak_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak Clientgeheim",auth_keycloak_custom_org_label:"Keycloak Aangepaste Organisatie",auth_keycloak_custom_icon_label:"Keycloak Aangepast Pictogram (URL)",auth_oidc_label:"OIDC Ontdekking URL",auth_oidc_ci_label:"OIDC-client-ID",auth_oidc_ci_hint:"Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC Clientgeheim",auth_oidc_custom_org_label:"OIDC Aangepaste Organisatienaam (bijv. Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC Aangepast Pictogram (URL)",currency_settings:"Valuta-instellingen",allowed_currencies:"Toegestane valuta's",allowed_currencies_hint:"Beperk het aantal beschikbare fiatvaluta's",default_account_currency:"Standaardrekeningvaluta",default_account_currency_hint:"Standaardvaluta voor boekhouding",service_fee_label:"Servicekosten (%)",service_fee_hint:"Toeslag per transactie (%)",service_fee_max_label:"Servicekosten max (sats)",service_fee_max_hint:"Maximale servicekosten om in rekening te brengen in (sats)",fee_wallet:"Kosten Portemonnee",fee_wallet_label:"Kosten portemonnee (wallet ID)",fee_wallet_hint:"Wallet-ID om geld naar over te maken",disable_fee:"Kosten uitschakelen",disable_fee_internal:"Servicekosten uitschakelen voor interne betalingen",disable_fee_internal_desc:"Dienstenkosten uitschakelen voor interne Lightning-betalingen",ui_management:"UI-beheer",ui_site_title:"Site titel",ui_site_tagline:"Site-slogan",ui_elements_enable:"Elementen op de homepage inschakelen",ui_elements_disable:"Elementen op de homepage uitschakelen",ui_toggle_elements_tip:"Verwijder startpagina-elementen zoals 'werkt op' enz.",ui_site_description:"Sitebeschrijving",ui_site_description_hint:"Gebruik platte tekst, Markdown, of ruwe HTML",ui_default_wallet_name:"Standaard Wallet Naam",lnbits_wallet:"LNbits-portemonnee",denomination:"Denominatie",denomination_hint:"De naam voor de FakeWallet token",ui_qr_code_logo:"QR-code-logo",ui_qr_code_logo_hint:"URL naar logo-afbeelding in QR-code",ui_custom_badge:"Aangepaste badge",ui_custom_badge_label:"Aangepaste Badge 'GEBRUIK MET VOORZICHTIGHEID - LNbits-portemonnee is nog in BÈTA'",ui_custom_badge_color_label:"Aangepaste Badge Kleur",themes:"Thema's",themes_hint:"Kies thema's beschikbaar voor gebruikers",custom_logo:"Aangepast logo",custom_logo_hint:"URL naar logo-afbeelding",ad_space_title:"Advertentieruimte Titel",ad_space_title_label:"Ondersteund door",ad_slots:"Advertentieblokken",ad_slots_hint:"Ad URL en afbeeldingspad in CSV-formaat, extensies kunnen ervoor kiezen te honoreren",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Advertenties ingeschakeld",ads_disabled:"Advertenties uitgeschakeld",user_management:"Gebruikersbeheer",admin_users:"Beheerdersgebruikers",admin_users_hint:"Gebruikers met beheerdersrechten",admin_users_label:"Gebruikers-ID",allowed_users:"Toegestane gebruikers",allowed_users_hint:"Alleen deze gebruikers kunnen LNbits gebruiken",allowed_users_label:"Gebruikers-ID",allow_creation_user:"Sta het aanmaken van nieuwe gebruikers toe",allow_creation_user_desc:"Sta de aanmaak van nieuwe gebruikers op de indexpagina toe",components:"Componenten",long_running_endpoints:"Top 5 langlopende eindpunten",http_request_methods:"HTTP-aanvraagmethoden",http_response_codes:"HTTP-responscodes",request_details:"Aanvraagdetails",http_request_details:"HTTP-verzoekdetails",block_explorer:"Block Explorer",enable_block_explorer:"Block Explorer inschakelen",block_explorer_desc:"Laat gebruikers Bitcoin-transacties en -adressen verkennen via Electrum.",blockexplorer_public_api:"Publieke API-toegang",blockexplorer_public_api_desc:"Niet-geauthenticeerde toegang tot de block explorer API-eindpunten toestaan.",electrum_server_url:"Electrum-server-URL",electrum_server_url_hint:"bijv. ssl://electrum.blockstream.info:50002 of tcp://localhost:50001",blockexplorer_search_label:"Zoeken op TXID of adres",blockexplorer_search_hint:"64-karakter hex = transactie · alles anders = Bitcoin-adres",recent_blocks:"Recente blokken",chain_tip:"Kettingtop",block_height:"Blokhoogte",block_fee:"blokvergoeding",fee_estimates:"Vergoedingsschattingen",confirmed_balance:"Bevestigd saldo",unconfirmed_balance:"Onbevestigd saldo",transaction_history:"Transactiegeschiedenis",coinbase:"Coinbase",inputs:"Invoer",outputs:"Uitvoer",confirmations:"Bevestigingen",confirmed:"Bevestigd",unconfirmed:"Onbevestigd",history_unavailable:"Transactiegeschiedenis niet beschikbaar (adres heeft te veel transacties)",address:"Adres",block_number:"Blok #{height}",block_diff:"moeil. {value}",block_hash:"Hash",previous_block:"Vorig blok",merkle_root:"Merkle-wortel",version:"Versie",bits:"Bits",difficulty:"Moeilijkheid",nonce:"Nonce",txid:"TXID",vsize:"Virtuele grootte",weight:"Gewicht",n_block_fee:"{n}-blok vergoeding"},window.localisation.we={confirm:"Ydw",server:"Gweinydd",theme:"Thema",site_customisation:"Addasu Safle",funding:"Arian fyndio",users:"Defnyddwyr",audit:"Archwilio",apps:"Apiau",channels:"Sianelau",transactions:"Trafodion",dashboard:"Panel Gweinyddol",node:"Nod",export_users:"Allfor Defnyddwyr",no_users:"Heb ganfod defnyddwyr",total_capacity:"Capasiti Cyfanswm",avg_channel_size:"Maint Sianel Cyf.",biggest_channel_size:"Maint Sianel Fwyaf",smallest_channel_size:"Maint Sianel Lleiaf",number_of_channels:"Nifer y Sianeli",active_channels:"Sianeli Gweithredol",connect_peer:"Cysylltu â Chymar",connect:"Cysylltu",open_channel:"Sianel Agored",open:"Agor",close_channel:"Cau Sianel",close:"cau",restart:"Ailgychwyn gweinydd",save:"Save",save_tooltip:"cadw eich newidiadau",credit_debit:"Credyd / Debyd",credit_hint:"Pwyswch Enter i gyfrif credyd",credit_label:"{denomination} i gredyd",credit_ok:"Credydu/dad-debydu llwyddiannus o gronfeydd rhithwir ({amount} sats). Mae taliadau yn dibynnu ar y cronfeydd gwirioneddol sydd ar y ffynhonnell ariannu.",restart_tooltip:"Ailgychwyn y gweinydd er mwyn i newidiadau ddod i rym",add_funds_tooltip:"Ychwanegu arian at waled.",reset_defaults:"Ailosod i`r rhagosodiadau",reset_defaults_tooltip:"Dileu pob gosodiad ac ailosod i`r rhagosodiadau.",download_backup:"Lawrlwytho copi wrth gefn cronfa ddata",name_your_wallet:"Enwch eich waled {name}",paste_invoice_label:"Gludwch anfoneb, cais am daliad neu god lnurl *",lnbits_description:"Yn hawdd iw sefydlu ac yn ysgafn, gall LNbits redeg ar unrhyw ffynhonnell ariannu rhwydwaith mellt a hyd yn oed LNbits ei hun! Gallwch redeg LNbits i chi`ch hun, neu gynnig datrysiad ceidwad i eraill yn hawdd. Mae gan bob waled ei allweddi API ei hun ac nid oes cyfyngiad ar nifer y waledi y gallwch eu gwneud. Mae gallu rhannu cronfeydd yn gwneud LNbits yn arf defnyddiol ar gyfer rheoli arian ac fel offeryn datblygu. Mae estyniadau yn ychwanegu ymarferoldeb ychwanegol at LNbits fel y gallwch arbrofi gydag ystod o dechnolegau blaengar ar y rhwydwaith mellt. Rydym wedi gwneud datblygu estyniadau mor hawdd â phosibl, ac fel prosiect ffynhonnell agored am ddim, rydym yn annog pobl i ddatblygu a chyflwyno eu rhai eu hunain.",export_to_phone:"Allforio i Ffôn gyda chod QR",export_to_phone_desc:"Mae`r cod QR hwn yn cynnwys URL eich waled gyda mynediad llawn. Gallwch ei sganio o`ch ffôn i agor eich waled oddi yno.",wallet:"Waled:",wallets:"Waledi",add_wallet:"Ychwanegu waled newydd",delete_wallet:"Dileu waled",delete_wallet_desc:"Bydd y waled gyfan hon yn cael ei dileu, ni fydd modd adennill yr arian.",rename_wallet:"Ailenwi waled",update_name:"Diweddaru enw",fiat_tracking:"Olrhain Fiat",currency:"Arian Cyfred",update_currency:"Diweddaru arian cyfred",press_to_claim:"Pwyswch i hawlio bitcoin",donate:"Rhoi",view_github:"Gweld ar GitHub",voidwallet_active:" Mae VoidWallet yn weithredol! Taliadau wedi`u hanalluogi",use_with_caution:"DEFNYDDIO GYDA GOFAL - mae waled {name} yn dal yn BETA",service_fee:"Ffi gwasanaeth: {amount} % y trafodiad",service_fee_max:"Ffi gwasanaeth: {amount} % y trafodiad (uchafswm {max} sats)",service_fee_tooltip:"Ffi gwasanaeth a godir gan weinyddwr gweinydd LNbits ym mhob trafodiad sy'n mynd allan",toggle_darkmode:"Toglo Modd Tywyll",payment_reactions:"Adweithiau Talu",view_swagger_docs:"Gweld dogfennau API LNbits Swagger",api_docs:"Dogfennau API",api_keys_api_docs:"URL y nod, allweddi API a dogfennau API",api_keys_warning:"Dylid cadw'r allweddi hyn yn ddiogel; gall eu rhannu arwain at golli arian.",admin_key_warning:"Mae eich allwedd weinyddol yn rhoi mynediad llawn i'ch waled, gan gynnwys y gallu i anfon taliadau. Peidiwch byth â'i rhannu oni bai eich bod yn ymddiried yn llwyr yn y derbynnydd.",lnbits_version:"Fersiwn LNbits",runs_on:"Yn rhedeg ymlaen",paste:"Gludo",paste_from_clipboard:"Gludo o'r clipfwrdd",paste_request:"Gludo Cais",create_invoice:"Creu Anfoneb",camera_tooltip:"Defnyddio camera i sganio anfoneb/QR",export_csv:"Allforio i CSV",chart_tooltip:"Dangos siart",pending:"yn yr arfaeth",copy_invoice:"Copi anfoneb",withdraw_from:"Tynnu oddi ar",cancel:"Canslo",scan:"Sgan",read:"Darllen",pay:"Talu",memo:"Memo",date:"Dyddiad",payment_processing:"Prosesu taliad...",not_enough_funds:"Dim digon o arian!",search_by_tag_memo_amount:"Chwilio yn ôl tag, memo, swm",invoice_waiting:"Anfoneb yn aros i gael ei thalu",payment_received:"Taliad a Dderbyniwyd",payment_sent:"Taliad a Anfonwyd",receive:"derbyn",send:"anfon",outgoing_payment_pending:"Taliad sy`n aros yn yr arfaeth",drain_funds:"Cronfeydd Draenio",drain_funds_desc:"Cod QR Tynnu`n ôl LNURL yw hwn ar gyfer slurpio popeth o`r waled hon. Peidiwch â rhannu gyda neb. Mae`n gydnaws â balanceCheck a balanceNotify felly efallai y bydd eich waled yn tynnu`r arian yn barhaus o`r fan hon ar ôl y codiad cyntaf.",i_understand:"Rwy`n deall",copy_wallet_url:"Copi URL waled",disclaimer_dialog_title:"Pwysig!",disclaimer_dialog:"Swyddogaeth mewngofnodi i`w ryddhau mewn diweddariad yn y dyfodol, am y tro, gwnewch yn siŵr eich bod yn rhoi nod tudalen ar y dudalen hon ar gyfer mynediad i`ch waled yn y dyfodol! Mae`r gwasanaeth hwn yn BETA, ac nid ydym yn gyfrifol am bobl sy`n colli mynediad at arian.",no_transactions:"Dim trafodion wedi`u gwneud eto",manage:"Rheoli",exchanges:"Cyfnewidfeydd",extensions:"Estyniadau",no_extensions:"Nid oes gennych unrhyw estyniadau wedi'u gosod :(",created:"Crëwyd",search_extensions:"Chwilio estyniadau",extension_sources:"Ffynonellau Estyniad",ext_sources_hint:"Repoau o ble gellir lawrlwytho'r estyniadau",ext_sources_label:"URL Ffynhonnell (defnyddiwch ffynhonnell estyniad swyddogol LNbits yn unig, a ffynonellau y gallwch ymddiried ynddynt)",warning:"Rhybudd",repository:"Ystorfa",confirm_continue:"Ydych chi'n siŵr eich bod chi eisiau parhau?",manage_extension_details:"Gosod/dadosod estyniad",install:"Gosod",uninstall:"Dadgymhwyso",drop_db:"Dileu Data",enable:"Galluogi",pay_to_enable:"Talu I Alluogi",enable_extension_details:"Galluogi estyniad ar gyfer y defnyddiwr presennol",disable:"Analluogi",delete:"Dileu",installed:"Gosodwyd",activated:"Wedi'i actifadu",deactivated:"Anweithredol",release_notes:"Nodiadau Rhyddhau",activate_extension_details:"Gwneud estyniad ar gael/anar gael i ddefnyddwyr",featured:"Nodweddwyd",all:"Pob",only_admins_can_install:"Dim ond cyfrifon gweinyddwr all osod estyniadau",admin_only:"Dim ond Gweinyddwr",new_version:"Fersiwn Newydd",extension_depends_on:"Dibynnu ar:",extension_rating_soon:"Sgôr yn dod yn fuan",extension_installed_version:"Fersiwn wedi'i gosod",extension_uninstall_warning:"Rydych chi ar fin dileu'r estyniad ar gyfer pob defnyddiwr.",uninstall_confirm:"Ie, Dad-osod",extension_db_drop_info:"Bydd yr holl ddata ar gyfer yr estyniad yn cael ei ddileu'n barhaol. Does dim ffordd o dadwneud y weithrediad hwn!",extension_db_drop_warning:"Rydych chi ar fin dileu'r holl ddata ar gyfer yr estyniad. Teipiwch enw'r estyniad i barhau:",extension_required_lnbits_version:"Mae'r rhyddhau hwn yn gofyn o leiaf am fersiwn LNbits",min_version:"Isafswm (cynnwys)",max_version:"Uchafswm (wedi'i eithrio)",payment_hash:"Hais Taliad",fee:"Fee",amount:"swm",amount_sats:"Swm (sats)",tag:"Tag",unit:"Uned",description:"Disgrifiad",expiry:"dod i ben",webhook:"bachyn we",payment_proof:"prawf taliad",update:"Diweddariad",update_available:"Diweddariad {version} ar gael!",latest_update:"Rydych chi ar y fersiwn diweddaraf {version}.",notifications:"Hysbysiadau",no_notifications:"Dim hysbysiadau",notifications_disabled:"Hysbysiadau statws LNbits wedi'u analluogi.",enable_notifications:"Galluogi Hysbysiadau",enable_notifications_desc:"Os bydd wedi'i alluogi bydd yn nôl y diweddariadau Statws LNbits diweddaraf, fel digwyddiadau diogelwch a diweddariadau.",enable_watchdog:"Galluogi Watchdog",enable_watchdog_desc:"Os bydd yn cael ei alluogi bydd yn newid eich ffynhonnell ariannu i VoidWallet yn awtomatig os bydd eich balans yn is na balans LNbits. Bydd angen i chi alluogi â llaw ar ôl diweddariad.",watchdog_interval:"Amserlennu Gwylio",watchdog_interval_desc:"Pa mor aml y dylai'r dasg gefndir wirio am signal torri yn y gwarchodfa delta [node_balance - lnbits_balance] (mewn munudau).",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Terfyn cyn i'r switshladd newid ffynhonnell ariannu i VoidWallet [lnbits_balance - node_balance > delta]",status:"Statws",notification_source:"Ffynhonnell Hysbysiad",notification_source_label:"URL Ffynhonnell (defnyddiwch yn unig ffynhonnell statws swyddogol LNbits, a ffynonellau y gallwch ymddiried ynddynt)",more:"mwy",less:"llai",releases:"Rhyddhau",watchdog:"Gwyliwr",server_logs:"Logiau Gweinydd",ip_blocker:"Rheolydd IP",security:"Diogelwch",security_tools:"Offer teclynnau diogelwch",block_access_hint:"Atal mynediad gan IP",allow_access_hint:"Caniatáu mynediad gan IP (bydd yn diystyru IPs sydd wedi'u blocio)",enter_ip:"Rhowch IP a gwasgwch enter",rate_limiter:"Cyfyngydd Cyfradd",wallet_limiter:"Cyfyngwr Waled",wallet_limit_max_withdraw_per_day:"Uchafswm tynnu’n ôl waled dyddiol mewn sats (0 i analluogi)",wallet_max_ballance:"Uchafswm balans y waled mewn sats (0 i analluogi)",wallet_limit_secs_between_trans:"Eiliadau lleiaf rhwng trafodion fesul waled (0 i analluogi)",number_of_requests:"Nifer y ceisiadau",time_unit:"Uned amser",minute:"munud",second:"ail",hour:"awr",disable_server_log:"Analluogi Log Gweinydd",enable_server_log:"Galluogi Log Gweinydd",coming_soon:"Nodwedd yn dod yn fuan",session_has_expired:"Mae eich sesiwn wedi dod i ben. Mewngofnodwch eto.",instant_access_question:"Eisiau mynediad ar unwaith?",login_with_user_id:"Mewngofnodi gyda ID y defnyddiwr",or:"neu",create_new_wallet:"Creu Waled Newydd",login_to_account:"Mewngofnodwch i'ch cyfrif",create_account:"Creu cyfrif",account_settings:"Gosodiadau Cyfrif",signin_with_nostr:"Parhewch gyda Nostr",signin_with_google:"Mewngofnodi gyda Google",signin_with_github:"Mewngofnodi gyda GitHub",signin_with_keycloak:"Mewngofnodi gyda Keycloak",username_or_email:"Defnyddiwr neu E-bost",password:"Cyfrinair",password_config:"Ffurfweddiad Cyfrinair",password_repeat:"Ailadrodd cyfrinair",change_password:"Newid Cyfrinair",update_credentials:"Diweddaru Cyfrifoldebau",update_pubkey:"Diweddaru Allwedd Gyhoeddus",set_password:"Gosod Cyfrinair",invalid_password:"Rhaid i'r cyfrinair gynnwys o leiaf 8 nod.",login:"Mewngofnodi",register:"Cofrestru",username:"Enw defnyddiwr",pubkey:"Allwedd Gyhoeddus",user_id:"ID Defnyddiwr",email:"E-bost",first_name:"Enw Cyntaf",last_name:"Cyfenw",picture:"Llun",verify_email:"Gwirio e-bost gyda",account:"Cyfrif",update_account:"Diweddaru Cyfrif",invalid_username:"Enw Defnyddiwr Annilys",auth_provider:"Darparwr Dilysiad",my_account:"Fy Nghyfrif",back:"Yn ôl",logout:"Allgofnodi",look_and_feel:"Edrych a Theimlo",toggle_gradient:"Toglo Graddiênt",gradient_background:"Cefndir Graddiant",language:"Iaith",color_scheme:"Cynllun Lliw",admin_settings:"Gosodiadau Gweinyddol",extension_cost:"Mae'r rhyddhad hwn yn gofyn am daliad o leiaf {cost} sats.",extension_paid_sats:"Rydych chi eisoes wedi talu {paid_sats} sats.",release_details_error:"Methu cael manylion y rhyddhau.",pay_from_wallet:"Talu o'r Waled",wallet_required:"Waled *",show_qr:"Dangos QR",retry_install:"Ailgeisio Gosod",new_payment:"Gwneud Taliad Newydd",update_payment:"Diweddarwch Dalu",already_paid_question:"Ydych chi eisoes wedi talu?",sell:"Gwerthu",sell_require:"Gofynnwch am daliad i alluogi estyniad",sell_info:"Mae angen taliad o leiaf {amount} sats ar yr estyniad {name} i'w alluogi.",hide_empty_wallets:"Cuddio waledau gwag",recheck:"Ailwirio",contributors:"Cyfranwyr",license:"Trwydded",reset_key:"Ailosod Allwedd",reset_password:"Ailosod Cyfrinair",border_choices:"Dewisiadau Ffin",select_all:"Dewis Pob Un",nfc_supported:"Cefnogir NFC",nfc_not_supported:"NFC heb ei Gefnogi",expire_date:"Dyddiad Dod i Ben:",hash:"Hash:",welcome_lnbits:"Croeso i LNbits",setup_su_account:"Sefydlu'r cyfrif Superuser isod.",create_ticker_converter:"Creu Trosi Ticiwr Arian",enable_audit:"Galluogi Archwilio",recommended:"Argymhellir",audit_desc:"Cofnodi ceisiadau HTTP yn ôl y hidlwyr penodedig",audit_record_req:"Cofnodi Corff y Cais",audit_record_warning:"Rhybudd:",audit_record_req_warning_1:"data cyfrinachol (fel cyfrineiriau) yn cael eu logio.",audit_record_req_warning_2:"mae gan y corff cais faint mawr.",audit_record_use:"Defnyddiwch ef gyda gofal.",audit_ip:"Cofnodi Cyfeiriad IP",audit_ip_desc:"Cofnodwch gyfeiriad IP y cleient",audit_path_params:"Cofnod Paramedrau Llwybr",audit_query_params:"Cofnod Paramedrau Holiannau",audit_http_methods:"Cynnwys Dulliau HTTP",audit_http_methods_hint:"Rhestr o ddulliau HTTP i'w cynnwys. Yn golygu pob un yw rhestrau gwag.",audit_http_methods_label:"Dulliau HTTP",audit_resp_codes:"Cynnwys Codau Ymateb HTTP",audit_resp_codes_hint:"Rhestr o godau HTTP i'w cynnwys (cydweddu regex). Mae rhestrau gwag yn golygu popeth. Ee: 4.*, 5.*",audit_resp_codes_label:"Cod Ymateb HTTP (regex)",audit_paths:"Cynnwys Llwybrau",audit_paths_hint:"Rhestr o lwybrau i'w cynnwys (cydweddiad rhegiwlar). Mae rhestr wag yn golygu pob un.",audit_paths_label:"Llwybr HTTP (regex)",audit_paths_exclude:"Eithrio Llwybrau",audit_paths_exclude_hint:"Rhestr o lwybrau i'w heithrio (cydweddu regex). Mae rhestr wag yn golygu dim.",audit_paths_exclude_label:"Llwybr HTTP (regex)",exchange_providers:"Darparwyr Cyfnewid",admin_extensions:"Estyniadau Gweinyddol",admin_extensions_label:"Estyniadau gweinyddu",admin_extensions_hint:"Dim ond defnyddiwr Estyniadau gyda braint gweinyddwr sy'n gallu defnyddio",user_default_extensions:"Rhyngwyneb Diofyn Defnyddiwr",user_default_extensions_label:"Estyniadau defnyddiwr",user_default_extensions_hint:"Estyniadau a fydd yn cael eu galluogi yn ddiofyn ar gyfer y defnyddwyr.",miscellanous:"Amrywiol",misc_disable_extensions:"Analluogi Estyniadau",misc_disable_extensions_label:"Analluogi'r holl estynniadau",misc_hide_api:"Cuddio API",misc_hide_api_label:"Yn cuddio api waled, gall estyniadau ddewis anrhydeddu",wallets_management:"Rheoli Waledau",funding_source_info:"Gwybodaeth am Ffynhonnell Ariannu",funding_source:"Ffynhonnell Ariannu: {wallet_class}",node_balance:"Cydbwysedd Nôd: {balance} sats",lnbits_balance:"Cydbwysedd LNbits: {balance} sats",funding_reserve_percent:"Cadw Canran: {percent} %",node_management:"Rheoli Nodau",node_management_not_supported:"Nid yw Rheoli Nodau yn cael ei gefnogi gan ffynhonnell ariannu weithredol",toggle_node_ui:"Node UI",toggle_public_node_ui:"UI Nod Cyhoeddus",toggle_transactions_node_ui:"Tab Trafodion (Analluoga ar nodau CLN mawr)",invoice_expiry:"Dyddiad Dod i Ben yr Anfoneb",invoice_expiry_label:"Darfod anfoneb (eiliadau)",fee_reserve:"Cadw Ffi",fee_reserve_msats:"Ffi cadw yn msats",fee_reserve_percent:"Ffioedd cadw mewn canran",server_management:"Rheoli Gweinyddwr",base_url:"Prif URL",base_url_label:"Url statig/sylfaen ar gyfer y gweinydd",authentication:"Dilysiad",auth_token_expiry_label:"Cofnodi munudau dod i ben",auth_token_expiry_hint:"Amser mewn munudau tan fod y tocyn yn dod i ben",auth_allowed_methods_label:"Dulliau awdurdodi a ganiateir",auth_allowed_methods_hint:"Dewiswch ddulliau awdurdodi",auth_nostr_label:"URL Cais Nostr",auth_nostr_hint:"URL absoliwt y bydd y cleientiaid yn ei ddefnyddio i fewngofnodi.",auth_google_ci_label:"ID Cleient Google",auth_google_ci_hint:"Sicrhewch fod yr URIs adnewyddu awdurdodedig yn cynnwys https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Cwsmer Google Dirgel",auth_gh_client_id_label:"ID Cleient GitHub",auth_gh_client_id_hint:"Gwnewch yn siŵr bod y URL galwad yn ôl awdurdodi wedi'i osod i https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Cudd-wybodaeth Cleient GitHub",auth_keycloak_label:"URL Darganfod Keycloak",auth_keycloak_ci_label:"ID Cleient Keycloak",auth_keycloak_ci_hint:"Gwnewch yn siŵr bod URL adalw awdurdodiad wedi'i osod i https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Cyfrinach Cleient Keycloak",auth_keycloak_custom_org_label:"Sefydliad Wedi'i Addasu Keycloak",auth_keycloak_custom_icon_label:"Eicon Wedi'i Addasu Keycloak (URL)",auth_oidc_label:"URL Darganfod OIDC",auth_oidc_ci_label:"ID Cleient OIDC",auth_oidc_ci_hint:"Gwnewch yn siŵr bod URL adalw awdurdodiad wedi'i osod i https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Cyfrinach Cleient OIDC",auth_oidc_custom_org_label:"Enw Sefydliad Wedi'i Addasu OIDC (e.e. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Eicon Wedi'i Addasu OIDC (URL)",currency_settings:"Gosodiadau Arian Cyfred",allowed_currencies:"Ariannau a Ganiateir",allowed_currencies_hint:"Cyfyngu nifer yr arian cyfred fiat sydd ar gael",default_account_currency:"Arian Cyfred Diofyn y Cyfrif",default_account_currency_hint:"Arian cyfred diofyn ar gyfer cyfrifyddu",service_fee_label:"Ffioedd gwasanaeth (%)",service_fee_hint:"Ffi a godir fesul trx (%)",service_fee_max_label:"Ffioedd gwasanaeth uchaf (sats)",service_fee_max_hint:"Uchafswm ffi gwasanaeth i godi mewn (sats)",fee_wallet:"Waled Ffioedd",fee_wallet_label:"Ffi waled (ID waled)",fee_wallet_hint:"ID Cwlt hon i anfon cronfeydd i",disable_fee:"Analluogi Ffi",disable_fee_internal:"Analluogi Ffi Gwasanaeth ar gyfer Taliadau Mewnol",disable_fee_internal_desc:"Analluogi Ffi Gwasanaeth ar gyfer Taliadau Mellt Mewnol",ui_management:"Rheoli UI",ui_site_title:"Teitl y Safle",ui_site_tagline:"Tagline'r Safle",ui_elements_enable:"Galluogi elfennau ar hafan",ui_elements_disable:"Analluoga elfennau ar y dudalen gartref",ui_toggle_elements_tip:"Tynn elfennau tudalen gartref fel 'yn rhedeg ar' ayyb.",ui_site_description:"Disgrifiad Safle",ui_site_description_hint:"Defnyddiwch destun plaen, Markdown, neu HTML crai",ui_default_wallet_name:"Enw Diofyn y Waled",lnbits_wallet:"Cwdyn LNbits",denomination:"Enwad",denomination_hint:"Enw'r token FakeWallet",ui_qr_code_logo:"Logo Cod QR",ui_qr_code_logo_hint:"URL i ddelwedd logo yn y cod QR",ui_custom_badge:"Bathodyn Personol",ui_custom_badge_label:"Bathodyn Custom 'DEFNYDDIO GYDA RHYBUDD - mae waled LNbits dal mewn BETA'",ui_custom_badge_color_label:"Lliw Bathodyn Personol",themes:"Themâu",themes_hint:"Dewiswch themâu sydd ar gael i ddefnyddwyr",custom_logo:"Logo Personol",custom_logo_hint:"URL i ddelwedd logo",ad_space_title:"Teitl Gofod Hysbysebu",ad_space_title_label:"Cefnogir gan",ad_slots:"Slotiau Hysbysebu",ad_slots_hint:"Ychwanegu url a llwybrau ffeil delwedd yn y fformat CSV, gall estyniadau ddewis i barchu",ad_slots_label:"url;url_delwedd_ysgafn;url_delwedd_tywyll, url...",ads_enabled:"Hysbysebion wedi'u Galluogi",ads_disabled:"Hysbysebion Wedi'u Analluogi",user_management:"Rheoli Defnyddwyr",admin_users:"Defnyddwyr Gweinyddol",admin_users_hint:"Defnyddwyr â breintiau gweinyddol",admin_users_label:"ID Defnyddiwr",allowed_users:"Defnyddwyr a Ganiateir",allowed_users_hint:"Dim ond y defnyddwyr hyn all ddefnyddio LNbits",allowed_users_label:"ID defnyddiwr",allow_creation_user:"Caniatáu creu defnyddwyr newydd",allow_creation_user_desc:"Caniatáu creu defnyddwyr newydd ar y dudalen fynegai",components:"Cydrannau",long_running_endpoints:"5 Pwynt Terfyn Hir-rhediad Uchaf",http_request_methods:"Dulliau Cais HTTP",http_response_codes:"Codau Ymateb HTTP",request_details:"Manylion y Cais",http_request_details:"Manylion Cais HTTP",block_explorer:"Archwiliwr Bloc",enable_block_explorer:"Galluogi'r Archwiliwr Bloc",block_explorer_desc:"Caniatáu i ddefnyddwyr archwilio trafodion a chyfeiriadau Bitcoin drwy Electrum.",blockexplorer_public_api:"Mynediad API Cyhoeddus",blockexplorer_public_api_desc:"Caniatáu mynediad heb ddilysu i bwyntiau terfyn API yr archwiliwr bloc.",electrum_server_url:"URL Gweinydd Electrum",electrum_server_url_hint:"e.e. ssl://electrum.blockstream.info:50002 neu tcp://localhost:50001",blockexplorer_search_label:"Chwilio yn ôl TXID neu Gyfeiriad",blockexplorer_search_hint:"Hex 64 nod = trafodiad · unrhyw beth arall = cyfeiriad Bitcoin",recent_blocks:"Blociau Diweddar",chain_tip:"Blaen y Gadwyn",block_height:"Uchder Bloc",block_fee:"ffi bloc",fee_estimates:"Amcangyfrifon Ffi",confirmed_balance:"Balans Cadarnhawyd",unconfirmed_balance:"Balans Heb ei Gadarnhau",transaction_history:"Hanes Trafodion",coinbase:"Coinbase",inputs:"Mewnbynnau",outputs:"Allbynnau",confirmations:"Cadarnhadau",confirmed:"Cadarnhawyd",unconfirmed:"Heb ei Gadarnhau",history_unavailable:"Hanes trafodion ar goll (mae cyfeiriad â gormod o drafodion)",address:"Cyfeiriad",block_number:"Bloc #{height}",block_diff:"anhawster {value}",block_hash:"Hash",previous_block:"Bloc Blaenorol",merkle_root:"Gwreiddyn Merkle",version:"Fersiwn",bits:"Bits",difficulty:"Anhawster",nonce:"Nonce",txid:"TXID",vsize:"Maint Rhithwir",weight:"Pwysau",n_block_fee:"ffi {n} bloc"},window.localisation.pt={confirm:"Sim",server:"Servidor",theme:"Tema",site_customisation:"Customização do Site",funding:"Financiamento",users:"Usuários",audit:"Auditoria",apps:"Aplicativos",channels:"Canais",transactions:"Transações",dashboard:"Painel de Controle",node:"Nó",export_users:"Exportar Usuários",no_users:"Nenhum usuário encontrado",total_capacity:"Capacidade Total",avg_channel_size:"Tamanho Médio do Canal",biggest_channel_size:"Maior Tamanho do Canal",smallest_channel_size:"Menor Tamanho de Canal",number_of_channels:"Número de Canais",active_channels:"Canais Ativos",connect_peer:"Conectar Par",connect:"Conectar",open_channel:"Canal Aberto",open:"Abrir",close_channel:"Fechar Canal",close:"Fechar",restart:"Reiniciar servidor",save:"Gravar",save_tooltip:"Gravar as alterações",credit_debit:"Crédito / Débito",credit_hint:"Pressione Enter para creditar a conta",credit_label:"{denomination} para creditar",credit_ok:"Sucesso ao creditar/debitar fundos virtuais ({amount} sats). Os pagamentos dependem dos fundos reais na fonte de financiamento.",restart_tooltip:"Reinicie o servidor para que as alterações tenham efeito",add_funds_tooltip:"Adicionar fundos a uma carteira.",reset_defaults:"Redefinir para padrões",reset_defaults_tooltip:"Apagar todas as configurações e redefinir para os padrões.",download_backup:"Fazer backup da base de dados",name_your_wallet:"Nomeie sua carteira {name}",paste_invoice_label:"Cole uma fatura, pedido de pagamento ou código lnurl *",lnbits_description:"Fácil de configurar e leve, o LNbits pode ser executado em qualquer fonte de financiamento da Lightning Network e até mesmo o LNbits em si! Você pode executar o LNbits para si mesmo ou oferecer facilmente uma solução de custódia para outros. Cada carteira tem suas próprias chaves de API e não há limite para o número de carteiras que você pode criar. Ser capaz de particionar fundos torna o LNbits uma ferramenta útil para gerenciamento de dinheiro e como uma ferramenta de desenvolvimento. As extensões adicionam funcionalidades extras ao LNbits para que você possa experimentar uma série de tecnologias de ponta na rede lightning. Nós tornamos o desenvolvimento de extensões o mais fácil possível e, como um projeto gratuito e de código aberto, incentivamos as pessoas a desenvolver e enviar as suas próprias.",export_to_phone:"Exportar para o telefone com código QR",export_to_phone_desc:"Este código QR contém a URL da sua carteira com acesso total. Você pode escaneá-lo do seu telefone para abrir sua carteira a partir dele.",wallet:"Carteira:",wallets:"Carteiras",add_wallet:"Adicionar nova carteira",delete_wallet:"Excluir carteira",delete_wallet_desc:"Toda a carteira será excluída, os fundos serão IRRECUPERÁVEIS.",rename_wallet:"Renomear carteira",update_name:"Atualizar nome",fiat_tracking:"Rastreamento Fiat",currency:"Moeda",update_currency:"Atualizar moeda",press_to_claim:"Pressione para solicitar bitcoin",donate:"Doar",view_github:"Ver no GitHub",voidwallet_active:"VoidWallet está ativo! Pagamentos desabilitados",use_with_caution:"USE COM CAUTELA - a carteira {name} ainda está em BETA",service_fee:"Taxa de serviço: {amount} % por transação",service_fee_max:"Taxa de serviço: {amount} % por transação (máximo de {max} sats)",service_fee_tooltip:"Taxa de serviço cobrada pelo administrador do servidor LNbits por transação de saída",toggle_darkmode:"Alternar modo escuro",payment_reactions:"Reações de Pagamento",view_swagger_docs:"Ver a documentação da API do LNbits Swagger",api_docs:"Documentação da API",api_keys_api_docs:"URL do Nó, chaves de API e documentação de API",api_keys_warning:"Estas chaves devem ser mantidas em segurança; partilhá-las pode resultar na perda de fundos.",admin_key_warning:"A sua chave de administrador concede acesso total à sua carteira, incluindo a capacidade de enviar pagamentos. Nunca a partilhe, a menos que confie plenamente no destinatário.",lnbits_version:"Versão do LNbits",runs_on:"Executa em",paste:"Colar",paste_from_clipboard:"Colar da área de transferência",paste_request:"Colar Pedido",create_invoice:"Criar Fatura",camera_tooltip:"Usar a câmara para escanear uma fatura / QR",export_csv:"Exportar para CSV",chart_tooltip:"Mostrar gráfico",pending:"Pendente",copy_invoice:"Copiar fatura",withdraw_from:"Retirar de",cancel:"Cancelar",scan:"Escanear",read:"Ler",pay:"Pagar",memo:"Memo",date:"Data",payment_processing:"Processando pagamento...",not_enough_funds:"Fundos insuficientes!",search_by_tag_memo_amount:"Pesquisar por tag, memo, quantidade",invoice_waiting:"Fatura aguardando pagamento",payment_received:"Pagamento Recebido",payment_sent:"Pagamento Enviado",receive:"receber",send:"enviar",outgoing_payment_pending:"Pagamento de saída pendente",drain_funds:"Esvasiar carteira",drain_funds_desc:"Este é um código QR de saque LNURL para sacar tudo desta carteira. Não o partilhe com ninguém. É compatível com balanceCheck e balanceNotify para que a sua carteira possa continuar levantando os fundos continuamente daqui após o primeiro saque.",i_understand:"Eu entendo",copy_wallet_url:"Copiar URL da carteira",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"Funcionalidade de login a ser lançada numa atualização futura, por enquanto, certifique-se que marca esta página para acesso futuro à sua carteira! Este serviço está em BETA, e não nos responsabilizamos por pessoas que perderem o acesso aos fundos.",no_transactions:"Ainda não foram feitas transações",manage:"Gerir",exchanges:"Trocas",extensions:"Extensões",no_extensions:"Não há nenhuma extensão instalada :(",created:"Criado",search_extensions:"Pesquisar extensões",extension_sources:"Fontes de Extensão",ext_sources_hint:"Repositórios de onde as extensões podem ser baixadas",ext_sources_label:"URL de origem (use apenas a fonte oficial da extensão LNbits e fontes em que você confia)",warning:"Aviso",repository:"Repositório",confirm_continue:"Tem certeza de que deseja continuar?",manage_extension_details:"Instalar/desinstalar extensão",install:"Instalar",uninstall:"Desinstalar",drop_db:"Remover Dados",enable:"Ativar",pay_to_enable:"Pagar para Ativar",enable_extension_details:"Ativar extensão para o usuário atual",disable:"Desativar",delete:"Excluir",installed:"Instalado",activated:"Ativado",deactivated:"Desativado",release_notes:"Notas de Lançamento",activate_extension_details:"Torne a extensão disponível/indisponível para usuários",featured:"Destacado",all:"Todos",only_admins_can_install:"Apenas contas de administrador podem instalar extensões.",admin_only:"Apenas para administradores",new_version:"Nova Versão",extension_depends_on:"Depende de:",extension_rating_soon:"Avaliações em breve",extension_installed_version:"Versão instalada",extension_uninstall_warning:"Você está prestes a remover a extensão para todos os usuários.",uninstall_confirm:"Sim, Desinstalar",extension_db_drop_info:"Todos os dados da extensão serão permanentemente excluídos. Não há como desfazer essa operação!",extension_db_drop_warning:"Você está prestes a remover todos os dados para a extensão. Por favor, digite o nome da extensão para continuar:",extension_required_lnbits_version:"Esta versão requer pelo menos a versão LNbits",min_version:"Mínimo (incluído)",max_version:"Máximo (excluído)",payment_hash:"Hash de pagamento",fee:"Taxa",amount:"Quantidade",amount_sats:"Quantidade (sats)",tag:"Etiqueta",unit:"Unidade",description:"Descrição",expiry:"Validade",webhook:"Webhook",payment_proof:"Comprovativo de pagamento",update:"Atualizar",update_available:"Atualização {version} disponível!",latest_update:"Você está na última versão {version}.",notifications:"Notificações",no_notifications:"Sem notificações",notifications_disabled:"As notificações de status do LNbits estão desativadas.",enable_notifications:"Ativar Notificações",enable_notifications_desc:"Se ativado, ele buscará as últimas atualizações de status do LNbits, como incidentes de segurança e atualizações.",enable_watchdog:"Ativar Watchdog",enable_watchdog_desc:"Se ativado, mudará automaticamente a sua fonte de financiamento para VoidWallet caso o seu saldo seja inferior ao saldo LNbits. Você precisará ativar manualmente após uma atualização.",watchdog_interval:"Intervalo do Watchdog",watchdog_interval_desc:"Com que frequência a tarefa de fundo deve verificar um sinal de desligamento no delta do watchdog [node_balance - lnbits_balance] (em minutos).",watchdog_delta:"Observador Delta",watchdog_delta_desc:"Limite antes que o killswitch altere a fonte de financiamento para VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fonte de Notificação",notification_source_label:"URL de Origem (use apenas a fonte oficial de status do LNbits e fontes em que confia)",more:"mais",less:"menos",releases:"Lançamentos",watchdog:"Cão de guarda",server_logs:"Registros do Servidor",ip_blocker:"Bloqueador de IP",security:"Segurança",security_tools:"Ferramentas de segurança",block_access_hint:"Bloquear acesso por IP",allow_access_hint:"Permitir acesso por IP (substituirá IPs bloqueados)",enter_ip:"Digite o IP e pressione enter.",rate_limiter:"Limitador de Taxa",wallet_limiter:"Limitador de Carteira",wallet_limit_max_withdraw_per_day:"Limite diário máximo de saque da carteira em sats (0 para desativar)",wallet_max_ballance:"Saldo máximo da carteira em sats (0 para desativar)",wallet_limit_secs_between_trans:"Minutos seg. entre transações por carteira (0 para desativar)",number_of_requests:"Número de solicitações",time_unit:"Unidade de tempo",minute:"minuto",second:"segundo",hour:"hora",disable_server_log:"Desativar Log do Servidor",enable_server_log:"Ativar Log do Servidor",coming_soon:"Funcionalidade em breve",session_has_expired:"Sua sessão expirou. Por favor, faça login novamente.",instant_access_question:"Quer acesso imediato?",login_with_user_id:"Entrar com ID do usuário",or:"ou",create_new_wallet:"Criar Nova Carteira",login_to_account:"Faça login na sua conta",create_account:"Criar conta",account_settings:"Configurações da Conta",signin_with_nostr:"Continue com Nostr",signin_with_google:"Entrar com o Google",signin_with_github:"Entrar com o GitHub",signin_with_keycloak:"Entrar com o Keycloak",username_or_email:"Nome de usuário ou Email",password:"Senha",password_config:"Configuração de Senha",password_repeat:"Repetição de senha",change_password:"Alterar Senha",update_credentials:"Atualizar Credenciais",update_pubkey:"Atualizar Chave Pública",set_password:"Definir Senha",invalid_password:"A senha deve ter pelo menos 8 caracteres",login:"Entrar",register:"Registrar",username:"Nome de usuário",pubkey:"Chave Pública",user_id:"ID do Usuário",email:"E-mail",first_name:"Nome próprio",last_name:"Sobrenome",picture:"Foto",verify_email:"Verifique o e-mail com",account:"Conta",update_account:"Atualizar Conta",invalid_username:"Nome de usuário inválido",auth_provider:"Provedor de Autenticação",my_account:"Minha Conta",back:"Voltar",logout:"Sair",look_and_feel:"Aparência e Sensação",toggle_gradient:"Alternar Gradiente",gradient_background:"Fundo Gradiente",language:"Idioma",color_scheme:"Esquema de Cores",admin_settings:"Configurações de Administração",extension_cost:"Este lançamento requer um pagamento mínimo de {cost} sats.",extension_paid_sats:"Você já pagou {paid_sats} sats.",release_details_error:"Não é possível obter os detalhes da versão.",pay_from_wallet:"Pague da Carteira",wallet_required:"Carteira *",show_qr:"Exibir QR",retry_install:"Reinstalar Tente Novamente",new_payment:"Realizar Novo Pagamento",update_payment:"Atualizar Pagamento",already_paid_question:"Já pagou?",sell:"Vender",sell_require:"Peça pagamento para habilitar a extensão",sell_info:"A extensão {name} requer um pagamento mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar carteiras vazias",recheck:"Rever",contributors:"Colaboradores",license:"Licença",reset_key:"Redefinir Chave",reset_password:"Redefinir Senha",border_choices:"Opções de Borda",select_all:"Selecionar tudo",nfc_supported:"NFC Suportado",nfc_not_supported:"NFC não suportado",expire_date:"Data de Expiração:",hash:"Hash:",welcome_lnbits:"Bem-vindo ao LNbits",setup_su_account:"Configure a conta Superusuário abaixo.",create_ticker_converter:"Criar Conversor de Moeda Ticker",enable_audit:"Ativar Auditoria",recommended:"Recomendado",audit_desc:"Registre solicitações HTTP de acordo com os filtros especificados",audit_record_req:"Registrar Corpo da Solicitação",audit_record_warning:"Aviso:",audit_record_req_warning_1:"dados confidenciais (como senhas) serão registrados.",audit_record_req_warning_2:"o corpo da solicitação pode ter um tamanho grande.",audit_record_use:"Use com cautela.",audit_ip:"Registrar Endereço IP",audit_ip_desc:"Registre o endereço IP do cliente",audit_path_params:"Registrar parâmetros de caminho",audit_query_params:"Registrar Parâmetros de Consulta",audit_http_methods:"Incluir métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a serem incluídos. Listas vazias significam todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Resposta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a serem incluídos (correspondência com expressões regulares). Listas vazias significam todos. Ex: 4.*, 5.*",audit_resp_codes_label:"Código de resposta HTTP (regex)",audit_paths:"Incluir Caminhos",audit_paths_hint:"Lista de caminhos a serem incluídos (correspondência regex). Lista vazia significa todos.",audit_paths_label:"Caminho HTTP (regex)",audit_paths_exclude:"Excluir Caminhos",audit_paths_exclude_hint:"Lista de caminhos a serem excluídos (correspondência com regex). Lista vazia significa nenhum.",audit_paths_exclude_label:"Caminho HTTP (regex)",exchange_providers:"Provedores de Câmbio",admin_extensions:"Extensões do Administrador",admin_extensions_label:"Extensões administrativas",admin_extensions_hint:"Somente usuários com privilégios de administrador podem usar extensões.",user_default_extensions:"Extensões Padrão do Usuário",user_default_extensions_label:"Extensões do usuário",user_default_extensions_hint:"Extensões que serão ativadas por padrão para os usuários.",miscellanous:"Diversos",misc_disable_extensions:"Desativar Extensões",misc_disable_extensions_label:"Desativar todas as extensões",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta a API da carteira, extensões podem optar por honrar",wallets_management:"Gestão de Carteiras",funding_source_info:"Informações da Fonte de Financiamento",funding_source:"Fonte de Financiamento: {wallet_class}",node_balance:"Saldo do Nó: {balance} sats",lnbits_balance:"Saldo do LNbits: {balance} sats",funding_reserve_percent:"Reserve Percentagem: {percent} %",node_management:"Gerenciamento de Nós",node_management_not_supported:"Gerenciamento de nós não suportado pela fonte de financiamento ativa",toggle_node_ui:"Interface do Usuário de Nó",toggle_public_node_ui:"Interface Pública do Nó",toggle_transactions_node_ui:"Aba de Transações (Desativar em nós grandes do CLN)",invoice_expiry:"Validade da Fatura",invoice_expiry_label:"Expiração da fatura (segundos)",fee_reserve:"Reserva de Taxa",fee_reserve_msats:"Taxa de reserva em msats",fee_reserve_percent:"Taxa de reserva em porcentagem",server_management:"Gerenciamento de Servidor",base_url:"URL base",base_url_label:"URL estático/base para o servidor",authentication:"Autenticação",auth_token_expiry_label:"Minutos de expiração do token",auth_token_expiry_hint:"Tempo em minutos até que o token expire",auth_allowed_methods_label:"Métodos de autorização permitidos",auth_allowed_methods_hint:"Selecione os métodos de autorização",auth_nostr_label:"URL de Solicitação Nostr",auth_nostr_hint:"URL absoluta que os clientes usarão para fazer login.",auth_google_ci_label:"ID do Cliente do Google",auth_google_ci_hint:"Certifique-se de que os URIs de redirecionamento autorizados contenham https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Segredo do Cliente do Google",auth_gh_client_id_label:"ID do Cliente do GitHub",auth_gh_client_id_hint:"Certifique-se de que a URL de retorno de chamada de autorização esteja definida como https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Cliente Secreto do GitHub",auth_keycloak_label:"URL de Descoberta do Keycloak",auth_keycloak_ci_label:"ID do Cliente do Keycloak",auth_keycloak_ci_hint:"Certifique-se de que o URL de retorno de chamada de autorização esteja definido como https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Segredo do Cliente do Keycloak",auth_keycloak_custom_org_label:"Organização Personalizada do Keycloak",auth_keycloak_custom_icon_label:"Ícone Personalizado do Keycloak (URL)",auth_oidc_label:"URL de Descoberta do OIDC",auth_oidc_ci_label:"ID do Cliente do OIDC",auth_oidc_ci_hint:"Certifique-se de que o URL de retorno de chamada de autorização esteja definido como https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Segredo do Cliente do OIDC",auth_oidc_custom_org_label:"Nome da Organização Personalizada OIDC (ex. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Ícone Personalizado do OIDC (URL)",currency_settings:"Configurações de Moeda",allowed_currencies:"Moedas Permitidas",allowed_currencies_hint:"Limite o número de moedas fiduciárias disponíveis",default_account_currency:"Moeda Padrão da Conta",default_account_currency_hint:"Moeda padrão para contabilidade",service_fee_label:"Taxa de serviço (%)",service_fee_hint:"Taxa cobrada por transação (%)",service_fee_max_label:"Taxa de serviço máx (sats)",service_fee_max_hint:"Taxa máxima de serviço a cobrar em (sats)",fee_wallet:"Carteira de Taxas",fee_wallet_label:"Carteira de taxa (ID da carteira)",fee_wallet_hint:"ID da carteira para enviar fundos para",disable_fee:"Desativar taxa",disable_fee_internal:"Desativar Taxa de Serviço para Pagamentos Internos",disable_fee_internal_desc:"Desativar Taxa de Serviço para Pagamentos Internos Lightning",ui_management:"Gestão de UI",ui_site_title:"Título do Site",ui_site_tagline:"Tagline do site",ui_elements_enable:"Ativar elementos na página inicial",ui_elements_disable:"Desativar elementos na página inicial",ui_toggle_elements_tip:"Remova elementos da homepage como 'executa em' etc.",ui_site_description:"Descrição do Site",ui_site_description_hint:"Use texto simples, Markdown ou HTML bruto",ui_default_wallet_name:"Nome Padrão da Carteira",lnbits_wallet:"Carteira LNbits",denomination:"Denominação",denomination_hint:"O nome para o token FakeWallet",ui_qr_code_logo:"Logo do Código QR",ui_qr_code_logo_hint:"URL para imagem do logotipo no código QR",ui_custom_badge:"Distintivo Personalizado",ui_custom_badge_label:"Emblema Personalizado 'USE COM CAUTELA - A carteira LNbits ainda está em BETA'",ui_custom_badge_color_label:"Cor Personalizada do Distintivo",themes:"Temas",themes_hint:"Escolha os temas disponíveis para os usuários",custom_logo:"Logotipo Personalizado",custom_logo_hint:"URL para imagem do logotipo",ad_space_title:"Título do Espaço Publicitário",ad_space_title_label:"Suportado por",ad_slots:"Espaços Publicitários",ad_slots_hint:"Adicionar URL e caminhos de arquivo de imagem no formato CSV, extensões podem optar por respeitar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anúncios Ativados",ads_disabled:"Anúncios Desativados",user_management:"Gestão de Usuários",admin_users:"Usuários Administrativos",admin_users_hint:"Usuários com privilégios de administrador",admin_users_label:"ID do Usuário",allowed_users:"Usuários Permitidos",allowed_users_hint:"Somente estes usuários podem usar LNbits",allowed_users_label:"ID do usuário",allow_creation_user:"Permitir a criação de novos usuários",allow_creation_user_desc:"Permitir a criação de novos usuários na página inicial",components:"Componentes",long_running_endpoints:"Principais 5 Endpoints de Longa Execução",http_request_methods:"Métodos de Requisição HTTP",http_response_codes:"Códigos de Resposta HTTP",request_details:"Detalhes da solicitação",http_request_details:"Detalhes da Solicitação HTTP",block_explorer:"Block Explorer",enable_block_explorer:"Ativar Block Explorer",block_explorer_desc:"Permite aos utilizadores explorar transações e endereços Bitcoin via Electrum.",blockexplorer_public_api:"Acesso à API pública",blockexplorer_public_api_desc:"Permitir acesso não autenticado aos endpoints da API do explorador de blocos.",electrum_server_url:"URL do servidor Electrum",electrum_server_url_hint:"ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001",blockexplorer_search_label:"Pesquisar por TXID ou endereço",blockexplorer_search_hint:"Hex de 64 caracteres = transação · qualquer outra coisa = endereço Bitcoin",recent_blocks:"Blocos recentes",chain_tip:"Ponta da cadeia",block_height:"Altura do bloco",block_fee:"taxa de bloco",fee_estimates:"Estimativas de taxa",confirmed_balance:"Saldo confirmado",unconfirmed_balance:"Saldo não confirmado",transaction_history:"Histórico de transações",coinbase:"Coinbase",inputs:"Entradas",outputs:"Saídas",confirmations:"Confirmações",confirmed:"Confirmado",unconfirmed:"Não confirmado",history_unavailable:"Histórico de transações indisponível (endereço tem demasiadas transações)",address:"Endereço",block_number:"Bloco #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Bloco anterior",merkle_root:"Raiz de Merkle",version:"Versão",bits:"Bits",difficulty:"Dificuldade",nonce:"Nonce",txid:"TXID",vsize:"Tamanho virtual",weight:"Peso",n_block_fee:"taxa {n} blocos"},window.localisation.br={confirm:"Sim",server:"Servidor",theme:"Tema",site_customisation:"Customização do Site",funding:"Financiamento",users:"Usuários",audit:"Auditoria",api_watch:"Relógio da API",apps:"Aplicativos",channels:"Canais",transactions:"Transações",dashboard:"Painel de Controle",node:"Nó",export_users:"Exportar Usuários",no_users:"Nenhum usuário encontrado",total_capacity:"Capacidade Total",avg_channel_size:"Tamanho médio do canal",biggest_channel_size:"Maior Tamanho de Canal",smallest_channel_size:"Tamanho Mínimo do Canal",number_of_channels:"Número de Canais",active_channels:"Canais Ativos",connect_peer:"Conectar Par",connect:"Conectar",reconnect:"Reconectar",open_channel:"Canal Aberto",open:"Abrir",clear:"Limpar",close_channel:"Fechar Canal",close:"Fechar",restart:"Reiniciar servidor",image_library:"Biblioteca de Imagens",save:"Salvar",save_tooltip:"Salvar suas alterações",must_save:"Você tem alterações não salvas",credit_debit:"Crédito / Débito",credit_hint:"Pressione Enter para creditar a conta",credit_label:"{denomination} para creditar",credit_ok:"Sucesso ao creditar/debitar fundos virtuais ({amount} sats). Os pagamentos dependem dos fundos reais na fonte de financiamento.",restart_tooltip:"Reinicie o servidor para que as alterações tenham efeito",add_funds_tooltip:"Adicionar fundos a uma carteira.",reset_defaults:"Redefinir para padrões",reset_defaults_tooltip:"Apagar todas as configurações e redefinir para os padrões.",download_backup:"Fazer backup do banco de dados",name_your_wallet:"Nomeie sua carteira {name}",paste_invoice_label:"Cole uma fatura, pedido de pagamento ou código lnurl *",lnbits_description:"Fácil de configurar e leve, o LNbits pode ser executado em qualquer fonte de financiamento da Lightning Network e até mesmo o LNbits em si! Você pode executar o LNbits para si mesmo ou oferecer facilmente uma solução de custódia para outros. Cada carteira tem suas próprias chaves de API e não há limite para o número de carteiras que você pode criar. Ser capaz de particionar fundos torna o LNbits uma ferramenta útil para gerenciamento de dinheiro e como uma ferramenta de desenvolvimento. As extensões adicionam funcionalidades extras ao LNbits para que você possa experimentar uma série de tecnologias de ponta na rede lightning. Nós tornamos o desenvolvimento de extensões o mais fácil possível e, como um projeto gratuito e de código aberto, incentivamos as pessoas a desenvolver e enviar as suas próprias.",export_to_phone:"Exportar para o telefone com código QR",export_to_phone_desc:"Este código QR contém a URL da sua carteira com acesso total. Você pode escaneá-lo do seu telefone para abrir sua carteira a partir dele.",access_wallet_on_mobile:"Acesso Móvel",stored_paylinks:"Links LNURL de pagamento armazenados",wallet:"Carteira:",wallet_name:"Nome da carteira",wallet_type:"Tipo de carteira",shared_wallet:"Carteira Compartilhada",share_wallet:"Compartilhar Carteira",update_permissions:"Atualizar Permissões",shared_wallet_id:"ID da Carteira Compartilhada",shared_wallet_desc:"Você foi convidado(a) para ter acesso à carteira de outra pessoa.",wallets:"Carteiras",exclude_wallets:"Excluir Carteiras",add_wallet:"Adicionar nova carteira",reject_wallet:"Rejeitar carteira",add_new_wallet:"Adicionar uma nova carteira",pin_wallet:"Fixar carteira",delete_wallet:"Excluir carteira",delete_wallet_desc:"Toda a carteira será excluída, os fundos serão IRRECUPERÁVEIS.",rename_wallet:"Renomear carteira",update_name:"Atualizar nome",fiat_tracking:"Rastreamento Fiat",fiat_providers:"Provedores fiat",fiat_warning_bitcoin:'Provedores Fiat podem ficar nervosos com qualquer coisa relacionada ao bitcoin, portanto, evite usar a palavra "bitcoin" nos seus memorandos!',currency:"Moeda",update_currency:"Atualizar moeda",press_to_claim:"Pressione para solicitar bitcoin",claim_desc:"Parece que você tem um valor resgatável de bitcoin, mas ainda não tem uma carteira. Pressione o botão abaixo para reivindicá-lo. Isso criará uma nova carteira para você.",donate:"Doar",view_github:"Ver no GitHub",voidwallet_active:"VoidWallet está ativo! Pagamentos desabilitados",voidwallet_active_user:"Fonte de financiamento indisponível. Por favor, entre em contato com seu administrador para configurar.",voidwallet_active_admin:"Fonte de financiamento indisponível. Clique aqui para configurar.",service_fee_badge:"Taxa de serviço: {amount} % por transação",service_fee_max_badge:"Taxa de serviço: {amount} % por transação (máximo {max} {denom})",service_fee_tooltip:"Taxa de serviço cobrada pelo administrador do servidor LNbits por transação de saída",toggle_darkmode:"Alternar modo escuro",payment_reactions:"Reações de Pagamento",view_swagger_docs:"Ver a documentação da API do LNbits Swagger",api_docs:"Documentação da API",api_keys_api_docs:"URL do Node, chaves da API e documentação da API",api_keys_warning:"Essas chaves devem ser mantidas em segurança; compartilhá-las pode resultar na perda de fundos.",admin_key_warning:"Sua chave de administrador concede acesso total à sua carteira, incluindo a capacidade de enviar pagamentos. Nunca a compartilhe, a menos que confie plenamente no destinatário.",lnbits_version:"Versão do LNbits",runs_on:"Executa em",paste:"Colar",paste_from_clipboard:"Cole do clipboard",paste_request:"Colar Pedido",create_invoice:"Criar Fatura",camera_tooltip:"Usar a câmara para escanear uma fatura / QR",export_csv:"Exportar para CSV",export_csv_details:"Exportar para CSV com detalhes",chart_tooltip:"Mostrar gráfico",pending:"Pendente",copy_invoice:"Copiar fatura",withdraw_from:"Sacar de",cancel:"Cancelar",scan:"Escanear",read:"Ler",write:"Escrever",pay:"Pagar",memo:"Memo",date:"Data",path:"Caminho",internal_memo:"Memorando interno (opcional)",internal_memo_hint_receive:"Este memorando não é mostrado ao pagador, mas é armazenado na fatura para sua referência.",internal_memo_hint_pay:"Este memorando não é exibido ao beneficiário, mas é armazenado no pagamento para sua referência.",payment_processing:"Processando pagamento...",payment_successful:"Pagamento bem-sucedido!",payment_pending:"Pagamento pendente...",payment_check:"Cheque pagamento",not_enough_funds:"Fundos insuficientes!",search_by_tag_memo_amount:"Pesquisar por tag, memo, quantidade",search:"Buscar",invoice_waiting:"Fatura aguardando pagamento",payment_received:"Pagamento Recebido",payment_sent:"Pagamento Enviado",payment_failed:"Pagamento Falhou",receive:"receber",send:"enviar",outgoing_payment_pending:"Pagamento pendente de saída",drain_funds:"Drenar Fundos",drain_funds_desc:"Este é um código QR de retirada do LNURL para sugar tudo desta carteira. Não compartilhe com ninguém. É compatível com balanceCheck e balanceNotify para que sua carteira possa continuar retirando os fundos continuamente daqui após a primeira retirada.",i_understand:"Eu entendo",copy_wallet_url:"Copiar URL da carteira",disclaimer_dialog_title:"Importante!",disclaimer_dialog:"Funcionalidade de login a ser lançada em uma atualização futura, por enquanto, certifique-se de marcar esta página para acesso futuro à sua carteira! Este serviço está em BETA, e não nos responsabilizamos por pessoas que perderem o acesso aos fundos.",no_transactions:"Ainda não foram feitas transações",manage:"Gerenciar",exchanges:"Bolsas de valores",extensions:"Extensões",no_extensions:"Você não possui nenhuma extensão instalada :(",created:"Criado",created_at:"Criado em",updated_at:"Atualizado em",search_extensions:"Extensões de pesquisa",search_wallets:"Pesquisar carteiras",extension_sources:"Fontes de Extensão",ext_sources_hint:"Repositórios de onde as extensões podem ser baixadas",ext_sources_label:"URL de origem (use apenas a fonte oficial da extensão LNbits e fontes confiáveis)",warning:"Aviso",repository:"Repositório",confirm_continue:"Você tem certeza de que deseja continuar?",manage_extension_details:"Instalar/desinstalar extensão",upload:"Enviar",install:"Instalar",uninstall:"Desinstalar",drop_db:"Remover Dados",enable:"Ativar",enabled:"Habilitado",disabled:"Desativado",pay_to_enable:"Pague para Habilitar",enable_extension_details:"Ativar extensão para o usuário atual",disable:"Desativar",delete:"Excluir",installed:"Instalado",activated:"Ativado",deactivated:"Desativado",activate:"Ativar",deactivate:"Desativar",release_notes:"Notas de Lançamento",activate_extension_details:"Tornar a extensão disponível/indisponível para usuários",featured:"Destacado",all:"Tudo",only_admins_can_install:"Apenas contas de administrador podem instalar extensões.",only_admins_can_create_extensions:"Apenas contas de administrador podem criar extensões",admin_only:"Apenas para Administração",make_user_admin:"Tornar usuário administrador",revoke_admin:"Revogar Admin",new_version:"Nova Versão",reviews_url:"URL de Avaliações",reviews_url_label:"URL do servidor de avaliações",reviews_url_hint:"URL completa do PaidReviews incluindo o id das configurações (por exemplo, https://example.com/paidreviews/SETTINGS_ID)",reviews_open:"Ver avaliações",reviews_leave:"Deixe uma avaliação",reviews_name:"Seu nome",reviews_comment:"Sua avaliação",reviews_rating:"Avaliação",reviews_submit:"Enviar avaliação",reviews_loading:"Carregando avaliações...",reviews_refresh:"Atualizar avaliações",reviews_error_load:"Não foi possível carregar as avaliações",reviews_url_not_configured:"URL de avaliações não configurada",reviews_pay_invoice:"Pagar fatura",reviews_invoice_paid:"Fatura paga",reviews_invoice_title:"Pague esta fatura para enviar sua avaliação",reviews_count:"Avaliações",no_reviews:"Ainda não há avaliações",extension_has_free_release:"Tem lançamentos gratuitos",extension_has_paid_release:"Tem lançamentos pagos",extension_depends_on:"Depende de:",extension_rating_soon:"Avaliações estarão disponíveis em breve",extension_installed_version:"Versão instalada",extension_uninstall_warning:"Você está prestes a remover a extensão para todos os usuários.",uninstall_confirm:"Sim, Desinstalar",extension_db_drop_info:"Todos os dados da extensão serão permanentemente excluídos. Não há como desfazer essa operação!",extension_db_drop_warning:"Você está prestes a remover todos os dados para a extensão. Por favor, digite o nome da extensão para continuar:",extension_required_lnbits_version:"Esta versão requer no mínimo a versão do LNbits",min_version:"Mínimo (incluído)",max_version:"Máximo (excluído)",preimage:"Pré-imagem",preimage_hint:"Pré-imagem para liquidar a fatura de retenção",hold_invoice:"Reter Fatura",hold_invoice_description:"Esta fatura está em espera e requer uma pré-imagem para ser liquidada.",payment_hash:"Hash de pagamento",invoice_cancelled:"Fatura Cancelada",invoice_settled:"Fatura Liquidada",hold_invoice_payment_hash:"Hash de pagamento para fatura em espera (opcional)",settle_invoice:"Liquidar Fatura",cancel_invoice:"Cancelar Fatura",fee:"Taxa",amount:"Quantidade",amount_limits:"Limites de Quantia",amount_sats:"Quantidade (sats)",faucest_wallet:"Carteira de Torneira",faucest_wallet_desc_1:"Toda vez que um pagamento for confirmado pelo provedor {provider}, os fundos serão subtraídos desta carteira.",faucest_wallet_desc_2:"Isso ajuda a monitorar todos os pagamentos do {provider} e seu status.",faucest_wallet_desc_3:"Esta carteira deve ser recarregada com a quantia de sats que o administrador está disposto a oferecer em troca da moeda fiduciária.",faucest_wallet_desc_4:"Se esta carteira estiver configurada, mas estiver vazia, os pagamentos de {provider} não serão processados.",faucest_wallet_desc_5:"Esta carteira pode eventualmente ficar com saldo negativo se pagamentos fiduciários paralelos forem feitos.",faucest_wallet_id:"ID da Carteira de Torneira (opcional)",faucest_wallet_id_hint:"ID da carteira a ser usado para a torneira. Será usado para enviar os fundos ao usuário.",tag:"Etiqueta",unit:"Unidade",description:"Descrição",expiry:"Validade",webhook:"Webhook",webhook_url:"URL do Webhook",webhook_url_hint:"URL de Webhook para enviar os detalhes do pagamento. Será chamada quando o pagamento for concluído.",copy_webhook_url:"Copiar URL do webhook",webhook_events_list:"Os seguintes eventos devem ser suportados pelo webhook:",webhook_stripe_description:"No lado do Stripe, você deve configurar um webhook com um URL que aponta para o seu servidor LNbits.",payment_proof:"Comprovante de pagamento",update:"Atualizar",update_available:"Atualização {version} disponível!",funding_sources:"Fontes de Financiamento",latest_update:"Você está na versão mais recente {version}.",notifications:"Notificações",notifications_configure:"Configurar Notificações",notifications_nostr_config:"Configuração do Nostr",notifications_enable_nostr:"Ativar Nostr",notifications_enable_nostr_desc:"Enviar notificações pelo Nostr",notifications_nostr_private_key:"Chave Privada Nostr",notifications_nostr_private_key_desc:"Chave privada (hex ou nsec) para assinar as mensagens enviadas para Nostr",notifications_nostr_identifier:"Identificador Nostr",notifications_nostr_identifier_desc:"Identificador Nip5 para enviar notificações para",notifications_nostr_identifiers:"Identificadores Nostr",notifications_nostr_identifiers_desc:"Lista de identificadores para enviar notificações.",notifications_telegram_config:"Configuração do Telegram",notifications_enable_telegram:"Ativar Telegram",notifications_enable_telegram_desc:"Enviar notificações pelo Telegram",notifications_telegram_access_token:"Token de Acesso",notifications_telegram_access_token_desc:"Token de acesso para o bot",notifications_chat_id:"ID de bate-papo do Telegram",notifications_chat_id_desc:"ID do chat do Telegram para enviar as notificações para",notifications_excluded_wallets_desc:"Não envie notificações para essas carteiras",notifications_email_config:"Configuração de Email",notifications_enable_email:"Habilitar Email",notifications_enable_email_desc:"Enviar notificações por e-mail",notifications_send_test_email:"Enviar e-mail de teste",notifications_send_email:"Enviar e-mail",notifications_send_email_desc:"Email que você enviará de",notifications_send_email_username:"Nome de usuário",notifications_send_email_username_desc:"Nome de usuário, usará o e-mail se não estiver definido",notifications_send_email_password:"Enviar senha de e-mail",notifications_send_email_password_desc:"Senha para o e-mail que você enviará de",notifications_send_email_server_port:"Enviar e-mail porta SMTP",notifications_send_email_server_port_desc:"Porta para o servidor SMTP",notifications_send_email_server:"Enviar e-mail servidor SMTP",notifications_send_email_server_desc:"Servidor SMTP para o e-mail de que você enviará",notifications_send_to_emails:"Emails para enviar para",notifications_send_to_emails_desc:"Notificações de e-mails serão enviadas para",notification_settings_update:"Configurações atualizadas",notification_settings_update_desc:"Notificar quando as configurações do servidor forem atualizadas",notification_server_start_stop:"Iniciar/Parar Servidor",notification_server_start_stop_desc:"Notificar quando o servidor tiver sido iniciado/parado",notification_watchdog_limit:"Notificação de Limite do Watchdog",notification_watchdog_limit_desc:"Notifique quando o limite do watchdog for alcançado (não afeta a fonte de financiamento)",notification_server_status:"Status do Servidor",notification_server_status_desc:"Enviar notificações regulares sobre o status do servidor (valor do intervalo em horas)",notification_incoming_payment:"Pagamentos Recebidos",notification_incoming_payment_desc:"Notificar quando uma carteira tiver recebido um pagamento acima do valor especificado (sats)",notification_outgoing_payment:"Pagamentos Saída",notification_outgoing_payment_desc:"Notificar quando uma carteira tiver enviado um pagamento acima do valor especificado (sats)",notification_credit_debit:"Crédito / Débito",notification_credit_debit_desc:"Notificar quando uma carteira tiver sido creditada/debitada pelo superusuário",notification_balance_delta_changed:"Mudança no Delta de Saldo",notification_balance_delta_changed_desc:"Notifique quando a diferença entre o saldo do nó e o saldo do LNbits tiver mudado mais do que a quantidade especificada (em sats). Defina como 0 para desativar. Isso é executado a cada minuto.",enable_watchdog:"Ativar Watchdog",enable_watchdog_desc:"Se ativado, ele mudará automaticamente sua fonte de financiamento para VoidWallet se o seu saldo for inferior ao saldo do LNbits. Você precisará ativar manualmente após uma atualização.",watchdog_interval:"Intervalo do Watchdog",watchdog_interval_desc:"Com que frequência a tarefa de fundo deve verificar um sinal de interrupção no delta do monitor [node_balance - lnbits_balance] (em minutos).",watchdog_delta:"Observador Delta",watchdog_delta_desc:"Limite antes da mudança do mecanismo de segurança alterar a fonte de financiamento para VoidWallet [lnbits_balance - node_balance > delta]",status:"Estado",notification_source:"Fonte de Notificação",notification_source_label:"URL de origem (use apenas a fonte de status oficial do LNbits e fontes de confiança)",more:"mais",more_count:"Mais {count}",less:"menos",releases:"Lançamentos",watchdog:"Cão de guarda",server_logs:"Registros do Servidor",ip_blocker:"Bloqueador de IP",security:"Segurança",security_tools:"Ferramentas de segurança",block_access_hint:"Bloquear acesso por IP",allow_access_hint:"Permitir acesso por IP (substituirá os IPs bloqueados)",enter_ip:"Digite o IP e pressione enter",rate_limiter:"Limitador de Taxa",callback_url_rules:"Regras de URL de Retorno",enter_callback_url_rule:"Digite a regra de URL como regex e pressione enter",callback_url_rule_hint:"URLs de retorno de chamada (como a de LNURL) serão validados conforme estas regras. Pelo menos uma regra deve corresponder. Nenhuma regra significa que todas as URLs são permitidas.",wallet_limiter:"Limitador de Carteira",wallet_config:"Configuração da Carteira",wallet_charts:"Gráficos da Carteira",wallet_limit_max_withdraw_per_day:"Retirada máxima diária da carteira em sats (0 para desativar)",wallet_max_ballance:"Saldo máximo da carteira em sats (0 para desativar)",wallet_limit_secs_between_trans:"Minutos e segundos entre transações por carteira (0 para desativar)",only_incoming_payments_allowed:"Apenas pagamentos recebidos são permitidos",disable_outgoing_payments:"Desativar pagamentos de saída",number_of_requests:"Número de solicitações",time_unit:"Unidade de tempo",minute:"minuto",settings:"Configurações",second:"segundo",hour:"hora",disable_server_log:"Desativar Log do Servidor",enable_server_log:"Ativar Registro do Servidor",coming_soon:"Funcionalidade em breve",session_has_expired:"Sua sessão expirou. Por favor, faça login novamente.",instant_access_question:"Quer acesso imediato?",login_with_user_id:"Faça login com ID do usuário",or:"ou",create_new_wallet:"Criar Nova Carteira",delete_all_wallets:"Excluir Todas as Carteiras",confirm_delete_all_wallets:"Tem certeza de que deseja excluir TODAS as carteiras deste usuário?",login_to_account:"Faça login na sua conta",create_account:"Criar conta",account_settings:"Configurações da Conta",signin_with_oauth:"Entrar com",signin_with_oauth_or:"ou entre com",signin_with_nostr:"Continuar com Nostr",signin_with_google:"Entrar com o Google",signin_with_github:"Entrar com GitHub",signin_with_custom_org:"Entrar com {custom_org}",username_or_email:"Nome de usuário ou E-mail",password:"Senha",password_config:"Configuração de Senha",password_repeat:"Repetição de senha",update_password:"Atualizar Senha",change_password:"Alterar Senha",update_credentials:"Atualizar credenciais",update_pubkey:"Atualizar Chave Pública",nostr_pubkey_tooltip:"Insira a chave pública Nostr deste usuário (valor hexadecimal)",set_password:"Definir Senha",set_password_tooltip:"Defina uma senha para este usuário",invalid_password:"A senha deve ter pelo menos 8 caracteres",invalid_password_repeat:"As senhas não coincidem",reset_key_generated:"Uma chave de reinicialização foi gerada.",reset_key_copy:"Clique em OK para copiar o URL de redefinição para sua área de transferência.",login:"Entrar",register:"Registrar",username:"Nome de usuário",pubkey:"Chave Pública",user_id:"ID do Usuário",id:"ID",email:"E-mail",first_name:"Primeiro Nome",last_name:"Sobrenome",picture:"Foto",user_picture_desc:"URL para uma imagem a ser usada como foto de perfil. Você pode carregá-la como um ativo.",verify_email:"Verifique o e-mail com",account:"Conta",update_account:"Atualizar Conta",invalid_username:"Nome de usuário inválido",auth_provider:"Provedor de Autenticação",external_id:"ID Externo",my_account:"Minha Conta",existing_account_question:"Já tem uma conta?",background_image:"Imagem de Fundo",back:"Voltar",logout:"Sair",look_and_feel:"Aparência",endpoint:"Ponto de extremidade",api:"API",api_stripe:"API",api_token:"Token de API",api_tokens:"Tokens da API",access_control_list:"Lista de Controle de Acesso",access_control_list_admin_warning:"Esta é uma conta de administrador. Os tokens gerados terão privilégios de administrador.",new_api_acl:"Nova Lista de Controle de Acesso",api_token_id:"Id do Token",toggle_gradient:"Alternar Gradiente",gradient_background:"Fundo em Degradê",rounded_ui:"Cartões e Botões Arredondados",toggle_rounded_ui:"Alternar cantos arredondados para cartões e botões",card_gradient:"Gradiente do Cartão",toggle_card_gradient:"Alternar gradiente nos cartões",card_shadow:"Sombra do Cartão",toggle_card_shadow:"Alternar sombra nas cartas",language:"Idioma",assets:"Ativos",max_asset_size_mb:"Tamanho Máximo do Ativo (MB)",max_asset_size_mb_desc:"O tamanho máximo permitido para uploads de ativos em megabytes (pode usar valores decimais).",assets_allowed_mime_types:"Tipos MIME permitidos",assets_allowed_mime_types_desc:"Os tipos MIME permitidos para uploads de ativos. Nenhum valor significa que todos os uploads são permitidos.",thumbnail_width:"Largura da Miniatura",thumbnail_width_desc:"Largura da miniatura gerada em pixels.",thumbnail_height:"Altura da miniatura",thumbnail_height_desc:"Altura da miniatura gerada em pixels.",thumbnail_format:"Formato da Miniatura",thumbnail_format_desc:"Formato de imagem da miniatura gerada (PNG, JPEG, etc.).",max_assets_per_user:"Máximo de ativos por usuário",max_assets_per_user_desc:"O número máximo de ativos que um usuário pode fazer upload. Zero significa que o upload está proibido.",assets_no_limit_users:"Usuários sem Limites de Ativos",assets_no_limit_users_desc:"Esses usuários podem enviar um número ilimitado de ativos (com base no ID do usuário).",color_scheme:"Esquema de Cores",visible_wallet_count:"Contagem de Carteiras Visíveis",admin_settings:"Configurações do Administrador",extension_cost:"Este lançamento requer um pagamento mínimo de {cost} sats.",extension_paid_sats:"Você já pagou {paid_sats} sats.",create_extension:"Criar Extensão",release_details_error:"Não é possível obter os detalhes da versão.",pay_from_wallet:"Pagar com a Carteira",pay_with:"Pague com {provider}",select_payment_provider:"Selecione o provedor de pagamento",wallet_required:"Carteira *",show_qr:"Exibir QR",retry_install:"Repetir Instalação",new_payment:"Efetuar Novo Pagamento",update_payment:"Atualizar Pagamento",already_paid_question:"Você já pagou?",sell:"Vender",sell_require:"Peça pagamento para habilitar a extensão",sell_info:"A extensão {name} requer um pagamento mínimo de {amount} sats para habilitar.",hide_empty_wallets:"Ocultar carteiras vazias",recheck:"Verificar novamente",check:"Verificar",check_connection:"Verificar Conexão",check_webhook:"Verificar Webhook",contributors:"Contribuidores",license:"Licença",reset_key:"Redefinir Chave",reset_password:"Redefinir senha",border_choices:"Opções de Borda",select_all:"Selecionar tudo",nfc_supported:"Compatível com NFC",nfc_not_supported:"NFC não suportado",expire_date:"Data de Expiração:",hash:"Hash:",welcome_lnbits:"Bem-vindo ao LNbits",setup_su_account:"Configure a conta Superuser abaixo.",first_install_token:"Primeiro Token de Instalação",create_ticker_converter:"Criar Conversor de Ticker de Moeda",enable_audit:"Habilitar Auditoria",recommended:"Recomendado",audit_desc:"Gravar solicitações HTTP de acordo com os filtros especificados",audit_record_req:"Gravar Corpo da Requisição",audit_record_warning:"Aviso:",audit_record_req_warning_1:"dados confidenciais (como senhas) serão registrados.",audit_record_req_warning_2:"o corpo da solicitação pode ter um tamanho grande.",audit_record_use:"Use com cuidado.",audit_ip:"Registrar endereço IP",audit_ip_desc:"Registre o endereço IP do cliente",audit_path_params:"Registrar Parâmetros de Caminho",audit_query_params:"Registrar Parâmetros de Consulta",audit_http_methods:"Incluir métodos HTTP",audit_http_methods_hint:"Lista de métodos HTTP a serem incluídos. Listas vazias significam todos.",audit_http_methods_label:"Métodos HTTP",audit_resp_codes:"Incluir Códigos de Resposta HTTP",audit_resp_codes_hint:"Lista de códigos HTTP a serem incluídos (correspondência regex). Listas vazias significam todos. Ex: 4.*, 5.*",audit_resp_codes_label:"Código de resposta HTTP (regex)",audit_paths:"Incluir Caminhos",audit_paths_hint:"Lista de caminhos a serem incluídos (correspondência de regex). Lista vazia significa todos.",audit_paths_label:"Caminho HTTP (regex)",audit_paths_exclude:"Excluir Caminhos",audit_paths_exclude_hint:"Lista de caminhos a serem excluídos (correspondência regex). Lista vazia significa nenhum.",audit_paths_exclude_label:"Caminho HTTP (regex)",exchange_providers:"Provedores de Câmbio",admin_extensions:"Extensões de Administração",admin_extensions_label:"Extensões de administração",admin_extensions_hint:"Somente usuários com privilégios de administrador podem usar extensões.",user_default_extensions:"Extensões Padrão do Usuário",user_default_extensions_label:"Extensões do usuário",user_default_extensions_hint:"Extensões que serão ativadas por padrão para os usuários.",extension_builder:"Construtor de Extensão",extension_builder_manifest_url:"URL do Manifesto do Criador de Extensões",extension_builder_manifest_url_hint:"URL para um arquivo JSON manifest com detalhes do extension builder",miscellanous:"Diversos",misc_disable_extensions:"Desativar extensões",misc_disable_extensions_label:"Desativar todas as extensões",misc_disable_extensions_builder:"Habilitar Extensions Builder",misc_disable_extensions_builder_label:"Habilitar Extensions Builder para usuários não administradores.",misc_hide_api:"Ocultar API",misc_hide_api_label:"Oculta a API de carteira, extensões podem optar por honrar",wallets_management:"Gerenciamento de Carteiras",funding_source_info:"Informações da Fonte de Financiamento",funding_source:"Fonte de Financiamento: {wallet_class}",node_balance:"Saldo do Nó: {balance} sats",lnbits_balance:"Saldo do LNbits: {balance} sats",funding_reserve_percent:"Reserve Percentual: {percent} %",node_management:"Gerenciamento de Nós",node_management_not_supported:"Gerenciamento de nó não suportado pela fonte de financiamento ativa",toggle_node_ui:"Interface do Nó",toggle_public_node_ui:"Interface Pública do Nó",toggle_transactions_node_ui:"Guia de Transações (Desativar em nós grandes CLN)",invoice_expiry:"Expiração da Fatura",invoice_expiry_label:"Validade da fatura",routing_fee_reserve_calculations:"Cálculos de Reserva de Taxa de Roteamento",routing_fee_reserve_calculations_desc:'LNbits reserva um "valor de reserva" para cada pagamento para cobrir as taxas de roteamento. A taxa de roteamento máxima passada para a fonte de financiamento é a que for maior: a reserva mínima de taxa de roteamento ou a percentagem de reserva de taxa de roteamento.',millisats:"milissats",fee_reserve:"Reserva Mínima de Taxa de Encaminhamento",fee_reserve_percent:"Porcentagem da Reserva de Taxa de Roteamento",fee_reserve_min_hint:"A taxa mínima reservada por pagamento.
Isso atua como um piso - a taxa de roteamento máxima nunca será inferior a este valor, independentemente do tamanho do pagamento.",fee_reserve_percent_hint:"A porcentagem do valor do pagamento a reservar para taxas de roteamento.",payment_timeouts:"Tempos de Espera de Pagamento",payment_wait_time:"Tempo de Espera do Pagamento",seconds:"segundos",payment_wait_time_desc:"Tempo de espera antes de marcar um pagamento de saída como pendente. Padrão: 5s; aumentar para faturas de liquidação lenta.",payment_wait_time_tooltip:"Controla quanto tempo o LNbits espera para uma tentativa de pagamento de saída ser confirmada antes de marcá-la como pendente. Valores mais altos ajudam ao pagar faturas de liquidação lenta (por exemplo, faturas HODL, Boltz). O pagamento será verificado novamente mais tarde e atualizado automaticamente ou manualmente.",server_management:"Gerenciamento de Servidor",base_url:"URL base",base_url_label:"URL estática/base para o servidor",authentication:"Autenticação",auth_token_expiry_label:"Minutos para expiração do token",auth_token_expiry_hint:"Tempo em minutos até o token expirar",auth_authentication_cache_label:"Tempo de cache (minutos)",auth_authentication_cache_hint:"Tempo em minutos para armazenar em cache a autenticação bem-sucedida (0 para desativar)",auth_allowed_methods_label:"Métodos de autorização permitidos",auth_allowed_methods_hint:"Selecione métodos de autorização",auth_nostr_label:"URL de Solicitação Nostr",auth_nostr_hint:"URL absoluta que os clientes usarão para fazer login.",auth_google_ci_label:"ID do Cliente do Google",auth_google_ci_hint:"Certifique-se de que os URIs de redirecionamento autorizados contenham https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Segredo do Cliente do Google",auth_gh_client_id_label:"ID do Cliente do GitHub",auth_gh_client_id_hint:"Certifique-se de que a URL de callback de autorização esteja definida como https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"Segredo do Cliente do GitHub",auth_keycloak_label:"URL de Descoberta do Keycloak",auth_keycloak_ci_label:"ID do Cliente Keycloak",auth_keycloak_ci_hint:"Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Segredo do Cliente Keycloak",auth_keycloak_custom_org_label:"Organização Personalizada do Keycloak",auth_keycloak_custom_icon_label:"Ícone Personalizado do Keycloak (URL)",auth_oidc_label:"URL de Descoberta do OIDC",auth_oidc_ci_label:"ID do Cliente OIDC",auth_oidc_ci_hint:"Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Segredo do Cliente OIDC",auth_oidc_custom_org_label:"Nome da Organização Personalizada OIDC (ex. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Ícone Personalizado do OIDC (URL)",auth_keycloak_custom_org_label:"Keycloak Custom Organization",auth_keycloak_custom_icon_label:"Ícone Personalizado do Keycloak (URL)",currency_settings:"Configurações de Moeda",allowed_currencies:"Moedas Permitidas",allowed_currencies_hint:"Limite o número de moedas fiduciárias disponíveis",default_account_currency:"Moeda Padrão da Conta",default_account_currency_hint:"Moeda padrão para contabilidade",min_incoming_payment_amount:"Quantia Mínima de Pagamento de Entrada",min_incoming_payment_amount_desc:"Quantidade mínima permitida para gerar uma fatura",max_incoming_payment_amount:"Valor Máximo do Pagamento Recebido",max_incoming_payment_amount_desc:"Quantidade máxima permitida para gerar uma fatura",max_outgoing_payment_amount:"Valor Máximo de Pagamento de Saída",max_outgoing_payment_amount_desc:"Valor máximo permitido para efetuar um pagamento",service_fee:"Taxa de serviço: {amount} % por transação",service_fee_label:"Taxa de serviço (%)",service_fee_hint:"Taxa cobrada por tx (%)",service_fee_max:"Taxa de serviço: {amount} % por transação (máx {max} sats)",service_fee_max_label:"Taxa de serviço máx (sats)",service_fee_max_hint:"Taxa máxima de serviço a cobrar em (sats)",fee_wallet:"Carteira de Taxas",fee_wallet_label:"Carteira de tarifas (ID da carteira)",fee_wallet_hint:"ID da carteira para enviar fundos para",disable_fee:"Desativar Taxa",disable_fee_internal:"Desativar taxa de serviço para pagamentos internos",disable_fee_internal_desc:"Desativar Taxa de Serviço para Pagamentos Internos Lightning",ui_management:"Gerenciamento de UI",ui_site_title:"Título do Site",ui_changing_remove_lnbits_elements:"(alterar removerá os elementos LNbits na página inicial e rodapé)",ui_site_tagline:"Tagline do site",ui_elements_enable:"Habilitar elementos na página inicial",ui_elements_disable:"Desativar elementos na página inicial",ui_toggle_elements_tip:"Remover elementos da página inicial, como 'funciona com', etc.",ui_site_description:"Descrição do Site",ui_site_description_hint:"Use texto simples, Markdown ou HTML bruto",ui_default_wallet_name:"Nome Padrão da Carteira",ui_default_theme:"Tema Padrão",wallet_featured_button_label:"Carteira Rótulo do Botão em Destaque",wallet_featured_button_label_hint:"Mostrar botão em destaque na página inicial da carteira",wallet_featured_button_url:"URL do Botão em Destaque",wallet_featured_button_url_hint:"Ao clicar, o botão abrirá este URL. Deixe em branco para ocultar o botão.",wallet_featured_button_icon:"Ícone do Botão em Destaque",wallet_featured_button_icon_hint:"Ícone mostrado no botão de destaque (verifique os ícones quasar)",lnbits_wallet:"Carteira LNbits",denomination:"Denominação",denomination_hint:"O nome para o token FakeWallet",denomination_error:"A denominação deve ter 3 caracteres ou `sats`.",ui_qr_code_logo:"Logo do QR Code",ui_qr_code_logo_hint:"URL para imagem de logo no código QR",ui_apple_touch_icon:"Ícone de Toque da Apple",ui_apple_touch_icon_hint:"URL do ícone de toque da Apple",ui_custom_image:"Imagem Personalizada",ui_custom_image_label:"URL para imagem personalizada",ui_custom_image_hint:"Imagem exibida na página inicial/login",ui_custom_badge:"Distintivo Personalizado",ui_custom_badge_label:"Distintivo Personalizado 'USE COM CUIDADO - a carteira LNbits ainda está em BETA'",ui_custom_badge_color_label:"Cor Personalizada do Distintivo",themes:"Temas",themes_hint:"Escolha temas disponíveis para usuários",custom_logo:"Logotipo personalizado",custom_logo_hint:"URL para a imagem do logotipo",ad_space_title:"Título do Espaço Publicitário",ad_space_title_label:"Suportado por",ad_slots:"Slots de Anúncio",ad_slots_hint:"Adicionar URL e caminhos de arquivo de imagem no formato CSV, as extensões podem optar por honrar",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Anúncios Ativados",ads_disabled:"Anúncios Desativados",user_management:"Gerenciamento de Usuários",admin_users:"Usuários Administradores",admin_users_hint:"Usuários com privilégios de administrador",admin_users_label:"ID do Usuário",allowed_users:"Usuários Permitidos",allowed_users_hint:"Somente esses usuários podem usar o LNbits",allowed_users_hint_feature:"Somente estes usuários podem usar {feature}",allowed_users_label:"ID do Usuário",allow_creation_user:"Permitir a criação de novos usuários",allow_creation_user_desc:"Permitir a criação de novos usuários na página de índice",require_user_activation:"Requer ativação do usuário",require_user_activation_desc:"Novos usuários serão ativados somente após passarem por um dos métodos de confirmação. Administradores podem ativar usuários manualmente a partir do painel de administração.",reusable_activation_code:"Código de ativação reutilizável",reusable_activation_code_label:"Código de ativação reutilizável",reusable_activation_code_hint:"Este código de ativação pode ser usado várias vezes por diferentes usuários.",one_time_activation_code:"Códigos de ativação única",one_time_activation_code_label:"Adicionar código de ativação",one_time_activation_code_hint:"Lista de códigos de ativação únicos. Cada código pode ser usado apenas uma vez, depois será removido da lista.",invitation_code:"Código de Convite",invitation_code_hint:"O código de convite que você recebeu.",email_confirmation_hint:"Endereço de e-mail para enviar o código de confirmação.",nostr_identifier:"Identificador Nostr",nostr_identifier_hint:"Identificador nostr nip5 ou para enviar o código de confirmação.",new_user_not_allowed:"O registro está desativado.",start_user_impersonation:"Personificar este usuário",stop_user_impersonation:"Parar a Personificação do Usuário",components:"Componentes",long_running_endpoints:"Top 5 Endpoints de Longa Execução",http_request_methods:"Métodos de Requisição HTTP",http_response_codes:"Códigos de Resposta HTTP",request_details:"Detalhes do Pedido",http_request_details:"Detalhes da Requisição HTTP",payment_details:"Detalhes do Pagamento",payment_details_desc:"Informações detalhadas sobre o pagamento",payments:"Pagamentos",payment_show_internal:"Mostrar Pagamentos Internos",payment_chart_flow:"Fluxo de Pagamento Mensal",payment_chart_status:"Status do Pagamento",payment_chart_tx_per_wallet:"Transações por Carteira (saldo/contagem)",payment_details_back:"Voltar para Pagamentos",payment_chart_tags:"Pagamentos por Tags",payments_balance_in_out:"Entradas/Saídas de Saldo",payments_count_in_out:"Contar Entrada/Saída",payments_status_chart:"Gráfico de Status",payments_tag_chart:"Gráfico de Marcadores",payments_balance_chart:"Gráfico de Saldo",payments_wallets_chart:"Gráfico de Carteiras",payments_balance_in_out_chart:"Gráfico de Entrada/Saída de Saldo",payments_count_in_out_chart:"Gráfico de Entrada/Saída",reset_wallet_keys:"Redefinir Chaves",reset_wallet_keys_desc:"Redefina as chaves de API para esta carteira. Isso invalidará as chaves atuais e gerará novas.",view_list:"Visualizar carteiras como lista",view_column:"Visualizar carteiras como linhas",filter_payments:"Filtrar pagamentos",filter_labels:"Rótulos de filtro",filter_date:"Filtrar por data",websocket_example:"Exemplo de Websocket",client_id:"ID do Cliente",secret_key:"Chave Secreta",signing_secret:"Segredo de Assinatura",signing_secret_hint:"Segredo de assinatura para o webhook. As mensagens serão assinadas com este segredo.",webhook_id:"ID do Webhook",webhook_id_hint:"ID do webhook do PayPal usado para verificar eventos recebidos.",webhook_paypal_description:"No lado do PayPal, configure um webhook apontando para o seu servidor LNbits.",callback_success_url:"URL de Sucesso de Callback",callback_success_url_hint:"O usuário será redirecionado para este URL após o pagamento ser bem-sucedido.",connected:"Conectado",not_connected:"Não Conectado",free:"Grátis",paid:"Pago",funding_source_retries:"Máximo de tentativas",funding_source_retries_desc:"Número máximo de tentativas para fontes de financiamento, antes de voltar para VoidWallet.",add_label:"Adicionar Rótulo",label:"Etiqueta",labels:"Rótulos",label_filter:"Filtro de Rótulo",no_labels_defined:"Ainda não há rótulos definidos",manage_labels:"Gerenciar Etiquetas",update_label:"Atualizar Rótulo",delete_label:"Excluir Rótulo",add_remove_labels:"Adicionar ou Remover Rótulos",payment_labels_updated:"Rótulos de pagamento atualizados",color:"Cor",sort:"Ordenar",sort_by:"Ordenar por",block_explorer:"Block Explorer",enable_block_explorer:"Ativar Block Explorer",block_explorer_desc:"Permite aos usuários explorar transações e endereços Bitcoin via Electrum.",blockexplorer_public_api:"Acesso à API pública",blockexplorer_public_api_desc:"Permitir acesso não autenticado aos endpoints da API do explorador de blocos.",electrum_server_url:"URL do servidor Electrum",electrum_server_url_hint:"ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001",blockexplorer_search_label:"Pesquisar por TXID ou endereço",blockexplorer_search_hint:"Hex de 64 caracteres = transação · qualquer outra coisa = endereço Bitcoin",recent_blocks:"Blocos recentes",chain_tip:"Ponta da cadeia",block_height:"Altura do bloco",block_fee:"taxa de bloco",fee_estimates:"Estimativas de taxa",confirmed_balance:"Saldo confirmado",unconfirmed_balance:"Saldo não confirmado",transaction_history:"Histórico de transações",coinbase:"Coinbase",inputs:"Entradas",outputs:"Saídas",confirmations:"Confirmações",confirmed:"Confirmado",unconfirmed:"Não confirmado",history_unavailable:"Histórico de transações indisponível (endereço tem transações demais)",address:"Endereço",block_number:"Bloco #{height}",block_diff:"diff {value}",block_hash:"Hash",previous_block:"Bloco anterior",merkle_root:"Raiz de Merkle",version:"Versão",bits:"Bits",difficulty:"Dificuldade",nonce:"Nonce",txid:"TXID",vsize:"Tamanho virtual",weight:"Peso",n_block_fee:"taxa {n} blocos"},window.localisation.cs={confirm:"Ano",server:"Server",theme:"Téma",site_customisation:"Přizpůsobení stránek",funding:"Financování",users:"Uživatelé",audit:"Audit",apps:"Aplikace",channels:"Kanály",transactions:"Transakce",dashboard:"Přehled",node:"Uzel",export_users:"Exportovat uživatele",no_users:"Nebyli nalezeni žádní uživatelé",total_capacity:"Celková kapacita",avg_channel_size:"Průmerná velikost kanálu",biggest_channel_size:"Největší velikost kanálu",smallest_channel_size:"Nejmenší velikost kanálu",number_of_channels:"Počet kanálů",active_channels:"Aktivní kanály",connect_peer:"Připojit peer",connect:"Připojit",open_channel:"Otevřít kanál",open:"Otevřít",close_channel:"Zavřít kanál",close:"Zavřít",restart:"Restartovat server",save:"Uložit",save_tooltip:"Uložit změny",credit_debit:"Kreditní / Debetní",credit_hint:"Stiskněte Enter pro připsání na účet",credit_label:"{denomination} k připsání",credit_ok:"Úspěšné připsání/odepsání virtuálních prostředků ({amount} satů). Platby závisí na skutečných prostředcích z financujícího zdroje.",restart_tooltip:"Restartujte server pro aplikaci změn",add_funds_tooltip:"Přidat prostředky do peněženky.",reset_defaults:"Obnovit výchozí",reset_defaults_tooltip:"Smazat všechna nastavení a obnovit výchozí.",download_backup:"Stáhnout zálohu databáze",name_your_wallet:"Pojmenujte svou {name} peněženku",paste_invoice_label:"Vložte fakturu, platební požadavek nebo lnurl kód *",lnbits_description:"Snadno nastavitelný a lehkotonážní, LNbits může běžet na jakémkoliv zdroji financování Lightning Network a dokonce LNbits samotné! LNbits můžete provozovat pro sebe, nebo snadno nabízet správu peněženek pro ostatní. Každá peněženka má své vlastní API klíče a není omezen počet peněženek, které můžete vytvořit. Možnost rozdělení prostředků dělá z LNbits užitečný nástroj pro správu peněz a jako vývojový nástroj. Rozšíření přidávají extra funkčnost k LNbits, takže můžete experimentovat s řadou špičkových technologií na lightning network. Vývoj rozšíření jsme učinili co nejjednodušší a jako svobodný a open-source projekt podporujeme lidi ve vývoji a zasílání vlastních rozšíření.",export_to_phone:"Exportovat do telefonu pomocí QR kódu",export_to_phone_desc:"Tento QR kód obsahuje URL vaší peněženky s plným přístupem. Můžete jej naskenovat z telefonu a otevřít peněženku odtamtud.",wallet:"Peněženka:",wallets:"Peněženky",add_wallet:"Přidat novou peněženku",delete_wallet:"Smazat peněženku",delete_wallet_desc:"Celá peněženka bude smazána, prostředky budou NEOBNOVITELNÉ.",rename_wallet:"Přejmenovat peněženku",update_name:"Aktualizovat název",fiat_tracking:"Sledování fiatu",currency:"Měna",update_currency:"Aktualizovat měnu",press_to_claim:"Stiskněte pro nárokování bitcoinu",donate:"Darovat",view_github:"Zobrazit na GitHubu",voidwallet_active:"VoidWallet je aktivní! Platby zakázány",use_with_caution:"POUŽÍVEJTE S OBEZŘETNOSTÍ - {name} peněženka je stále v BETĚ",service_fee:"Servisný poplatek: {amount} % za transakci",service_fee_max:"Servisný poplatek: {amount} % za transakci (max {max} satoshi)",service_fee_tooltip:"Servisní poplatek účtovaný správcem LNbits serveru za odchozí transakci",toggle_darkmode:"Přepnout tmavý režim",payment_reactions:"Reakce na platby",view_swagger_docs:"Zobrazit LNbits Swagger API dokumentaci",api_docs:"API dokumentace",api_keys_api_docs:"Adresa uzlu, API klíče a API dokumentace",api_keys_warning:"Tyto klíče uchovávejte v bezpečí, jejich sdílení může vést ke ztrátě prostředků.",admin_key_warning:"Váš administrátorský klíč poskytuje plný přístup k peněžence včetně možnosti odesílat platby. Nikdy jej nesdílejte, pokud příjemci plně nedůvěřujete.",lnbits_version:"Verze LNbits",runs_on:"Běží na",paste:"Vložit",paste_from_clipboard:"Vložit ze schránky",paste_request:"Vložit požadavek",create_invoice:"Vytvořit fakturu",camera_tooltip:"Použijte kameru pro skenování faktury/QR",export_csv:"Exportovat do CSV",chart_tooltip:"Zobrazit graf",pending:"Čeká na vyřízení",copy_invoice:"Kopírovat fakturu",withdraw_from:"Vybrat z",cancel:"Zrušit",scan:"Skenovat",read:"Číst",pay:"Platit",memo:"Poznámka",date:"Datum",payment_processing:"Zpracování platby...",not_enough_funds:"Nedostatek prostředků!",search_by_tag_memo_amount:"Hledat podle tagu, poznámky, částky",invoice_waiting:"Faktura čeká na platbu",payment_received:"Platba přijata",payment_sent:"Platba odeslána",receive:"přijmout",send:"odeslat",outgoing_payment_pending:"Odchozí platba čeká na vyřízení",drain_funds:"Vyčerpat prostředky",drain_funds_desc:"Toto je LNURL-withdraw QR kód pro vyčerpání všeho z této peněženky. Nesdílejte s nikým. Je kompatibilní s balanceCheck a balanceNotify, takže vaše peněženka může kontinuálně čerpat prostředky odsud po prvním výběru.",i_understand:"Rozumím",copy_wallet_url:"Kopírovat URL peněženky",disclaimer_dialog_title:"Důležité!",disclaimer_dialog:"Funkcionalita přihlášení bude vydána v budoucí aktualizaci, zatím si ujistěte, že jste si tuto stránku uložili do záložek pro budoucí přístup k vaší peněžence! Tato služba je v BETA verzi a nepřebíráme žádnou zodpovědnost za ztrátu přístupu k prostředkům.",no_transactions:"Zatím žádné transakce",manage:"Spravovat",exchanges:"Burzy",extensions:"Rozšíření",no_extensions:"Nemáte nainstalováno žádné rozšíření :(",created:"Vytvořeno",search_extensions:"Hledat rozšíření",extension_sources:"Zdroje rozšíření",ext_sources_hint:"Úložiště, odkud lze rozšíření stáhnout.",ext_sources_label:"Zdrojová URL (používejte pouze oficiální zdroj rozšíření LNbits a zdroje, kterým můžete důvěřovat)",warning:"Varování",repository:"Repositář",confirm_continue:"Jste si jistí, že chcete pokračovat?",manage_extension_details:"Instalovat/odinstalovat rozšíření",install:"Instalovat",uninstall:"Odinstalovat",drop_db:"Odstranit data",enable:"Povolit",pay_to_enable:"Zaplatit pro aktivaci",enable_extension_details:"Povolit rozšíření pro aktuálního uživatele",disable:"Zakázat",delete:"Smazat",installed:"Nainstalováno",activated:"Aktivováno",deactivated:"Deaktivováno",release_notes:"Poznámky k vydání",activate_extension_details:"Zpřístupnit/zakázat rozšíření pro uživatele",featured:"Doporučené",all:"Vše",only_admins_can_install:"(Pouze administrátorské účty mohou instalovat rozšíření)",admin_only:"Pouze pro adminy",new_version:"Nová verze",extension_depends_on:"Závisí na:",extension_rating_soon:"Hodnocení brzy dostupné",extension_installed_version:"Nainstalovaná verze",extension_uninstall_warning:"Chystáte se odstranit rozšíření pro všechny uživatele.",uninstall_confirm:"Ano, odinstalovat",extension_db_drop_info:"Všechna data pro rozšíření budou trvale odstraněna. Tuto operaci nelze vrátit zpět!",extension_db_drop_warning:"Chystáte se odstranit všechna data pro rozšíření. Prosím, pokračujte zadáním názvu rozšíření:",extension_required_lnbits_version:"Toto vydání vyžaduje alespoň verzi LNbits",min_version:"Minimum (včetně)",max_version:"Maximální (vyloučeno)",payment_hash:"Hash platby",fee:"Poplatek",amount:"Částka",amount_sats:"Částka (sats)",tag:"Tag",unit:"Jednotka",description:"Popis",expiry:"Expirace",webhook:"Webhook",payment_proof:"Důkaz platby",update:"Aktualizovat",update_available:"Dostupná aktualizace {version}!",latest_update:"Máte nejnovější verzi {version}.",notifications:"Notifikace",no_notifications:"Žádné notifikace",notifications_disabled:"Notifikace stavu LNbits jsou zakázány.",enable_notifications:"Povolit notifikace",enable_notifications_desc:"Pokud je povoleno, bude stahovat nejnovější aktualizace stavu LNbits, jako jsou bezpečnostní incidenty a aktualizace.",watchdog_interval:"Interval Watchdog",watchdog_interval_desc:"Jak často by měl úkol na pozadí kontrolovat signál killswitch v watchdog delta [node_balance - lnbits_balance] (v minutách).",watchdog_delta:"Delta Watchdog",watchdog_delta_desc:"Limit předtím, než killswitch změní zdroj financování na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stav",notification_source:"Zdroj notifikací",notification_source_label:"URL zdroje (používejte pouze oficiální zdroj stavu LNbits a zdroje, kterým můžete věřit)",more:"více",less:"méně",releases:"Vydání",watchdog:"Watchdog",server_logs:"Logy serveru",ip_blocker:"Blokování IP",security:"Bezpečnost",security_tools:"Nástroje bezpečnosti",block_access_hint:"Blokovat přístup podle IP",allow_access_hint:"Povolit přístup podle IP (přepíše blokované IP)",enter_ip:"Zadejte IP a stiskněte enter",rate_limiter:"Omezovač počtu požadavků",wallet_limiter:"Omezení peněženky",wallet_limit_max_withdraw_per_day:"Maximální denní limit pro výběr z peněženky v sats (0 pro deaktivaci)",wallet_max_ballance:"Maximální zůstatek v peněžence v sats (0 pro zakázání)",wallet_limit_secs_between_trans:"Minimální počet sekund mezi transakcemi na peněženku (0 pro vypnutí)",number_of_requests:"Počet požadavků",time_unit:"Časová jednotka",minute:"minuta",second:"sekunda",hour:"hodina",disable_server_log:"Zakázat log serveru",enable_server_log:"Povolit log serveru",coming_soon:"Funkce brzy dostupná",session_has_expired:"Vaše relace vypršela. Prosím, přihlašte se znovu.",instant_access_question:"Chcete okamžitý přístup?",login_with_user_id:"Přihlásit se s uživatelským ID",or:"nebo",create_new_wallet:"Vytvořit novou peněženku",login_to_account:"Přihlaste se ke svému účtu",create_account:"Vytvořit účet",account_settings:"Nastavení účtu",signin_with_nostr:"Pokračovat s Nostr",signin_with_google:"Přihlásit se přes Google",signin_with_github:"Přihlásit se přes GitHub",signin_with_keycloak:"Přihlásit se přes Keycloak",username_or_email:"Uživatelské jméno nebo Email",password:"Heslo",password_config:"Konfigurace hesla",password_repeat:"Opakujte heslo",change_password:"Změnit heslo",update_credentials:"Aktualizovat přihlašovací údaje",update_pubkey:"Aktualizovat veřejný klíč",set_password:"Nastavit heslo",invalid_password:"Heslo musí mít alespoň 8 znaků",login:"Přihlášení",register:"Registrovat",username:"Uživatelské jméno",pubkey:"Veřejný klíč",user_id:"ID uživatele",email:"Email",first_name:"Křestní jméno",last_name:"Příjmení",picture:"Obrázek",verify_email:"Ověřte e-mail s",account:"Účet",update_account:"Aktualizovat účet",invalid_username:"Neplatné uživatelské jméno",auth_provider:"Poskytovatel ověření",my_account:"Můj účet",back:"Zpět",logout:"Odhlásit se",look_and_feel:"Vzhled a chování",toggle_gradient:"Přepnout gradient",gradient_background:"Barevný přechod pozadí",language:"Jazyk",color_scheme:"Barevné schéma",admin_settings:"Nastavení administrátora",extension_cost:"Toto vydání vyžaduje minimální platbu {cost} satoshi.",extension_paid_sats:"Již jste zaplatili {paid_sats} sats.",release_details_error:"Nelze získat podrobnosti o vydání.",pay_from_wallet:"Platit z peněženky",wallet_required:"Peněženka *",show_qr:"Zobrazit QR",retry_install:"Zkusit znovu nainstalovat",new_payment:"Vytvořit novou platbu",update_payment:"Aktualizovat platbu",already_paid_question:"Už jste zaplatili?",sell:"Prodat",sell_require:"Požádejte o platbu, abyste povolili rozšíření",sell_info:"Rozšíření {name} vyžaduje platbu minimálně {amount} sats pro aktivaci.",hide_empty_wallets:"Skrýt prázdné peněženky",recheck:"Znovu zkontrolovat",contributors:"Přispěvatelé",license:"Licence",reset_key:"Obnovit klíč",reset_password:"Obnovit heslo",border_choices:"Možnosti ohraničení",select_all:"Vybrat vše",nfc_supported:"Podpora NFC",nfc_not_supported:"NFC není podporováno",expire_date:"Datum expirace:",hash:"Hash:",welcome_lnbits:"Vítejte v LNbits",setup_su_account:"Nastavte účet Superuser níže.",create_ticker_converter:"Vytvořit převodník měnových tickerů",enable_audit:"Povolit audit",recommended:"Doporučeno",audit_desc:"Zaznamenávejte HTTP požadavky podle zadaných filtrů",audit_record_req:"Záznam Tělo Požadavku",audit_record_warning:"Varování:",audit_record_req_warning_1:"důvěrná data (jako hesla) budou zaznamenána.",audit_record_req_warning_2:"tělo žádosti může mít velkou velikost.",audit_record_use:"Používejte to opatrně.",audit_ip:"Zaznamenat IP adresu",audit_ip_desc:"Zaznamenejte IP adresu klienta",audit_path_params:"Zaznamenat parametry cesty",audit_query_params:"Zaznamenat parametry dotazu",audit_http_methods:"Zahrnout metody HTTP",audit_http_methods_hint:"Seznam metod HTTP, které mají být zahrnuty. Prázdné seznamy znamenají všechny.",audit_http_methods_label:"Metody HTTP",audit_resp_codes:"Zahrnout kódy odpovědí HTTP",audit_resp_codes_hint:"Seznam kódů HTTP, které mají být zahrnuty (regex match). Prázdné seznamy znamenají všechny. Např.: 4.*, 5.*",audit_resp_codes_label:"Kód odpovědi HTTP (regex)",audit_paths:"Zahrnout cesty",audit_paths_hint:"Seznam cest, které mají být zahrnuty (regex shoda). Prázdný seznam znamená vše.",audit_paths_label:"HTTP cesta (regex)",audit_paths_exclude:"Vyloučit cesty",audit_paths_exclude_hint:"Seznam cest, které mají být vyloučeny (regex shoda). Prázdný seznam znamená žádné.",audit_paths_exclude_label:"HTTP cesta (regex)",exchange_providers:"Poskytovatelé směny",admin_extensions:"Rozšíření pro správce",admin_extensions_label:"Administrátorské rozšíření",admin_extensions_hint:"Rozšíření může používat pouze uživatel s administrátorskými oprávněními.",user_default_extensions:"Výchozí rozšíření uživatele",user_default_extensions_label:"Uživatelská rozšíření",user_default_extensions_hint:"Rozšíření, která budou u uživatelů ve výchozím nastavení povolena.",miscellanous:"Různé",misc_disable_extensions:"Zakázat rozšíření",misc_disable_extensions_label:"Zakázat všechna rozšíření",misc_hide_api:"Skrýt API",misc_hide_api_label:"Skrývá API peněženky, rozšíření se mohou rozhodnout ctít",wallets_management:"Správa peněženek",funding_source_info:"Informace o zdroji financování",funding_source:"Zdroj financování: {wallet_class}",node_balance:"Stav uzlu: {balance} sats",lnbits_balance:"Zůstatek LNbits: {balance} sats",funding_reserve_percent:"Rezervovat procento: {percent} %",node_management:"Správa uzlů",node_management_not_supported:"Správa uzlů není podporována aktivním zdrojem financování",toggle_node_ui:"Uživatelské rozhraní uzlu",toggle_public_node_ui:"Veřejné rozhraní uzlu",toggle_transactions_node_ui:"Karta Transakce (Zakázat na velkých uzlech CLN)",invoice_expiry:"Datum vypršení faktury",invoice_expiry_label:"Vypršení faktury (sekundy)",fee_reserve:"Rezerva poplatku",fee_reserve_msats:"Rezervační poplatek v msats",fee_reserve_percent:"Rezervační poplatek v procentech",server_management:"Správa serveru",base_url:"Základní URL",base_url_label:"Statická/Základní URL pro server",authentication:"Ověření",auth_token_expiry_label:"Minuty vypršení platnosti tokenu",auth_token_expiry_hint:"Čas v minutách do vypršení tokenu",auth_allowed_methods_label:"Povolené metody autorizace",auth_allowed_methods_hint:"Vyberte metody autorizace",auth_nostr_label:"URL žádosti Nostr",auth_nostr_hint:"Absolutní URL, které klienti použijí pro přihlášení.",auth_google_ci_label:"ID klienta Google",auth_google_ci_hint:"Ujistěte se, že autorizované přesměrovací URI obsahují https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Heslo klienta Google",auth_gh_client_id_label:"ID klienta GitHub",auth_gh_client_id_hint:"Ujistěte se, že je nastavena zpětná adresa URL pro autorizaci na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Klientský tajný klíč",auth_keycloak_label:"URL pro zjištění Keycloak",auth_keycloak_ci_label:"ID klienta Keycloak",auth_keycloak_ci_hint:"Ujistěte se, že je autorizace callback URL nastavena na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Klíč k aplikaci Keycloak tajemství",auth_keycloak_custom_org_label:"Vlastní organizace Keycloak",auth_keycloak_custom_icon_label:"Vlastní ikona Keycloak (URL)",auth_oidc_label:"URL pro zjištění OIDC",auth_oidc_ci_label:"ID klienta OIDC",auth_oidc_ci_hint:"Ujistěte se, že je autorizace callback URL nastavena na https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Klíč k aplikaci OIDC tajemství",auth_oidc_custom_org_label:"Název vlastní organizace OIDC (např. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Vlastní ikona OIDC (URL)",currency_settings:"Nastavení měny",allowed_currencies:"Povolené měny",allowed_currencies_hint:"Omezte počet dostupných fiat měn",default_account_currency:"Výchozí měna účtu",default_account_currency_hint:"Výchozí měna pro účetnictví",service_fee_label:"Poplatek za službu (%)",service_fee_hint:"Poplatek účtovaný za transakci (%)",service_fee_max_label:"Poplatek za službu max (sats)",service_fee_max_hint:"Maximální poplatek za službu k účtování v (sats)",fee_wallet:"Poplatková peněženka",fee_wallet_label:"Poplatková peněženka (ID peněženky)",fee_wallet_hint:"ID peněženky, na kterou se mají odeslat prostředky",disable_fee:"Zakázat poplatek",disable_fee_internal:"Zakázat poplatek za službu pro interní platby",disable_fee_internal_desc:"Zakázat servisní poplatek za interní lightning platby",ui_management:"Správa uživatelského rozhraní",ui_site_title:"Název stránky",ui_site_tagline:"Stránkový slogan",ui_elements_enable:"Povolit prvky na domovské stránce",ui_elements_disable:"Zakázat prvky na úvodní stránce",ui_toggle_elements_tip:"Odebrat prvky z domovské stránky, jako je 'běží na' atd.",ui_site_description:"Popis webu",ui_site_description_hint:"Použijte prostý text, Markdown nebo surové HTML.",ui_default_wallet_name:"Výchozí název peněženky",lnbits_wallet:"Peněženka LNbits",denomination:"Nominální hodnota",denomination_hint:"Název pro token FakeWallet",ui_qr_code_logo:"Logo QR kódu",ui_qr_code_logo_hint:"URL k obrázku loga v QR kódu",ui_custom_badge:"Vlastní odznak",ui_custom_badge_label:"Vlastní odznak 'POUŽÍVEJTE S OPATRNOSTÍ - Peněženka LNbits je stále v BETA verzi'",ui_custom_badge_color_label:"Barva vlastního odznaku",themes:"Motivy",themes_hint:"Vyberte motivy dostupné pro uživatele",custom_logo:"Vlastní logo",custom_logo_hint:"URL k obrázku loga",ad_space_title:"Název reklamního prostoru",ad_space_title_label:"Podporováno",ad_slots:"Reklamní sloty",ad_slots_hint:"Adresa URL reklamy a cesty k souborům obrázků ve formátu CSV, rozšíření se mohou rozhodnout respektovat",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy povoleny",ads_disabled:"Reklamy deaktivovány",user_management:"Správa uživatelů",admin_users:"Administrátorští uživatelé",admin_users_hint:"Uživatelé s administrátorskými oprávněními",admin_users_label:"ID uživatele",allowed_users:"Povolení uživatelé",allowed_users_hint:"Pouze tito uživatelé mohou používat LNbits.",allowed_users_label:"Uživatelské ID",allow_creation_user:"Povolit vytvoření nových uživatelů",allow_creation_user_desc:"Povolit vytváření nových uživatelů na úvodní stránce",components:"Soubory",long_running_endpoints:"Top 5 dlouho běžících koncových bodů",http_request_methods:"Metody HTTP požadavků",http_response_codes:"Kódy HTTP odpovědí",request_details:"Podrobnosti žádosti",http_request_details:"Podrobnosti HTTP žádosti",block_explorer:"Průzkumník bloků",enable_block_explorer:"Povolit průzkumník bloků",block_explorer_desc:"Umožňuje uživatelům procházet bitcoinové transakce a adresy přes Electrum.",blockexplorer_public_api:"Veřejný přístup k API",blockexplorer_public_api_desc:"Povolit neověřený přístup k API koncovým bodům průzkumníku bloků.",electrum_server_url:"URL Electrum serveru",electrum_server_url_hint:"např. ssl://electrum.blockstream.info:50002 nebo tcp://localhost:50001",blockexplorer_search_label:"Hledat podle TXID nebo adresy",blockexplorer_search_hint:"64-znakový hex = transakce · cokoli jiného = bitcoinová adresa",recent_blocks:"Nedávné bloky",chain_tip:"Vrchol řetězu",block_height:"Výška bloku",block_fee:"poplatek bloku",fee_estimates:"Odhady poplatků",confirmed_balance:"Potvrzený zůstatek",unconfirmed_balance:"Nepotvrzený zůstatek",transaction_history:"Historie transakcí",coinbase:"Coinbase",inputs:"Vstupy",outputs:"Výstupy",confirmations:"Potvrzení",confirmed:"Potvrzeno",unconfirmed:"Nepotvrzeno",history_unavailable:"Historie transakcí nedostupná (adresa má příliš mnoho transakcí)",address:"Adresa",block_number:"Blok #{height}",block_diff:"obth. {value}",block_hash:"Hash",previous_block:"Předchozí blok",merkle_root:"Merkle kořen",version:"Verze",bits:"Bity",difficulty:"Obtížnost",nonce:"Nonce",txid:"TXID",vsize:"Virtuální velikost",weight:"Váha",n_block_fee:"poplatek {n} bloků"},window.localisation.sk={confirm:"Áno",server:"Server",theme:"Téma",site_customisation:"Prispôsobenie lokality",funding:"Financovanie",users:"Používatelia",audit:"Audit",apps:"Aplikácie",channels:"Kanály",transactions:"Transakcie",dashboard:"Prehľad",node:"Uzol",export_users:"Exportovať používateľov",no_users:"Nenašli sa žiadni používatelia",total_capacity:"Celková kapacita",avg_channel_size:"Priemerná veľkosť kanálu",biggest_channel_size:"Najväčší kanál",smallest_channel_size:"Najmenší kanál",number_of_channels:"Počet kanálov",active_channels:"Aktívne kanály",connect_peer:"Pripojiť peer",connect:"Pripojiť",open_channel:"Otvoriť kanál",open:"Otvoriť",close_channel:"Zatvoriť kanál",close:"Zatvoriť",restart:"Reštartovať server",save:"Uložiť",save_tooltip:"Uložiť vaše zmeny",credit_debit:"Kreditná / Debetná",credit_hint:"Stlačte Enter pre pripísanie na účet",credit_label:"{denomination} na pripísanie",restart_tooltip:"Pre prejavenie zmien reštartujte server",add_funds_tooltip:"Pridať prostriedky do peňaženky.",reset_defaults:"Obnoviť predvolené",reset_defaults_tooltip:"Odstrániť všetky nastavenia a obnoviť predvolené.",download_backup:"Stiahnuť zálohu databázy",name_your_wallet:"Pomenujte vašu {name} peňaženku",paste_invoice_label:"Vložte faktúru, platobnú požiadavku alebo lnurl kód *",lnbits_description:"Ľahko nastaviteľný a ľahkotonážny, LNbits môže bežať na akomkoľvek zdroji financovania Lightning Network a dokonca LNbits samotný! LNbits môžete používať pre seba, alebo ľahko ponúknuť správcovské riešenie pre iných. Každá peňaženka má svoje vlastné API kľúče a nie je limit na počet peňaženiek, ktoré môžete vytvoriť. Schopnosť rozdeľovať finančné prostriedky robí z LNbits užitočný nástroj pre správu peňazí a ako vývojový nástroj. Rozšírenia pridávajú extra funkčnosť do LNbits, takže môžete experimentovať s radou najnovších technológií na lightning sieti. Vývoj rozšírení sme urobili čo najjednoduchší a ako voľný a open-source projekt, podporujeme ľudí vývoj a odovzdávanie vlastných rozšírení.",export_to_phone:"Exportovať do telefónu s QR kódom",export_to_phone_desc:"Tento QR kód obsahuje URL vašej peňaženky s plným prístupom. Môžete ho naskenovať z vášho telefónu a otvoriť vašu peňaženku odtiaľ.",wallet:"Peňaženka:",wallets:"Peňaženky",add_wallet:"Pridať novú peňaženku",delete_wallet:"Zmazať peňaženku",delete_wallet_desc:"Celá peňaženka bude zmazaná, prostriedky budú NEOBNOVITEĽNÉ.",rename_wallet:"Premenovať peňaženku",update_name:"Aktualizovať meno",fiat_tracking:"Sledovanie fiat",currency:"Mena",update_currency:"Aktualizovať menu",press_to_claim:"Stlačte pre nárok na bitcoin",donate:"Prispieť",view_github:"Zobraziť na GitHube",voidwallet_active:"VoidWallet je aktívny! Platby zakázané",use_with_caution:"POUŽÍVAJTE OPATRNE - {name} peňaženka je stále v BETE",service_fee:"Servisný poplatok: {amount} % za transakciu",service_fee_max:"Servisný poplatok: {amount} % za transakciu (max {max} satoshi)",service_fee_tooltip:"Servisný poplatok účtovaný správcom LNbits servera za odchádzajúcu transakciu",toggle_darkmode:"Prepnúť Tmavý režim",payment_reactions:"Reakcie na platbu",view_swagger_docs:"Zobraziť LNbits Swagger API dokumentáciu",api_docs:"API dokumentácia",api_keys_api_docs:"Adresa uzla, API kľúče a API dokumentácia",api_keys_warning:"Tieto kľúče uchovávajte v bezpečí, ich zdieľanie môže viesť k strate prostriedkov.",admin_key_warning:"Váš administrátorský kľúč poskytuje úplný prístup k peňaženke vrátane možnosti odosielať platby. Nikdy ho nezdieľajte, pokiaľ príjemcovi úplne nedôverujete.",lnbits_version:"Verzia LNbits",runs_on:"Beží na",paste:"Vložiť",paste_from_clipboard:"Vložiť zo schránky",paste_request:"Vložiť požiadavku",create_invoice:"Vytvoriť faktúru",camera_tooltip:"Použite kameru na naskenovanie faktúry/QR",export_csv:"Exportovať do CSV",chart_tooltip:"Zobraziť graf",pending:"Čakajúce",copy_invoice:"Kopírovať faktúru",withdraw_from:"Vybrať z",cancel:"Zrušiť",scan:"Skenovať",read:"Čítať",pay:"Platiť",memo:"Poznámka",date:"Dátum",payment_processing:"Spracovávanie platby...",not_enough_funds:"Nedostatok prostriedkov!",search_by_tag_memo_amount:"Vyhľadať podľa značky, poznámky, sumy",invoice_waiting:"Faktúra čakajúca na zaplatenie",payment_received:"Platba prijatá",payment_sent:"Platba odoslaná",receive:"prijímať",send:"posielať",outgoing_payment_pending:"Odchádzajúca platba čaká",drain_funds:"Vyprázdniť prostriedky",drain_funds_desc:"Toto je LNURL-withdraw QR kód pre vyprázdnienie všetkého z tejto peňaženky. S nikým ho nezdieľajte. Je kompatibilný s balanceCheck a balanceNotify, takže vaša peňaženka môže naďalej kontinuálne vyťahovať prostriedky odtiaľto po prvom výbere.",i_understand:"Rozumiem",copy_wallet_url:"Kopírovať URL peňaženky",disclaimer_dialog_title:"Dôležité!",disclaimer_dialog:"Funkcionalita prihlásenia bude vydaná v budúcej aktualizácii, zatiaľ si uistite, že ste si túto stránku pridali medzi záložky pre budúci prístup k vašej peňaženke! Táto služba je v BETA verzii a nenesieme zodpovednosť za stratu prístupu k prostriedkom.",no_transactions:"Zatiaľ žiadne transakcie",manage:"Spravovať",exchanges:"Burzy",extensions:"Rozšírenia",no_extensions:"Nemáte nainštalované žiadne rozšírenia :(",created:"Vytvorené",search_extensions:"Hľadať rozšírenia",extension_sources:"Rozšírenie zdrojov",ext_sources_hint:"Úložiská, z ktorých sa môžu stiahnuť rozšírenia.",ext_sources_label:"Zdrojová URL (použite iba oficiálny zdroj rozšírenia LNbits a zdroje, ktorým môžete dôverovať)",warning:"Upozornenie",repository:"Repozitár",confirm_continue:"Ste si istí, že chcete pokračovať?",manage_extension_details:"Inštalovať/odinštalovať rozšírenie",install:"Inštalovať",uninstall:"Odinštalovať",drop_db:"Odstrániť údaje",enable:"Povoliť",pay_to_enable:"Zaplaťte na aktiváciu",enable_extension_details:"Povoliť rozšírenie pre aktuálneho používateľa",disable:"Zakázať",delete:"Odstrániť",installed:"Nainštalované",activated:"Aktivované",deactivated:"Deaktivované",release_notes:"Poznámky k vydaniu",activate_extension_details:"Sprístupniť/neprístupniť rozšírenie pre používateľov",featured:"Odporúčané",all:"Všetky",only_admins_can_install:"(Iba administrátorské účty môžu inštalovať rozšírenia)",admin_only:"Iba pre administrátorov",new_version:"Nová verzia",extension_depends_on:"Závisí na:",extension_rating_soon:"Hodnotenia budú čoskoro dostupné",extension_installed_version:"Nainštalovaná verzia",extension_uninstall_warning:"Chystáte sa odstrániť rozšírenie pre všetkých používateľov.",uninstall_confirm:"Áno, Odinštalovať",extension_db_drop_info:"Všetky údaje pre rozšírenie budú trvalo vymazané. Túto operáciu nie je možné vrátiť!",extension_db_drop_warning:"Chystáte sa odstrániť všetky údaje pre rozšírenie. Pre pokračovanie prosím napíšte názov rozšírenia:",extension_required_lnbits_version:"Toto vydanie vyžaduje aspoň verziu LNbits",min_version:"Minimum (vrátane)",max_version:"Maximálne (vylúčené)",payment_hash:"Hash platby",fee:"Poplatok",amount:"Suma",amount_sats:"Suma (sats)",tag:"Tag",unit:"Jednotka",description:"Popis",expiry:"Expirácia",webhook:"Webhook",payment_proof:"Dôkaz platby",update:"Aktualizovať",update_available:"Dostupná aktualizácia {version}!",latest_update:"Máte najnovšiu verziu {version}.",notifications:"Notifikácie",no_notifications:"Žiadne notifikácie",notifications_disabled:"Notifikácie stavu LNbits sú zakázané.",enable_notifications:"Povoliť Notifikácie",enable_notifications_desc:"Ak povolené, budú sa načítavať najnovšie aktualizácie stavu LNbits, ako sú bezpečnostné incidenty a aktualizácie.",enable_watchdog:"Povoliť Watchdog",enable_watchdog_desc:"Ak povolené, vaš zdroj financovania sa automaticky zmení na VoidWallet, ak je váš zostatok nižší ako zostatok LNbits. Po aktualizácii bude treba povoliť manuálne.",watchdog_interval:"Interval Watchdog",watchdog_interval_desc:"Ako často by malo pozadie kontrolovať signál killswitch v watchdog delta [node_balance - lnbits_balance] (v minútach).",watchdog_delta:"Delta Watchdog",watchdog_delta_desc:"Limit pred zmenou zdroja financovania na VoidWallet [lnbits_balance - node_balance > delta]",status:"Stav",notification_source:"Zdroj notifikácií",notification_source_label:"URL zdroja (používajte len oficiálny LNbits zdroj stavu a zdroje, ktorým môžete dôverovať)",more:"viac",less:"menej",releases:"Vydania",watchdog:"Watchdog",server_logs:"Logy servera",ip_blocker:"Blokovanie IP",security:"Bezpečnosť",security_tools:"Nástroje bezpečnosti",block_access_hint:"Blokovať prístup podľa IP",allow_access_hint:"Povoliť prístup podľa IP (prebije blokované IP)",enter_ip:"Zadajte IP a stlačte enter",rate_limiter:"Obmedzovač počtu požiadaviek",wallet_limiter:"Obmedzovač peňaženky",wallet_limit_max_withdraw_per_day:"Maximálny denný výber z peňaženky v satošiach (0 pre zrušenie)",wallet_max_ballance:"Maximálny zostatok v peňaženke v satošiach (0 pre deaktiváciu)",wallet_limit_secs_between_trans:"Minimálny počet sekúnd medzi transakciami na peňaženku (0 na deaktiváciu)",number_of_requests:"Počet požiadaviek",time_unit:"Časová jednotka",minute:"minúta",second:"sekunda",hour:"hodina",disable_server_log:"Zakázať Log servera",enable_server_log:"Povoliť Log servera",coming_soon:"Funkcia bude čoskoro dostupná",session_has_expired:"Vaša relácia vypršala. Prosím, prihláste sa znova.",instant_access_question:"Chcete okamžitý prístup?",login_with_user_id:"Prihlásiť sa s používateľským ID",or:"alebo",create_new_wallet:"Vytvoriť novú peňaženku",login_to_account:"Prihláste sa do vášho účtu",create_account:"Vytvoriť účet",account_settings:"Nastavenia účtu",signin_with_nostr:"Pokračovať s Nostr",signin_with_google:"Prihlásiť sa pomocou Google",signin_with_github:"Prihlásiť sa pomocou GitHub",signin_with_keycloak:"Prihlásiť sa pomocou Keycloak",username_or_email:"Používateľské meno alebo email",password:"Heslo",password_config:"Konfigurácia hesla",password_repeat:"Opakovanie hesla",change_password:"Zmeniť heslo",update_credentials:"Aktualizovať poverenia",update_pubkey:"Aktualizovať verejný kľúč",set_password:"Nastaviť heslo",invalid_password:"Heslo musí mať aspoň 8 znakov",login:"Prihlásenie",register:"Registrovať",username:"Používateľské meno",pubkey:"Verejný kľúč",user_id:"ID používateľa",email:"Email",first_name:"Meno",last_name:"Priezvisko",picture:"Obrázok",verify_email:"Overiť e-mail s",account:"Účet",update_account:"Aktualizovať účet",invalid_username:"Neplatné užívateľské meno",auth_provider:"Poskytovateľ autentifikácie",my_account:"Môj účet",back:"Späť",logout:"Odhlásiť sa",look_and_feel:"Vzhľad a dojem",toggle_gradient:"Prepnúť prechodový režim",gradient_background:"Gradientné pozadie",language:"Jazyk",color_scheme:"Farebná schéma",admin_settings:"Nastavenia správcu",extension_cost:"Táto verzia vyžaduje minimálnu platbu {cost} satoshi.",extension_paid_sats:"Už ste zaplatili {paid_sats} sats.",release_details_error:"Nepodarilo sa získať podrobnosti o vydaní.",pay_from_wallet:"Zaplatiť z peňaženky",wallet_required:"Peňaženka *",show_qr:"Zobraziť QR",retry_install:"Skúste inštaláciu znova",new_payment:"Vytvoriť novú platbu",update_payment:"Aktualizovať platbu",already_paid_question:"Už ste zaplatili?",sell:"Predať",sell_require:"Požiadajte o platbu na povolenie rozšírenia",sell_info:"Rozšírenie {name} vyžaduje platbu minimálne {amount} sats na aktiváciu.",hide_empty_wallets:"Skryť prázdne peňaženky",recheck:"Prekontrolovať znova",contributors:"Prispievatelia",license:"Licencia",reset_key:"Resetovať kľúč",reset_password:"Obnoviť heslo",border_choices:"Výber obrysov",select_all:"Vybrať všetko",nfc_supported:"Podpora NFC",nfc_not_supported:"NFC nie je podporované",expire_date:"Dátum exspirácie:",hash:"Hash:",welcome_lnbits:"Vitajte v LNbits",setup_su_account:"Nastavte účet Superuser nižšie.",create_ticker_converter:"Vytvoriť prevodník mienových tickerov",enable_audit:"Povoliť audit",recommended:"Odporúčané",audit_desc:"Zaznamenávajte HTTP požiadavky podľa špecifikovaných filtrov.",audit_record_req:"Zaznamenať telo žiadosti",audit_record_warning:"Upozornenie:",audit_record_req_warning_1:"dôverné údaje (ako napríklad heslá) budú zaznamenané.",audit_record_req_warning_2:"telo žiadosti môže mať veľkú veľkosť.",audit_record_use:"Používajte to s opatrnosťou.",audit_ip:"Zaznamenať IP adresu",audit_ip_desc:"Zaznamenajte IP adresu klienta",audit_path_params:"Zaznamenať hodnoty cesty",audit_query_params:"Zaznamenať parametre dopytu",audit_http_methods:"Zahrnúť metódy HTTP",audit_http_methods_hint:"Zoznam zahrnutých metód HTTP. Prázdne zoznamy znamenajú všetky.",audit_http_methods_label:"HTTP metódy",audit_resp_codes:"Zahrnúť kódy odpovede HTTP",audit_resp_codes_hint:"Zoznam kódov HTTP, ktoré sa majú zahrnúť (zhoda s regexom). Prázdny zoznam znamená všetky. Napr: 4.*, 5.*",audit_resp_codes_label:"Kód odpovede HTTP (regex)",audit_paths:"Cesty zahrnúť",audit_paths_hint:"Zoznam ciest, ktoré sa majú zahrnúť (zhoda s regexom). Prázdny zoznam znamená všetky.",audit_paths_label:"HTTP cesta (regex)",audit_paths_exclude:"Vylúčiť cesty",audit_paths_exclude_hint:"Zoznam ciest, ktoré majú byť vylúčené (zhoda s regexom). Prázdny zoznam znamená žiadne.",audit_paths_exclude_label:"Cesta HTTP (regex)",exchange_providers:"Poskytovatelia výmeny",admin_extensions:"Rozšírenia administrátora",admin_extensions_label:"Rozšírenia správcu",admin_extensions_hint:"Rozšírenia môže používať iba používateľ s administrátorskými právami.",user_default_extensions:"Predvolené rozšírenia používateľa",user_default_extensions_label:"Používateľské rozšírenia",user_default_extensions_hint:"Rozšírenia, ktoré budú predvolene povolené pre používateľov.",miscellanous:"Rôzne",misc_disable_extensions:"Zakázať rozšírenia",misc_disable_extensions_label:"Zakázať všetky rozšírenia",misc_hide_api:"Skryť API",misc_hide_api_label:"Skryje API peňaženky, rozšírenia sa môžu rozhodnúť dodržiavať",wallets_management:"Správa peňaženiek",funding_source_info:"Informácie o zdroji financovania",funding_source:"Zdroj financovania: {wallet_class}",node_balance:"Stav uzla: {balance} sats",lnbits_balance:"Zostatok LNbits: {balance} sats",funding_reserve_percent:"Rezervovať percento: {percent} %",node_management:"Správa uzlov",node_management_not_supported:"Správa uzlov nie je podporovaná aktívnym zdrojom financovania",toggle_node_ui:"Používateľské rozhranie uzla",toggle_public_node_ui:"Verejné používateľské rozhranie uzla",toggle_transactions_node_ui:"Karta transakcií (Zakázať na veľkých CLN uzloch)",invoice_expiry:"Platnosť faktúry",invoice_expiry_label:"Doba platnosti faktúry (sekundy)",fee_reserve:"Rezerva poplatkov",fee_reserve_msats:"Rezervačný poplatok v msats",fee_reserve_percent:"Rezervačný poplatok v percentách",server_management:"Správa servera",base_url:"Základná URL adresa",base_url_label:"Statická/Základná URL adresa pre server",authentication:"Autentifikácia",auth_token_expiry_label:"Minúty do vypršania tokenu",auth_token_expiry_hint:"Čas v minútach do vypršania platnosti tokenu",auth_allowed_methods_label:"Povolené metódy autorizácie",auth_allowed_methods_hint:"Vyberte metódy autorizácie",auth_nostr_label:"Adresa URL žiadosti Nostr",auth_nostr_hint:"Absolútna URL adresa, ktorú klienti použijú na prihlásenie.",auth_google_ci_label:"ID klienta Google",auth_google_ci_hint:"Uistite sa, že autorizované presmerovacie URI obsahujú https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google Client Secret",auth_gh_client_id_label:"Identifikátor klienta GitHub",auth_gh_client_id_hint:"Uistite sa, že URL adresa pre spätné volanie autorizácie je nastavená na https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub Client Secret",auth_keycloak_label:"URL zistenia Keycloak",auth_keycloak_ci_label:"ID klienta Keycloak",auth_keycloak_ci_hint:"Uistite sa, že URL spätného volania autorizácie je nastavená na https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Tajný kľúč klienta Keycloak",auth_keycloak_custom_org_label:"Vlastná organizácia Keycloak",auth_keycloak_custom_icon_label:"Vlastná ikona Keycloak (URL)",auth_oidc_label:"URL zistenia OIDC",auth_oidc_ci_label:"ID klienta OIDC",auth_oidc_ci_hint:"Uistite sa, že URL spätného volania autorizácie je nastavená na https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"Tajný kľúč klienta OIDC",auth_oidc_custom_org_label:"Názov vlastnej organizácie OIDC (napr. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Vlastná ikona OIDC (URL)",currency_settings:"Nastavenia meny",allowed_currencies:"Povolené meny",allowed_currencies_hint:"Obmedzte počet dostupných fiat mien",default_account_currency:"Predvolená mena účtu",default_account_currency_hint:"Predvolená mena pre účtovníctvo",service_fee_label:"Poplatok za službu (%)",service_fee_hint:"Poplatok účtovaný za transakciu (%)",service_fee_max_label:"Poplatok za službu max (sats)",service_fee_max_hint:"Maximálny servisný poplatok na účtovanie v (sats)",fee_wallet:"Peňaženka s poplatkami",fee_wallet_label:"Peňaženka poplatkov (ID peňaženky)",fee_wallet_hint:"ID peňaženky, do ktorej sa majú odoslať prostriedky",disable_fee:"Zakázať poplatok",disable_fee_internal:"Zakázať poplatok za službu pre interné platby",disable_fee_internal_desc:"Zakázať poplatok za službu pre interné platby Lightning",ui_management:"Správa používateľského rozhrania",ui_site_title:"Názov stránky",ui_site_tagline:"Slogan webovej stránky",ui_elements_enable:"Povoliť prvky na domovskej stránke",ui_elements_disable:"Zakázať prvky na domovskej stránke",ui_toggle_elements_tip:"Odstrániť prvky úvodnej stránky, ako napríklad 'používa' atď.",ui_site_description:"Popis lokality",ui_site_description_hint:"Použite obyčajný text, Markdown alebo surové HTML.",ui_default_wallet_name:"Predvolený názov peňaženky",lnbits_wallet:"LNbits peňaženka",denomination:"Nominálna hodnota",denomination_hint:"Názov pre token FakeWallet",ui_qr_code_logo:"Logo QR kódu",ui_qr_code_logo_hint:"URL k obrázku loga v QR kóde",ui_custom_badge:"Vlastná odznak",ui_custom_badge_label:"Vlastný odznak 'POUŽÍVAŤ S OPATRNOSŤOU - LNbits peňaženka je stále v BETA verzii'",ui_custom_badge_color_label:"Vlastná farba odznaku",themes:"Motívy",themes_hint:"Vyberte témy dostupné pre používateľov",custom_logo:"Vlastné logo",custom_logo_hint:"URL k obrázku loga",ad_space_title:"Názov reklamného priestoru",ad_space_title_label:"Podporované spoločnosťou",ad_slots:"Reklamné sloty",ad_slots_hint:"Pridajte URL adresu a cesty k obrazovým súborom vo formáte CSV, rozšírenia sa môžu rozhodnúť dodržať",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Reklamy povolené",ads_disabled:"Reklamy deaktivované",user_management:"Správa používateľov",admin_users:"Administrátorskí používatelia",admin_users_hint:"Používatelia s administrátorskými oprávneniami",admin_users_label:"ID používateľa",allowed_users:"Povolení používatelia",allowed_users_hint:"Iba títo používatelia môžu používať LNbits.",allowed_users_label:"ID používateľa",allow_creation_user:"Povoliť vytváranie nových používateľov",allow_creation_user_desc:"Povoliť vytváranie nových používateľov na indexovej stránke",components:"Súčasti",long_running_endpoints:"Top 5 dlho bežiacich koncových bodov",http_request_methods:"Metódy HTTP žiadostí",http_response_codes:"Kódy odpovedí HTTP",request_details:"Podrobnosti žiadosti",http_request_details:"Podrobnosti požiadavky HTTP",block_explorer:"Prehliadač blokov",enable_block_explorer:"Povoliť prehliadač blokov",block_explorer_desc:"Umožňuje používateľom prehliadať bitcoinové transakcie a adresy cez Electrum.",blockexplorer_public_api:"Verejný prístup k API",blockexplorer_public_api_desc:"Povoliť neoverený prístup k API koncovým bodom prieskumníka blokov.",electrum_server_url:"URL Electrum servera",electrum_server_url_hint:"napr. ssl://electrum.blockstream.info:50002 alebo tcp://localhost:50001",blockexplorer_search_label:"Hľadať podľa TXID alebo adresy",blockexplorer_search_hint:"64-znakový hex = transakcia · čokoľvek iné = bitcoinová adresa",recent_blocks:"Nedávne bloky",chain_tip:"Vrchol reťaze",block_height:"Výška bloku",block_fee:"poplatok bloku",fee_estimates:"Odhady poplatkov",confirmed_balance:"Potvrdený zostatok",unconfirmed_balance:"Nepotvrdený zostatok",transaction_history:"História transakcií",coinbase:"Coinbase",inputs:"Vstupy",outputs:"Výstupy",confirmations:"Potvrdenia",confirmed:"Potvrdené",unconfirmed:"Nepotvrdené",history_unavailable:"História transakcií nedostupná (adresa má príliš veľa transakcií)",address:"Adresa",block_number:"Blok #{height}",block_diff:"obth. {value}",block_hash:"Hash",previous_block:"Predchádzajúci blok",merkle_root:"Merkle koreň",version:"Verzia",bits:"Bity",difficulty:"Obťažnosť",nonce:"Nonce",txid:"TXID",vsize:"Virtuálna veľkosť",weight:"Váha",n_block_fee:"poplatok {n} blokov"},window.localisation.kr={confirm:"확인",server:"서버",theme:"테마",site_customisation:"사이트 사용자 정의",funding:"자금",users:"사용자",audit:"감사",apps:"앱",channels:"채널",transactions:"거래 내역",dashboard:"현황판",node:"노드",export_users:"사용자 내보내기",no_users:"사용자가 없습니다",total_capacity:"총 용량",avg_channel_size:"평균 채널 용량",biggest_channel_size:"가장 큰 채널 용량",smallest_channel_size:"가장 작은 채널 용량",number_of_channels:"채널 수",active_channels:"활성화된 채널",connect_peer:"피어 연결하기",connect:"연결하기",open_channel:"채널 개설하기",open:"개설",close_channel:"채널 폐쇄하기",close:"폐쇄",restart:"서버 재시작",save:"저장",save_tooltip:"변경 사항 저장",credit_debit:"크레딧 / 직불카드",credit_hint:"계정에 자금을 넣으려면 Enter를 눌러주세요",credit_label:"{denomination} 단위로 충전하기",credit_ok:"가상 자금({amount} sats) 입출금 성공. 지불은 자금 출처의 실제 자금에 따라 달라집니다.",restart_tooltip:"변경 사항을 적용하려면 서버를 재시작해야 합니다.",add_funds_tooltip:"지갑에 자금을 추가합니다.",reset_defaults:"기본 설정으로 돌아가기",reset_defaults_tooltip:"설정했던 내용들을 모두 지우고, 기본 설정으로 돌아갑니다.",download_backup:"데이터베이스 백업 다운로드",name_your_wallet:"사용할 {name}지갑의 이름을 정하세요",paste_invoice_label:"인보이스, 결제 요청, 혹은 lnurl 코드를 붙여넣으세요 *",lnbits_description:"설정이 쉽고 가벼운 LNbits는 어떤 라이트닝 네트워크의 예산 자원 위에서든 돌아갈 수 있습니다, 그리고 다른 LNbits 지갑들입니다. 스스로 사용하기 위해, 또는 다른 사람들에게 수탁형 솔루션을 제공하기 위해 LNbits를 운영할 수 있습니다. 각 지갑들은 자신만의 API key를 가지며, 생성 가능한 지갑의 수에는 제한이 없습니다. 자금을 분할할 수 있는 기능으로 인해, LNbits는 자금 운영 도구로써뿐만 아니라 개발 도구로써도 유용합니다. 확장 기능들은 LNbits에 여러분들이 라이트닝 네트워크의 다양한 최신 기술들을 수행해볼 수 있게 하는 추가 기능을 제공합니다. LNbits 개발진들은 확장 기능들의 개발 또한 가능한 쉽게 만들었으며, 무료 오픈 소스 프로젝트답게 사람들이 자신만의 확장 기능들을 개발하고 제출하기를 응원합니다.",export_to_phone:"QR 코드를 이용해 모바일 기기로 내보내기",export_to_phone_desc:"이 QR 코드는 선택된 지갑의 최대 접근 권한을 가진 전체 URL을 담고 있습니다. 스캔 후, 모바일 기기에서 지갑을 열 수 있습니다.",wallet:"지갑:",wallets:"지갑",add_wallet:"새로운 지갑을 추가합니다",delete_wallet:"지갑을 삭제합니다",delete_wallet_desc:"이 지갑은 삭제될 것이며, 삭제 시 지갑 내 자금은 복구가 불가능합니다.",rename_wallet:"지갑 이름 변경",update_name:"이름 변경하기",fiat_tracking:"법정통화 가격 표시",currency:"통화",update_currency:"통화 수정하기",press_to_claim:"비트코인을 수령하려면 눌러주세요",donate:"기부",view_github:"GitHub 페이지 보기",voidwallet_active:"VoidWallet이 활성화되었습니다! 결제가 불가능합니다.",use_with_caution:"주의하세요 - {name} 지갑은 아직 BETA 단계입니다.",service_fee:"서비스 수수료: 거래액의 {amount} %",service_fee_max:"서비스 수수료: 거래액의 {amount} % (최대 {max} sats)",service_fee_tooltip:"지불 결제 시마다 LNbits 서버 관리자에게 납부되는 서비스 수수료",toggle_darkmode:"다크 모드 전환",payment_reactions:"결제 반응",view_swagger_docs:"LNbits Swagger API 문서를 봅니다",api_docs:"API 문서",api_keys_api_docs:"노드 URL, API 키와 API 문서",api_keys_warning:"이 키는 안전하게 보관해야 하며, 공유하면 자금을 잃을 위험이 있습니다.",admin_key_warning:"관리자 키는 결제 전송을 포함하여 지갑에 대한 모든 권한을 부여합니다. 수신자를 완전히 신뢰하는 경우가 아니라면 절대 공유하지 마세요.",lnbits_version:"LNbits 버전",runs_on:"Runs on",paste:"붙여넣기",paste_from_clipboard:"클립보드에서 붙여넣기",paste_request:"지불 요청 붙여넣기",create_invoice:"인보이스 생성하기",camera_tooltip:"카메라를 이용해서 인보이스/QR을 스캔하세요",export_csv:"CSV 형태로 내보내기",chart_tooltip:"그래프로 보여주기",pending:"대기 중",copy_invoice:"인보이스 복사하기",withdraw_from:"출금",cancel:"취소",scan:"스캔",read:"분석하기",pay:"지불하기",memo:"Memo",date:"일시",payment_processing:"결제 처리 중...",not_enough_funds:"자금이 부족합니다!",search_by_tag_memo_amount:"태그, memo, 수량으로 검색하기",invoice_waiting:"결제를 기다리는 인보이스",payment_received:"받은 결제액",payment_sent:"보낸 결제액",receive:"받기",send:"보내기",outgoing_payment_pending:"지불 대기 중",drain_funds:"자금 비우기",drain_funds_desc:"이는 선택된 지갑으로부터 모든 자금을 인출하는 LNURL-withdraw QR 코드입니다. 그 누구와도 공유하지 마세요. balanceCheck 및 balanceNotify 기능과 호환되며, 당신의 지갑은 첫 출금 이후로도 계속 자금을 끌어당기고 있을 수 있습니다.",i_understand:"이해하였습니다",copy_wallet_url:"지갑 URL 복사하기",disclaimer_dialog_title:"중요!",disclaimer_dialog:"로그인 기능은 향후 업데이트를 통해 지원될 계획이지만, 현재로써는 이 페이지에 향후 다시 접속하기 위해 북마크 설정하는 것을 잊지 마세요! 이 서비스는 아직 BETA 과정에 있고, LNbits 개발자들은 자금 손실에 대해 전혀 책임을 지지 않습니다.",no_transactions:"아직 아무런 거래도 이루어지지 않았습니다",manage:"관리",exchanges:"거래소",extensions:"확장 기능",no_extensions:"아직 설치된 확장 기능들이 없네요 :(",created:"생성됨",search_extensions:"확장 기능 검색하기",extension_sources:"확장 소스",ext_sources_hint:"확장 프로그램을 다운로드할 수 있는 저장소",ext_sources_label:"출처 URL (공식 LNbits 확장 소스만 사용하고, 신뢰할 수 있는 출처를 사용하세요)",warning:"주의",repository:"저장소",confirm_continue:"정말로 계속할까요?",manage_extension_details:"확장 기능 설치/삭제하기",install:"설치",uninstall:"삭제",drop_db:"데이터 삭제",enable:"활성화",pay_to_enable:"지불하여 활성화",enable_extension_details:"현재 사용자 계정에 해당 확장 기능을 활성화합니다",disable:"비활성화",delete:"삭제",installed:"설치됨",activated:"작동됨",deactivated:"작동 중지",release_notes:"배포 노트",activate_extension_details:"사용자들의 확장 기능 사용 가능 여부를 결정합니다",featured:"추천",all:"전체",only_admins_can_install:"(관리자 계정만이 확장 기능을 설치할 수 있습니다)",admin_only:"관리자 전용",new_version:"새로운 버전",extension_depends_on:"의존성 존재:",extension_rating_soon:"평점 기능도 곧 구현됩니다",extension_installed_version:"설치된 버전",extension_uninstall_warning:"모든 사용자들로부터 이 확장 기능을 제거한다는 점에 유의하세요.",uninstall_confirm:"네, 삭제합니다",extension_db_drop_info:"해당 확장 기능의 모든 데이터가 영구적으로 삭제됩니다. 작업 수행 후에는 되돌릴 수 없습니다!",extension_db_drop_warning:"해당 확장 기능의 모든 데이터가 영구적으로 삭제될 겁니다. 계속하려면 확장 기능의 이름을 입력해주세요:",extension_required_lnbits_version:"이 배포 버전은 더 높은 버전의 lnbits가 설치되어 있어야 합니다.",min_version:"최소값 (포함됨)",max_version:"최대값 (제외됨)",payment_hash:"결제 해쉬값",fee:"수수료",amount:"액수",amount_sats:"금액 (사토시)",tag:"태그",unit:"단위",description:"상세",expiry:"만료",webhook:"Webhook",payment_proof:"Payment 증거",update:"업데이트",update_available:"{version}으로 업데이트가 가능합니다.",latest_update:"이미 {version} 버전으로 업데이트되었습니다.",notifications:"알림",no_notifications:"알림 없음",notifications_disabled:"LNbits 상태 알림이 비활성화되었습니다.",enable_notifications:"알림 활성화",enable_notifications_desc:"활성화 시, 가장 최신의 보안 사고나 소프트웨어 업데이트 등의 LNbits 상황 업데이트를 불러옵니다.",enable_watchdog:"와치독 활성화",enable_watchdog_desc:"활성화 시, LNbits 잔금보다 당신의 잔금이 지정한 수준보다 더 낮아질 경우 자동으로 자금의 원천을 VoidWallet으로 변경합니다. 업데이트 이후 수동으로 활성화해 주어야 합니다.",watchdog_interval:"와치독 시간 간격",watchdog_interval_desc:"와치독 델타 값을 기반으로 하여 당신의 LNbits 서버에서 나오는 비상 정지 신호를 백그라운드 작업으로 얼마나 자주 확인할 것인지를 결정합니다. (분 단위)",watchdog_delta:"와치독 델타",watchdog_delta_desc:"당신의 자금 원천을 VoidWallet으로 변경하기까지의 기준 값 [LNbits 잔액 - 노드 잔액 > 델타 값]",status:"상황",notification_source:"알림 메세지 출처",notification_source_label:"알림 메세지를 가져올 URL (공식 LNbits 상황판 출처나, 당신이 신뢰할 수 있는 출처만을 사용하세요)",more:"더 알아보기",less:"적게",releases:"배포 버전들",watchdog:"와치독",server_logs:"서버 로그",ip_blocker:"IP 기반 차단기",security:"보안",security_tools:"보안 도구들",block_access_hint:"IP 기준으로 접속 차단하기",allow_access_hint:"IP 기준으로 접속 허용하기 (차단한 IP들을 무시합니다)",enter_ip:"IP 주소를 입력하고 Enter를 눌러주세요",rate_limiter:"횟수로 제한하기",wallet_limiter:"지갑 제한기",wallet_limit_max_withdraw_per_day:"일일 최대 지갑 출금액(sats) (0은 비활성화)",wallet_max_ballance:"지갑 최대 잔액(sats) (0은 비활성화)",wallet_limit_secs_between_trans:"지갑 당 거래 사이 최소 초 (0은 비활성화)",number_of_requests:"요청 횟수",time_unit:"시간 단위",minute:"분",second:"초",hour:"시간",disable_server_log:"서버 로깅 중단하기",enable_server_log:"서버 로깅 활성화하기",coming_soon:"곧 구현될 기능들입니다",session_has_expired:"세션 유효 기간이 만료되었습니다. 다시 로그인해 주세요.",instant_access_question:"즉시 액세스하시겠습니까?",login_with_user_id:"사용자 ID로 로그인",or:"또는",create_new_wallet:"새 지갑 만들기",login_to_account:"계정에 로그인하세요.",create_account:"계정 생성",account_settings:"계정 설정",signin_with_nostr:"Nostr로 계속하기",signin_with_google:"Google으로 로그인",signin_with_github:"GitHub으로 로그인",signin_with_keycloak:"Keycloak으로 로그인",username_or_email:"사용자 이름 또는 이메일",password:"비밀번호",password_config:"비밀번호 설정",password_repeat:"비밀번호 재입력",change_password:"비밀번호 변경",update_credentials:"자격 증명 업데이트",update_pubkey:"공개 키 업데이트",set_password:"비밀번호 설정",invalid_password:"비밀번호는 최소 8자 이상이어야 합니다",login:"로그인",register:"등록",username:"사용자 이름",pubkey:"공개 키",user_id:"사용자 ID",email:"이메일",first_name:"성명",last_name:"성",picture:"사진",verify_email:"이메일을 인증하려면",account:"계정",update_account:"계정 업데이트",invalid_username:"잘못된 사용자 이름",auth_provider:"인증 제공자",my_account:"내 계정",back:"뒤로",logout:"로그아웃",look_and_feel:"외관과 느낌",toggle_gradient:"그라디언트 전환",gradient_background:"그라디언트 배경",language:"언어",color_scheme:"색상 구성",admin_settings:"관리자 설정",extension_cost:"이 버전은 최소 {cost} sats의 지불이 필요합니다.",extension_paid_sats:"당신은 이미 {paid_sats} sats를 지불했습니다.",release_details_error:"릴리스 세부 정보를 가져올 수 없습니다.",pay_from_wallet:"지갑에서 결제하다",wallet_required:"지갑 *",show_qr:"QR 보기",retry_install:"다시 설치하세요",new_payment:"새로운 결제하기",update_payment:"결제 업데이트",already_paid_question:"이미 지불하셨나요?",sell:"판매",sell_require:"확장을 활성화하려면 결제를 요청하십시오.",sell_info:"{name} 확장 기능을 활성화하려면 최소 {amount} 사토시의 결제가 필요합니다.",hide_empty_wallets:"빈 지갑 숨기기",recheck:"재확인",contributors:"기여자",license:"라이선스",reset_key:"재설정 키",reset_password:"비밀번호 재설정",border_choices:"테두리 선택사항",select_all:"모두 선택",nfc_supported:"NFC 지원됨",nfc_not_supported:"NFC 지원되지 않음",expire_date:"만료 날짜:",hash:"해시:",welcome_lnbits:"LNbits에 오신 것을 환영합니다.",setup_su_account:"슈퍼유저 계정을 아래에 설정하십시오.",create_ticker_converter:"통화 티커 변환기 생성",enable_audit:"감사 활성화",recommended:"추천됨",audit_desc:"지정된 필터에 따라 HTTP 요청 기록",audit_record_req:"레코드 요청 본문",audit_record_warning:"경고:",audit_record_req_warning_1:"암호와 같은 기밀 데이터가 기록됩니다.",audit_record_req_warning_2:"요청 본문은 큰 크기를 가질 수 있습니다.",audit_record_use:"주의해서 사용하십시오.",audit_ip:"IP 주소 기록",audit_ip_desc:"클라이언트의 IP 주소를 기록하십시오.",audit_path_params:"경로 매개변수 기록",audit_query_params:"쿼리 매개변수 기록",audit_http_methods:"HTTP 메서드 포함",audit_http_methods_hint:"포함할 HTTP 메서드 목록. 목록이 비어 있으면 모두 포함됩니다.",audit_http_methods_label:"HTTP 방법",audit_resp_codes:"HTTP 응답 코드 포함",audit_resp_codes_hint:"포함할 HTTP 코드 목록(정규 표현식 일치). 빈 목록은 모두를 의미합니다. 예: 4.*, 5.*",audit_resp_codes_label:"HTTP 응답 코드 (정규식)",audit_paths:"포함 경로",audit_paths_hint:"포함할 경로 목록 (정규 표현식 일치). 빈 목록은 모두를 의미합니다.",audit_paths_label:"HTTP 경로 (정규식)",audit_paths_exclude:"제외 경로",audit_paths_exclude_hint:"제외할 경로 목록 (정규 표현식 일치). 빈 목록은 없음을 의미합니다.",audit_paths_exclude_label:"HTTP 경로 (정규식)",exchange_providers:"거래소 공급자",admin_extensions:"관리자 확장 프로그램",admin_extensions_label:"관리자 확장 기능",admin_extensions_hint:"확장 기능은 관리자 권한이 있는 사용자만 사용할 수 있습니다.",user_default_extensions:"사용자 기본 확장자",user_default_extensions_label:"사용자 확장 기능",user_default_extensions_hint:"사용자에게 기본적으로 활성화될 확장 기능.",miscellanous:"기타",misc_disable_extensions:"확장 프로그램 사용 안 함",misc_disable_extensions_label:"모든 확장 프로그램 비활성화",misc_hide_api:"API 숨기기",misc_hide_api_label:"지갑 API 숨기기, 확장 기능은 준수할 수 있음",wallets_management:"지갑 관리",funding_source_info:"자금 출처 정보",funding_source:"자금 출처: {wallet_class}",node_balance:"노드 잔액: {balance} 사토시",lnbits_balance:"LNbits 잔액: {balance} sats",funding_reserve_percent:"예약 비율: {percent} %",node_management:"노드 관리",node_management_not_supported:"활성화된 자금 출처에 의해 노드 관리는 지원되지 않습니다.",toggle_node_ui:"노드 UI",toggle_public_node_ui:"공개 노드 UI",toggle_transactions_node_ui:"트랜잭션 탭 (대형 CLN 노드에서는 비활성화)",invoice_expiry:"송장 만료",invoice_expiry_label:"송장 만료 (초)",fee_reserve:"수수료 예약",fee_reserve_msats:"msats의 예약 수수료",fee_reserve_percent:"예약 수수료(%)",server_management:"서버 관리",base_url:"기본 URL",base_url_label:"서버의 정적/기본 URL",authentication:"인증",auth_token_expiry_label:"토큰 만료 시간(분)",auth_token_expiry_hint:"토큰이 만료되기까지 남은 시간(분)",auth_allowed_methods_label:"허용된 인증 방법",auth_allowed_methods_hint:"인증 방법 선택",auth_nostr_label:"Nostr 요청 URL",auth_nostr_hint:"클라이언트가 로그인하는 데 사용할 절대 URL.",auth_google_ci_label:"Google 클라이언트 ID",auth_google_ci_hint:"허가된 리디렉션 URI에 https://{domain}/api/v1/auth/google/token이 포함되어 있는지 확인하세요.",auth_google_cs_label:"Google 클라이언트 시크릿",auth_gh_client_id_label:"GitHub 클라이언트 ID",auth_gh_client_id_hint:"인가 콜백 URL이 https://{domain}/api/v1/auth/github/token으로 설정되어 있는지 확인하십시오.",auth_gh_client_secret_label:"GitHub 클라이언트 비밀키",auth_keycloak_label:"Keycloak 디스커버리 URL",auth_keycloak_ci_label:"키클록 클라이언트 ID",auth_keycloak_ci_hint:"승인 콜백 URL이 https://{domain}/api/v1/auth/keycloak/token으로 설정되어 있는지 확인하십시오.",auth_keycloak_cs_label:"Keycloak 클라이언트 시크릿",auth_keycloak_custom_org_label:"Keycloak 사용자 정의 조직",auth_keycloak_custom_icon_label:"Keycloak 사용자 정의 아이콘 (URL)",auth_oidc_label:"OIDC 디스커버리 URL",auth_oidc_ci_label:"OIDC 클라이언트 ID",auth_oidc_ci_hint:"승인 콜백 URL이 https://{domain}/api/v1/auth/oidc/token으로 설정되어 있는지 확인하십시오.",auth_oidc_cs_label:"OIDC 클라이언트 시크릿",auth_oidc_custom_org_label:"OIDC 사용자 정의 조직 이름 (예: Zitadel, Authentik)",auth_oidc_custom_icon_label:"OIDC 사용자 정의 아이콘 (URL)",currency_settings:"통화 설정",allowed_currencies:"허용되는 통화",allowed_currencies_hint:"사용 가능한 법정 화폐의 수를 제한하십시오.",default_account_currency:"기본 계좌 통화",default_account_currency_hint:"회계 기본 통화",service_fee_label:"서비스 수수료 (%)",service_fee_hint:"트랜잭션당 수수료 (%)",service_fee_max_label:"서비스 수수료 최대 (sats)",service_fee_max_hint:"(사토시)로 부과할 최대 서비스 요금",fee_wallet:"수수료 지갑",fee_wallet_label:"수수료 지갑 (지갑 ID)",fee_wallet_hint:"자금을 보낼 지갑 ID",disable_fee:"수수료 비활성화",disable_fee_internal:"내부 결제에 대한 서비스 요금 비활성화",disable_fee_internal_desc:"내부 라이트닝 결제에 대한 서비스 요금 비활성화",ui_management:"UI 관리",ui_site_title:"사이트 제목",ui_site_tagline:"사이트 태그라인",ui_elements_enable:"홈페이지의 요소 활성화",ui_elements_disable:"홈페이지의 요소 비활성화",ui_toggle_elements_tip:"'에 의해 구동됨' 등의 홈페이지 요소 제거",ui_site_description:"사이트 설명",ui_site_description_hint:"일반 텍스트, Markdown, 또는 원시 HTML을 사용하십시오.",ui_default_wallet_name:"기본 지갑 이름",lnbits_wallet:"LNbits 지갑",denomination:"액면가",denomination_hint:"FakeWallet 토큰의 이름",ui_qr_code_logo:"QR 코드 로고",ui_qr_code_logo_hint:"QR 코드의 로고 이미지 URL",ui_custom_badge:"맞춤 배지",ui_custom_badge_label:"사용자 지정 배지 '주의하여 사용 - LNbits 지갑은 여전히 BETA 상태입니다'",ui_custom_badge_color_label:"사용자 정의 배지 색상",themes:"테마",themes_hint:"사용자가 사용할 수 있는 테마 선택",custom_logo:"맞춤 로고",custom_logo_hint:"로고 이미지의 URL",ad_space_title:"광고 공간 제목",ad_space_title_label:"지원:",ad_slots:"광고 슬롯",ad_slots_hint:"광고 URL 및 이미지 파일 경로를 CSV 형식으로, 확장자는 준수할 수 있습니다.",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"광고 활성화됨",ads_disabled:"광고 비활성화됨",user_management:"사용자 관리",admin_users:"관리자 사용자",admin_users_hint:"관리자 권한이 있는 사용자",admin_users_label:"사용자 ID",allowed_users:"허용된 사용자",allowed_users_hint:"LNbits는 이 사용자들만 사용할 수 있습니다.",allowed_users_label:"사용자 ID",allow_creation_user:"새 사용자 생성 허용",allow_creation_user_desc:"색인 페이지에서 새 사용자 생성 허용",components:"구성 요소",long_running_endpoints:"최상위 5개의 장시간 실행 엔드포인트",http_request_methods:"HTTP 요청 메서드",http_response_codes:"HTTP 응답 코드",request_details:"요청 세부사항",http_request_details:"HTTP 요청 세부사항",block_explorer:"블록 탐색기",enable_block_explorer:"블록 탐색기 활성화",block_explorer_desc:"Electrum을 통해 비트코인 거래 및 주소를 탐색할 수 있습니다.",blockexplorer_public_api:"공개 API 접근",blockexplorer_public_api_desc:"블록 탐색기 API 엔드포인트에 대한 비인증 접근을 허용합니다.",electrum_server_url:"Electrum 서버 URL",electrum_server_url_hint:"예: ssl://electrum.blockstream.info:50002 또는 tcp://localhost:50001",blockexplorer_search_label:"TXID 또는 주소로 검색",blockexplorer_search_hint:"64자 16진수 = 거래 · 그 외 = 비트코인 주소",recent_blocks:"최근 블록",chain_tip:"체인 끝",block_height:"블록 높이",block_fee:"블록 수수료",fee_estimates:"수수료 추정",confirmed_balance:"확인된 잔액",unconfirmed_balance:"미확인 잔액",transaction_history:"거래 내역",coinbase:"Coinbase",inputs:"입력",outputs:"출력",confirmations:"확인 수",confirmed:"확인됨",unconfirmed:"미확인",history_unavailable:"거래 내역을 불러올 수 없습니다 (주소의 거래가 너무 많음)",address:"주소",block_number:"블록 #{height}",block_diff:"diff {value}",block_hash:"해시",previous_block:"이전 블록",merkle_root:"머클 루트",version:"버전",bits:"Bits",difficulty:"난이도",nonce:"Nonce",txid:"TXID",vsize:"가상 크기",weight:"무게",n_block_fee:"{n}블록 수수료"},window.localisation.fi={confirm:"Kyllä",server:"Palvelin",theme:"Teema",site_customisation:"Sivuston kustomointi",funding:"Rahoitus",users:"Käyttäjät",audit:"Seuranta",api_watch:"API-seuranta",apps:"Sovellukset",channels:"Kanavat",transactions:"Tapahtumat",dashboard:"Ohjauspaneeli",node:"Solmu",export_users:"Vie käyttäjät",no_users:"Käyttäjiä ei löytynyt",total_capacity:"Kokonaiskapasiteetti",avg_channel_size:"Keskimääräisen kanavan kapasiteetti",biggest_channel_size:"Suurimman kanavan kapasiteetti",smallest_channel_size:"Pienimmän kanavan kapasiteetti",number_of_channels:"Kanavien lukumäärä",active_channels:"Aktiivisia kanavia",connect_peer:"Yhdistä naapuriin",connect:"Yhdistä",reconnect:"Uudista yhteys",open_channel:"Avaa kanava",open:"Avaa",close_channel:"Sulje kanava",close:"Sulje",restart:"Palvelimen uudelleen käynnistys",image_library:"Kuvakirjasto",save:"Tallenna",save_tooltip:"Tallenna muutokset",credit_debit:"Hyvitä / Veloita",credit_hint:"Hyväksy painamalla Enter (negatiivisetkin arvot ovat sallittuja)",credit_label:"Hyvitä / Veloita tilille {denomination}-varoja",credit_ok:"Virtuaalivarojen ({amount} sat) hyvitys-/veloitustapahtuma onnistui. Maksukyky riippuuu rahoituslähteen todellisista varoista.",restart_tooltip:"Uudelleenkäynnistä palvelu muutosten käyttöönottamiseksi",add_funds_tooltip:"Lisää varoja lompakkoon",reset_defaults:"Palauta oletusasetukset",reset_defaults_tooltip:"Poista kaikki asetusten muutokset ja palauta järjestelmän oletusasetukset.",download_backup:"Lataa tietokannan varmuuskopio",name_your_wallet:"Nimeä lompakkosi {name}",paste_invoice_label:"Liita lasku, maksupyyntö tai LNURL-koodi*",lnbits_description:"Kevyt ja helppokäyttöinen LNbits voi käyttää rahoituslähteinään mitä vain Lightning-palveluita ja jopa LNbits-palvelua! Voit käyttää sitä itsenäisesti ja helposti tarjota erilaisia Lightning-palveluita. Pystyt luomaan sillä salamaverkkolompakoita eikä niiden määrää ole rajoitettu. Jokaiselle lompakolle saat yksilölliset API-avaimet. Varojen osittaminen tekee siitä erittäin kätevän varojen hallinnassa sekä myös ohjelmistokehityksen työkalun. Laajennukset lisäävät LNbits:in toiminnallisuuksia. Näinpä voit helposti testailla useita erilaisia ja viimeisimpiä salamaverkon teknologioita. Laajennuksien kehittämisen olemme pyrkineet tekemään mahdollisimman helpoksi pitämällä LNbits:in ilmaisena OpenSource-projektina. Kannustamme kaikkia kehittämään ja jakelemaan omia laajennuksia!",export_to_phone:"Käytä puhelimessa lukemalla QR-koodi",export_to_phone_desc:"Tämä QR-koodi sisältää URL-osoitteen, jolla saa lompakkoosi täydet valtuudet. Voit lukea sen puhelimellasi ja avata sillä lompakkosi. Voit myös lisätä lompakkosi selaimella käytettäväksi PWA-sovellukseksi puhelimen aloitusruudulle. ",access_wallet_on_mobile:"Mobiili käyttö",wallet:"Lompakko:",wallet_name:"Lompakon nimi",wallets:"Lompakot",add_wallet:"Lisää lompakko",add_new_wallet:"Lisää uusi lompakko",pin_wallet:"Kiinnitä lompakko",delete_wallet:"Poista lompakko",delete_wallet_desc:"Lompakko poistetaan pysyvästi. Siirrä lompakosta varat ennalta muualle, sillä tämä toiminto on PERUUTTAMATON!",rename_wallet:"Nimeä lompakko uudelleen",update_name:"Tallenna",fiat_tracking:"Käytettävä valuutta",fiat_providers:"Valuutan välittäjät",currency:"Valuutta",update_currency:"Tallenna",press_to_claim:"Lunasta varat painamalla tästä",claim_desc:"Näyttää että sinulla on lunastamattomia bitcoin varoja, mutta sinulla ei vielä ole lompakkoa. Lunasta varat allaolevaa nappia painamalla, ja sinulle luodaan lompakko.",donate:"Lahjoita",view_github:"Näytä GitHub:ssa",voidwallet_active:"VoidWallet on aktiivinen. Se ei tue maksutapahtumia!",use_with_caution:"KÄYTÄ VAROEN - BETA-ohjelmisto on käytössä palvelussa: {name}",service_fee_tooltip:"LNbits palvelimen ylläpitäjä veloittaa lähtevästä maksusta palvelumaksun.",toggle_darkmode:"Tumma näkymä",payment_reactions:"Maksureaktiot",view_swagger_docs:"Näytä LNbits Swagger API-dokumentit",api_docs:"API-dokumentaatio",api_keys_api_docs:"Solmun URL, API-avaimet ja -dokumentaatio",api_keys_warning:"Pidä nämä avaimet turvassa, sillä niiden jakaminen voi johtaa varojen menetykseen.",admin_key_warning:"Ylläpitäjäavaimesi antaa täyden pääsyn lompakkoosi, myös maksujen lähettämiseen. Älä koskaan jaa sitä, ellet täysin luota vastaanottajaan.",lnbits_version:"LNbits versio",runs_on:"Mukana menossa",paste:"Liitä",paste_from_clipboard:"Liitä leikepöydältä",paste_request:"Liitä pyyntö",create_invoice:"Laskuta",camera_tooltip:"Kuvaa lasku tai QR-koodi",export_csv:"Vie CSV-tiedostoon",export_csv_details:"Vie CSV-tiedostoon lisätietoineen",chart_tooltip:"Näytä kaaviokuva",pending:"Odottaa",copy_invoice:"Kopioi lasku",withdraw_from:"Nosta kohteesta",cancel:"Peruuta",scan:"Scannaa",read:"Lue",write:"Kirjoita",pay:"Maksa",memo:"Kuvaus",date:"Päiväys",path:"Path",payment_processing:"Maksua käsitellään...",not_enough_funds:"Varat eivät riitä!",search_by_tag_memo_amount:"Etsi tunnisteella, muistiolla tai määrällä",invoice_waiting:"Lasku odottaa maksua",payment_received:"Maksu vastaanotettu",payment_sent:"Maksu lähetetty",payment_failed:"Maksu epäonnistui",receive:"vastaanota",send:"lähetä",outgoing_payment_pending:"Lähtevä maksu odottaa",drain_funds:"Tyhjennä varat",drain_funds_desc:"Tämä LNURL-withdraw -tyyppinen QR-koodi on tarkoitettu kaikkien varojen imurointiin lompakosta. ÄLÄ JAA SITÄ KENELLEKÄÄN! Se on balanceCheck- ja balanceNotify-toimintojen kanssa yhteensopiva, joten sitä voi käyttää lompakon tyhjentämiseen ensimmäisen käytön jälleen jatkuvasti.",i_understand:"Vakuutan ymmärtäväni",copy_wallet_url:"Kopioi lompakon URL",disclaimer_dialog_title:"Tärkeää!",disclaimer_dialog:"Sinun *PITÄÄ TALLETTAA* kirjautumistietosi turvallisesta ja helposti saataville, jotta pääset jatkossa kirjautumaan lompakkoosi! Löydät kirjautumistiedot Tilin asetukset -sivulta. Kukaan ei ota mitään vastuuta varojen säilymisestä tai niiden käytettävyyden takaamisesta.",no_transactions:"Lompakossa ei ole yhtään tapahtumaa",manage:"Hallinnointi",exchanges:"Vaihtokurssit",extensions:"Laajennukset",no_extensions:"Laajennuksia ei ole asennettu :(",created:"Luotu",search_extensions:"Etsi laajennuksia",search_wallets:"Etsi lompakkoa",extension_sources:"Laajennuslähteet",ext_sources_hint:"Lähteet joista laajennuksia voi ladata",ext_sources_label:"Lähde-URL (käytä vain virallista LNbits tai muuta luotettaa laajennuslähdettä)",warning:"Varoitus",repository:"Laajennuksien lähde",confirm_continue:"Haluatko varmasti jatkaa?",manage_extension_details:"Asenna/Poista laajennus",install:"Asenna",uninstall:"Poista",drop_db:"Poista tiedot",enable:"Ota käyttöön",enabled:"Käytössä",pay_to_enable:"Maksa ottaaksesi käyttöön",enable_extension_details:"Ota laajennus käyttöön tälle käyttäjälle",disable:"Poista käytöstä",delete:"Poista",installed:"Asennettu",activated:"Käytössä",deactivated:"Poissa käytöstä",release_notes:"Julkaisutiedot",activate_extension_details:"Aseta/Poista laajennus käyttäjien saatavilta",featured:"Esittelyssä",all:"Kaikki",only_admins_can_install:"(Vain pääkäyttäjät voivat asentaa laajennuksia)",admin_only:"Pääkäyttäjille",new_version:"Uusi versio",extension_depends_on:"Edellyttää:",extension_rating_soon:"Arvostelut on tulossa pian",extension_installed_version:"Nykyinen versio",extension_uninstall_warning:"Olet poistamassa laajennuksen kaikilta käyttäjiltä.",uninstall_confirm:"Kyllä, poista asennus",extension_db_drop_info:"Kaikki laajennuksen tallettama tieto poistetaan pysyvästi. Poistoa ei voi jälkikäteen peruuttaa!",extension_db_drop_warning:"Olet tuhoamassa laajennuksen tallettamat tiedot. Vahvista poisto kirjoittamalla viivalle seuraavassa näkyvä laajennuksen nimi:",extension_required_lnbits_version:"Tämä laajennus vaatii vähintään LNbits-version",min_version:"Minimi (sisältyy)",max_version:"Enimmäismäärä (ei sisälly)",payment_hash:"Maksun tiiviste",fee:"Kulu",amount:"Määrä",amount_limits:"Määrien rajat",amount_sats:"Määrä (sat)",faucest_wallet:"Faucet Wallet",faucest_wallet_desc_1:"Each time a payment is confirmed by the {provider} provider funds will be subtracted from this wallet.",faucest_wallet_desc_2:"This helps monitor all {provider} payments and their status.",faucest_wallet_desc_3:"This wallet must be topped up with the amount of sats that the admin is willing to offer in exchange for the fiat currency.",faucest_wallet_desc_4:"If this wallet is configured, but is empty, the {provider} payments will not be processed.",faucest_wallet_desc_5:"This wallet can eventually get to a negative balance if parallel fiat payments are made.",faucest_wallet_id:"Faucet Wallet ID (optional)",faucest_wallet_id_hint:"Wallet ID to use for the faucet. It will be used to send the funds to the user.",tag:"Tunniste",unit:"Yksikkö",description:"Kuvaus",expiry:"Vanhenee",webhook:"Webhook",webhook_url:"Webhook URL",webhook_url_hint:"Webhook URL to send the payment details to. It will be called when the payment is completed.",webhook_events_list:"The following events must be supported by the webhook:",webhook_stripe_description:"One the stripe side you must configure a webhook with a URL that points to your LNbits server.",payment_proof:"Maksun varmenne",update:"Päivitä",update_available:"Saatavilla on päivitys {version}-versioon!",update_available:"Rahoituslähteet",latest_update:"Käytössä oleva versio {version}, on viimeisin saatavilla oleva.",notifications:"Tiedotteet",notifications_configure:"Määritä tiedotukset",notifications_nostr_config:"Nostr-määritykset",notifications_enable_nostr:"Kaytä Nostr:ia",notifications_enable_nostr_desc:"Lähetä tietodukset Nostr:in kautta",notifications_nostr_private_key:"Nostr-yksityisavain",notifications_nostr_private_key_desc:"Yksityinen avain (hex tai nsec) Nostr-viestien lähettämisen allekirjoitukseen",notifications_nostr_identifiers:"Nostr-tunnisteet",notifications_nostr_identifiers_desc:"Lista tunnisteista kenelle tiedotukset lähetetään",notifications_telegram_config:"Telegram-määritykset",notifications_enable_telegram:"Käytä Telegram:ia",notifications_enable_telegram_desc:"Lähetä tietodukset Telegram:in kautta",notifications_telegram_access_token:"Access Token",notifications_telegram_access_token_desc:"Telegram botin Access token",notifications_chat_id:"Keskustelun tunnus",notifications_chat_id_desc:"Keskustelun tunnus minne tiedotukset lähetetään",notifications_email_config:"Sähköposti määritykset",notifications_enable_email:"Käytä sähköpostia",notifications_enable_email_desc:"Lähetä tiedotteet sähköpostilla",notifications_send_test_email:"Lähetä testiposti",notifications_send_email:"Lähetä sähköpostiosoitteella",notifications_send_email_desc:"Lähettäjänä näkyvä sähköpostiosoite",notifications_send_email_username:"Käyttäjätunnus",notifications_send_email_username_desc:"Käyttäjätunnus, mikäli tyhjä, käytetään sähköpostiosoitetta",notifications_send_email_password:"Lähtevän sähköpostin salasana",notifications_send_email_password_desc:"Salasana lähettävälle sähköpostille",notifications_send_email_server_port:"Lähtevän sähköpostin SMTP-portti",notifications_send_email_server_port_desc:"SMTP-palvelimen portti",notifications_send_email_server:"Lähtevän sähköpostin SMTP-palvelin",notifications_send_email_server_desc:"SMTP-palvelin jonka kautta sähköpostit lähetetään",notifications_send_to_emails:"Sähköpostien vastaanottaja",notifications_send_to_emails_desc:"Kenelle sähköpostit lähetetään",notification_settings_update:"Asetuksia päivitetty",notification_settings_update_desc:"Tiedota kun palvelimen asetuksia on päivitetty",notification_server_start_stop:"Palvelimen Käynnystys/Sammutus",notification_server_start_stop_desc:"Tiedota kun palvelin on käynnistetty tai sammutettu",notification_watchdog_limit:"Watchdog-raja -tiedote",notification_watchdog_limit_desc:"Tiedota kun watchdog-raja on saavutettu (ei vaikuta rahoituslähteeseen)",notification_server_status:"Palvelimen tila",notification_server_status_desc:"Lähetä säännölliset tiedotteet palvelimen tilasta (anna tiedotusväli tunteina)",notification_incoming_payment:"Saapuvat maksut",notification_incoming_payment_desc:"Tiedota kun lompakon vastaanottaman ja saapuvan maksun määrä ylittää rajan (sat)",notification_outgoing_payment:"Lähtevät maksut",notification_outgoing_payment_desc:"Tiedota kun lompakon lähettävän ja maksettavan maksun määrä ylittää rajan (sat)",notification_credit_debit:"Hyvitys / Veloitus",notification_credit_debit_desc:"Tiedota kun Superuser tekee lompakon hyvitys- tai veloitustapahtumia",notification_balance_delta_changed:"Saldon määrän muutos",notification_balance_delta_changed_desc:"Tiedota kun solmun ja LNbits saldojen eri poikkeaa edes yhden satoshin. Tämä tarkastus tehdään joka minuuttu.",enable_watchdog:"Watchdog-kytkin",enable_watchdog_desc:"Tämän ollessa käytössä, ja solmun varojen laskiessa alle LNbits-varojen määrän, otetaan automaattisesti käyttöön VoidWallet. Päivityksen jälkeen tämä asetus pitää tarkastaa uudelleen.",watchdog_interval:"Watchdog-aikaväli",watchdog_interval_desc:"Tällä määritetään kuinka usein taustatoiminto tarkistaa varojen Delta-muutokset [node_balance - lnbits_balance] killswitch-signaalille. Hakujen väli ilmoitetaan minuutteina.",watchdog_delta:"Watchdog Delta",watchdog_delta_desc:"Mikäli rahoituslähteen saldo laskee alle LNbits kokonaissaldon, muutetaan rahoituslähteeksi heti VoidWallet. Päivittämisen jälkeen asetus pitää päivittää manuaalisestsi.",status:"Tilanne",notification_source:"Tiedotteiden lähde",notification_source_label:"Lähde-URL (käytä ainoastaan LNbits:iä tai muuta luotettavaa lähdettä)",more:"näytä lisää",more_count:"näytä {count} lisää",less:"supista",releases:"Julkaisut",watchdog:"Watchdog",server_logs:"Palvelimen lokit",ip_blocker:"Palvelimen suojaus IP-osoitesuodattimella",security:"Turvallisuus",security_tools:"Turvallisuus työkalut",block_access_hint:"Estä pääsy IP-osoitteen perusteella",allow_access_hint:"Salli pääsy IP-osoitteen perusteella (ohittaa estot)",enter_ip:"Anna IP ja paina +",rate_limiter:"Toiston rajoitin",callback_url_rules:"Callback URL -säännöt",enter_callback_url_rule:"Anna URL-sääntö regex-muodossa ja paina enter",callback_url_rule_hint:"Callback URL:it (kuten LNURL) tarkistetaan kaikkien näiden sääntöjen mukaisesti. Jos sääntöjä ei ole määritetty, kaikki URL:it ovat sallittuja.",wallet_limiter:"Lompakon käyttörajoitin",wallet_config:"Wallet Config",wallet_charts:"Wallet Charts",wallet_limit_max_withdraw_per_day:"Päivittäin nostettavissa sat maksimi (0 poistaa käytöstä)",wallet_max_ballance:"Maksimisaldo (sat) (0 poistaa käytöstä)",wallet_limit_secs_between_trans:"Tapahtumien välinen minimi (sec) (0 poistaa käytöstä)",only_incoming_payments_allowed:"Vain saapuvat maksut sallittuna",disable_outgoing_payments:"Poista lähtevät maksut käytöstä",number_of_requests:"Pyyntöjen lukumäärä",time_unit:"aikayksikkö",minute:"minuutti",settings:"Asetukset",second:"sekunti",hour:"tunti",disable_server_log:"Piilota palvelimen loki",enable_server_log:"Näytä palvelimen loki",coming_soon:"Ominaisuus on tulossa pian",session_has_expired:"Käyttämätön sessio on vanhentunut. Kirjaudu uudelleen.",instant_access_question:"perinteinen kirjautuminen",login_with_user_id:"Kirjaudu käyttäjä-ID:llä",or:"tai",create_new_wallet:"Avaa uusi lompakko",delete_all_wallets:"Poista kaikki lompakot",confirm_delete_all_wallets:"Oletko todellakin varma, että haluat poistaa käyttäjältä KAIKKI lompakot?",login_to_account:"Kirjaudu käyttäjänimellä",create_account:"Luo tili",account_settings:"Tilin asetukset",signin_with_oauth:"Login with",signin_with_oauth_or:"or Login with",signin_with_nostr:"Kirjaudu Nostr:lla",signin_with_google:"Kirjaudu Google-tunnuksella",signin_with_github:"Kirjaudu GitHub-tunnuksella",signin_with_custom_org:"Kirjaudu {custom_org}-palvelulla",username_or_email:"Käyttäjänimi tai sähköposti",password:"Anna uusi salasana",password_config:"Salasanan määritys",password_repeat:"Toista uusi salasana",update_password:"Päivitä salasana",change_password:"Vaihda salasana",update_credentials:"Päivitä käyttöoikeustiedot",update_pubkey:"Päivitä julkinen avain",nostr_pubkey_tooltip:"Syötä tämän käyttäjän julkinen Nostr avain (hex arvona)",set_password:"Aseta salasana",set_password_tooltip:"Aseta käyttäjätunnukselle salasana",invalid_password:"Salasanassa tulee olla vähintään kahdeksan merkkiä",invalid_password_repeat:"Salasanat eivät täsmää",reset_key_generated:"Salasanan vaihtoavain on luotu.",reset_key_copy:"Kopioi vaihto-URL leikepöydälle painamalla OK.",login:"Kirjaudu",register:"Rekisteröidy",username:"Käyttäjänimi",pubkey:"Julkinen avain",user_id:"Käyttäjä tunnus",id:"tunnus",email:"Sähköposti",first_name:"Etunimi",last_name:"Sukunimi",picture:"Kuva",verify_email:"Vahvista sähköposti",account:"Tili",update_account:"Päivitä tiliä",invalid_username:"Virheellinen käyttäjänimi",auth_provider:"Tunnistamisen toimittaja",my_account:"Tilini",existing_account_question:"Onkohan sinulla jo tili?",background_image:"Taustakuva",back:"Takaisin",logout:"Poistu",look_and_feel:"Kieli ja värit",endpoint:"Endpoint",api:"API",api_token:"API Token",api_tokens:"API Tokens",access_control_list:"Access Control List",access_control_list_admin_warning:"This is an admin account. The generated tokens will have admin privileges.",new_api_acl:"New Access Control List",api_token_id:"Token Id",toggle_gradient:"Toggle Gradient",gradient_background:"Gradient Background",language:"Kieli",color_scheme:"Väriteema",visible_wallet_count:"Näytettävien lompakkojen määrä",admin_settings:"Pääkäyttäjän asetukset",extension_cost:"Tämä laajennus edellyttää vähintään {cost} sat maksua.",extension_paid_sats:"Olet jo maksanut {paid_sats} satsia.",release_details_error:"Ei voi hakea julkaisun tietoja.",pay_from_wallet:"Maksa lompakosta",pay_with:"Maksa {provider}:lla",select_payment_provider:"Valitse maksun välittäjä",wallet_required:"Lompakko *",show_qr:"Näytä QR",retry_install:"Yritä asennusta uudelleen",new_payment:"Luo uusi maksu",update_payment:"Päivitä maksu",already_paid_question:"Kenties maksoit jo?",sell:"Myy",sell_require:"Pyydä maksua laajennuksen käytöstä",sell_info:"{name} -laajennuksen aktivointi edellyttää vähintään {amount} sat maksua.",hide_empty_wallets:"Piilota tyhjät lompakot",recheck:"Tarkista uudelleen",check:"Tarkista",check_connection:"Tarkista yhteys",check_webhook:"Tarkista Webhook",contributors:"Avustajat",license:"Lisenssi",reset_key:"Vaihda avain",reset_password:"Vaihda salasana",border_choices:"Reunuksen vaihtoehdot",select_all:"Valitse kaikki",nfc_supported:"NFC on tuettu",nfc_not_supported:"NFC:tä ei tueta",expire_date:"Vanhenemispäivämäärä:",hash:"Tiiviste:",welcome_lnbits:"Tervetuloa LNbits-palveluun",setup_su_account:"Määritä Superuser-tili alta.",create_ticker_converter:"Luo valuuttamuuntimen Ticker",enable_audit:"Ota seuranta käyttöön",recommended:"Suositeltu",audit_desc:"Tallenna HTTP-pyyntöjä seuraavien suodattimien mukaisesti",audit_record_req:"Tallenna pyynnön Body",audit_record_warning:"Varoitus:",audit_record_req_warning_1:"Luottamukselliset tiedot (kuten salasanat) tallennetaan.",audit_record_req_warning_2:"Body-datamäätä voi olla iso.",audit_record_use:"Käytä varoen!",audit_ip:"Tallenna IP-osoite",audit_ip_desc:"Tallenna asiakkaan IP-osoite",audit_path_params:"Tallenna Path-parametrit",audit_query_params:"Tallenna Query-parametrit",audit_http_methods:"Tallenna HTTP-menetelmät",audit_http_methods_hint:"Luettelo mukaan otettavista HTTP-menetelmistä. Tyhjä luettelo tallettaa kaikki.",audit_http_methods_label:"HTTP-metodit",audit_resp_codes:"Tallenna HTTP-vastauskoodit",audit_resp_codes_hint:"HTTP-koodien lista, jotka sisällytetään (regex-match). Tyhjä luettelo tallettaa kaikki. Esim: 4.*, 5.*",audit_resp_codes_label:"HTTP-vastauskoodi (säännöllinen lauseke)",audit_paths:"Sisällytä polut",audit_paths_hint:"Luettelo poluista, jotka sisällytetään (regex-vastaavuus). Tyhjä luettelo tarkoittaa kaikkia.",audit_paths_label:"HTTP-polku (regex)",audit_paths_exclude:"Ohita polut",audit_paths_exclude_hint:"Lista poluista, jotka jätetään pois (regex-vastaavuus). Tyhjällä listalla mitään ei jätetä pois.",audit_paths_exclude_label:"HTTP-polku (regex)",exchange_providers:"Vaihtokurssin tarjoajat",admin_extensions:"Pääkäyttäjän laajennukset",admin_extensions_label:"Pääkäyttäjän laajennukset",admin_extensions_hint:"Laajennuksia voi käyttää vain käyttäjä, jolla on pääkäyttäjäoikeudet",user_default_extensions:"Käyttäjän oletuslaajennukset",user_default_extensions_label:"Käyttäjän laajennukset",user_default_extensions_hint:"Laajennukset, jotka otetaan oletusarvoisesti käyttöön kaikille käyttäjille.",miscellanous:"Sekalaiset",misc_disable_extensions:"Poista laajennukset käytöstä",misc_disable_extensions_label:"Poista kaikki laajennukset käytöstä",misc_hide_api:"Piilota API",misc_hide_api_label:"Piilottaa lompakon rajapinnan, laajennukset voivat valita välittävätkö tästä asetuksesta",wallets_management:"Lompakoiden hallinta",funding_source_info:"Rahoituslähteen tiedot",funding_source:"Rahoituslähde: {wallet_class}",node_balance:"Solmun saldo: {balance} sats",lnbits_balance:"LNbits-saldo: {balance} sat",funding_reserve_percent:"Omavaraisuusaste: {percent} %",node_management:"Solmun hallinta",node_management_not_supported:"Solmun hallinta ei ole mahdollista valitun rahoituslähteen kanssa.",toggle_node_ui:"Solmun käyttöliittymä",toggle_public_node_ui:"Julkinen näkymä solmun tietoihin",toggle_transactions_node_ui:"Tapahtumat-välilehti (Poista käytöstä suurilla CLN-solmuilla)",invoice_expiry:"Laskun vanhenemisaika",invoice_expiry_label:"Laskun vanhentuminen (sekunteina)",fee_reserve:"Kuluvaraus",fee_reserve_percent:"Kuluvaraus prosentteina",fee_reserve_msats:"Kuluvaraus milli-sat",reserve_fee_in_percent:"Kuluvaraus prosentteina",payment_wait_time:"Maksun odotusaika (sekuntia)",payment_wait_time_desc:"Kuinka pitkään maksua odotetaan saapuvaksi, ennen kuin se merkitään Odotetaan-tilaan. Aseta pidemmäksi käytettäessä HODL-laskuja, Boltz-palvelua, tms",server_management:"Palvelimen hallinta",base_url:"Palvelimen URL-osoite",base_url_label:"Palvelun staattinen pohja-URL",authentication:"Käyttäjän todennus",auth_token_expiry_label:"Kirjautumisen vanhentumisaika minuutteina",auth_token_expiry_hint:"Aika minuuteissa, jossa kirjautuminen vanhenee",auth_allowed_methods_label:"Sallitut kirjautumismenetelmät",auth_allowed_methods_hint:"Valitse kirjautumismenetelmät",auth_nostr_label:"Nostr kutsujen URL",auth_nostr_hint:"Asiakkaiden kirjautumiseen käyttämä absoluuttinen URL-osoite.",auth_google_ci_label:"Google-asiakastunnus",auth_google_ci_hint:"Varmista, että valtuutetut uudelleenohjaus-URI:t sisältävät https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google-asiakassalasana",auth_gh_client_id_label:"GitHub-asiakastunnus",auth_gh_client_id_hint:"Varmista, että valtuutuksen paluuosoite-URL on asetettu osoitteeseen https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub-asiakassalaisuusavain",auth_keycloak_label:"Keycloak-discovery-URL",auth_keycloak_ci_label:"Keycloak-asiakastunnus",auth_keycloak_ci_hint:"Varmista, että valtuutuksen palautus-URL on asetettu muotoon https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak-asiakassalasana",auth_keycloak_custom_org_label:"Valinnainen Keycloak-organisaatio",auth_keycloak_custom_icon_label:"Valinnainen Keycloak-kuvake (URL)",auth_oidc_label:"OIDC-discovery-URL",auth_oidc_ci_label:"OIDC-asiakastunnus",auth_oidc_ci_hint:"Varmista, että valtuutuksen palautus-URL on asetettu muotoon https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC-asiakassalasana",auth_oidc_custom_org_label:"OIDC mukautetun organisaation nimi (esim. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Valinnainen OIDC-kuvake (URL)",currency_settings:"Valuutta-asetukset",allowed_currencies:"Käytettävät valuutat",allowed_currencies_hint:"Valitse käytettävissä olevat fiat-valuutat",default_account_currency:"Tilin oletusvaluutta",default_account_currency_hint:"Kirjanpidon oletusvaluutta",min_incoming_payment_amount:"Pienin vastaanotettava maksun määrä",min_incoming_payment_amount_desc:"Pienin maksun määrä jolle voi luoda laskun",max_incoming_payment_amount:"Saapuvan maksun enimmäismäärä",max_incoming_payment_amount_desc:"Enimmäismäärä jonka voi laskuttaa",max_outgoing_payment_amount:"Lähtevän maksun enimmäismäärä",max_outgoing_payment_amount_desc:"Enimmäismäärä jonka voi maksaa",service_fee:"Palvelumaksut",service_fee_label:"Palvelumaksu (%)",service_fee_hint:"Tapahtumastakohtainen palvelumaksu (%)",service_fee_max:"Palvelumaksun enimmäismäärä",service_fee_max_label:"Palvelumaksu max (sat)",service_fee_max_hint:"Suurin veloitettava palvelumaksu (sat)",fee_wallet:"Palvelumaksujen lompakko",fee_wallet_label:"Palvelumaksujen tilityslompakko (lompakon tunnus)",fee_wallet_hint:"Lompakon tunnus, johon palvelumaksut tilitetään",disable_fee:"Poista maksu käytöstä",disable_fee_internal:"Poista palvelumaksu sisäisiltä maksuilta",disable_fee_internal_desc:"Poista palvelumaksu sisäisiltä salamaksuilta",ui_management:"Käyttöliittymän hallinta",ui_site_title:"Sivuston nimi",ui_changing_remove_lnbits_elements:" (tämän muuttamalla LNbits elementit poistuvat kotisivulla ja alareunasta)",ui_site_tagline:"Sivuston iskulause",ui_elements_enable:"Ota käyttöön elementit etusivulla/alareunassa",ui_elements_disable:"Poista elementit käytöstä etusivulla/alareunassa",ui_toggle_elements_tip:"Poista kotisivuelementit kuten 'toimii' jne.",ui_site_description:"Sivuston kuvaus",ui_site_description_hint:"Käytä tavallista tekstiä, Markdownia tai puhdasta HTML:ää",ui_default_wallet_name:"Oletuslompakon nimi",ui_default_theme:"Oletusteema",lnbits_wallet:"LNbits-lompakko",denomination:"Valuutan nimi",denomination_hint:"FakeWallet-lompakon valuutan nimi",denomination_error:"Valuutta tunnisssa on oltava 3 merkkiä, tai `sat`",ui_qr_code_logo:"QR- ja Favicon-logo",ui_qr_code_logo_hint:"Anna QR-koodissa ja Faviconissa käytettävän logo-kuvan URL",ui_custom_image:"Yksilöity kuva",ui_custom_image_label:"Anna yksilöidyn kuvan URL-osoite",ui_custom_image_hint:"Yksilöity kuva näytetään aloitus- ja kirjautumissivuilla",ui_custom_badge:"Yksilöity tunnus",ui_custom_badge_label:"Yksilöity tunnus 'KÄYTÄ VAROVAISUUTTA - LNbits-lompakko on edelleen BETA-versiossa'",ui_custom_badge_color_label:"Kustomoidun tunnuksen väri",themes:"Teemat",themes_hint:"Valitse käyttäjille saatavilla olevat teemat",custom_logo:"Mukautettu logo",custom_logo_hint:"Logokuvan sisältävä URL-osoite",ad_space_title:"Mainospaikan otsikko",ad_space_title_label:"Palvelua tukevat ",ad_slots:"Mainospaikat",ad_slots_hint:"Mainoslinkit ja kuvatiedostopolut CSV-muodossa, lisäosat voivat valita välittävätkö asetuksesta",ad_slots_label:"url;img_light_url;img_dark_url, url...",ads_enabled:"Mainokset käytössä",ads_disabled:"Mainokset poistettu käytöstä",user_management:"Käyttäjänhallinta",admin_users:"Pääkäyttäjät",admin_users_hint:"Käyttäjät, joilla on pääkäyttäjän oikeudet",admin_users_label:"Käyttäjätunnus",allowed_users:"Sallitut käyttäjät",allowed_users_hint:"Vain nämä käyttäjät voivat käyttää LNbitsiä",allowed_users_hint_feature:"Ainoastaan nämä käyttäjät voivat käyttää ominaisuutta {feature}",allowed_users_label:"Käyttäjätunnus",allow_creation_user:"Salli uusien käyttäjien luominen",allow_creation_user_desc:"Etusivulta on mahdollisuus luoda uusia käyttäjiä",new_user_not_allowed:"Tunnusten luonti on estetty.",components:"Komponentit",long_running_endpoints:"Top 5 pisimpään yhteydessä ollutta päätepistettä",http_request_methods:"HTTP-pyynnön menetelmät",http_response_codes:"HTTP-vastaukset koodit",request_details:"Pyynnön tiedot",http_request_details:"HTTP-pyynnön tiedot",payment_details:"Maksun yksityiskohdat",payment_details_desc:"Yksityiskohtaisen maksun sisältö",payments:"Maksut",payment_show_internal:"Näytä sisäiset maksut",payment_chart_flow:"Kuukausittainen maksuvirta",payment_chart_status:"Maksun Tila",payment_chart_tx_per_wallet:"Lompakkokohtaiset tapahtumat (saldo/kappaletta)",payment_details_back:"Takaisin Maksuihin",payment_chart_tags:"Maksut Tag:eittäin",payments_balance_in_out:"Saldo Sisään/Ulos",payments_count_in_out:"Tapahtumia Sisään/Ulos",payments_status_chart:"Tilakaavio",payments_tag_chart:"Tag-kaavio",payments_balance_chart:"Saldo-kaavio",payments_wallets_chart:"Lompakko-kaavio",payments_balance_in_out_chart:"Saldo Sisään/Ulos -kaavio",payments_count_in_out_chart:"Lukumäärä Sisään/Ulos -kaavio",reset_wallet_keys:"Uusi API-avaimet",reset_wallet_keys_desc:"Tämän lompakon API-avaimet uusitaan. Edelliset API-avaimet lakkaavat toimimasta ja uudet luodaan niiden tilalle..",view_list:"Näytä lompakot allekain",view_column:"Näytä lompakot rinnakkain",filter_payments:"Suodata maksuja",filter_date:"Suodata päiväyksellä",websocket_example:"Websocket example",client_id:"Client ID",secret_key:"Secret Key",signing_secret:"Signing Secret",signing_secret_hint:"Signing secret for the webhook. Messages will be signed with this secret.",webhook_id:"Webhook ID",webhook_id_hint:"PayPal webhook ID used to verify incoming events.",webhook_paypal_description:"On the PayPal side configure a webhook pointing to your LNbits server.",callback_success_url:"Callback Success URL",callback_success_url_hint:"The user will be redirected to this URL after the payment is successful",block_explorer:"Lohkoselain",enable_block_explorer:"Ota lohkoselain käyttöön",block_explorer_desc:"Salli käyttäjien tutkia Bitcoin-transaktioita ja -osoitteita Electrumin kautta.",blockexplorer_public_api:"Julkinen API-pääsy",blockexplorer_public_api_desc:"Salli todentamaton pääsy lohkoselain API-päätteisiin.",electrum_server_url:"Electrum-palvelimen URL",electrum_server_url_hint:"esim. ssl://electrum.blockstream.info:50002 tai tcp://localhost:50001",blockexplorer_search_label:"Hae TXID:llä tai osoitteella",blockexplorer_search_hint:"64 merkin heksa = transaktio · muu = Bitcoin-osoite",recent_blocks:"Viimeisimmät lohkot",chain_tip:"Ketjun kärki",block_height:"Lohkokorkeus",block_fee:"lohkomaksu",fee_estimates:"Maksuarviot",confirmed_balance:"Vahvistettu saldo",unconfirmed_balance:"Vahvistamaton saldo",transaction_history:"Tapahtumahistoria",coinbase:"Coinbase",inputs:"Syötteet",outputs:"Tulosteet",confirmations:"Vahvistukset",confirmed:"Vahvistettu",unconfirmed:"Vahvistamaton",history_unavailable:"Tapahtumahistoria ei saatavilla (osoitteella on liikaa tapahtumia)",address:"Osoite",block_number:"Lohko #{height}",block_diff:"vaikeus {value}",block_hash:"Hash",previous_block:"Edellinen lohko",merkle_root:"Merkle-juuri",version:"Versio",bits:"Bitit",difficulty:"Vaikeus",nonce:"Nonce",txid:"TXID",vsize:"Virtuaalikoko",weight:"Paino",n_block_fee:"{n} lohkon maksu"},window.localisation.fo={confirm:"Ja",server:"Ambætari",theme:"Snið",site_customisation:"Vevsíðu tillagingar",funding:"Fígging",users:"Brúkarar",audit:"Slóðfesti",api_watch:"API nýtsluyvirlit",apps:"Appir",channels:"Rásir",transactions:"Flytingar",dashboard:"Yvirlitssýni",node:"Knútur",export_users:"Tak brúkarar út",no_users:"Eingin brúkari finst",total_capacity:"Samlað rásarupphædd",avg_channel_size:"Miðal rásarupphædd",biggest_channel_size:"Størsta rásarupphædd",smallest_channel_size:"Minsta rásarupphædd",number_of_channels:"Tal av rásum",active_channels:"Virknar rásir",connect_peer:"Sambind við javninga",connect:"Sambind",reconnect:"Sambind aftur",open_channel:"Ger rás",open:"Lat upp",clear:"Tómstilla",close_channel:"Loka rás",close:"Loka",restart:"Endurbyrja ambætara",image_library:"Myndasavn",save:"Goym",save_tooltip:"Goym broytingarnar",must_save:"Tú hevur framt broytingar ið enn ikki eru goymdar.",credit_debit:"Góðskriva / Skuldskriva",credit_hint:"Trýst á Enter til tess at góðskriva/skuldskriva mappu (negativ viðri eru loyvd)",credit_label:"{denomination} at góðskriva/skuldskriva",credit_ok:"Tað eydnaðist at góðskriva/skuldskriva tykisligan pening ({amount} sats). Gjøld eru treytaði av veruligum peningi á fíggingarkelduni.",restart_tooltip:"Endurbyrja ambætaran fyri at broytingarnar fáa virknað",add_funds_tooltip:"Set pening á eina mappu.",reset_defaults:"Endurset til forsettar stillingar",reset_defaults_tooltip:"Strika allar stillingar og endurset tær til forsettar.",download_backup:"Tak niður dátugrunstrygdaravrit",name_your_wallet:"Navngev tína {name} mappu",paste_invoice_label:"Innset ein faktura, gjaldsumbøn ella LNURL-kotu *",lnbits_description:"LNbits er kravlítil skipan, ið er løtt at innleggja og uppseta, og kann brúka einhvørja fíggingarkeldu á Lightning netinum. Tú kanst koyra LNbits til egna nýtslu og lættliga veita øðrum eina varðveitsluloysn. Tú fært gjørt eitt óavmarkað tal av mappum har hvør mappa hevur sínar egnu API-lyklar. Við møgulleikanum at býta pening gerst LNbits eitt hent amboð til peningaumsiting og eitt menningaramboð. Ískoytisforrit leggja virkisføri afturat LNbits so at tú kanst royna teg við eini røð av framkomnum tøknum á Lightning netinum. Vit hava gjørt tað so lætt sum møguligt, at menna ískoytisforrit, og sum ein fræls og gjøgnumskygd verkætlan eggja vit fólki, at menna og leggja fram teirra egnu ískoytisforrit.",export_to_phone:"Tak út til snildfon við QR-kotu",export_to_phone_desc:"QR-kotan inniheldur eina leinkju ið vísir til og gevur full rættindi til tína mappu. Skannar tú hana, t.d. við tíni snildfon, kanst tú lata upp mappu nýtaramótið har.",access_wallet_on_mobile:"Faratgongd",stored_paylinks:"Goymdar LNURL-gjaldleinkjur",wallet:"Mappa: ",wallet_name:"Mappunavn",wallet_type:"Slag av mappu",shared_wallet:"Deild mappa",share_wallet:"Deil mappu",update_permissions:"Broyt loyvir",shared_wallet_id:"Eyðmerki á deildari mappu",shared_wallet_desc:"Tú ert boðin atgongd til aðra mappu.",wallets:"Mappur",exclude_wallets:"Útiloka mappur",add_wallet:"Ger mappu",reject_wallet:"Vraka mappuatgongd",add_new_wallet:"Legg nýggja mappu afturat",pin_wallet:"Fest á mappulista",delete_wallet:"Strika mappu",delete_wallet_desc:"Mappan verður strikað og peningurin í henni fæst IKKI AFTUR.",rename_wallet:"Nýnevn mappu",update_name:"Nýnevn",fiat_tracking:"Fiat rekjan",fiat_providers:"Fiat meklarir",fiat_warning_bitcoin:'Ber teg undan at brúka orðið "bitcoin" tínum samskifti við fiat meklarar, tí teir hava lyndi at gerast fjálturstungnir um tað ið hevur við Bitcoin at gera!',currency:"Gjaldoyra",update_currency:"Broyt gjaldoyra",press_to_claim:"Trýst til tess at taka ímóti bitcoin",claim_desc:"Tú tykist hava krav á einari bitcoin upphædd men hevur ikki eina mappu enn. Trýst á knøttin niðanfyri fyri at taka ímóti henni. Ein nýggj mappa verður gjørd tær.",donate:"Veit fíggjarligan stuðul",view_github:"Lat upp LNbits verkætlanina á GitHub",voidwallet_active:"VoidWallet er virkin! Gjøld eru óvirkt",voidwallet_active_user:"Fíggingarkelda er ikki tøk. Vinaliga bið skipanarumsitaran um at fáa fíggingarkelduna í rættlag.",voidwallet_active_admin:"Fíggingarkelda er ikki tøk. Trýst á her fyri at uppseta.",service_fee_badge:"Tænastuavgjald: {amount} % fyri hvørja flyting",service_fee_max_badge:"Tænastuavgjald: {amount} % fyri hvørja flyting (í mesta lagi {max} {denom})",service_fee_tooltip:"Tænastuavgjald ið LNbits-ambætaraumsitarin krevur fyri hvørt útgjald",toggle_darkmode:"Myrkt snið",payment_reactions:"Gjaldsviðbrøgd",view_swagger_docs:"Lat upp LNbits Swagger API-skjalfestingina",api_docs:"API skjalfesting",api_keys_api_docs:"Knútaleinkja, API-lyklar og API-skjalfesting",lnbits_version:"LNbits útgáva",runs_on:"Koyrir á",paste:"Innset",paste_from_clipboard:"Innset frá setiborði",paste_request:"Innset umbøn",create_invoice:"Stovna gjaldsumbøn",camera_tooltip:"Brúka myntatólið at skanna eina gjaldsumbøn/QR-kotu",export_csv:"Tak út sum CSV",export_csv_details:"Tak út sum CSV, við smálutum",chart_tooltip:"Vís talvu",pending:"Ógoldin",copy_invoice:"Avrita gjaldsumbøn",withdraw_from:"Tak út úr",cancel:"Avlýs",scan:"Skanna",read:"Innles",write:"Skriva",pay:"Rinda",sending:"Sendur",memo:"Viðmerking",date:"Dagfesting",path:"Leið",internal_memo:"Egin viðmerking (valfríur)",internal_memo_hint_receive:"Viðmerkingin verður ikki víst rindaranum men verður knýtt at fakturanum, so tú kanst nýta hana sum tilvísing.",internal_memo_hint_pay:"Viðmerkingin verður ikki vist móttakaranum men verður knýtt at gjaldsumbønini, so tú kanst nýta hana sum tilvísing.",payment_processing:"Gjald verður avgreitt...",payment_successful:"Goldið!",payment_pending:"Gjald er ikki goldið enn...",payment_check:"Kanna greiðslu",not_enough_funds:"Ónøktandi salda!",search_by_tag_memo_amount:"Leita eftir spjaldri, viðmerking, upphædd",search:"Leita",invoice_waiting:"Gjaldsumbøn ið bíðar eftir at verða goldin",payment_received:"Inngjald",payment_sent:"Útgjald",payment_failed:"Gjald miseydnaðist",receive:"Móttak",send:"Send",outgoing_payment_pending:"Útgjald í bíðistøðu",drain_funds:"Tøm mappu",drain_funds_desc:"Hendan LNURL-úttøku QR-kotan kann brúkast at taka allan peningin úr mappuni. Ikki deila QR-kotuna við nakran. Hon ger nýtslu av balanceCheck og balanceNotify og kann tí brúkast fleiri ferðir at tøma mappuna.",i_understand:"Eg skilji",copy_wallet_url:"Avrita mappuleinkju",disclaimer_dialog_title:"Gev gætur!",disclaimer_dialog:'Tú *noyðist* at varðveita tínar innritanarupplýsingar til tess at fáa atgongd til mappuna aftur. Missir tú tær missir tú atgongd til mappuna og peningin.\n\nTú finnur tínar innritanarupplýsingar undir "Mín brúkari" > "Brúkara uppsetan".\n\nLNbits tekur ikki ábyrgd fyri mistari atgongd til pening.',no_transactions:"Enn eru ongar flytingar gjørdar",manage:"Umsit",exchanges:"Gjaldoyrakostnaðir",extensions:"Ískoytisforrit",no_extensions:"Einki ískoytisforrit er innlagt :(",created:"Stovnað",created_at:"Stovnað",updated_at:"Broytt",search_extensions:"Leita eftir ískoytisforritum",search_wallets:"Leita eftir mappum",extension_sources:"Ískoytisforritakeldur",ext_sources_hint:"Keldur hiðan ískoytisforrit verða tikin niður",ext_sources_label:"Kelduleinkja (brúka einans almennu LNbits-ískoytisforritakelduna og keldur tú hevur álit á)",warning:"Gev gætur",repository:"Kelda",confirm_continue:"Ynskir tú at halda áfram?",manage_extension_details:"Innlegg/Strika ískoytisforritið",upload:"Uppsend",install:"Innlegg",uninstall:"Strika",drop_db:"Strika dáturnar",enable:"Virkja",enabled:"Virktur",disabled:"Óvirkt(ur)",pay_to_enable:"Rinda til tess at virkja",enable_extension_details:"Virkja ískoytisforrit fyri verandi brúkara",disable:"Óvirkja",delete:"Strika",installed:"Innløgd",activated:"Virkt(ur)",deactivated:"Óvirkt",activate:"Virkja",deactivate:"Óvirkja",release_notes:"Sleppingarskriv",activate_extension_details:"Virkja ella óvirkja ískoytisforritið fyri brúkarum",featured:"Víðagitin",categories:"Flokkar",all:"Øll",only_admins_can_install:"(Einans umsitarar kunnu innleggja ískoytisforrit)",only_admins_can_create_extensions:"Einans umsitarar kunnu gera ískoytisforrit",admin_only:"Einans umsitarar",make_user_admin:"Játta umsitanarrættindi",revoke_admin:"Ógilda umsitanarrættindi",new_version:"Nýggj útgáva",reviews_url:"Ummælaleinkja",reviews_url_label:"Ummælaambætaraleinkja",reviews_url_hint:"Leinkja til PaidReviews/ummælir, íroknað stillingareymerki (t.d. https://example.com/paidreviews/SETTINGS_ID)",reviews_open:"Sí ummælir",reviews_leave:"Gev ummæli",reviews_name:"Títt navn",reviews_comment:"Títt ummæli",reviews_rating:"Meting",reviews_submit:"Send inn ummælið",reviews_loading:"Innlesur ummælir...",reviews_refresh:"Endurinnlesur ummælir",reviews_error_load:"Miseydnaðist at innlesa ummælir",reviews_url_not_configured:"Ummælaleinkja ikki ásett",reviews_pay_invoice:"Rinda gjaldsumbøn",reviews_invoice_paid:"Gjaldsumbøn goldin",reviews_invoice_title:"Rinda hesa gjaldsumbøn til tess at skráseta títt ummæli",reviews_count:"Ummælir",no_reviews:"Ongin ummælir enn",extension_has_free_release:"Hevur ókeypis útgávur",extension_has_paid_release:"Hevur útgávur til keyps",extension_depends_on:"Er treytað av:",extension_rating_soon:"Metingar koma skjótt",extension_installed_version:"Innløgd útgáva",extension_uninstall_warning:"Tú ert í ferð við at strika ískoytisforritið fyri allar brúkararnar.",uninstall_confirm:"Ja, strika",extension_db_drop_info:"Allar dátur tilhoyrandi ískoytisforritið verða strikaðar. Eftir hesa gerð vendst ikki aftur!",extension_db_drop_warning:"Tú ert í ferð við at strika allar dátur tilhoyrandi ískoytisforritið. Vinaliga skriva navnið á ískoytisforritinum til tess at halda á fram:",extension_required_lnbits_version:"Hendan útgávan tørvar LNbits útgávu",min_version:"Í minsta lagi",max_version:"Upp til (ikki íroknað)",preimage:"Frumvirði",preimage_hint:"Frumvirði til tess at avrokna varðveitslugjaldsumbøn",hold_invoice:"Varðveitslugjaldsumbøn",hold_invoice_description:"Hendan gjaldsumbønin er í varðveitslu og tørvur er á frumvirði til tess at gjalda hana.",payment_hash:"Gjalds-hash",invoice_cancelled:"Gjaldsumbøn ógilda",invoice_settled:"Gjaldsumbøn avroknað",hold_invoice_payment_hash:"Gjalds-hash fyri varðveitslugjaldsumbøn (valfríur)",settle_invoice:"Avrokna gjaldsumbøn",cancel_invoice:"Ógilda gjaldsumbøn",fee:"Avgjald",amount:"Upphædd",amount_limits:"Upphæddarmørk",amount_sats:"Upphædd (sats)",faucest_wallet:"Tiltaksmappa",faucest_wallet_desc_1:"Fyri hvørt gjald váttað av {provider} verður upphæddin drigin frá hesi mappuni.",faucest_wallet_desc_2:"Hetta hjálpir at halda skil á øllum {provider} gjøldum og støðum teirra.",faucest_wallet_desc_3:"Mappan skal hava upphædd av sats ið umsitarin bjóðar í býti fyri fiat gjaldoyrað.",faucest_wallet_desc_4:"Er ásetta mappan tóm verða gjøld umvegis {provider} ikki avgreidd.",faucest_wallet_desc_5:"Upphæddin á tiltaksmappuni kann umsíðir gerast negativ í fall fleiri fiat gjøld verða rindaði.",faucest_wallet_id:"Tiltaksmappueyðmerki (valfríur)",faucest_wallet_id_hint:"Eyðmerki á mappu við tøkari upphædd at senda til brúkaran.",tag:"Spjaldur",unit:"Eind",description:"Lýsing",expiry:"Fyrnar",webhook:"Vevongul",webhook_url:"Vevongulsleinkja",webhook_url_hint:"Vevongulsleinkja ið gjaldsupplýsingarnir verða sendir til. Tað verður koyrt fyri hvørt gjald.",copy_webhook_url:"Avrita vevongulsleinkju",webhook_events_list:"Vevongulin noyðist at koyra undir fylgjandi hendingum:",webhook_stripe_description:"Á Stripe síðuni noyðist tú at uppseta ein vevongul við einari leinkju ið peikar á tín LNbits-ambætara.",webhook_square_description:"Á Square síðuni noyðist tú at uppseta ein vevongul ið peikar á hesa LNbits-leinkjuna.",square_webhook_url_hint:"Skal samsvara við fráboðanarleinkjuna hjá Square. LNbits tørvar /api/v1/callback/square slóðina.",access_token:"Atgongdarmerki",location_id:"Staðsetingareyðmerki",square_location_id_hint:"Square-staðsetingareyðmerkið ið gjaldsumbønarleinkjur verða gjørdar fyri. Brúka endapunktið at velja royndar- ella framleiðsluumhvørvi.",api_version:"API útgáva",payment_proof:"Gjaldsprógv",update:"Dagfør",update_available:"Dagføring {version} tøk!",funding_sources:"Fíggingarkeldur",funding_source:"Fíggingarkelda",requires_server_restart:"Eftir broyting av hesum stillingunum er neyðugt at endurbyrja ambætaran, til tess at broytingarnar fáa virknað.",funding_source_info:"Fíggingarkelduupplýsingar",phoenixd_warning:"Phoenixd áminningarramsan kann einans ásetast um phoenixd dátuskjáttan er ásett og LNbits fær lisið hana. Tað er ikki eitt tekin um at phoenixd ikki koyrir. Tað merkir bara at LNbits ikki hevur atgongd at vísa áminningarramsuna her.",latest_update:"Tú ert á nýggjastu útgávuni {version}.",notifications:"Fráboðanir",notifications_configure:"Fráboðanaruppsetan",notifications_nostr_config:"Nostr uppsetan",notifications_enable_nostr:"Virkja Nostr fráboðanir",notifications_enable_nostr_desc:"Send fráboðanir umvegis Nostr",notifications_nostr_private_key:"Nostr privatur lykil",notifications_nostr_private_key_desc:"Privatur lykil, í sekstandatal ella nsec skapi, at undirrita boð send til Nostr",notifications_nostr_identifier:"Nostr-dátuheiti",notifications_nostr_identifier_desc:"Nip5-dátuheiti ið fráboðanir verða sendar til",notifications_nostr_identifiers:"Nostr-dátuheitir",notifications_nostr_identifiers_desc:"Listi av dátuheitum ið fráboðanir verða sendar til",notifications_telegram_config:"Telegram-uppsetan",notifications_enable_telegram:"Virkja Telegram-fráboðanir",notifications_enable_telegram_desc:"Send fráboðanir umvegis Telegram",notifications_telegram_access_token:"Atgongdarmerki",notifications_telegram_access_token_desc:"Atgongdarmerki til bottin",notifications_chat_id:"Telegram-kjatteyðmerki",notifications_chat_id_desc:"Eyðmerkið á Telegram-kjatti ið fráboðanir verða sendar til",notifications_excluded_wallets_desc:"Send ikki fráboðanir fyri hesar mappur",notifications_email_config:"Teldupost uppsetan",notifications_enable_email:"Virkja teldupost",notifications_enable_email_desc:"Send fráboðanir o.a. umvegis teldupost",notifications_send_test_email:"Send royndar teldubræv",notifications_send_email:"Send teldupost frá",notifications_send_email_desc:"Teldupostbústaður ið sent verður frá",notifications_send_email_username:"Brúkaranavn",notifications_send_email_username_desc:"Brúkaranavn. Verður brúkaranavn ikki tilskila verður teldupostbústaðurin brúktur",notifications_send_email_password:"Loyniorð fyri at senda teldupost",notifications_send_email_password_desc:"Loyniorð fyri teldupostbústaðin ið sent verður frá",notifications_send_email_server_port:"SMTP-portur",notifications_send_email_server_port_desc:"Portur á SMTP-ambætaranum",notifications_send_email_server:"SMTP-ambætari",notifications_send_email_server_desc:"SMTP-ambætari ið skal senda teldupostin",notifications_send_to_emails:"Send teldubrøv til",notifications_send_to_emails_desc:"Fráboðanir verða sendar, sum teldubrøv, til",notification_settings_update:"Broyttar stillingar",notification_settings_update_desc:"Fráboða um broyttar ambætarastillingar",notification_server_start_stop:"Startaðan/Steðgaðan ambætara",notification_server_start_stop_desc:"Fráboða um startaðan og steðgaðan ambætara",notification_watchdog_limit:"Varðhundsmarkfráboðan",notification_watchdog_limit_desc:"Boða frá tá mark varðhundsins er rokkið. Hetta broytir ikki fíggingarkelduna.",notification_server_status:"Ambætarastøðu",notification_server_status_desc:"Fráboða regluliga um ambætarastøðuna (tilskila tíðarbil í tímum)",notification_incoming_payment:"Inngjøld",notification_incoming_payment_desc:"Fráboða um inngjøld, á mappur, ið er hægri enn tilskillaða upphæddin (sats)",notification_outgoing_payment:"Útgjøld",notification_outgoing_payment_desc:"Fráboða um útgjøld, frá mappum, ið er størri enn tilskilaða upphæddin (sats)",notification_credit_debit:"Góð- og skuldskrivingar",notification_credit_debit_desc:"Fráboða um mappur góðskrivaðar ella skuldskrivaðar av úrvalsbrúkaranum",notification_balance_delta_changed:"Saldumunur broyttur",notification_balance_delta_changed_desc:"Boða frá tá munurin á knútasalduni og LNbits-salduni er broyttur meira enn tað ávístu upphæddina (í sats). Áset 0 fyri at óvirkja. Verður kannað hvønn minutt.",watchdog_introduction:"Varðhundurin er ein funka ið sjálvvirkandi kann skifta fíggingarkelduna til VoidWallet, í fall munurin á saldu fíggingarkeldunnar og saldu LNbits er størri enn eitt vist. Hetta kann hjálpa at fyribyrgja ovurnýtslu og tryggja saldu fíggingarkeldunnar.",enable_watchdog:"Varðhundaskifti",enable_watchdog_desc:"Um virkt, og LNbits-saldan gerst hægri enn knútasaldan, so verður fíggingarkeldan sjálvvirkandi broytt til VoidWallet. Eftir dagføringar er neyðugt at virkja hetta aftur.",watchdog_interval:"Títtleiki varðhundsins",watchdog_interval_desc:"Títtleikin — í minuttum — har varðhundurin kannar, um skifti, treytað av saldumuninum [knúta_salda - lnbits_salda], er neyðugt.",watchdog_delta:"Delta varðhundsins",watchdog_delta_desc:"Mark fyri skifti av fíggingarkeldu til VoidWallet [lnbits_salda - knúta_salda > delta]",status:"Støða",notification_source:"Fráboðanarkeldur",notification_source_label:"Kelduleinkja (brúka einans almennu LNbits fráboðanarkelduna og keldur tú hevur álit á)",more:"Frætt meira",more_count:"{count} afturat",less:"minni",releases:"Útgávur",watchdog:"Varðhundur",server_logs:"Gerðalisti ambætarans",ip_blocker:"IP-noktan",security:"Trygd",security_tools:"Trygdaramboð",block_access_hint:"Nokta atgongd frá IP-atsetri",allow_access_hint:"Loyv atgongd frá IP-atsetri (hevur hægri raðfesting enn noktaði IP-atsetur)",enter_ip:"Inntøppa IP-atsetur og trýst Enter",rate_limiter:"Umbønaravmarkan",callback_url_rules:"Afturtøkukallleinkjureglur",enter_callback_url_rule:"Inntøppa leinkjuregul í regex forsniði og trýst 'enter'",callback_url_rule_hint:"Afturtøkukallleinkjur, harímillum LNURL-leinkjur, verða kannaðar sambært hesum reglunum. Í minsta lagi ein regla skal lúkast. Eru ongar reglur skrásettir eru allar leinkjur loyvdar.",wallet_limiter:"Mappuavmarkingar",wallet_config:"Mappustillingar",wallet_charts:"Mapputalvur",wallet_limit_max_withdraw_per_day:"Hámark á dagligum útgjøldum í sats (0 merkir óavmarkað, -1 noktar fyri útgjøldum)",wallet_max_ballance:"Mappusalduhámark í sats (0 merkir óavmarkað)",wallet_limit_secs_between_trans:"Lágmark fyri sekund ímillum flytingar fyri hvørja mappu (0 merkir einki mark)",only_incoming_payments_allowed:"Loyv bert inngjøldum",disable_outgoing_payments:"Óvirkja útgjøld",number_of_requests:"Tal av umbønum",number_of_requests_hint:'Loyvdar umbønir fyri hvørt "tíðarbil" hjá umbønaravmarkaranum. Áset 0 fyri at óvirkja umbønaravmarkaran.',time_unit:"Tíðarbil",minute:"minutt",settings:"Stillingar",second:"sekund",hour:"tíma",disable_server_log:"Óvirkja gerðalista ambætarans",enable_server_log:"Virkja gerðalista ambætarans",coming_soon:"Hentleikin er undir menning",session_has_expired:"Tín seta er útgingin. Vinaliga rita innaftur.",instant_access_question:"ella stundisliga atgongd",login_with_user_id:"Rita inn við brúkaraeyðmerki",or:"ella",create_new_wallet:"Ger nýggja mappu",delete_all_wallets:"Strika allar mappur",confirm_delete_all_wallets:"Ynskir tú at strika ALLAR mappurnar hjá hesum brúkaranum?",login_to_account:"Rita inn á tín brúkara",create_account:"Stovna brúkara",account_settings:"Brúkara uppsetan",signin_with_oauth:"Rita inn við",signin_with_oauth_or:"ella rita inn við",signin_with_nostr:"Rita inn við Nostr",signin_with_google:"Rita inn við Google",signin_with_github:"Rita inn við GitHub",signin_with_custom_org:"Rita inn við {custom_org}",username_or_email:"Brúkaranavn ella teldupostbústaður",password:"Loyniorð",password_config:"Loyniorðsuppsetan",password_repeat:"Endurtak loyniorðið",update_password:"Broyt loyniorðið",change_password:"Broyt loyniorð",update_credentials:"Dagfør innritanarupplýsingar",update_pubkey:"Broyt almenna lykilin",nostr_pubkey_tooltip:"Inntøppa almenna Nostr-lykil brúkarans (sekstandatøl)",set_password:"Áset loyniorð",set_password_tooltip:"Áset hesum brúkaranum eitt loyniorð",invalid_password:"Loyniorð skulu hava í minsta lagi 8 tekn",invalid_password_repeat:"Loyniorðini eru ikki eins",reset_key_generated:"Ein endursetanarlykil er hervið gjørdur.",reset_key_copy:"Trýst á OK fyri at avrita endursetanarleinkjuna til setiborðið.",login:"Rita inn",register:"Skráset",username:"Brúkaranavn",pubkey:"Almennur lykil",user_id:"Brúkaraeyðmerki",id:"Eyðmerki",email:"Teldupostbústaður",email_confirmation_hint:"Teldupostbústaður ið váttanarkota skal sendast til.",nostr_identifier:"Nostr-dátuheiti",nostr_identifier_hint:"Nostr nip5-dátuheiti ella ið váttanarkota skal sendast til.",first_name:"Fornavn",last_name:"Eftirnavn",picture:"Mynd",user_picture_desc:"Leinkja ið vísur til vangamynd. Tú kanst leggja hana út undir Tilfar.",verify_email:"Vátta teldupost umvegis",account:"Brúkari",update_account:"Broyt brúkara",invalid_username:"Ógildigt brúkaranavn",auth_provider:"Samgildisveitari",external_id:"Ytri eyðmerki",my_account:"Mín brúkari",existing_account_question:"Hevur tú longu ein brúkara?",background_image:"Bakgrundsmynd",back:"Aftur",logout:"Rita út",look_and_feel:"Útsjónd",endpoint:"Endapunkt",api:"API",api_stripe:"API",api_token:"API-merki",api_tokens:"API-merkir",access_control_list:"Atgongdarstýringarlisti",access_control_list_admin_warning:"Hetta er ein umsitanarbrúkari. Framleidd merkir fáa tí umsitanarrættindir.",new_api_acl:"Nýggjan atgongdarstýringarlista",api_token_id:"API-merki",toggle_gradient:"Litskifti",gradient_background:"Litskifti á bakgrund",rounded_ui:"Avrundaði kort & knøttar",toggle_rounded_ui:"Virkja ella óvirkja avrundaði horn á kortum og knøttum",card_gradient:"Litskifti á kortum",toggle_card_gradient:"Virkja ella óvirkja litskifti á kortum",card_shadow:"Kortskuggar",toggle_card_shadow:"Virkja ella óvirkja skugga handan kort",burger_menu_background:"Bakgrund á síðuteigi",toggle_burger_menu_background:"Virkja ella óvirkja bakgrund síðuteigsins",language:"Mál",assets:"Tilfar",max_asset_size_mb:"Hámarksstødd á tilfari (MB)",max_asset_size_mb_desc:"Hámarksstøddin, í megabýtum, á tilfari ið verður uppsent. Møguligt er at nýta desimalar.",assets_allowed_mime_types:"Loyvt slag av tilfari",assets_allowed_mime_types_desc:"(MIME) Sløg av tilfari ið loyvt verður at uppsenda. Um einki slag er ásett eru øll sløg loyvd.",thumbnail_width:"Smámyndavídd",thumbnail_width_desc:"Víddin á framleiddu smámyndunum, í piksilum.",thumbnail_height:"Smámyndahædd",thumbnail_height_desc:"Hæddin á framleiddu smámyndunum, í piksilum.",thumbnail_format:"Smámyndaforsnið",thumbnail_format_desc:"Forsnið á framleiddu smámyndunum (PNG, JPEG, o.s.fr.).",max_assets_per_user:"Hámark av tilfari fyri hvønn brúkara",max_assets_per_user_desc:"Hámark av tilfari ið hvør brúkari sleppur at uppsenda. Null merkir at uppsending er noktað.",assets_no_limit_users:"Brúkarir undantiknir tilfarsmørkum",assets_no_limit_users_desc:"Hesir brúkarir eru undantiknir hámarkinum av uppsendum tilfari (grundað á brúkaraeyðkenni).",color_scheme:"Litaval",visible_wallet_count:"Nøgd av vístum mappum",admin_settings:"Umsit stillingar",extension_cost:"Útgávan krevur eitt gjald á í minsta lagi {cost} sats.",extension_paid_sats:"Tú hevur longu goldið {paid_sats} sats.",extension_permissions_title:"Játta ískoytisforriti rættindir",extension_permissions_tab:"Rættindir ískoytisforritsins",user_permissions_tab:"Mínar játtanir",extension_permissions_none:"Hetta ískoytisforritið krevur ongi rættindir undir innlegging.",user_permissions_none:"Tú hevur ikki játtað hesum ískoytisforriti nøkur rættindir.",user_permissions_max_amount:"Mark á gjaldsupphædd",user_permissions_destination_policy:"Loyvi at rinda til",user_permissions_no_editable_settings:"Hendan játtanin hevur einki at tillaga.",extension_permissions_grant_install:"Játta og innlegg",extension_permissions_high_risk_warning:"Hetta ískoytisforritið biður um rættindi at flyta pening.",extension_permission_risk_low:"Lítil váði",extension_permission_risk_medium:"Miðal váði",extension_permission_risk_high:"Stórur váði",extension_permission_warning_wallet_pay_invoice:"Kann brúka pening úr mappum ið eru tøkar á tínum brúkara.",extension_permission_warning_wallet_pay_invoice_background:"Kann brúka pening úr ásettum mappum seinni og uttan inntriv frá brúkara.",extension_permission_warning_wallet_payments_watch:"Kann lesa gjaldssmálutir viðvíkjandi ásettum mappum.",extension_permission_warning_extension_api_request_write:"Kann skriva dátur ella koyra tilgongdir í ásettum ískoytisforritum.",extension_permission_ext_storage_read:"Lesa ískoytisforritagoymslu",extension_permission_ext_storage_read_public:"Lesa almenna ískoytisforritagoymslu",extension_permission_ext_storage_write:"Skriva til ískoytisforritagoymslu",extension_permission_ext_storage_read_write:"Lesa og skriva til ískoytisforritagoymslu",extension_permission_extension_api_request:"Brúka onnur ískoytisforrit",extension_permission_extension_api_request_extensions:"Loyvd ískoytisforrit",extension_permission_access_read:"Lesa",extension_permission_access_write:"Skriva",extension_permission_http_request:"Sambinda til ytri vevsíður",extension_permission_http_request_hosts:"Loyvdir vertir",extension_permission_utils_basic:"Brúka grundleggjandi LNbits hentleikar",extension_permission_ui_camera_scan_qr:"Skanna QR-kotur",extension_permission_wallet_payments_watch:"Eygleiða gjøld á mappum",extension_permission_wallet_create_invoice:"Gera gjaldsumbønir",extension_permission_wallet_create_invoice_public:"Gera Lightning-gjaldsumbønir frá almennum síðum",extension_permission_wallet_balance_read:"Síggja mappusaldur",extension_permission_wallet_list:"Vísa mappur",extension_permission_wallet_pay_invoice:"Rinda gjaldsumbønir",extension_permission_wallet_pay_invoice_background:"Rinda í bakgrundini, uttan inntriv frá brúkara",create_extension:"Stovna ískoytisforrit",release_details_error:"Bar ikki til at útvega sleppingarstaklutir.",pay_from_wallet:"Rinda úr mappuni",pay_with:"Rinda við {provider}",select_payment_provider:"Vel gjaldsmeklara",wallet_required:"Mappa *",show_qr:"Vís QR-kotu",retry_install:"Royn at leggja inn aftur",new_payment:"Rinda av nýggjum",update_payment:"Goym gjaldsupplýsingar",already_paid_question:"Hevur tú longu goldið?",sell:"Sel",sell_require:"Virkja ískoytisforritið fyri eitt gjald",sell_info:"Eitt gjald á í minsta lagi {amount} sats er kravt fyri at virkja {name}-ískoytisforritið.",hide_empty_wallets:"Fjal tómar mappur",recheck:"Eftirkanna",check:"Kanna",check_connection:"Kanna sambinding",check_webhook:"Kanna vevongul",contributors:"Stigtakarir",license:"Loyvi",reset_key:"Endursetanarlykil",reset_password:"Endurset loyniorð",border_choices:"Rammusnið",select_all:"Vel øll",nfc_supported:"NFC-hentleiki er møguligur",nfc_not_supported:"NFC-hentleiki er ikki møguligur",expire_date:"Útgongudagfesting: ",hash:"Hash: ",welcome_lnbits:"Vælkomin til LNbits",setup_su_account:"Ger úrvalsbrúkaran niðanfyri.",first_install_token:"Merkið fyri fyrstu innlegging",create_ticker_converter:"Ger gjaldoyramerkilíka",enable_audit:"Virkja slóðfesti",recommended:"Viðmælt",audit_desc:"Skráset HTTP-umbønirnar sambært fylgjandi ásetingum",audit_record_req:"Skráset body-partin av umbønum",audit_record_warning:"Gev gætur: ",audit_record_req_warning_1:"trúnaðardátur, teirra millum loyniorð, verða skrásettar.",audit_record_req_warning_2:"body-parturin av umbønunum kann fylla nógv.",audit_record_use:"Skal brúkast við fyrivarni.",audit_ip:"Skráset IP-atsetur",audit_ip_desc:"Skráset IP-atsetur viðskiftarans",audit_path_params:"Skráset slóðávirkir (Path Parameters)",audit_query_params:"Skráset fyrispurningsávirkir (Query Parameters)",audit_http_methods:"Íroknaðir HTTP-háttir",audit_http_methods_hint:"Íroknaðir HTTP-háttir. Er listin tómur verða allir háttir íroknaðir.",audit_http_methods_label:"HTTP-háttir",audit_resp_codes:"Íroknaðar HTTP-svarkotur",audit_resp_codes_hint:"Íroknaðar HTTP-svarkotur (regex forsnið). Er listin tómur verða allar kotur íroknaðar. T.d.: 4.*, 5.*",audit_resp_codes_label:"HTTP-svarkotur (regex)",audit_paths:"Íroknaðar slóðir",audit_paths_hint:"Íroknaðar slóðir (regex forsnið). Er listin tómur verða allar slóðir íroknaðar.",audit_paths_label:"HTTP-slóð (regex)",audit_paths_exclude:"Útiloka slóðir",audit_paths_exclude_hint:"Listi av útilokaðum slóðum (regex forsnið). Er listin tómur verða ongar slóðir útilokaðar.",audit_paths_exclude_label:"HTTP-slóð (regex)",exchange_providers:"Gjaldoyrakursveitarir",admin_extensions:"Umsitingarískoytisforrit",admin_extensions_label:"Umsitingarískoytisforrit",admin_extensions_hint:"Ískoytisforrit ið einans er tøk fyri brúkarum við umsitingarligum rættindum",user_default_extensions:"Brúkaraforsett ískoytisforrit",user_default_extensions_label:"Brúkaraforsett ískoytisforrit",user_default_extensions_hint:"Ískoytisforrit ið forsett verða virkt fyri brúkarunum",extension_builder:"Ískoytisforritasavnari",extension_builder_manifest_url:"Leinkja til ískoytisforritasavnaraskrá",extension_builder_manifest_url_hint:"Leinkja til eina JSON-skrá við ískoytisforritasavnarastaklutum",miscellanous:"Ymiskt",misc_disable_extensions:"Óvirkja ískoytsiforrit",misc_disable_extensions_label:"Óvirkja øll ískoytisforrit",misc_disable_extensions_builder:"Virkja ískoytisforritasavnara",misc_disable_extensions_builder_label:"Lova brúkarum ið ikki hava umsitanarrættindi at brúka ískoytisforritasavnaran",misc_hide_api:"Fjal API-upplýsingar",misc_hide_api_label:"Fjalur mappu-API. Tað er upp til hvørt ískoytisforrit sær at halda við stillingini",wallets_management:"Fíggjaruppsetan",funding_source_info:"Fíggingarkeldu upplýsingar",funding_source:"Fíggingarkelda: {wallet_class}",node_balance:"Salda knútsins: {balance} sats",lnbits_balance:"LNbits-salda: {balance} sats",funding_reserve_percent:"Tiltakspeningur: {percent} %",node_management:"Knútaumsiting",node_management_not_supported:"Knútaumsiting er ikki møgulig við verandi fíggingarkeldu",toggle_node_ui:"Knútanýtslumót",toggle_public_node_ui:"Alment knútanýtslumót",toggle_transactions_node_ui:"Flytingarskiljiblað (frámælt á størri CLN-knútum vegna ovbyrjan)",invoice_expiry:"Loka gjaldsumbøn eftir",routing_fee_reserve_calculations:"Beiningaravgjaldstiltaksútrokningar",routing_fee_reserve_calculations_desc:'Fyri hvørt útgjald setur LNbits eina "tiltaksupphædd" til síðis at rinda beiningaravgjøld. Hámarkið á beiningaravgjaldinum ið verður handað fíggingarkelduni er tað hægra av fylgjandi: lágmarkið fyri beiningaravgjald ella beiningaravgjald í prosentum.',millisats:"millisats",fee_reserve:"Lágmark fyri beiningaravgjald",fee_reserve_percent:"Beiningaravgjald í prosentum",fee_reserve_min_hint:"Lágmark fyri beiningariavgjald fyri hvørt gjald.
Hetta riggar sum eitt minstamark - mest loyvda beiningaravgjald verður ongantíð lægri, uttan mun til gjaldsupphæddina.",fee_reserve_percent_hint:"Prosent av gjaldsupphæddini at seta av til beiningaravgjald.",payment_timeouts:"Gjaldsfreistir",payment_wait_time:"Greiðslubíðitíð (sek.)",seconds:"sekund",payment_pending_interval:"Greiðslukanningarmillumbil (sek.)",payment_pending_interval_desc:"Tíðin ímillum óavgreidd gjøld verða kannaði",payment_pending_interval_tooltip:"Ásetur títtleikan ið LNbits kannar og tillagar støðuna á óavgreiddum gjøldum. Longri millumbil kunnu lætta um byrðu knútsins og elva til skjótari greiðslur, ímeðan støðan á óavgreiddum gjøldum ikki verður dagførd líka títt.",payment_wait_time_desc:"Bíðitíð áðrenn útgjøld verða merkt at verða í bíðistøðu. Forsett: 5 sek.; hækka í fall gjaldsumbønirnar taka langa tíð at avroknað.",payment_wait_time_tooltip:"Ásetur tíðina ið LNbits bíðar eftir váttan fyri eitt útgjáld áðrenn útgjaldið verður sett í bíðistøðu. Longri bíðitíðir eru hóskandi tá ein skal rinda gjaldsumbønir ið taka longri tí at avroknað (t.d. HODL-gjaldsumbønir, Boltz). Møguligt er at kannað útgjaldið seinni og tað verður eisini kannað sjálvvirkandi við jøvnum millumbilum.",server_management:"Ambætaraumsiting",base_url_label:"Fastbundin rótleinkja til hendan ambætaran",authentication:"Samgilding",auth_token_expiry_label:"Merkigildistíð í minuttum",auth_token_expiry_hint:"Minuttir ið merkir eru gildið",auth_authentication_cache_label:"Kovatíð (minuttir)",auth_authentication_cache_hint:"Minuttir ið eydnaðar samgildingar verða goymdar í kovanum (áset 0 fyri at óvirkja)",auth_allowed_methods_label:"Loyvdir samgildisháttir",auth_allowed_methods_hint:"Vel samgildisháttir",auth_nostr_label:"Nostr-umbønarleinkja",auth_nostr_hint:"Fullfíggjaðar leinkjur ið viðskiftarar skulu brúka til innritanir.",auth_google_ci_label:"Google-viðskiftaraeyðmerki",auth_google_ci_hint:"Tryggja at góðkenda víðaribeiningin inniheldur https://{domain}/api/v1/auth/google/token",auth_google_cs_label:"Google-viðskiftaraloyna",auth_gh_client_id_label:"GitHub-viðskiftaraeyðmerki",auth_gh_client_id_hint:"Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/github/token",auth_gh_client_secret_label:"GitHub-viðskiftaraloyna",auth_keycloak_label:"Keycloak-viðrakanarleinkja",auth_keycloak_ci_label:"Keycloak-viðskiftaraeyðmerki",auth_keycloak_ci_hint:"Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/keycloak/token",auth_keycloak_cs_label:"Keycloak-viðskiftaraloyna",auth_keycloak_custom_org_label:"Tillaga Keycloak-felag",auth_keycloak_custom_icon_label:"Tillaga Keycloak ímynd (leinkja)",auth_oidc_label:"OIDC-viðrakanarleinkja",auth_oidc_ci_label:"OIDC-viðskiftaraeyðmerki",auth_oidc_ci_hint:"Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/oidc/token",auth_oidc_cs_label:"OIDC-viðskiftaraloyna",auth_oidc_custom_org_label:"Tillaga OIDC navn á felagi (t.d. Zitadel, Authentik)",auth_oidc_custom_icon_label:"Tillaga OIDC ímynd (leinkja)",currency_settings:"Gjaldoyrastillingar",allowed_currencies:"Loyvd gjaldoyru",allowed_currencies_hint:"Avmarka tøk fiat gjaldoyru",default_account_currency:"Forsett roknskapargjaldoyra",default_account_currency_hint:"Forsett gjaldoyra til roknskaparførslu",min_incoming_payment_amount:"Inngjaldslágmark",min_incoming_payment_amount_desc:"Minst loyvda upphædd tá gjaldsumbøn verður gjørd",max_incoming_payment_amount:"Inngjaldshámark",max_incoming_payment_amount_desc:"Hægst loyvda upphædd tá gjaldsumbøn verður gjørd",max_outgoing_payment_amount:"Útgjaldshámark",max_outgoing_payment_amount_desc:"Hægst loyvda upphædd á hvørjum útgjaldi sær",service_fees:"Tænastuavgjøld",service_fee:"Tænastuavgjald",service_fee_label:"Tænastuavgjald (%)",service_fee_hint:"Avgjald kravt fyri hvørja flyting (%)",service_fee_max:"Hámark fyri tænastuavgjald",service_fee_max_label:"Hámark fyri tænastuavgjald (sats)",service_fee_max_hint:"Hámark fyri kravt tænastugjald í satoshis",fee_wallet:"Avgjaldsmappa",fee_wallet_label:"Avgjaldsmappa (mappueyðmerki)",fee_wallet_hint:"Eyðmerki á mappu ið tænastuavgjøld verða góðskrivað á",disable_fee:"Óvirkja tænastuavgjald",disable_fee_internal:"Óvirkja tænastuavgjald fyri innanknútsins gjøld",disable_fee_internal_desc:"Óvirkja tænastuavgjald fyri innanknútsins Lightning gjøld",ui_management:"Nýtslumótumsiting",ui_site_title:"Síðuheiti",ui_changing_remove_lnbits_elements:" (tillaging elvir til at LNbits-lutir á forsíðuni og síðufótinum verða strikaðir)",ui_site_tagline:"Síðuslagorð",ui_elements_enable:"Vís lutir á forsíðufótinum",ui_elements_disable:"Fjal lutir á forsíðufótinum",ui_toggle_elements_tip:"Strikar lutir so sum LNbits-útgávu og 'Koyrir á' frá forsíðuni",ui_site_description:"Síðulýsing",ui_site_description_hint:"Nýt vanligan tekst, Markdown, ella rátt HTML",ui_default_wallet_name:"Forsett mappunavn",ui_default_theme:"Forsett snið",wallet_featured_button_title:"Tillagaður knøttur á mappusíðuni",wallet_featured_button_label:"Tekstur á tillagaum knøtti",wallet_featured_button_label_hint:"Vís sermerktan knøtt á mappusíðuni",wallet_featured_button_url:"Leinkja ið tillagi knøtturin peikar á",wallet_featured_button_url_hint:"Leinkjan verður latin upp tá trýst verður á knøttin. Lat teigin verða tóman fyri at fjala knøttin.",wallet_featured_button_icon:"Ímynd á tillagaða knøttinum",wallet_featured_button_icon_hint:'Quasar-ímyndarnavnið ið skal vísast á knøttinum (t.d. "bolt")',lnbits_wallet:"LNbits-mappa",denomination:"Heiti",denomination_hint:"Heitið á FakeWallet-myntlíkinum",denomination_error:"Heitið skal verða 3 stavir, ella `sats`",ui_qr_code_logo:"Ímynd á QR-kotum og snarvegum",ui_qr_code_logo_hint:"Leinkja til ímynd ið skal brúkast á QR-kotum og snarvegum",ui_apple_touch_icon:"Apple Touch ímynd",ui_apple_touch_icon_hint:"Leinkja til Apple touch ímynd",ui_custom_image:"Tillagað mynd",ui_custom_image_label:"Leinkja til tillagaða mynd",ui_custom_image_hint:"Mynd víst á forsíðu/innritanarsíðu",ui_custom_badge_title:"Tillaga spjaldur",ui_custom_badge_desc:"Vís tillagaðan spjaldratekst ovast á LNbits síðuni",ui_custom_badge:"Tillagaður spjaldratekstur",ui_custom_badge_label:"Tillagaður spjaldratekstur 'BRÚKA VIÐ FYRIVARNI'",ui_custom_badge_color_label:"Litur á spjaldrinum",themes:"Snið",themes_hint:"Tilskilaði snið ið verða tøk fyri brúkarum",custom_logo:"Umsitaravalt búmerki",custom_logo_hint:"Leinkja ið peikar til búmerkið",ad_space_section_title:"Lýsingarteigur",ad_space_section_desc:"Tillaga lýsingarteigin á mappusíðuni.",ad_space_title:"Tekstur á lýsingarteigi",ad_space_title_hint:"Tekstur vístur omanfyri lýsingarteigin",ad_slots:"Lýsingar",ad_slots_hint:"Leinkjur og myndaleinkjur í CSV-forsniði. Tað er upp til hvørt ískoytisforrit sær at halda við stillingini.",ads_enabled:"Vís lýsingar",ads_disabled:"Fjal lýsingar",user_management:"Brúkaraumsiting",admin_users:"Umsitarir",admin_users_hint:"Brúkarar við umsitingarrættindum",admin_users_label:"Brúkaraeyðmerki",allowed_users:"Loyvdir brúkarar",allowed_users_hint:"Einans fylgjandi brúkarar kunnu nýta LNbits",allowed_users_hint_feature:"{feature} er avmarkað til hesar brúkararnar",allowed_users_label:"Brúkaraeyðmerki",allow_creation_user:"Loyv skráseting av nýggjum brúkarum",allow_creation_user_desc:"Loyv stovnan av nýggjum brúkarum umvegis forsíðuna",require_user_activation:"Krev virkjan av nýggjum brúkarum",require_user_activation_desc:"Nýggir brúkarir verða virktir við at lúka eina av váttanartreytunum. Umsitarir kunnu virkja brúkarir frá umsitanarsíðuni og harvið skúgva váttanartreytirnar til viks fyri brúkarar.",reusable_activation_code:"Endurnýtsluvirkjanarkota",reusable_activation_code_label:"Endurnýtsluvirkjanarkota",reusable_activation_code_hint:"Hendan virkjanarkotan kann nýtast fleiri ferðir av ymiskum brúkarum.",one_time_activation_code:"Einnýtisvirkjanarkotur",one_time_activation_code_label:"Legg virkjanarkotu inn",one_time_activation_code_hint:"Einnýtisvirkjanarkotur. Hvør kota kann bert nýtast einaferð og verður strika úr listanum eftir at hon er brúkt.",invitation_code:"Innbjóðingarkota",invitation_code_hint:"Innbjóðingarkotan ið tú hevur fingið.",new_user_not_allowed:"Skráseting av nýggjum brúkarum er óvirkt.",start_user_impersonation:"Lát at vera hesin brúkarin",stop_user_impersonation:"Lát ikki longur at vera brúkari",components:"Forritsliðir",long_running_endpoints:"5 endapunktini ið hava koyrt longst",http_request_methods:"HTTP-umbønarháttir",http_response_codes:"HTTP-svarkotur",request_details:"Smálutir umbønarinnar",http_request_details:"HTTP-umbønarsmálutir",payment_details:"Gjaldssmálutir",payment_details_desc:"Nágreiniligir staklutir gjaldsins",payments:"Gjøld",payment_show_internal:"Vís innanhýsis gjøld",payment_chart_flow:"Mánaðarligur peningastreymur",payment_chart_status:"Gjaldstøður",payment_chart_tx_per_wallet:"Flytingar fyri hvørja mappu (upphædd/nøgd)",payment_details_back:"Aftur til gjøld",payment_chart_tags:"Gjøld eftir spjøldrum",payments_balance_in_out:"Inn- og útgjaldsupphæddir",payments_count_in_out:"Nøgd av inn- og útgjøldum",payments_status_chart:"Støðumynd",payments_tag_chart:"Spjaldrasirkulmynd",payments_balance_chart:"Saldulinjumynd",payments_wallets_chart:"Mappumynd",payments_balance_in_out_chart:"Inn- og útgjaldsupphæddir",payments_count_in_out_chart:"Nøgd av inn- og útgjøldum",reset_wallet_keys:"Endurset lyklar",reset_wallet_keys_desc:"Endurset API lyklarnar fyri mappuna. Hetta ógildar verandi lyklar og framleiður nýggjar lyklar.",view_list:"Vís mappur í lista",view_column:"Vís mappur í teigum",filter_payments:"Filtrera gjøld",filter_labels:"Filtrera spjøldur",filter_date:"Filtrera út frá tíðarskeiði",websocket_example:"Vevsokkul dømi",client_id:"Viðskiftaraeyðmerki",secret_key:"Loyniligur lykil",signing_secret:"Undirritanarlykil",signing_secret_hint:"Undirritanarlykil fyri vevongulin. Boð verða undirritaði við hesum lyklinum.",webhook_id:"Vevongulseyðmerki",webhook_id_hint:"PayPal-vevongulseyðmerki ið váttar inngangandi hendingar.",webhook_paypal_description:"Uppset ein vevongul ið peikar á tín LNbits-ambætara á PayPal-síðuni.",square_webhook_signature_key_hint:"Square-vevongulsundirritanarlykil ið váttar inngandi hendingar.",callback_success_url:"Afturtøkukallsleinkja",callback_success_url_hint:"Eftir avgreitt gjald verður brúkarin víðaribeindur til hesa leinkjuna",connected:"Sambundin",not_connected:"Ikki sambundin",free:"Ókeypis",paid:"Til keyps",funding_source_retries:"Hámark av endurroyndum",funding_source_retries_desc:"Hámark av endurroyndum av knýta í fíggingarkelduna áðrenn VoidWallet verður virkt.",add_label:"Nýtt spjaldur",label:"Spjaldur",labels:"Spjøldur",label_filter:"Spjaldrafiltur",no_labels_defined:"Enn eru eingi spjøldur gjørd",manage_labels:"Umsit spjøldur",update_label:"Broyt spjaldur",delete_label:"Strika spjaldur",add_remove_labels:"Áset ella strika spøldur",payment_labels_updated:"Spjøldur á gjaldi broytt",color:"Litur",sort:"Raða",sort_by:"Raða eftir"},window._lnbitsUtils={url_for(e){const t=new URL(e,window.location.origin);return t.searchParams.set("v",window.g.settings.cacheKey),t.toString()},loadScript(e){return new Promise((t,n)=>{const a=document.createElement("script");a.src=this.url_for(e),a.onload=()=>{t()},a.onerror=()=>{n(new Error(`Failed to load script ${e}`))},document.body.appendChild(a)})},async loadTemplate(e){return fetch(this.url_for(e)).then(t=>{if(!t.ok)throw new Error(`Failed to load template from ${e}`);return t.text()}).then(e=>{const t=document.createElement("div");t.innerHTML=e.trim(),document.body.appendChild(t)})},copyText(e,t,n){Quasar.copyToClipboard(e).then(()=>{Quasar.Notify.create({message:t||"Copied to clipboard!",position:n||"bottom"})})},confirmDialog:e=>Quasar.Dialog.create({message:e,ok:{flat:!0,color:"orange"},cancel:{flat:!0,color:"grey"}}),async logout(){LNbits.utils.confirmDialog('Do you really want to logout? Please visit "My Account" page to check your credentials!').onOk(async()=>{try{await LNbits.api.logout(),window.location="/"}catch(e){LNbits.utils.notifyApiError(e)}})},backupLocalStorage(e,t=!1){const n=Object.entries(Quasar.LocalStorage.getAll()).filter(([t,n])=>t.startsWith("lnbits.")&&t!==`lnbits.${e}`)||[];Quasar.LocalStorage.setItem(`lnbits.${e}`,n),t&&n.forEach(([e,t])=>Quasar.LocalStorage.remove(e))},restoreLocalStorage(e){Object.entries(Quasar.LocalStorage.getAll()).filter(([t,n])=>t.startsWith("lnbits.")&&t!==`lnbits.${e}`).forEach(([e,t])=>Quasar.LocalStorage.remove(e));(Quasar.LocalStorage.getItem(`lnbits.${e}`)||[]).forEach(([e,t])=>Quasar.LocalStorage.setItem(e,t)),Quasar.LocalStorage.remove(`lnbits.${e}`)},async digestMessage(e){const t=(new TextEncoder).encode(e),n=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(n)).map(e=>e.toString(16).padStart(2,"0")).join("")},formatTimestamp:(e,t=null)=>(t=t||window.dateFormat,Quasar.date.formatDate(new Date(1e3*e),t)),formatDateString(e){this.formatDate(e)},formatDate:(e,t=null)=>(t=t||window.dateFormat,Quasar.date.formatDate(new Date(e),t)),formatTimestampFrom:e=>moment.utc(1e3*e).local().fromNow(),formatDateFrom(e){const t=new Date(e).getTime();return moment.utc(t).local().fromNow()},formatBalance:(e,t="sats")=>"sats"===t?LNbits.utils.formatSat(e)+" sats":LNbits.utils.formatCurrency(e/100,t),formatCurrency:(e,t)=>new Intl.NumberFormat(window.i18n.global.locale,{style:"currency",currency:t||"sat"}).format(e),getCurrencySymbol(e){const t=(e||"").toUpperCase();if("BTC"===t||"XBT"===t||"SAT"===t||"SATS"===t)return"₿";try{const e=new Intl.NumberFormat(window.i18n.global.locale,{style:"currency",currency:t}).formatToParts(0).find(e=>"currency"===e.type);return e?.value||t||"¤"}catch(e){return t||"¤"}},formatSat:e=>new Intl.NumberFormat(window.i18n.global.locale).format(e),formatMsat(e){return this.formatSat(e/1e3)},parseJSONSafe(e){try{return JSON.parse(e)}catch(e){return null}},isValidBech32(e){if("string"!=typeof e)return!1;const t=e.trim();if(!t||t!==t.toLowerCase()&&t!==t.toUpperCase())return!1;const n=t.toLowerCase(),a=n.lastIndexOf("1");if(a<=0)return!1;const i=n.substring(0,a),r=n.substring(a+1);if(r.length<6)return!1;if("function"!=typeof bech32ToFiveBitArray||"function"!=typeof verify_checksum)return!1;const o=bech32ToFiveBitArray(r);return!o.some(e=>e<0)&&verify_checksum(i,o)},async notifyApiError(e){if(!e.response)return console.error(e);const t={400:"warning",401:"warning",500:"negative"};let n=e.response.data.detail;if(!n){const t=await(e.response.data?.text());n=this.parseJSONSafe(t)?.detail}n=n?Array.isArray(n)?n.map(e=>e.msg+` (${e.loc?.join("/")})`):n=[n]:[e.response.data.message||e.response.data.detail],n.forEach(n=>Quasar.Notify.create({timeout:5e3,type:t[e.response.status]||"warning",message:n,caption:[e.response.status," ",e.response.statusText].join("").toUpperCase()||null,icon:null,closeBtn:!0}))},search(e,t,n,a){try{const i=t.toLowerCase().split(a||" ");return e.filter(e=>{let t=0;return _.each(i,a=>{-1!==e[n].indexOf(a)&&t++}),t===i.length})}catch(t){return e}},prepareFilterQuery(e,t,n){e.filter=n||e.filter||{},t&&(e.pagination=t.pagination,Object.assign(e.filter,t.filter));const a=e.pagination;e.loading=!0;const i={limit:a.rowsPerPage,offset:(a.page-1)*a.rowsPerPage,sortby:a.sortBy??"",direction:a.descending?"desc":"asc",...e.filter};return e.search&&(i.search=e.search),new URLSearchParams(i)},exportCSV(e,t,n){const a=(e,t)=>{let n=void 0!==t?t(e):e;return n=null==n?"":String(n),n=n.split('"').join('""'),`"${n}"`},i=[e.map(e=>a(e.label))].concat(t.map(t=>e.map(e=>a("function"==typeof e.field?e.field(t):t[void 0===e.field?e.name:e.field],e.format)).join(","))).join("\r\n");!0!==Quasar.exportFile(`${n||"table-export"}.csv`,i,"text/csv")&&Quasar.Notify.create({message:"Browser denied file download...",color:"negative",icon:null})},convertMarkdown(e){const t=new showdown.Converter;return t.setFlavor("github"),t.setOption("simpleLineBreaks",!0),t.makeHtml(e)},_extI18nDirs:new Set,_extI18nLoaded:{},loadExtI18n(e,t){this._extI18nDirs.add(e);const n=this._extI18nLoaded[e]??={};return n[t]||(n[t]=this.loadScript(`${e}/${t}.js`).catch(()=>{if("en"!==t)return n.en??=this.loadScript(`${e}/en.js`).catch(()=>{}),n.en})),n[t]},async decryptLnurlPayAES(e,t){let n=new Uint8Array(t.match(/[\da-f]{2}/gi).map(e=>parseInt(e,16)));return crypto.subtle.importKey("raw",n,{name:"AES-CBC",length:256},!1,["decrypt"]).then(t=>{let n=Uint8Array.from(window.atob(e.iv),e=>e.charCodeAt(0)),a=Uint8Array.from(window.atob(e.ciphertext),e=>e.charCodeAt(0));return crypto.subtle.decrypt({name:"AES-CBC",iv:n},t,a)}).then(e=>new TextDecoder("utf-8").decode(e))},validateBrowsableUrl(e,t=!1){const n=new URL(e);if("http:"!==n.protocol&&"https:"!==n.protocol)throw new Error("Invalid protocol");if(!t){const e=n.hostname;if("localhost"===e||"[::1]"===e||"::1"===e||e.startsWith("127.")||e.startsWith("::ffff:127."))throw new Error("Loopback addresses are not allowed")}},openUrlInNewTab(e,t=!1){this.validateBrowsableUrl(e,t),window.open(e,"_blank","noopener,noreferrer")}},window._lnbitsApi={request:(e,t,n,a,i={})=>axios({method:e,url:t,headers:{"X-Api-Key":n},data:a,...i}),getServerHealth(){return this.request("get","/api/v1/health")},async createInvoice(e,t,n,a="sat",i=null,r=null,o=null,s=null){const l={out:!1,amount:t,memo:n,unit:a,lnurl_withdraw:i,fiat_provider:r,payment_hash:s};return o&&(l.extra={internal_memo:String(o)}),this.request("post","/api/v1/payments",e.inkey,l)},payInvoice(e,t,n=null){const a={out:!0,bolt11:t};return n&&(a.extra={internal_memo:String(n)}),this.request("post","/api/v1/payments",e.adminkey,a)},cancelInvoice(e,t){return this.request("post","/api/v1/payments/cancel",e.adminkey,{payment_hash:t})},settleInvoice(e,t){return this.request("post","/api/v1/payments/settle",e.adminkey,{preimage:t})},createAccount(e){return this.request("post","/api/v1/account",null,{name:e})},register:(e,t,n,a,i)=>axios({method:"POST",url:"/api/v1/auth/register",data:{username:e,email:t,password:n,password_repeat:a,invitation_code:i}}),reset:(e,t,n)=>axios({method:"PUT",url:"/api/v1/auth/reset",data:{reset_key:e,password:t,password_repeat:n}}),getAuthUser:()=>axios({method:"GET",url:"/api/v1/auth"}),login:(e,t)=>axios({method:"POST",url:"/api/v1/auth",data:{username:e,password:t}}),loginByProvider:(e,t,n)=>axios({method:"POST",url:`/api/v1/auth/${e}`,headers:t,data:n}),loginUsr:e=>axios({method:"POST",url:"/api/v1/auth/usr",data:{usr:e}}),logout:()=>axios({method:"POST",url:"/api/v1/auth/logout"}),impersonateUser:e=>axios({method:"POST",url:"/api/v1/auth/impersonate",data:{usr:e}}),stopImpersonation:()=>axios({method:"DELETE",url:"/api/v1/auth/impersonate"}),getAuthenticatedUser(){return this.request("get","/api/v1/auth")},getWallet(e){return this.request("get","/api/v1/wallet",e.inkey)},createWallet(e,t,n={}){return this.request("post","/api/v1/wallet",null,{name:e,wallet_type:t,...n})},updateWallet(e,t){return this.request("patch","/api/v1/wallet",t.adminkey,{name:e})},updateUiCustomization(e={}){return this.request("patch","/api/v1/auth/ui",null,e)},resetWalletKeys(e){return this.request("put",`/api/v1/wallet/reset/${e.id}`).then(e=>e.data)},deleteWallet(e){return this.request("delete",`/api/v1/wallet/${e.id}`)},getPayments(e,t){return this.request("get","/api/v1/payments/paginated?"+t,e.inkey)},getPaymentTotalBreakdown(e){return this.request("get","/api/v1/payments/stats/breakdown",e.inkey)},getPayment(e,t){return this.request("get","/api/v1/payments/"+t,e.inkey)},updateBalance(e,t){return this.request("PUT","/users/api/v1/balance",null,{amount:e,id:t})},getCurrencies(){return this.request("GET","/api/v1/currencies").then(e=>["sats",...e.data])},getDefaultSetting:e=>LNbits.api.request("GET",`/admin/api/v1/settings/default?field_name=${e}`).catch(LNbits.utils.notifyApiError),getBlockexplorerAddress(e){return this.request("get",`/blockexplorer/api/v1/address/${e}`)},getBlockexplorerTransaction(e){return this.request("get",`/blockexplorer/api/v1/tx/${e}`)},getBlockexplorerUtxos(e){return this.request("get",`/blockexplorer/api/v1/utxos/${e}`)}};const localStore=(e,t)=>{const n=Quasar.LocalStorage.getItem(e);return null!==n&&"null"!==n&&void 0!==n&&"undefined"!==n?n:t};window.g=Vue.reactive({settings:SETTINGS,currencies:CURRENCIES,extensions:SETTINGS.extensions,allowedCurrencies:SETTINGS.allowedCurrencies,denomination:SETTINGS.denomination,isSatsDenomination:"sats"==SETTINGS.denomination,themeChoice:localStore("lnbits.theme",SETTINGS.defaultTheme),borderChoice:localStore("lnbits.border",SETTINGS.defaultBorder),gradientChoice:localStore("lnbits.gradientBg",SETTINGS.defaultGradient),cardRoundedChoice:localStore("lnbits.cardRounded",SETTINGS.defaultCardRounded),cardGradientChoice:localStore("lnbits.cardGradient",SETTINGS.defaultCardGradient),cardShadowChoice:localStore("lnbits.cardShadow",SETTINGS.defaultCardShadow),burgerMenuChoice:localStore("lnbits.burgerMenu",SETTINGS.defaultBurgerMenuBackground),reactionChoice:localStore("lnbits.reactions",SETTINGS.defaultReaction),bgimageChoice:localStore("lnbits.backgroundImage",SETTINGS.defaultBgimage||""),locale:localStore("lnbits.lang",navigator.languages[1]??"en"),disclaimerShown:localStore("lnbits.disclaimerShown",!1),isFiatPriority:localStore("lnbits.isFiatPriority",!1),mobileSimple:localStore("lnbits.mobileSimple",!0),walletFlip:localStore("lnbits.walletFlip",!1),lastActiveWallet:localStore("lnbits.lastActiveWallet",null),darkChoice:localStore("lnbits.darkMode",SETTINGS.defaultDark),isUserAuthorized:!!Quasar.Cookies.get("is_lnbits_user_authorized"),isUserImpersonated:!!Quasar.Cookies.get("is_lnbits_user_impersonated"),errorCode:null,errorMessage:null,user:null,wallet:null,isPublicPage:!0,offline:!navigator.onLine,hasCamera:!1,visibleDrawer:!1,fiatBalance:0,exchangeRate:0,fiatTracking:!1,payments:[],walletEventListeners:[],updatePayments:!1,updatePaymentsHash:!1,scanner:null,newWalletType:null}),window.dateFormat="YYYY-MM-DD HH:mm";const websocketPrefix="http:"===window.location.protocol?"ws://":"wss://",websocketUrl=`${websocketPrefix}${window.location.host}/api/v1/ws`,_access_cookies_for_safari_refresh_do_not_delete=document.cookie;function eventReaction(e){localUrl="";const t=Quasar.LocalStorage.getItem("lnbits.reactions")||SETTINGS.defaultReaction;if(t&&"none"!==t.toLowerCase())try{if(e<0)return;"function"==typeof window[t]&&window[t]()}catch(e){console.log(e)}}function confettiTop(){document.getElementById("vue").disabled=!0;var e=Date.now()+200,t=[localStorage.getItem("lnbits.primaryColor")||"#FFD700",localStorage.getItem("lnbits.secondaryColor")||"E89400","#ffffff"];!function n(){confetti({particleCount:3,angle:270,spread:1e3,origin:{y:0},colors:t,zIndex:999999}),Date.now().5?1:-1,i=3+Math.floor(4*Math.random());for(let e=1;e<=i;e++)n.push({x:t.x+a*e*(18+22*Math.random()),y:t.y+e*(14+18*Math.random())});s.push(n)}let l=0;function u(e,n,a){t.beginPath(),t.moveTo(e[0].x,e[0].y),e.slice(1).forEach(e=>t.lineTo(e.x,e.y)),t.strokeStyle=`rgba(170, 220, 255, ${a})`,t.lineWidth=n,t.lineJoin="round",t.lineCap="round",t.shadowBlur=18,t.shadowColor="#7dd3fc",t.stroke(),t.strokeStyle=`rgba(255, 255, 255, ${Math.min(1,a+.2)})`,t.lineWidth=Math.max(1,.35*n),t.shadowBlur=4,t.stroke()}!function n(){const a=1-l/48;t.clearRect(0,0,window.innerWidth,window.innerHeight),l<3&&(t.fillStyle=`rgba(255, 255, 255, ${.22-.06*l})`,t.fillRect(0,0,window.innerWidth,window.innerHeight)),u(o,5*a+1,a),s.forEach(e=>u(e,2.5*a+.5,.75*a)),l+=1,l<=48?requestAnimationFrame(n):e.remove()}()}function decode(e){let t=e.toLowerCase(),n=t.lastIndexOf("1"),a=t.substring(0,n),i=t.substring(n+1,t.length-6),r=t.substring(t.length-6,t.length);if(!verify_checksum(a,bech32ToFiveBitArray(i+r)))throw"Malformed request: checksum is incorrect";return{human_readable_part:decodeHumanReadablePart(a),data:decodeData(i,a),checksum:r}}function decodeHumanReadablePart(e){let t;if(["lnbc","lntb","lnbcrt","lnsb","lntbs"].forEach(n=>{e.substring(0,n.length)===n&&(t=n)}),null==t)throw"Malformed request: unknown prefix";let n=decodeAmount(e.substring(t.length,e.length));return{prefix:t,amount:n}}function decodeData(e,t){let n=e.substring(0,7),a=bech32ToInt(n),i=e.substring(e.length-104,e.length),r=e.substring(7,e.length-104),o=decodeTags(r),s=bech32ToFiveBitArray(n+r);return s=fiveBitArrayTo8BitArray(s,!0),s=textToHexString(t).concat(byteArrayToHexString(s)),{time_stamp:a,tags:o,signature:decodeSignature(i),signing_data:s}}function decodeSignature(e){let t=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(e)),n=t[t.length-1];return{r:byteArrayToHexString(t.slice(0,32)),s:byteArrayToHexString(t.slice(32,t.length-1)),recovery_flag:n}}function decodeAmount(e){let t=e.charAt(e.length-1),n=e.substring(0,e.length-1);if("0"===n.substring(0,1))throw"Malformed request: amount cannot contain leading zeros";if(n=Number(n),n<0||!Number.isInteger(n))throw"Malformed request: amount must be a positive decimal integer";switch(t){case"":return"Any amount";case"p":return n/10;case"n":return 100*n;case"u":return 1e5*n;case"m":return 1e8*n;default:throw"Malformed request: undefined amount multiplier"}}function decodeTags(e){let t=extractTags(e),n=[];return t.forEach(e=>n.push(decodeTag(e.type,e.length,e.data))),n}function extractTags(e){let t=[];for(;e.length>0;){let n=e.charAt(0),a=bech32ToInt(e.substring(1,3)),i=e.substring(3,a+3);t.push({type:n,length:a,data:i}),e=e.substring(3+a,e.length)}return t}function decodeTag(e,t,n){switch(e){case"p":if(52!==t)break;return{type:e,length:t,description:"payment_hash",value:byteArrayToHexString(fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n)))};case"d":return{type:e,length:t,description:"description",value:bech32ToUTF8String(n)};case"n":if(53!==t)break;return{type:e,length:t,description:"payee_public_key",value:byteArrayToHexString(fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n)))};case"h":if(52!==t)break;return{type:e,length:t,description:"description_hash",value:n};case"x":return{type:e,length:t,description:"expiry",value:bech32ToInt(n)};case"c":return{type:e,length:t,description:"min_final_cltv_expiry",value:bech32ToInt(n)};case"f":let a=bech32ToFiveBitArray(n.charAt(0))[0];if(a<0||a>18)break;return{type:e,length:t,description:"fallback_address",value:{version:a,fallback_address:n=n.substring(1,n.length)}};case"r":let i=(n=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(n))).slice(0,33),r=n.slice(33,41),o=n.slice(41,45),s=n.slice(45,49),l=n.slice(49,51);return{type:e,length:t,description:"routing_information",value:{public_key:byteArrayToHexString(i),short_channel_id:byteArrayToHexString(r),fee_base_msat:byteArrayToInt(o),fee_proportional_millionths:byteArrayToInt(s),cltv_expiry_delta:byteArrayToInt(l)}}}}function polymod(e){let t=[996825010,642813549,513874426,1027748829,705979059],n=1;return e.forEach(e=>{let a=n>>25;n=(33554431&n)<<5^e;for(let e=0;e<5;e++)n^=1==(a>>e&1)?t[e]:0}),n}function expand(e){let t=[];for(let n=0;n>5);t.push(0);for(let n=0;n{console.log("offline",e),this.g.offline=!0}),addEventListener("online",e=>{console.log("back online",e),this.g.offline=!1}),null!=navigator.serviceWorker&&navigator.serviceWorker.register("/service-worker.js").then(e=>{console.log("Registered events at scope: ",e.scope)}),navigator.mediaDevices&&navigator.mediaDevices.enumerateDevices&&navigator.mediaDevices.enumerateDevices().then(e=>{window.g.hasCamera=e.some(e=>"videoinput"===e.kind)}),window.LNbits={g:window.g,utils:window._lnbitsUtils,api:window._lnbitsApi,map:{user(e){const t={id:e.id,username:e.username,admin:e.admin,email:e.email,extensions:e.extensions,wallets:e.wallets,fiat_providers:e.fiat_providers||[],super_user:e.super_user,extra:e.extra??{},hasPassword:e.has_password??!1,uiCustomization:e.ui_customization||{}},n=this.wallet;return t.wallets=t.wallets.map(n).sort((e,t)=>e.extra.pinned!==t.extra.pinned?e.extra.pinned?-1:1:e.name.localeCompare(t.name)),t.walletOptions=t.wallets.map(e=>({label:[e.name," - ",e.id.substring(0,5),"..."].join(""),value:e.id})),t.hiddenWalletsCount=Math.max(0,e.wallets.length-e.extra.visible_wallet_count),t.walletInvitesCount=e.extra.wallet_invite_requests?.length||0,t},wallet(e){if(newWallet={id:e.id,name:e.name,walletType:e.wallet_type,sharePermissions:e.share_permissions,sharedWalletId:e.shared_wallet_id,adminkey:e.adminkey,inkey:e.inkey,currency:e.currency,lightningAddress:e.lightning_address,extra:e.extra,canReceivePayments:!0,canSendPayments:!0},newWallet.msat=e.balance_msat,newWallet.sat=Math.floor(e.balance_msat/1e3),"lightning-shared"===newWallet.walletType){const e=newWallet.sharePermissions;newWallet.canReceivePayments=e.includes("receive-payments"),newWallet.canSendPayments=e.includes("send-payments")}return newWallet.url=`/wallet?&wal=${e.id}`,newWallet.lightningAddressFull=newWallet.lightningAddress?`${newWallet.lightningAddress}@${window.location.host}`:null,newWallet.storedPaylinks=e.stored_paylinks.links,newWallet}}},window.windowMixin={},function(e,t){!function e(t,n,a,i){var r=!!(t.Worker&&t.Blob&&t.Promise&&t.OffscreenCanvas&&t.OffscreenCanvasRenderingContext2D&&t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype.transferControlToOffscreen&&t.URL&&t.URL.createObjectURL);function o(){}function s(e){var a=n.exports.Promise,i=void 0!==a?a:t.Promise;return"function"==typeof i?new i(e):(e(o,o),null)}var l,u,c,d,h,p,f,m,_=(c=Math.floor(1e3/60),d={},h=0,"function"==typeof requestAnimationFrame&&"function"==typeof cancelAnimationFrame?(l=function(e){var t=Math.random();return d[t]=requestAnimationFrame(function n(a){h===a||h+c-1{a=(a<<5)+e,n+=5,n>=8&&(i.push(a>>n-8&255),n-=8)}),t&&n>0&&i.push(a<<8-n&255),i}function bech32ToUTF8String(e){let t=fiveBitArrayTo8BitArray(bech32ToFiveBitArray(e)),n="";for(let e=0;e20&&(t-=20,e/=Math.pow(10,t),e+=new Array(t+1).join("0"));return e} \ No newline at end of file diff --git a/lnbits/static/css/base.css b/lnbits/static/css/base.css index a42a2c827..cc26be02e 100644 --- a/lnbits/static/css/base.css +++ b/lnbits/static/css/base.css @@ -212,12 +212,15 @@ body.bg-image .q-page-container { backdrop-filter: none; /* Ensure the page content is not affected */ } -body.body--dark .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark), +body.body--dark .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { + --q-dark: rgba(29, 29, 29, 0.3); + background-color: var(--q-dark); +} body.body--dark .q-header, body.body--dark .q-drawer { --q-dark: rgba(29, 29, 29, 0.3); background-color: var(--q-dark); - backdrop-filter: blur(6px) brightness(0.8); + backdrop-filter: brightness(0.8); } body.rounded-ui .q-card, @@ -388,11 +391,18 @@ body[data-theme=salvador].card-gradient.body--dark .q-drawer { } body.card-shadow .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { - filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.18)); + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18); } body.card-shadow.body--dark .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { - filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45)); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45); +} + +body.no-burger-background .q-drawer { + background-color: transparent !important; + background-image: none !important; + backdrop-filter: none !important; + box-shadow: none !important; } :root { diff --git a/lnbits/static/i18n/br.js b/lnbits/static/i18n/br.js index 79f0d59d7..80ecf478c 100644 --- a/lnbits/static/i18n/br.js +++ b/lnbits/static/i18n/br.js @@ -99,6 +99,10 @@ window.localisation.br = { view_swagger_docs: 'Ver a documentação da API do LNbits Swagger', api_docs: 'Documentação da API', api_keys_api_docs: 'URL do Node, chaves da API e documentação da API', + api_keys_warning: + 'Essas chaves devem ser mantidas em segurança; compartilhá-las pode resultar na perda de fundos.', + admin_key_warning: + 'Sua chave de administrador concede acesso total à sua carteira, incluindo a capacidade de enviar pagamentos. Nunca a compartilhe, a menos que confie plenamente no destinatário.', lnbits_version: 'Versão do LNbits', runs_on: 'Executa em', paste: 'Colar', @@ -640,6 +644,16 @@ window.localisation.br = { auth_keycloak_ci_hint: 'Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Segredo do Cliente Keycloak', + auth_keycloak_custom_org_label: 'Organização Personalizada do Keycloak', + auth_keycloak_custom_icon_label: 'Ícone Personalizado do Keycloak (URL)', + auth_oidc_label: 'URL de Descoberta do OIDC', + auth_oidc_ci_label: 'ID do Cliente OIDC', + auth_oidc_ci_hint: + 'Certifique-se de que a URL de retorno de chamada de autorização esteja definida para https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Segredo do Cliente OIDC', + auth_oidc_custom_org_label: + 'Nome da Organização Personalizada OIDC (ex. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Ícone Personalizado do OIDC (URL)', auth_keycloak_custom_org_label: 'Keycloak Custom Organization', auth_keycloak_custom_icon_label: 'Ícone Personalizado do Keycloak (URL)', currency_settings: 'Configurações de Moeda', @@ -814,5 +828,48 @@ window.localisation.br = { payment_labels_updated: 'Rótulos de pagamento atualizados', color: 'Cor', sort: 'Ordenar', - sort_by: 'Ordenar por' + sort_by: 'Ordenar por', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Ativar Block Explorer', + block_explorer_desc: + 'Permite aos usuários explorar transações e endereços Bitcoin via Electrum.', + blockexplorer_public_api: 'Acesso à API pública', + blockexplorer_public_api_desc: + 'Permitir acesso não autenticado aos endpoints da API do explorador de blocos.', + electrum_server_url: 'URL do servidor Electrum', + electrum_server_url_hint: + 'ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001', + blockexplorer_search_label: 'Pesquisar por TXID ou endereço', + blockexplorer_search_hint: + 'Hex de 64 caracteres = transação · qualquer outra coisa = endereço Bitcoin', + recent_blocks: 'Blocos recentes', + chain_tip: 'Ponta da cadeia', + block_height: 'Altura do bloco', + block_fee: 'taxa de bloco', + fee_estimates: 'Estimativas de taxa', + confirmed_balance: 'Saldo confirmado', + unconfirmed_balance: 'Saldo não confirmado', + transaction_history: 'Histórico de transações', + coinbase: 'Coinbase', + inputs: 'Entradas', + outputs: 'Saídas', + confirmations: 'Confirmações', + confirmed: 'Confirmado', + unconfirmed: 'Não confirmado', + history_unavailable: + 'Histórico de transações indisponível (endereço tem transações demais)', + address: 'Endereço', + block_number: 'Bloco #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Bloco anterior', + merkle_root: 'Raiz de Merkle', + version: 'Versão', + bits: 'Bits', + difficulty: 'Dificuldade', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Tamanho virtual', + weight: 'Peso', + n_block_fee: 'taxa {n} blocos' } diff --git a/lnbits/static/i18n/cn.js b/lnbits/static/i18n/cn.js index 0ac3ff8d3..2785a9946 100644 --- a/lnbits/static/i18n/cn.js +++ b/lnbits/static/i18n/cn.js @@ -68,6 +68,9 @@ window.localisation.cn = { view_swagger_docs: '查看 LNbits Swagger API 文档', api_docs: 'API文档', api_keys_api_docs: '节点URL、API密钥和API文档', + api_keys_warning: '请妥善保管这些密钥,分享它们可能导致资金损失。', + admin_key_warning: + '您的管理员密钥可完全访问您的钱包,包括发送付款的权限。除非您完全信任接收者,否则切勿分享。', lnbits_version: 'LNbits版本', runs_on: '可运行在', paste: '粘贴', @@ -353,6 +356,15 @@ window.localisation.cn = { auth_keycloak_ci_hint: '确保授权回调URL设置为https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Keycloak客户端密钥', + auth_keycloak_custom_org_label: 'Keycloak 自定义组织', + auth_keycloak_custom_icon_label: 'Keycloak 自定义图标 (URL)', + auth_oidc_label: 'OIDC 发现 URL', + auth_oidc_ci_label: 'OIDC 客户端 ID', + auth_oidc_ci_hint: + '确保授权回调URL设置为https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'OIDC客户端密钥', + auth_oidc_custom_org_label: 'OIDC 自定义组织名称(例如 Zitadel、Authentik)', + auth_oidc_custom_icon_label: 'OIDC 自定义图标 (URL)', currency_settings: '货币设置', allowed_currencies: '允许的货币', allowed_currencies_hint: '限制可用法定货币的数量', @@ -410,5 +422,44 @@ window.localisation.cn = { http_request_methods: 'HTTP请求方法', http_response_codes: 'HTTP响应代码', request_details: '请求详情', - http_request_details: 'HTTP请求详细信息' + http_request_details: 'HTTP请求详细信息', + block_explorer: '区块浏览器', + enable_block_explorer: '启用区块浏览器', + block_explorer_desc: '允许用户通过 Electrum 浏览比特币交易和地址。', + blockexplorer_public_api: '公开 API 访问', + blockexplorer_public_api_desc: '允许对区块浏览器 API 端点的未认证访问。', + electrum_server_url: 'Electrum 服务器 URL', + electrum_server_url_hint: + '例如 ssl://electrum.blockstream.info:50002 或 tcp://localhost:50001', + blockexplorer_search_label: '按 TXID 或地址搜索', + blockexplorer_search_hint: '64位十六进制 = 交易 · 其他 = 比特币地址', + recent_blocks: '最新区块', + chain_tip: '链尖', + block_height: '区块高度', + block_fee: '区块手续费', + fee_estimates: '手续费估算', + confirmed_balance: '已确认余额', + unconfirmed_balance: '未确认余额', + transaction_history: '交易历史', + coinbase: 'Coinbase', + inputs: '输入', + outputs: '输出', + confirmations: '确认数', + confirmed: '已确认', + unconfirmed: '未确认', + history_unavailable: '交易历史不可用(地址交易过多)', + address: '地址', + block_number: '区块 #{height}', + block_diff: '难度 {value}', + block_hash: '哈希', + previous_block: '上一区块', + merkle_root: 'Merkle 根', + version: '版本', + bits: 'Bits', + difficulty: '难度', + nonce: 'Nonce', + txid: 'TXID', + vsize: '虚拟大小', + weight: '权重', + n_block_fee: '{n} 区块手续费' } diff --git a/lnbits/static/i18n/cs.js b/lnbits/static/i18n/cs.js index 985c51700..331f60692 100644 --- a/lnbits/static/i18n/cs.js +++ b/lnbits/static/i18n/cs.js @@ -72,6 +72,10 @@ window.localisation.cs = { view_swagger_docs: 'Zobrazit LNbits Swagger API dokumentaci', api_docs: 'API dokumentace', api_keys_api_docs: 'Adresa uzlu, API klíče a API dokumentace', + api_keys_warning: + 'Tyto klíče uchovávejte v bezpečí, jejich sdílení může vést ke ztrátě prostředků.', + admin_key_warning: + 'Váš administrátorský klíč poskytuje plný přístup k peněžence včetně možnosti odesílat platby. Nikdy jej nesdílejte, pokud příjemci plně nedůvěřujete.', lnbits_version: 'Verze LNbits', runs_on: 'Běží na', paste: 'Vložit', @@ -367,6 +371,16 @@ window.localisation.cs = { auth_keycloak_ci_hint: 'Ujistěte se, že je autorizace callback URL nastavena na https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Klíč k aplikaci Keycloak tajemství', + auth_keycloak_custom_org_label: 'Vlastní organizace Keycloak', + auth_keycloak_custom_icon_label: 'Vlastní ikona Keycloak (URL)', + auth_oidc_label: 'URL pro zjištění OIDC', + auth_oidc_ci_label: 'ID klienta OIDC', + auth_oidc_ci_hint: + 'Ujistěte se, že je autorizace callback URL nastavena na https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Klíč k aplikaci OIDC tajemství', + auth_oidc_custom_org_label: + 'Název vlastní organizace OIDC (např. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Vlastní ikona OIDC (URL)', currency_settings: 'Nastavení měny', allowed_currencies: 'Povolené měny', allowed_currencies_hint: 'Omezte počet dostupných fiat měn', @@ -429,5 +443,48 @@ window.localisation.cs = { http_request_methods: 'Metody HTTP požadavků', http_response_codes: 'Kódy HTTP odpovědí', request_details: 'Podrobnosti žádosti', - http_request_details: 'Podrobnosti HTTP žádosti' + http_request_details: 'Podrobnosti HTTP žádosti', + block_explorer: 'Průzkumník bloků', + enable_block_explorer: 'Povolit průzkumník bloků', + block_explorer_desc: + 'Umožňuje uživatelům procházet bitcoinové transakce a adresy přes Electrum.', + blockexplorer_public_api: 'Veřejný přístup k API', + blockexplorer_public_api_desc: + 'Povolit neověřený přístup k API koncovým bodům průzkumníku bloků.', + electrum_server_url: 'URL Electrum serveru', + electrum_server_url_hint: + 'např. ssl://electrum.blockstream.info:50002 nebo tcp://localhost:50001', + blockexplorer_search_label: 'Hledat podle TXID nebo adresy', + blockexplorer_search_hint: + '64-znakový hex = transakce · cokoli jiného = bitcoinová adresa', + recent_blocks: 'Nedávné bloky', + chain_tip: 'Vrchol řetězu', + block_height: 'Výška bloku', + block_fee: 'poplatek bloku', + fee_estimates: 'Odhady poplatků', + confirmed_balance: 'Potvrzený zůstatek', + unconfirmed_balance: 'Nepotvrzený zůstatek', + transaction_history: 'Historie transakcí', + coinbase: 'Coinbase', + inputs: 'Vstupy', + outputs: 'Výstupy', + confirmations: 'Potvrzení', + confirmed: 'Potvrzeno', + unconfirmed: 'Nepotvrzeno', + history_unavailable: + 'Historie transakcí nedostupná (adresa má příliš mnoho transakcí)', + address: 'Adresa', + block_number: 'Blok #{height}', + block_diff: 'obth. {value}', + block_hash: 'Hash', + previous_block: 'Předchozí blok', + merkle_root: 'Merkle kořen', + version: 'Verze', + bits: 'Bity', + difficulty: 'Obtížnost', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtuální velikost', + weight: 'Váha', + n_block_fee: 'poplatek {n} bloků' } diff --git a/lnbits/static/i18n/de.js b/lnbits/static/i18n/de.js index 423d48544..30935d3a2 100644 --- a/lnbits/static/i18n/de.js +++ b/lnbits/static/i18n/de.js @@ -72,6 +72,10 @@ window.localisation.de = { view_swagger_docs: 'LNbits Swagger API-Dokumentation', api_docs: 'API-Dokumentation', api_keys_api_docs: 'Knoten-URL, API-Schlüssel und API-Dokumentation', + api_keys_warning: + 'Diese Schlüssel sollten sicher aufbewahrt werden; ihre Weitergabe kann zum Verlust von Guthaben führen.', + admin_key_warning: + 'Dein Admin-Schlüssel gewährt vollen Zugriff auf deine Wallet, einschließlich der Möglichkeit, Zahlungen zu senden. Teile ihn niemals, es sei denn, du vertraust dem Empfänger vollständig.', lnbits_version: 'LNbits-Version', runs_on: 'Läuft auf', paste: 'Einfügen', @@ -377,6 +381,16 @@ window.localisation.de = { auth_keycloak_ci_hint: 'Stellen Sie sicher, dass die Autorisierungs-Callback-URL auf https://{domain}/api/v1/auth/keycloak/token eingestellt ist.', auth_keycloak_cs_label: 'Keycloak-Client-Geheimnis', + auth_keycloak_custom_org_label: 'Keycloak Benutzerdefinierte Organisation', + auth_keycloak_custom_icon_label: 'Keycloak Benutzerdefiniertes Symbol (URL)', + auth_oidc_label: 'OIDC Discovery-URL', + auth_oidc_ci_label: 'OIDC-Client-ID', + auth_oidc_ci_hint: + 'Stellen Sie sicher, dass die Autorisierungs-Callback-URL auf https://{domain}/api/v1/auth/oidc/token eingestellt ist.', + auth_oidc_cs_label: 'OIDC-Client-Geheimnis', + auth_oidc_custom_org_label: + 'OIDC Benutzerdefinierter Organisationsname (z.B. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'OIDC Benutzerdefiniertes Symbol (URL)', currency_settings: 'Währungseinstellungen', allowed_currencies: 'Erlaubte Währungen', allowed_currencies_hint: @@ -442,5 +456,48 @@ window.localisation.de = { http_request_methods: 'HTTP-Anfragemethoden', http_response_codes: 'HTTP-Antwortcodes', request_details: 'Anfragedetails', - http_request_details: 'HTTP-Anfragedetails' + http_request_details: 'HTTP-Anfragedetails', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Block Explorer aktivieren', + block_explorer_desc: + 'Ermöglicht Nutzern das Durchsuchen von Bitcoin-Transaktionen und -Adressen über Electrum.', + blockexplorer_public_api: 'Öffentlicher API-Zugang', + blockexplorer_public_api_desc: + 'Nicht-authentifizierten Zugriff auf die Block-Explorer-API-Endpunkte erlauben.', + electrum_server_url: 'Electrum-Server-URL', + electrum_server_url_hint: + 'z.B. ssl://electrum.blockstream.info:50002 oder tcp://localhost:50001', + blockexplorer_search_label: 'Nach TXID oder Adresse suchen', + blockexplorer_search_hint: + '64-Zeichen-Hex = Transaktion · Alles andere = Bitcoin-Adresse', + recent_blocks: 'Aktuelle Blöcke', + chain_tip: 'Kettenspitze', + block_height: 'Blockhöhe', + block_fee: 'Blockgebühr', + fee_estimates: 'Gebührenschätzungen', + confirmed_balance: 'Bestätigtes Guthaben', + unconfirmed_balance: 'Unbestätigtes Guthaben', + transaction_history: 'Transaktionsverlauf', + coinbase: 'Coinbase', + inputs: 'Eingaben', + outputs: 'Ausgaben', + confirmations: 'Bestätigungen', + confirmed: 'Bestätigt', + unconfirmed: 'Unbestätigt', + history_unavailable: + 'Transaktionsverlauf nicht verfügbar (Adresse hat zu viele Transaktionen)', + address: 'Adresse', + block_number: 'Block #{height}', + block_diff: 'Schw. {value}', + block_hash: 'Hash', + previous_block: 'Vorheriger Block', + merkle_root: 'Merkle-Wurzel', + version: 'Version', + bits: 'Bits', + difficulty: 'Schwierigkeit', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtuelle Größe', + weight: 'Gewicht', + n_block_fee: '{n}-Block-Gebühr' } diff --git a/lnbits/static/i18n/en.js b/lnbits/static/i18n/en.js index 59eab8029..61ce6b3d8 100644 --- a/lnbits/static/i18n/en.js +++ b/lnbits/static/i18n/en.js @@ -44,7 +44,8 @@ window.localisation.en = { reset_defaults_tooltip: 'Delete all settings and reset to defaults.', download_backup: 'Download database backup', name_your_wallet: 'Name your {name} wallet', - paste_invoice_label: 'Paste an invoice, payment request or lnurl code *', + paste_invoice_label: + 'Paste an invoice, payment request, Lightning Address or LNURL*', lnbits_description: 'Easy to set up and lightweight, LNbits can run on any Lightning Network funding source and even LNbits itself! You can run LNbits for yourself, or easily offer a custodian solution for others. Each wallet has its own API keys and there is no limit to the number of wallets you can make. Being able to partition funds makes LNbits a useful tool for money management and as a development tool. Extensions add extra functionality to LNbits so you can experiment with a range of cutting-edge technologies on the lightning network. We have made developing extensions as easy as possible, and as a free and open-source project, we encourage people to develop and submit their own.', export_to_phone: 'Export to Phone with QR Code', @@ -64,6 +65,7 @@ window.localisation.en = { wallets: 'Wallets', exclude_wallets: 'Exclude Wallets', add_wallet: 'Add wallet', + add_field: 'Add field', reject_wallet: 'Reject wallet', add_new_wallet: 'Add a new wallet', pin_wallet: 'Pin wallet', @@ -98,6 +100,10 @@ window.localisation.en = { view_swagger_docs: 'View LNbits Swagger API docs', api_docs: 'API docs', api_keys_api_docs: 'Node URL, API keys and API docs', + api_keys_warning: + 'These keys should be kept safe, sharing them could risk losing funds.', + admin_key_warning: + 'Your admin key grants full access to your wallet, including the ability to send payments. Never share it unless you fully trust the recipient.', lnbits_version: 'LNbits version', runs_on: 'Runs on', paste: 'Paste', @@ -116,6 +122,7 @@ window.localisation.en = { read: 'Read', write: 'Write', pay: 'Pay', + sending: 'Sending', memo: 'Memo', date: 'Date', path: 'Path', @@ -161,6 +168,10 @@ window.localisation.en = { ext_sources_hint: 'Repositories from where the extensions can be downloaded', ext_sources_label: 'Source URL (only use the official LNbits extension source, and sources you can trust)', + wasm_sources_hint: + 'Repositories from where WASM extensions can be downloaded', + wasm_sources_label: + 'WASM source URL (only use WASM extension sources you can trust)', warning: 'Warning', repository: 'Repository', confirm_continue: 'Are you sure you want to continue?', @@ -184,6 +195,7 @@ window.localisation.en = { release_notes: 'Release Notes', activate_extension_details: 'Make extension available/unavailable for users', featured: 'Featured', + categories: 'Categories', all: 'All', only_admins_can_install: '(Only admin accounts can install extensions)', only_admins_can_create_extensions: @@ -267,6 +279,15 @@ window.localisation.en = { webhook_events_list: 'The following events must be supported by the webhook:', webhook_stripe_description: 'One the stripe side you must configure a webhook with a URL that points to your LNbits server.', + webhook_square_description: + 'On the Square side configure a webhook pointing to this exact LNbits URL.', + square_webhook_url_hint: + 'Must exactly match the Square notification URL. LNbits requires the /api/v1/callback/square path.', + access_token: 'Access Token', + location_id: 'Location ID', + square_location_id_hint: + 'Square location ID to create payment links for. Use the endpoint to select sandbox or production.', + api_version: 'API Version', payment_proof: 'Payment Proof', update: 'Update', update_available: 'Update {version} available!', @@ -275,6 +296,8 @@ window.localisation.en = { requires_server_restart: 'Changing these settings requires a server restart to take effect.', funding_source_info: 'Select the active funding wallet', + phoenixd_warning: + "Phoenixd mnemonic is only available if phoenixd data-dir is specified and is readable by LNbits. It's not indicative of phoenixd not running. It just means LNbits cannot access the mnemonic to display it here.", latest_update: 'You are on the latest version {version}.', notifications: 'Notifications', notifications_configure: 'Configure Notifications', @@ -470,6 +493,8 @@ window.localisation.en = { access_control_list_admin_warning: 'This is an admin account. The generated tokens will have admin privileges.', new_api_acl: 'New Access Control List', + acl_token_active: 'Active', + acl_token_expired: 'Expired', api_token_id: 'Token Id', toggle_gradient: 'Toggle Gradient', gradient_background: 'Gradient Background', @@ -479,6 +504,8 @@ window.localisation.en = { toggle_card_gradient: 'Toggle gradient on cards', card_shadow: 'Card Shadow', toggle_card_shadow: 'Toggle shadow on cards', + burger_menu_background: 'Burger Menu Background', + toggle_burger_menu_background: 'Toggle burger menu background', language: 'Language', assets: 'Assets', max_asset_size_mb: 'Max Asset Size (MB)', @@ -505,6 +532,64 @@ window.localisation.en = { admin_settings: 'Admin Settings', extension_cost: 'This release requires a payment of minimum {cost} sats.', extension_paid_sats: 'You have already paid {paid_sats} sats.', + extension_permissions_title: 'Grant extension permissions', + extension_permissions_tab: 'Extension Permissions', + user_permissions_tab: 'My Grants', + extension_permissions_none: 'This extension has no install-time permissions.', + user_permissions_none: + 'You have not granted any permissions for this extension.', + user_permissions_max_amount: 'Max payment amount', + user_permissions_destination_policy: 'Allowed destinations', + user_permissions_no_editable_settings: 'This grant has no editable settings.', + extension_permissions_grant_install: 'Grant and install', + extension_permissions_high_risk_warning: + 'This extension requests permissions that can move funds.', + extension_permission_risk_low: 'Low risk', + extension_permission_risk_medium: 'Medium risk', + extension_permission_risk_high: 'High risk', + extension_permission_warning_wallet_pay_invoice: + 'Can spend funds from wallets available to your account.', + extension_permission_warning_wallet_pay_invoice_background: + 'Can spend funds later from approved wallets without an active click.', + extension_permission_warning_wallet_payments_watch: + 'Can read payment metadata for approved wallets.', + extension_permission_warning_extension_api_request_write: + 'Can write data or trigger actions in approved extensions.', + extension_permission_ext_storage_read: 'Read extension storage', + extension_permission_ext_storage_append_public: + 'Append public extension storage', + extension_permission_ext_storage_append_public_sources: + 'Allowed append targets', + extension_permission_ext_storage_append_public_max_rows_per_source: + 'Max rows per source', + extension_permission_ext_storage_read_public: 'Read public extension storage', + extension_permission_ext_storage_read_public_source_required: + 'required to read', + extension_permission_ext_storage_write: 'Write extension storage', + extension_permission_ext_storage_read_write: 'Read & Write extension storage', + extension_permission_extension_api_request: 'Use other extensions', + extension_permission_extension_api_request_extensions: 'Allowed extensions', + extension_permission_access_read: 'Read', + extension_permission_access_write: 'Write', + extension_permission_http_request: 'Connect to external websites', + extension_permission_http_request_hosts: 'Allowed hosts', + extension_permission_utils_basic: 'Use basic LNbits utilities', + extension_permission_ui_camera_scan_qr: 'Scan QR codes', + extension_permission_websocket: 'Use extension websockets', + extension_permission_websocket_publish_limits: 'Publish limits', + extension_permission_websocket_publish_max_messages_per_second: + 'Max messages per second', + extension_permission_websocket_publish: 'Publish websocket messages', + extension_permission_websocket_subscribe: 'Subscribe to websocket messages', + extension_permission_wallet_payments_watch: 'Watch wallet payments', + extension_permission_wallet_create_invoice: 'Create invoices', + extension_permission_wallet_create_invoice_public: + 'Create Lightning invoices from public pages', + extension_permission_wallet_balance_read: 'View wallet balances', + extension_permission_wallet_list: 'List wallets', + extension_permission_wallet_pay_invoice: 'Pay invoices', + extension_permission_wallet_pay_invoice_background: + 'Make background payments', create_extension: 'Create Extension', release_details_error: 'Cannot get the release details.', pay_from_wallet: 'Pay from Wallet', @@ -611,6 +696,10 @@ window.localisation.en = { payment_timeouts: 'Payment Timeouts', payment_wait_time: 'Payment Wait Time', seconds: 'seconds', + payment_pending_interval: 'Check payment interval (sec)', + payment_pending_interval_desc: 'Interval to check pending payments', + payment_pending_interval_tooltip: + 'Controls how often LNbits checks for pending payments to update their status. Higher values can reduce the load on the node and speed up the payment process, but it will take longer for pending payments to be updated.', payment_wait_time_desc: 'Wait time before marking an outgoing payment as pending. Default: 5s; raise for slow-settling invoices.', payment_wait_time_tooltip: @@ -642,6 +731,14 @@ window.localisation.en = { auth_keycloak_cs_label: 'Keycloak Client Secret', auth_keycloak_custom_org_label: 'Keycloak Custom Organization', auth_keycloak_custom_icon_label: 'Keycloak Custom Icon (URL)', + auth_oidc_label: 'OIDC Discovery URL', + auth_oidc_ci_label: 'OIDC Client ID', + auth_oidc_ci_hint: + 'Make sure that the authorization callback URL is set to https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'OIDC Client Secret', + auth_oidc_custom_org_label: + 'OIDC Custom Organization Name (e.g., Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'OIDC Custom Icon (URL)', currency_settings: 'Currency Settings', allowed_currencies: 'Allowed Currencies', allowed_currencies_hint: @@ -661,7 +758,10 @@ window.localisation.en = { service_fees: 'Service Fees', service_fee: 'Service Fee', service_fee_label: 'Service Fee Charged Per Transaction', + service_fee_hint: 'Fee charged per transaction (%)', + service_fee_max: 'Maximum Service Fee (sats)', service_fee_max_label: 'Maximum Service Fee Limit', + service_fee_max_hint: 'Maximum service fee to charge in (sats)', fee_wallet_label: 'Service Fee Wallet ID', fee_wallet_hint: 'The ID of the wallet to which to send service funds', disable_fee: 'Disable Service Fees for Internal Payments', @@ -791,6 +891,8 @@ window.localisation.en = { webhook_id_hint: 'PayPal webhook ID used to verify incoming events.', webhook_paypal_description: 'On the PayPal side configure a webhook pointing to your LNbits server.', + square_webhook_signature_key_hint: + 'Square webhook signature key used to verify incoming events.', callback_success_url: 'Callback Success URL', callback_success_url_hint: 'The user will be redirected to this URL after the payment is successful', @@ -813,5 +915,80 @@ window.localisation.en = { payment_labels_updated: 'Payment labels updated', color: 'Color', sort: 'Sort', - sort_by: 'Sort by' + sort_by: 'Sort by', + lightning_address: 'Lightning Address', + lightning_addresses: 'Lightning Addresses', + lightning_address_price: 'Lightning Address price', + enable_lightning_address: 'Enable Lightning Addresses', + ln_address_mode: 'Lightning Address Resolution Mode', + ln_address_core_first: 'Resolve from LNbits Core first', + ln_address_extension_first: 'Resolve from Pay Links extension first', + ln_address_extension_only: 'Resolve from Pay Links extension only', + ln_address_mode_hint: + 'Choose how LNbits should resolve Lightning Addresses. Using both LNbits Core and the Pay Links extension will have a small impact on performance.', + enable_lightning_address_for_all_wallets: + 'Enable Lightning Addresses for all LNbits wallets', + allow_users_specify_lightning_addresses: + 'Allow users to specify Lightning Addresses', + allow_wallet_owners_set_custom_lightning_addresses: + 'Allow wallet owners to set custom Lightning Addresses', + charge_for_lightning_addresses: 'Charge for Lightning Addresses', + charge_users_set_change_lightning_address: + 'Charge users when they set or change a Lightning Address.', + service_fee_wallet_id_must_be_set: + 'Service Fee Wallet ID must be set in the Service Fees section below for this to work.', + lightning_address_blacklist: 'Lightning Address blacklist', + lightning_address_blacklist_instructions: + 'Newline separated reserved words. Users cannot choose a Lightning Address that matches any of these words.', + set_lightning_address: 'Set Lightning Address', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Enable Block Explorer', + block_explorer_desc: + 'Allow users to explore Bitcoin transactions and addresses via Electrum.', + blockexplorer_public_api: 'Public API Access', + blockexplorer_public_api_desc: + 'Allow unauthenticated access to the block explorer API endpoints.', + electrum_compatible_server: 'Electrum compatible server', + electrum_server_url: 'Electrum Server URL', + electrum_server_url_hint: + 'Choose a public Electrum server or enter your own.', + electrum_server_url_custom: 'Custom Electrum Server URL', + view_public_electrum_servers: 'View public Electrum servers', + blockexplorer_network: 'Bitcoin Network', + blockexplorer_network_hint: + 'The network the Electrum server is connected to, used to render addresses correctly.', + blockexplorer_search_label: 'Search by TXID or Address', + blockexplorer_search_hint: + '64-char hex = transaction · anything else = Bitcoin address', + recent_blocks: 'Recent Blocks', + chain_tip: 'Chain Tip', + block_height: 'Block Height', + block_fee: 'block fee', + fee_estimates: 'Fee Estimates', + confirmed_balance: 'Confirmed Balance', + unconfirmed_balance: 'Unconfirmed Balance', + transaction_history: 'Transaction History', + coinbase: 'Coinbase', + inputs: 'Inputs', + outputs: 'Outputs', + confirmations: 'Confirmations', + confirmed: 'Confirmed', + unconfirmed: 'Unconfirmed', + no_transactions: 'No transactions found', + history_unavailable: + 'Transaction history unavailable (address has too many transactions)', + address: 'Address', + block_number: 'Block #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Previous Block', + merkle_root: 'Merkle Root', + version: 'Version', + bits: 'Bits', + difficulty: 'Difficulty', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtual Size', + weight: 'Weight', + n_block_fee: '{n}-block fee' } diff --git a/lnbits/static/i18n/es.js b/lnbits/static/i18n/es.js index 2e43dd852..cb7e9d126 100644 --- a/lnbits/static/i18n/es.js +++ b/lnbits/static/i18n/es.js @@ -72,6 +72,10 @@ window.localisation.es = { view_swagger_docs: 'Ver documentación de API de LNbits Swagger', api_docs: 'Documentación de API', api_keys_api_docs: 'URL del nodo, claves de API y documentación de API', + api_keys_warning: + 'Estas claves deben mantenerse seguras; compartirlas podría provocar la pérdida de fondos.', + admin_key_warning: + 'Tu clave de administrador otorga acceso total a tu billetera, incluida la posibilidad de enviar pagos. Nunca la compartas a menos que confíes plenamente en el destinatario.', lnbits_version: 'Versión de LNbits', runs_on: 'Corre en', paste: 'Pegar', @@ -379,6 +383,16 @@ window.localisation.es = { auth_keycloak_ci_hint: 'Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Secreto del Cliente de Keycloak', + auth_keycloak_custom_org_label: 'Organización personalizada de Keycloak', + auth_keycloak_custom_icon_label: 'Icono personalizado de Keycloak (URL)', + auth_oidc_label: 'URL de descubrimiento de OIDC', + auth_oidc_ci_label: 'ID de cliente de OIDC', + auth_oidc_ci_hint: + 'Asegúrate de que la URL de devolución de llamada de autorización esté configurada en https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Secreto del Cliente de OIDC', + auth_oidc_custom_org_label: + 'Nombre de organización personalizada OIDC (ej. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Icono personalizado de OIDC (URL)', currency_settings: 'Configuración de moneda', allowed_currencies: 'Monedas permitidas', allowed_currencies_hint: @@ -443,5 +457,48 @@ window.localisation.es = { http_request_methods: 'Métodos de solicitud HTTP', http_response_codes: 'Códigos de Respuesta HTTP', request_details: 'Detalles de la solicitud', - http_request_details: 'Detalles de la Solicitud HTTP' + http_request_details: 'Detalles de la Solicitud HTTP', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Activar Block Explorer', + block_explorer_desc: + 'Permite a los usuarios explorar transacciones y direcciones de Bitcoin a través de Electrum.', + blockexplorer_public_api: 'Acceso a la API pública', + blockexplorer_public_api_desc: + 'Permitir acceso no autenticado a los endpoints de la API del explorador de bloques.', + electrum_server_url: 'URL del servidor Electrum', + electrum_server_url_hint: + 'p.ej. ssl://electrum.blockstream.info:50002 o tcp://localhost:50001', + blockexplorer_search_label: 'Buscar por TXID o dirección', + blockexplorer_search_hint: + 'Hex de 64 caracteres = transacción · cualquier otra cosa = dirección Bitcoin', + recent_blocks: 'Bloques recientes', + chain_tip: 'Punta de cadena', + block_height: 'Altura de bloque', + block_fee: 'tarifa de bloque', + fee_estimates: 'Estimaciones de tarifa', + confirmed_balance: 'Saldo confirmado', + unconfirmed_balance: 'Saldo no confirmado', + transaction_history: 'Historial de transacciones', + coinbase: 'Coinbase', + inputs: 'Entradas', + outputs: 'Salidas', + confirmations: 'Confirmaciones', + confirmed: 'Confirmado', + unconfirmed: 'No confirmado', + history_unavailable: + 'Historial de transacciones no disponible (la dirección tiene demasiadas transacciones)', + address: 'Dirección', + block_number: 'Bloque #{height}', + block_diff: 'dif {value}', + block_hash: 'Hash', + previous_block: 'Bloque anterior', + merkle_root: 'Raíz de Merkle', + version: 'Versión', + bits: 'Bits', + difficulty: 'Dificultad', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Tamaño virtual', + weight: 'Peso', + n_block_fee: 'tarifa {n} bloques' } diff --git a/lnbits/static/i18n/fi.js b/lnbits/static/i18n/fi.js index a7506d315..58ffe3f55 100644 --- a/lnbits/static/i18n/fi.js +++ b/lnbits/static/i18n/fi.js @@ -81,6 +81,10 @@ window.localisation.fi = { view_swagger_docs: 'Näytä LNbits Swagger API-dokumentit', api_docs: 'API-dokumentaatio', api_keys_api_docs: 'Solmun URL, API-avaimet ja -dokumentaatio', + api_keys_warning: + 'Pidä nämä avaimet turvassa, sillä niiden jakaminen voi johtaa varojen menetykseen.', + admin_key_warning: + 'Ylläpitäjäavaimesi antaa täyden pääsyn lompakkoosi, myös maksujen lähettämiseen. Älä koskaan jaa sitä, ellet täysin luota vastaanottajaan.', lnbits_version: 'LNbits versio', runs_on: 'Mukana menossa', paste: 'Liitä', @@ -520,6 +524,14 @@ window.localisation.fi = { auth_keycloak_cs_label: 'Keycloak-asiakassalasana', auth_keycloak_custom_org_label: 'Valinnainen Keycloak-organisaatio', auth_keycloak_custom_icon_label: 'Valinnainen Keycloak-kuvake (URL)', + auth_oidc_label: 'OIDC-discovery-URL', + auth_oidc_ci_label: 'OIDC-asiakastunnus', + auth_oidc_ci_hint: + 'Varmista, että valtuutuksen palautus-URL on asetettu muotoon https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'OIDC-asiakassalasana', + auth_oidc_custom_org_label: + 'OIDC mukautetun organisaation nimi (esim. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Valinnainen OIDC-kuvake (URL)', currency_settings: 'Valuutta-asetukset', allowed_currencies: 'Käytettävät valuutat', allowed_currencies_hint: 'Valitse käytettävissä olevat fiat-valuutat', @@ -639,5 +651,48 @@ window.localisation.fi = { 'On the PayPal side configure a webhook pointing to your LNbits server.', callback_success_url: 'Callback Success URL', callback_success_url_hint: - 'The user will be redirected to this URL after the payment is successful' + 'The user will be redirected to this URL after the payment is successful', + block_explorer: 'Lohkoselain', + enable_block_explorer: 'Ota lohkoselain käyttöön', + block_explorer_desc: + 'Salli käyttäjien tutkia Bitcoin-transaktioita ja -osoitteita Electrumin kautta.', + blockexplorer_public_api: 'Julkinen API-pääsy', + blockexplorer_public_api_desc: + 'Salli todentamaton pääsy lohkoselain API-päätteisiin.', + electrum_server_url: 'Electrum-palvelimen URL', + electrum_server_url_hint: + 'esim. ssl://electrum.blockstream.info:50002 tai tcp://localhost:50001', + blockexplorer_search_label: 'Hae TXID:llä tai osoitteella', + blockexplorer_search_hint: + '64 merkin heksa = transaktio · muu = Bitcoin-osoite', + recent_blocks: 'Viimeisimmät lohkot', + chain_tip: 'Ketjun kärki', + block_height: 'Lohkokorkeus', + block_fee: 'lohkomaksu', + fee_estimates: 'Maksuarviot', + confirmed_balance: 'Vahvistettu saldo', + unconfirmed_balance: 'Vahvistamaton saldo', + transaction_history: 'Tapahtumahistoria', + coinbase: 'Coinbase', + inputs: 'Syötteet', + outputs: 'Tulosteet', + confirmations: 'Vahvistukset', + confirmed: 'Vahvistettu', + unconfirmed: 'Vahvistamaton', + history_unavailable: + 'Tapahtumahistoria ei saatavilla (osoitteella on liikaa tapahtumia)', + address: 'Osoite', + block_number: 'Lohko #{height}', + block_diff: 'vaikeus {value}', + block_hash: 'Hash', + previous_block: 'Edellinen lohko', + merkle_root: 'Merkle-juuri', + version: 'Versio', + bits: 'Bitit', + difficulty: 'Vaikeus', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtuaalikoko', + weight: 'Paino', + n_block_fee: '{n} lohkon maksu' } diff --git a/lnbits/static/i18n/fo.js b/lnbits/static/i18n/fo.js new file mode 100644 index 000000000..c40572fff --- /dev/null +++ b/lnbits/static/i18n/fo.js @@ -0,0 +1,901 @@ +window.localisation.fo = { + confirm: 'Ja', + server: 'Ambætari', + theme: 'Snið', + site_customisation: 'Vevsíðu tillagingar', + funding: 'Fígging', + users: 'Brúkarar', + audit: 'Slóðfesti', + api_watch: 'API nýtsluyvirlit', + apps: 'Appir', + channels: 'Rásir', + transactions: 'Flytingar', + dashboard: 'Yvirlitssýni', + node: 'Knútur', + export_users: 'Tak brúkarar út', + no_users: 'Eingin brúkari finst', + total_capacity: 'Samlað rásarupphædd', + avg_channel_size: 'Miðal rásarupphædd', + biggest_channel_size: 'Størsta rásarupphædd', + smallest_channel_size: 'Minsta rásarupphædd', + number_of_channels: 'Tal av rásum', + active_channels: 'Virknar rásir', + connect_peer: 'Sambind við javninga', + connect: 'Sambind', + reconnect: 'Sambind aftur', + open_channel: 'Ger rás', + open: 'Lat upp', + clear: 'Tómstilla', + close_channel: 'Loka rás', + close: 'Loka', + restart: 'Endurbyrja ambætara', + image_library: 'Myndasavn', + save: 'Goym', + save_tooltip: 'Goym broytingarnar', + must_save: 'Tú hevur framt broytingar ið enn ikki eru goymdar.', + credit_debit: 'Góðskriva / Skuldskriva', + credit_hint: + 'Trýst á Enter til tess at góðskriva/skuldskriva mappu (negativ viðri eru loyvd)', + credit_label: '{denomination} at góðskriva/skuldskriva', + credit_ok: + 'Tað eydnaðist at góðskriva/skuldskriva tykisligan pening ({amount} sats). Gjøld eru treytaði av veruligum peningi á fíggingarkelduni.', + restart_tooltip: 'Endurbyrja ambætaran fyri at broytingarnar fáa virknað', + add_funds_tooltip: 'Set pening á eina mappu.', + reset_defaults: 'Endurset til forsettar stillingar', + reset_defaults_tooltip: + 'Strika allar stillingar og endurset tær til forsettar.', + download_backup: 'Tak niður dátugrunstrygdaravrit', + name_your_wallet: 'Navngev tína {name} mappu', + paste_invoice_label: 'Innset ein faktura, gjaldsumbøn ella LNURL-kotu *', + lnbits_description: + 'LNbits er kravlítil skipan, ið er løtt at innleggja og uppseta, og kann brúka einhvørja fíggingarkeldu á Lightning netinum. Tú kanst koyra LNbits til egna nýtslu og lættliga veita øðrum eina varðveitsluloysn. Tú fært gjørt eitt óavmarkað tal av mappum har hvør mappa hevur sínar egnu API-lyklar. Við møgulleikanum at býta pening gerst LNbits eitt hent amboð til peningaumsiting og eitt menningaramboð. Ískoytisforrit leggja virkisføri afturat LNbits so at tú kanst royna teg við eini røð av framkomnum tøknum á Lightning netinum. Vit hava gjørt tað so lætt sum møguligt, at menna ískoytisforrit, og sum ein fræls og gjøgnumskygd verkætlan eggja vit fólki, at menna og leggja fram teirra egnu ískoytisforrit.', + export_to_phone: 'Tak út til snildfon við QR-kotu', + export_to_phone_desc: + 'QR-kotan inniheldur eina leinkju ið vísir til og gevur full rættindi til tína mappu. Skannar tú hana, t.d. við tíni snildfon, kanst tú lata upp mappu nýtaramótið har.', + access_wallet_on_mobile: 'Faratgongd', + stored_paylinks: 'Goymdar LNURL-gjaldleinkjur', + wallet: 'Mappa: ', + wallet_name: 'Mappunavn', + wallet_type: 'Slag av mappu', + shared_wallet: 'Deild mappa', + share_wallet: 'Deil mappu', + update_permissions: 'Broyt loyvir', + shared_wallet_id: 'Eyðmerki á deildari mappu', + shared_wallet_desc: 'Tú ert boðin atgongd til aðra mappu.', + wallets: 'Mappur', + exclude_wallets: 'Útiloka mappur', + add_wallet: 'Ger mappu', + reject_wallet: 'Vraka mappuatgongd', + add_new_wallet: 'Legg nýggja mappu afturat', + pin_wallet: 'Fest á mappulista', + delete_wallet: 'Strika mappu', + delete_wallet_desc: + 'Mappan verður strikað og peningurin í henni fæst IKKI AFTUR.', + rename_wallet: 'Nýnevn mappu', + update_name: 'Nýnevn', + fiat_tracking: 'Fiat rekjan', + fiat_providers: 'Fiat meklarir', + fiat_warning_bitcoin: + 'Ber teg undan at brúka orðið "bitcoin" tínum samskifti við fiat meklarar, tí teir hava lyndi at gerast fjálturstungnir um tað ið hevur við Bitcoin at gera!', + currency: 'Gjaldoyra', + update_currency: 'Broyt gjaldoyra', + press_to_claim: 'Trýst til tess at taka ímóti bitcoin', + claim_desc: + 'Tú tykist hava krav á einari bitcoin upphædd men hevur ikki eina mappu enn. Trýst á knøttin niðanfyri fyri at taka ímóti henni. Ein nýggj mappa verður gjørd tær.', + donate: 'Veit fíggjarligan stuðul', + view_github: 'Lat upp LNbits verkætlanina á GitHub', + voidwallet_active: 'VoidWallet er virkin! Gjøld eru óvirkt', + voidwallet_active_user: + 'Fíggingarkelda er ikki tøk. Vinaliga bið skipanarumsitaran um at fáa fíggingarkelduna í rættlag.', + voidwallet_active_admin: + 'Fíggingarkelda er ikki tøk. Trýst á her fyri at uppseta.', + service_fee_badge: 'Tænastuavgjald: {amount} % fyri hvørja flyting', + service_fee_max_badge: + 'Tænastuavgjald: {amount} % fyri hvørja flyting (í mesta lagi {max} {denom})', + service_fee_tooltip: + 'Tænastuavgjald ið LNbits-ambætaraumsitarin krevur fyri hvørt útgjald', + toggle_darkmode: 'Myrkt snið', + payment_reactions: 'Gjaldsviðbrøgd', + view_swagger_docs: 'Lat upp LNbits Swagger API-skjalfestingina', + api_docs: 'API skjalfesting', + api_keys_api_docs: 'Knútaleinkja, API-lyklar og API-skjalfesting', + lnbits_version: 'LNbits útgáva', + runs_on: 'Koyrir á', + paste: 'Innset', + paste_from_clipboard: 'Innset frá setiborði', + paste_request: 'Innset umbøn', + create_invoice: 'Stovna gjaldsumbøn', + camera_tooltip: 'Brúka myntatólið at skanna eina gjaldsumbøn/QR-kotu', + export_csv: 'Tak út sum CSV', + export_csv_details: 'Tak út sum CSV, við smálutum', + chart_tooltip: 'Vís talvu', + pending: 'Ógoldin', + copy_invoice: 'Avrita gjaldsumbøn', + withdraw_from: 'Tak út úr', + cancel: 'Avlýs', + scan: 'Skanna', + read: 'Innles', // This is used both in terms of "reading/loading/parsing an invoice" and in terms of "ACL read rights". The word for those terms is not the same in faroese, but the former was chosen because it is the most visible in LNbits. + write: 'Skriva', + pay: 'Rinda', + sending: 'Sendur', + memo: 'Viðmerking', + date: 'Dagfesting', + path: 'Leið', + internal_memo: 'Egin viðmerking (valfríur)', + internal_memo_hint_receive: + 'Viðmerkingin verður ikki víst rindaranum men verður knýtt at fakturanum, so tú kanst nýta hana sum tilvísing.', + internal_memo_hint_pay: + 'Viðmerkingin verður ikki vist móttakaranum men verður knýtt at gjaldsumbønini, so tú kanst nýta hana sum tilvísing.', + payment_processing: 'Gjald verður avgreitt...', + payment_successful: 'Goldið!', + payment_pending: 'Gjald er ikki goldið enn...', + payment_check: 'Kanna greiðslu', + not_enough_funds: 'Ónøktandi salda!', + search_by_tag_memo_amount: 'Leita eftir spjaldri, viðmerking, upphædd', + search: 'Leita', + invoice_waiting: 'Gjaldsumbøn ið bíðar eftir at verða goldin', + payment_received: 'Inngjald', + payment_sent: 'Útgjald', + payment_failed: 'Gjald miseydnaðist', + receive: 'Móttak', + send: 'Send', + outgoing_payment_pending: 'Útgjald í bíðistøðu', + drain_funds: 'Tøm mappu', + drain_funds_desc: + 'Hendan LNURL-úttøku QR-kotan kann brúkast at taka allan peningin úr mappuni. Ikki deila QR-kotuna við nakran. Hon ger nýtslu av balanceCheck og balanceNotify og kann tí brúkast fleiri ferðir at tøma mappuna.', + i_understand: 'Eg skilji', + copy_wallet_url: 'Avrita mappuleinkju', + disclaimer_dialog_title: 'Gev gætur!', + disclaimer_dialog: + 'Tú *noyðist* at varðveita tínar innritanarupplýsingar til tess at fáa atgongd til mappuna aftur. Missir tú tær missir tú atgongd til mappuna og peningin.\n\nTú finnur tínar innritanarupplýsingar undir "Mín brúkari" > "Brúkara uppsetan".\n\nLNbits tekur ikki ábyrgd fyri mistari atgongd til pening.', + no_transactions: 'Enn eru ongar flytingar gjørdar', + manage: 'Umsit', + exchanges: 'Gjaldoyrakostnaðir', + extensions: 'Ískoytisforrit', + no_extensions: 'Einki ískoytisforrit er innlagt :(', + created: 'Stovnað', + created_at: 'Stovnað', + updated_at: 'Broytt', + search_extensions: 'Leita eftir ískoytisforritum', + search_wallets: 'Leita eftir mappum', + extension_sources: 'Ískoytisforritakeldur', + ext_sources_hint: 'Keldur hiðan ískoytisforrit verða tikin niður', + ext_sources_label: + 'Kelduleinkja (brúka einans almennu LNbits-ískoytisforritakelduna og keldur tú hevur álit á)', + warning: 'Gev gætur', + repository: 'Kelda', + confirm_continue: 'Ynskir tú at halda áfram?', + manage_extension_details: 'Innlegg/Strika ískoytisforritið', + upload: 'Uppsend', + install: 'Innlegg', + uninstall: 'Strika', + drop_db: 'Strika dáturnar', + enable: 'Virkja', + enabled: 'Virktur', + disabled: 'Óvirkt(ur)', + pay_to_enable: 'Rinda til tess at virkja', + enable_extension_details: 'Virkja ískoytisforrit fyri verandi brúkara', + disable: 'Óvirkja', + delete: 'Strika', + installed: 'Innløgd', + activated: 'Virkt(ur)', //used for users and extensions which are different genders in faroese + deactivated: 'Óvirkt', + activate: 'Virkja', + deactivate: 'Óvirkja', + release_notes: 'Sleppingarskriv', + activate_extension_details: + 'Virkja ella óvirkja ískoytisforritið fyri brúkarum', + featured: 'Víðagitin', + categories: 'Flokkar', + all: 'Øll', + only_admins_can_install: '(Einans umsitarar kunnu innleggja ískoytisforrit)', + only_admins_can_create_extensions: + 'Einans umsitarar kunnu gera ískoytisforrit', + admin_only: 'Einans umsitarar', + make_user_admin: 'Játta umsitanarrættindi', + revoke_admin: 'Ógilda umsitanarrættindi', + new_version: 'Nýggj útgáva', + reviews_url: 'Ummælaleinkja', + reviews_url_label: 'Ummælaambætaraleinkja', + reviews_url_hint: + 'Leinkja til PaidReviews/ummælir, íroknað stillingareymerki (t.d. https://example.com/paidreviews/SETTINGS_ID)', + reviews_open: 'Sí ummælir', + reviews_leave: 'Gev ummæli', + reviews_name: 'Títt navn', + reviews_comment: 'Títt ummæli', + reviews_rating: 'Meting', + reviews_submit: 'Send inn ummælið', + reviews_loading: 'Innlesur ummælir...', + reviews_refresh: 'Endurinnlesur ummælir', + reviews_error_load: 'Miseydnaðist at innlesa ummælir', + reviews_url_not_configured: 'Ummælaleinkja ikki ásett', + reviews_pay_invoice: 'Rinda gjaldsumbøn', + reviews_invoice_paid: 'Gjaldsumbøn goldin', + reviews_invoice_title: + 'Rinda hesa gjaldsumbøn til tess at skráseta títt ummæli', + reviews_count: 'Ummælir', + no_reviews: 'Ongin ummælir enn', + extension_has_free_release: 'Hevur ókeypis útgávur', + extension_has_paid_release: 'Hevur útgávur til keyps', + extension_depends_on: 'Er treytað av:', + extension_rating_soon: 'Metingar koma skjótt', + extension_installed_version: 'Innløgd útgáva', + extension_uninstall_warning: + 'Tú ert í ferð við at strika ískoytisforritið fyri allar brúkararnar.', + uninstall_confirm: 'Ja, strika', + extension_db_drop_info: + 'Allar dátur tilhoyrandi ískoytisforritið verða strikaðar. Eftir hesa gerð vendst ikki aftur!', + extension_db_drop_warning: + 'Tú ert í ferð við at strika allar dátur tilhoyrandi ískoytisforritið. Vinaliga skriva navnið á ískoytisforritinum til tess at halda á fram:', + extension_required_lnbits_version: 'Hendan útgávan tørvar LNbits útgávu', + min_version: 'Í minsta lagi', + max_version: 'Upp til (ikki íroknað)', + preimage: 'Frumvirði', + preimage_hint: 'Frumvirði til tess at avrokna varðveitslugjaldsumbøn', + hold_invoice: 'Varðveitslugjaldsumbøn', + hold_invoice_description: + 'Hendan gjaldsumbønin er í varðveitslu og tørvur er á frumvirði til tess at gjalda hana.', + payment_hash: 'Gjalds-hash', + invoice_cancelled: 'Gjaldsumbøn ógilda', + invoice_settled: 'Gjaldsumbøn avroknað', + hold_invoice_payment_hash: + 'Gjalds-hash fyri varðveitslugjaldsumbøn (valfríur)', + settle_invoice: 'Avrokna gjaldsumbøn', + cancel_invoice: 'Ógilda gjaldsumbøn', + fee: 'Avgjald', + amount: 'Upphædd', + amount_limits: 'Upphæddarmørk', + amount_sats: 'Upphædd (sats)', + faucest_wallet: 'Tiltaksmappa', + faucest_wallet_desc_1: + 'Fyri hvørt gjald váttað av {provider} verður upphæddin drigin frá hesi mappuni.', + faucest_wallet_desc_2: + 'Hetta hjálpir at halda skil á øllum {provider} gjøldum og støðum teirra.', + faucest_wallet_desc_3: + 'Mappan skal hava upphædd av sats ið umsitarin bjóðar í býti fyri fiat gjaldoyrað.', + faucest_wallet_desc_4: + 'Er ásetta mappan tóm verða gjøld umvegis {provider} ikki avgreidd.', + faucest_wallet_desc_5: + 'Upphæddin á tiltaksmappuni kann umsíðir gerast negativ í fall fleiri fiat gjøld verða rindaði.', + faucest_wallet_id: 'Tiltaksmappueyðmerki (valfríur)', + faucest_wallet_id_hint: + 'Eyðmerki á mappu við tøkari upphædd at senda til brúkaran.', + tag: 'Spjaldur', + unit: 'Eind', + description: 'Lýsing', + expiry: 'Fyrnar', + webhook: 'Vevongul', + webhook_url: 'Vevongulsleinkja', + webhook_url_hint: + 'Vevongulsleinkja ið gjaldsupplýsingarnir verða sendir til. Tað verður koyrt fyri hvørt gjald.', + copy_webhook_url: 'Avrita vevongulsleinkju', + webhook_events_list: 'Vevongulin noyðist at koyra undir fylgjandi hendingum:', + webhook_stripe_description: + 'Á Stripe síðuni noyðist tú at uppseta ein vevongul við einari leinkju ið peikar á tín LNbits-ambætara.', + webhook_square_description: + 'Á Square síðuni noyðist tú at uppseta ein vevongul ið peikar á hesa LNbits-leinkjuna.', + square_webhook_url_hint: + 'Skal samsvara við fráboðanarleinkjuna hjá Square. LNbits tørvar /api/v1/callback/square slóðina.', + access_token: 'Atgongdarmerki', + location_id: 'Staðsetingareyðmerki', + square_location_id_hint: + 'Square-staðsetingareyðmerkið ið gjaldsumbønarleinkjur verða gjørdar fyri. Brúka endapunktið at velja royndar- ella framleiðsluumhvørvi.', + api_version: 'API útgáva', + payment_proof: 'Gjaldsprógv', + update: 'Dagfør', // This is used in terms of "updating extensions", and in terms of "Saving ACL changes" + update_available: 'Dagføring {version} tøk!', + funding_sources: 'Fíggingarkeldur', + funding_source: 'Fíggingarkelda', + requires_server_restart: + 'Eftir broyting av hesum stillingunum er neyðugt at endurbyrja ambætaran, til tess at broytingarnar fáa virknað.', + funding_source_info: 'Fíggingarkelduupplýsingar', + phoenixd_warning: + 'Phoenixd áminningarramsan kann einans ásetast um phoenixd dátuskjáttan er ásett og LNbits fær lisið hana. Tað er ikki eitt tekin um at phoenixd ikki koyrir. Tað merkir bara at LNbits ikki hevur atgongd at vísa áminningarramsuna her.', + latest_update: 'Tú ert á nýggjastu útgávuni {version}.', + notifications: 'Fráboðanir', + notifications_configure: 'Fráboðanaruppsetan', + notifications_nostr_config: 'Nostr uppsetan', + notifications_enable_nostr: 'Virkja Nostr fráboðanir', + notifications_enable_nostr_desc: 'Send fráboðanir umvegis Nostr', + notifications_nostr_private_key: 'Nostr privatur lykil', + notifications_nostr_private_key_desc: + 'Privatur lykil, í sekstandatal ella nsec skapi, at undirrita boð send til Nostr', + notifications_nostr_identifier: 'Nostr-dátuheiti', + notifications_nostr_identifier_desc: + 'Nip5-dátuheiti ið fráboðanir verða sendar til', + notifications_nostr_identifiers: 'Nostr-dátuheitir', + notifications_nostr_identifiers_desc: + 'Listi av dátuheitum ið fráboðanir verða sendar til', + notifications_telegram_config: 'Telegram-uppsetan', + notifications_enable_telegram: 'Virkja Telegram-fráboðanir', + notifications_enable_telegram_desc: 'Send fráboðanir umvegis Telegram', + notifications_telegram_access_token: 'Atgongdarmerki', + notifications_telegram_access_token_desc: 'Atgongdarmerki til bottin', + notifications_chat_id: 'Telegram-kjatteyðmerki', + notifications_chat_id_desc: + 'Eyðmerkið á Telegram-kjatti ið fráboðanir verða sendar til', + notifications_excluded_wallets_desc: 'Send ikki fráboðanir fyri hesar mappur', + notifications_email_config: 'Teldupost uppsetan', + notifications_enable_email: 'Virkja teldupost', + notifications_enable_email_desc: 'Send fráboðanir o.a. umvegis teldupost', + notifications_send_test_email: 'Send royndar teldubræv', + notifications_send_email: 'Send teldupost frá', + notifications_send_email_desc: 'Teldupostbústaður ið sent verður frá', + notifications_send_email_username: 'Brúkaranavn', + notifications_send_email_username_desc: + 'Brúkaranavn. Verður brúkaranavn ikki tilskila verður teldupostbústaðurin brúktur', + notifications_send_email_password: 'Loyniorð fyri at senda teldupost', + notifications_send_email_password_desc: + 'Loyniorð fyri teldupostbústaðin ið sent verður frá', + notifications_send_email_server_port: 'SMTP-portur', + notifications_send_email_server_port_desc: 'Portur á SMTP-ambætaranum', + notifications_send_email_server: 'SMTP-ambætari', + notifications_send_email_server_desc: + 'SMTP-ambætari ið skal senda teldupostin', + notifications_send_to_emails: 'Send teldubrøv til', + notifications_send_to_emails_desc: + 'Fráboðanir verða sendar, sum teldubrøv, til', + notification_settings_update: 'Broyttar stillingar', + notification_settings_update_desc: 'Fráboða um broyttar ambætarastillingar', + notification_server_start_stop: 'Startaðan/Steðgaðan ambætara', + notification_server_start_stop_desc: + 'Fráboða um startaðan og steðgaðan ambætara', + notification_watchdog_limit: 'Varðhundsmarkfráboðan', + notification_watchdog_limit_desc: + 'Boða frá tá mark varðhundsins er rokkið. Hetta broytir ikki fíggingarkelduna.', + notification_server_status: 'Ambætarastøðu', + notification_server_status_desc: + 'Fráboða regluliga um ambætarastøðuna (tilskila tíðarbil í tímum)', + notification_incoming_payment: 'Inngjøld', + notification_incoming_payment_desc: + 'Fráboða um inngjøld, á mappur, ið er hægri enn tilskillaða upphæddin (sats)', + notification_outgoing_payment: 'Útgjøld', + notification_outgoing_payment_desc: + 'Fráboða um útgjøld, frá mappum, ið er størri enn tilskilaða upphæddin (sats)', + notification_credit_debit: 'Góð- og skuldskrivingar', + notification_credit_debit_desc: + 'Fráboða um mappur góðskrivaðar ella skuldskrivaðar av úrvalsbrúkaranum', + notification_balance_delta_changed: 'Saldumunur broyttur', + notification_balance_delta_changed_desc: + 'Boða frá tá munurin á knútasalduni og LNbits-salduni er broyttur meira enn tað ávístu upphæddina (í sats). Áset 0 fyri at óvirkja. Verður kannað hvønn minutt.', + watchdog_introduction: + 'Varðhundurin er ein funka ið sjálvvirkandi kann skifta fíggingarkelduna til VoidWallet, í fall munurin á saldu fíggingarkeldunnar og saldu LNbits er størri enn eitt vist. Hetta kann hjálpa at fyribyrgja ovurnýtslu og tryggja saldu fíggingarkeldunnar.', + enable_watchdog: 'Varðhundaskifti', + enable_watchdog_desc: + 'Um virkt, og LNbits-saldan gerst hægri enn knútasaldan, so verður fíggingarkeldan sjálvvirkandi broytt til VoidWallet. Eftir dagføringar er neyðugt at virkja hetta aftur.', + watchdog_interval: 'Títtleiki varðhundsins', + watchdog_interval_desc: + 'Títtleikin — í minuttum — har varðhundurin kannar, um skifti, treytað av saldumuninum [knúta_salda - lnbits_salda], er neyðugt.', + watchdog_delta: 'Delta varðhundsins', + watchdog_delta_desc: + 'Mark fyri skifti av fíggingarkeldu til VoidWallet [lnbits_salda - knúta_salda > delta]', + status: 'Støða', + notification_source: 'Fráboðanarkeldur', + notification_source_label: + 'Kelduleinkja (brúka einans almennu LNbits fráboðanarkelduna og keldur tú hevur álit á)', + more: 'Frætt meira', + more_count: '{count} afturat', + less: 'minni', + releases: 'Útgávur', + watchdog: 'Varðhundur', + server_logs: 'Gerðalisti ambætarans', + ip_blocker: 'IP-noktan', + security: 'Trygd', + security_tools: 'Trygdaramboð', + block_access_hint: 'Nokta atgongd frá IP-atsetri', + allow_access_hint: + 'Loyv atgongd frá IP-atsetri (hevur hægri raðfesting enn noktaði IP-atsetur)', + enter_ip: 'Inntøppa IP-atsetur og trýst Enter', + rate_limiter: 'Umbønaravmarkan', + callback_url_rules: 'Afturtøkukallleinkjureglur', + enter_callback_url_rule: + "Inntøppa leinkjuregul í regex forsniði og trýst 'enter'", + callback_url_rule_hint: + 'Afturtøkukallleinkjur, harímillum LNURL-leinkjur, verða kannaðar sambært hesum reglunum. Í minsta lagi ein regla skal lúkast. Eru ongar reglur skrásettir eru allar leinkjur loyvdar.', + wallet_limiter: 'Mappuavmarkingar', + wallet_config: 'Mappustillingar', + wallet_charts: 'Mapputalvur', + wallet_limit_max_withdraw_per_day: + 'Hámark á dagligum útgjøldum í sats (0 merkir óavmarkað, -1 noktar fyri útgjøldum)', + wallet_max_ballance: 'Mappusalduhámark í sats (0 merkir óavmarkað)', + wallet_limit_secs_between_trans: + 'Lágmark fyri sekund ímillum flytingar fyri hvørja mappu (0 merkir einki mark)', + only_incoming_payments_allowed: 'Loyv bert inngjøldum', + disable_outgoing_payments: 'Óvirkja útgjøld', + number_of_requests: 'Tal av umbønum', + number_of_requests_hint: + 'Loyvdar umbønir fyri hvørt "tíðarbil" hjá umbønaravmarkaranum. Áset 0 fyri at óvirkja umbønaravmarkaran.', + time_unit: 'Tíðarbil', + minute: 'minutt', + settings: 'Stillingar', + second: 'sekund', + hour: 'tíma', + disable_server_log: 'Óvirkja gerðalista ambætarans', + enable_server_log: 'Virkja gerðalista ambætarans', + coming_soon: 'Hentleikin er undir menning', + session_has_expired: 'Tín seta er útgingin. Vinaliga rita innaftur.', + instant_access_question: 'ella stundisliga atgongd', + login_with_user_id: 'Rita inn við brúkaraeyðmerki', + or: 'ella', + create_new_wallet: 'Ger nýggja mappu', + delete_all_wallets: 'Strika allar mappur', + confirm_delete_all_wallets: + 'Ynskir tú at strika ALLAR mappurnar hjá hesum brúkaranum?', + login_to_account: 'Rita inn á tín brúkara', + create_account: 'Stovna brúkara', + account_settings: 'Brúkara uppsetan', + signin_with_oauth: 'Rita inn við', + signin_with_oauth_or: 'ella rita inn við', + signin_with_nostr: 'Rita inn við Nostr', + signin_with_google: 'Rita inn við Google', + signin_with_github: 'Rita inn við GitHub', + signin_with_custom_org: 'Rita inn við {custom_org}', + username_or_email: 'Brúkaranavn ella teldupostbústaður', + password: 'Loyniorð', + password_config: 'Loyniorðsuppsetan', + password_repeat: 'Endurtak loyniorðið', + update_password: 'Broyt loyniorðið', + change_password: 'Broyt loyniorð', + update_credentials: 'Dagfør innritanarupplýsingar', + update_pubkey: 'Broyt almenna lykilin', + nostr_pubkey_tooltip: 'Inntøppa almenna Nostr-lykil brúkarans (sekstandatøl)', + set_password: 'Áset loyniorð', + set_password_tooltip: 'Áset hesum brúkaranum eitt loyniorð', + invalid_password: 'Loyniorð skulu hava í minsta lagi 8 tekn', + invalid_password_repeat: 'Loyniorðini eru ikki eins', + reset_key_generated: 'Ein endursetanarlykil er hervið gjørdur.', + reset_key_copy: + 'Trýst á OK fyri at avrita endursetanarleinkjuna til setiborðið.', + login: 'Rita inn', + register: 'Skráset', + username: 'Brúkaranavn', + pubkey: 'Almennur lykil', + user_id: 'Brúkaraeyðmerki', + id: 'Eyðmerki', + email: 'Teldupostbústaður', + email_confirmation_hint: + 'Teldupostbústaður ið váttanarkota skal sendast til.', + nostr_identifier: 'Nostr-dátuheiti', + nostr_identifier_hint: + 'Nostr nip5-dátuheiti ella ið váttanarkota skal sendast til.', + first_name: 'Fornavn', + last_name: 'Eftirnavn', + picture: 'Mynd', + user_picture_desc: + 'Leinkja ið vísur til vangamynd. Tú kanst leggja hana út undir Tilfar.', + verify_email: 'Vátta teldupost umvegis', + account: 'Brúkari', + update_account: 'Broyt brúkara', + invalid_username: 'Ógildigt brúkaranavn', + auth_provider: 'Samgildisveitari', + external_id: 'Ytri eyðmerki', + my_account: 'Mín brúkari', + existing_account_question: 'Hevur tú longu ein brúkara?', + background_image: 'Bakgrundsmynd', + back: 'Aftur', + logout: 'Rita út', + look_and_feel: 'Útsjónd', + endpoint: 'Endapunkt', + api: 'API', + api_stripe: 'API', + api_token: 'API-merki', + api_tokens: 'API-merkir', + access_control_list: 'Atgongdarstýringarlisti', + access_control_list_admin_warning: + 'Hetta er ein umsitanarbrúkari. Framleidd merkir fáa tí umsitanarrættindir.', + new_api_acl: 'Nýggjan atgongdarstýringarlista', + api_token_id: 'API-merki', + toggle_gradient: 'Litskifti', + gradient_background: 'Litskifti á bakgrund', + rounded_ui: 'Avrundaði kort & knøttar', + toggle_rounded_ui: 'Virkja ella óvirkja avrundaði horn á kortum og knøttum', + card_gradient: 'Litskifti á kortum', + toggle_card_gradient: 'Virkja ella óvirkja litskifti á kortum', + card_shadow: 'Kortskuggar', + toggle_card_shadow: 'Virkja ella óvirkja skugga handan kort', + burger_menu_background: 'Bakgrund á síðuteigi', + toggle_burger_menu_background: 'Virkja ella óvirkja bakgrund síðuteigsins', + language: 'Mál', + assets: 'Tilfar', + max_asset_size_mb: 'Hámarksstødd á tilfari (MB)', + max_asset_size_mb_desc: + 'Hámarksstøddin, í megabýtum, á tilfari ið verður uppsent. Møguligt er at nýta desimalar.', + assets_allowed_mime_types: 'Loyvt slag av tilfari', + assets_allowed_mime_types_desc: + '(MIME) Sløg av tilfari ið loyvt verður at uppsenda. Um einki slag er ásett eru øll sløg loyvd.', + thumbnail_width: 'Smámyndavídd', + thumbnail_width_desc: 'Víddin á framleiddu smámyndunum, í piksilum.', + thumbnail_height: 'Smámyndahædd', + thumbnail_height_desc: 'Hæddin á framleiddu smámyndunum, í piksilum.', + thumbnail_format: 'Smámyndaforsnið', + thumbnail_format_desc: + 'Forsnið á framleiddu smámyndunum (PNG, JPEG, o.s.fr.).', + max_assets_per_user: 'Hámark av tilfari fyri hvønn brúkara', + max_assets_per_user_desc: + 'Hámark av tilfari ið hvør brúkari sleppur at uppsenda. Null merkir at uppsending er noktað.', + assets_no_limit_users: 'Brúkarir undantiknir tilfarsmørkum', + assets_no_limit_users_desc: + 'Hesir brúkarir eru undantiknir hámarkinum av uppsendum tilfari (grundað á brúkaraeyðkenni).', + color_scheme: 'Litaval', + visible_wallet_count: 'Nøgd av vístum mappum', + admin_settings: 'Umsit stillingar', + extension_cost: 'Útgávan krevur eitt gjald á í minsta lagi {cost} sats.', + extension_paid_sats: 'Tú hevur longu goldið {paid_sats} sats.', + extension_permissions_title: 'Játta ískoytisforriti rættindir', + extension_permissions_tab: 'Rættindir ískoytisforritsins', + user_permissions_tab: 'Mínar játtanir', + extension_permissions_none: + 'Hetta ískoytisforritið krevur ongi rættindir undir innlegging.', + user_permissions_none: + 'Tú hevur ikki játtað hesum ískoytisforriti nøkur rættindir.', + user_permissions_max_amount: 'Mark á gjaldsupphædd', + user_permissions_destination_policy: 'Loyvi at rinda til', + user_permissions_no_editable_settings: + 'Hendan játtanin hevur einki at tillaga.', + extension_permissions_grant_install: 'Játta og innlegg', + extension_permissions_high_risk_warning: + 'Hetta ískoytisforritið biður um rættindi at flyta pening.', + extension_permission_risk_low: 'Lítil váði', + extension_permission_risk_medium: 'Miðal váði', + extension_permission_risk_high: 'Stórur váði', + extension_permission_warning_wallet_pay_invoice: + 'Kann brúka pening úr mappum ið eru tøkar á tínum brúkara.', + extension_permission_warning_wallet_pay_invoice_background: + 'Kann brúka pening úr ásettum mappum seinni og uttan inntriv frá brúkara.', + extension_permission_warning_wallet_payments_watch: + 'Kann lesa gjaldssmálutir viðvíkjandi ásettum mappum.', + extension_permission_warning_extension_api_request_write: + 'Kann skriva dátur ella koyra tilgongdir í ásettum ískoytisforritum.', + extension_permission_ext_storage_read: 'Lesa ískoytisforritagoymslu', + extension_permission_ext_storage_read_public: + 'Lesa almenna ískoytisforritagoymslu', + extension_permission_ext_storage_write: 'Skriva til ískoytisforritagoymslu', + extension_permission_ext_storage_read_write: + 'Lesa og skriva til ískoytisforritagoymslu', + extension_permission_extension_api_request: 'Brúka onnur ískoytisforrit', + extension_permission_extension_api_request_extensions: 'Loyvd ískoytisforrit', + extension_permission_access_read: 'Lesa', + extension_permission_access_write: 'Skriva', + extension_permission_http_request: 'Sambinda til ytri vevsíður', + extension_permission_http_request_hosts: 'Loyvdir vertir', + extension_permission_utils_basic: 'Brúka grundleggjandi LNbits hentleikar', + extension_permission_ui_camera_scan_qr: 'Skanna QR-kotur', + extension_permission_wallet_payments_watch: 'Eygleiða gjøld á mappum', + extension_permission_wallet_create_invoice: 'Gera gjaldsumbønir', + extension_permission_wallet_create_invoice_public: + 'Gera Lightning-gjaldsumbønir frá almennum síðum', + extension_permission_wallet_balance_read: 'Síggja mappusaldur', + extension_permission_wallet_list: 'Vísa mappur', + extension_permission_wallet_pay_invoice: 'Rinda gjaldsumbønir', + extension_permission_wallet_pay_invoice_background: + 'Rinda í bakgrundini, uttan inntriv frá brúkara', + create_extension: 'Stovna ískoytisforrit', + release_details_error: 'Bar ikki til at útvega sleppingarstaklutir.', + pay_from_wallet: 'Rinda úr mappuni', + pay_with: 'Rinda við {provider}', + select_payment_provider: 'Vel gjaldsmeklara', + wallet_required: 'Mappa *', + show_qr: 'Vís QR-kotu', + retry_install: 'Royn at leggja inn aftur', + new_payment: 'Rinda av nýggjum', + update_payment: 'Goym gjaldsupplýsingar', + already_paid_question: 'Hevur tú longu goldið?', + sell: 'Sel', + sell_require: 'Virkja ískoytisforritið fyri eitt gjald', + sell_info: + 'Eitt gjald á í minsta lagi {amount} sats er kravt fyri at virkja {name}-ískoytisforritið.', + hide_empty_wallets: 'Fjal tómar mappur', + recheck: 'Eftirkanna', + check: 'Kanna', + check_connection: 'Kanna sambinding', + check_webhook: 'Kanna vevongul', + contributors: 'Stigtakarir', + license: 'Loyvi', + reset_key: 'Endursetanarlykil', + reset_password: 'Endurset loyniorð', + border_choices: 'Rammusnið', + select_all: 'Vel øll', + nfc_supported: 'NFC-hentleiki er møguligur', + nfc_not_supported: 'NFC-hentleiki er ikki møguligur', + expire_date: 'Útgongudagfesting: ', + hash: 'Hash: ', + welcome_lnbits: 'Vælkomin til LNbits', + setup_su_account: 'Ger úrvalsbrúkaran niðanfyri.', + first_install_token: 'Merkið fyri fyrstu innlegging', + create_ticker_converter: 'Ger gjaldoyramerkilíka', + enable_audit: 'Virkja slóðfesti', + recommended: 'Viðmælt', + audit_desc: 'Skráset HTTP-umbønirnar sambært fylgjandi ásetingum', + audit_record_req: 'Skráset body-partin av umbønum', + audit_record_warning: 'Gev gætur: ', + audit_record_req_warning_1: + 'trúnaðardátur, teirra millum loyniorð, verða skrásettar.', + audit_record_req_warning_2: 'body-parturin av umbønunum kann fylla nógv.', + audit_record_use: 'Skal brúkast við fyrivarni.', + audit_ip: 'Skráset IP-atsetur', + audit_ip_desc: 'Skráset IP-atsetur viðskiftarans', + audit_path_params: 'Skráset slóðávirkir (Path Parameters)', + audit_query_params: 'Skráset fyrispurningsávirkir (Query Parameters)', + audit_http_methods: 'Íroknaðir HTTP-háttir', + audit_http_methods_hint: + 'Íroknaðir HTTP-háttir. Er listin tómur verða allir háttir íroknaðir.', + audit_http_methods_label: 'HTTP-háttir', + audit_resp_codes: 'Íroknaðar HTTP-svarkotur', + audit_resp_codes_hint: + 'Íroknaðar HTTP-svarkotur (regex forsnið). Er listin tómur verða allar kotur íroknaðar. T.d.: 4.*, 5.*', + audit_resp_codes_label: 'HTTP-svarkotur (regex)', + audit_paths: 'Íroknaðar slóðir', + audit_paths_hint: + 'Íroknaðar slóðir (regex forsnið). Er listin tómur verða allar slóðir íroknaðar.', + audit_paths_label: 'HTTP-slóð (regex)', + audit_paths_exclude: 'Útiloka slóðir', + audit_paths_exclude_hint: + 'Listi av útilokaðum slóðum (regex forsnið). Er listin tómur verða ongar slóðir útilokaðar.', + audit_paths_exclude_label: 'HTTP-slóð (regex)', + exchange_providers: 'Gjaldoyrakursveitarir', + admin_extensions: 'Umsitingarískoytisforrit', + admin_extensions_label: 'Umsitingarískoytisforrit', + admin_extensions_hint: + 'Ískoytisforrit ið einans er tøk fyri brúkarum við umsitingarligum rættindum', + user_default_extensions: 'Brúkaraforsett ískoytisforrit', + user_default_extensions_label: 'Brúkaraforsett ískoytisforrit', + user_default_extensions_hint: + 'Ískoytisforrit ið forsett verða virkt fyri brúkarunum', + extension_builder: 'Ískoytisforritasavnari', + extension_builder_manifest_url: 'Leinkja til ískoytisforritasavnaraskrá', + extension_builder_manifest_url_hint: + 'Leinkja til eina JSON-skrá við ískoytisforritasavnarastaklutum', + miscellanous: 'Ymiskt', + misc_disable_extensions: 'Óvirkja ískoytsiforrit', + misc_disable_extensions_label: 'Óvirkja øll ískoytisforrit', + misc_disable_extensions_builder: 'Virkja ískoytisforritasavnara', + misc_disable_extensions_builder_label: + 'Lova brúkarum ið ikki hava umsitanarrættindi at brúka ískoytisforritasavnaran', + misc_hide_api: 'Fjal API-upplýsingar', + misc_hide_api_label: + 'Fjalur mappu-API. Tað er upp til hvørt ískoytisforrit sær at halda við stillingini', + wallets_management: 'Fíggjaruppsetan', + funding_source_info: 'Fíggingarkeldu upplýsingar', + funding_source: 'Fíggingarkelda: {wallet_class}', + node_balance: 'Salda knútsins: {balance} sats', + lnbits_balance: 'LNbits-salda: {balance} sats', + funding_reserve_percent: 'Tiltakspeningur: {percent} %', + node_management: 'Knútaumsiting', + node_management_not_supported: + 'Knútaumsiting er ikki møgulig við verandi fíggingarkeldu', + toggle_node_ui: 'Knútanýtslumót', + toggle_public_node_ui: 'Alment knútanýtslumót', + toggle_transactions_node_ui: + 'Flytingarskiljiblað (frámælt á størri CLN-knútum vegna ovbyrjan)', + invoice_expiry: 'Loka gjaldsumbøn eftir', + routing_fee_reserve_calculations: 'Beiningaravgjaldstiltaksútrokningar', + routing_fee_reserve_calculations_desc: + 'Fyri hvørt útgjald setur LNbits eina "tiltaksupphædd" til síðis at rinda beiningaravgjøld. Hámarkið á beiningaravgjaldinum ið verður handað fíggingarkelduni er tað hægra av fylgjandi: lágmarkið fyri beiningaravgjald ella beiningaravgjald í prosentum.', + millisats: 'millisats', + fee_reserve: 'Lágmark fyri beiningaravgjald', + fee_reserve_percent: 'Beiningaravgjald í prosentum', + fee_reserve_min_hint: + 'Lágmark fyri beiningariavgjald fyri hvørt gjald.
Hetta riggar sum eitt minstamark - mest loyvda beiningaravgjald verður ongantíð lægri, uttan mun til gjaldsupphæddina.', + fee_reserve_percent_hint: + 'Prosent av gjaldsupphæddini at seta av til beiningaravgjald.', + payment_timeouts: 'Gjaldsfreistir', + payment_wait_time: 'Greiðslubíðitíð (sek.)', + seconds: 'sekund', + payment_pending_interval: 'Greiðslukanningarmillumbil (sek.)', + payment_pending_interval_desc: 'Tíðin ímillum óavgreidd gjøld verða kannaði', + payment_pending_interval_tooltip: + 'Ásetur títtleikan ið LNbits kannar og tillagar støðuna á óavgreiddum gjøldum. Longri millumbil kunnu lætta um byrðu knútsins og elva til skjótari greiðslur, ímeðan støðan á óavgreiddum gjøldum ikki verður dagførd líka títt.', + payment_wait_time_desc: + 'Bíðitíð áðrenn útgjøld verða merkt at verða í bíðistøðu. Forsett: 5 sek.; hækka í fall gjaldsumbønirnar taka langa tíð at avroknað.', + payment_wait_time_tooltip: + 'Ásetur tíðina ið LNbits bíðar eftir váttan fyri eitt útgjáld áðrenn útgjaldið verður sett í bíðistøðu. Longri bíðitíðir eru hóskandi tá ein skal rinda gjaldsumbønir ið taka longri tí at avroknað (t.d. HODL-gjaldsumbønir, Boltz). Møguligt er at kannað útgjaldið seinni og tað verður eisini kannað sjálvvirkandi við jøvnum millumbilum.', + server_management: 'Ambætaraumsiting', + base_url_label: 'Fastbundin rótleinkja til hendan ambætaran', + authentication: 'Samgilding', + auth_token_expiry_label: 'Merkigildistíð í minuttum', + auth_token_expiry_hint: 'Minuttir ið merkir eru gildið', + auth_authentication_cache_label: 'Kovatíð (minuttir)', + auth_authentication_cache_hint: + 'Minuttir ið eydnaðar samgildingar verða goymdar í kovanum (áset 0 fyri at óvirkja)', + auth_allowed_methods_label: 'Loyvdir samgildisháttir', + auth_allowed_methods_hint: 'Vel samgildisháttir', + auth_nostr_label: 'Nostr-umbønarleinkja', + auth_nostr_hint: + 'Fullfíggjaðar leinkjur ið viðskiftarar skulu brúka til innritanir.', + auth_google_ci_label: 'Google-viðskiftaraeyðmerki', + auth_google_ci_hint: + 'Tryggja at góðkenda víðaribeiningin inniheldur https://{domain}/api/v1/auth/google/token', + auth_google_cs_label: 'Google-viðskiftaraloyna', + auth_gh_client_id_label: 'GitHub-viðskiftaraeyðmerki', + auth_gh_client_id_hint: + 'Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/github/token', + auth_gh_client_secret_label: 'GitHub-viðskiftaraloyna', + auth_keycloak_label: 'Keycloak-viðrakanarleinkja', + auth_keycloak_ci_label: 'Keycloak-viðskiftaraeyðmerki', + auth_keycloak_ci_hint: + 'Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/keycloak/token', + auth_keycloak_cs_label: 'Keycloak-viðskiftaraloyna', + auth_keycloak_custom_org_label: 'Tillaga Keycloak-felag', + auth_keycloak_custom_icon_label: 'Tillaga Keycloak ímynd (leinkja)', + auth_oidc_label: 'OIDC-viðrakanarleinkja', + auth_oidc_ci_label: 'OIDC-viðskiftaraeyðmerki', + auth_oidc_ci_hint: + 'Tryggja at samgildisafturtøkukallsleinkjan er sett til https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'OIDC-viðskiftaraloyna', + auth_oidc_custom_org_label: + 'Tillaga OIDC navn á felagi (t.d. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Tillaga OIDC ímynd (leinkja)', + currency_settings: 'Gjaldoyrastillingar', + allowed_currencies: 'Loyvd gjaldoyru', + allowed_currencies_hint: 'Avmarka tøk fiat gjaldoyru', + default_account_currency: 'Forsett roknskapargjaldoyra', + default_account_currency_hint: 'Forsett gjaldoyra til roknskaparførslu', + min_incoming_payment_amount: 'Inngjaldslágmark', + min_incoming_payment_amount_desc: + 'Minst loyvda upphædd tá gjaldsumbøn verður gjørd', + max_incoming_payment_amount: 'Inngjaldshámark', + max_incoming_payment_amount_desc: + 'Hægst loyvda upphædd tá gjaldsumbøn verður gjørd', + max_outgoing_payment_amount: 'Útgjaldshámark', + max_outgoing_payment_amount_desc: + 'Hægst loyvda upphædd á hvørjum útgjaldi sær', + service_fees: 'Tænastuavgjøld', + service_fee: 'Tænastuavgjald', + service_fee_label: 'Tænastuavgjald (%)', + service_fee_hint: 'Avgjald kravt fyri hvørja flyting (%)', + service_fee_max: 'Hámark fyri tænastuavgjald', + service_fee_max_label: 'Hámark fyri tænastuavgjald (sats)', + service_fee_max_hint: 'Hámark fyri kravt tænastugjald í satoshis', + fee_wallet: 'Avgjaldsmappa', + fee_wallet_label: 'Avgjaldsmappa (mappueyðmerki)', + fee_wallet_hint: 'Eyðmerki á mappu ið tænastuavgjøld verða góðskrivað á', + disable_fee: 'Óvirkja tænastuavgjald', + disable_fee_internal: 'Óvirkja tænastuavgjald fyri innanknútsins gjøld', + disable_fee_internal_desc: + 'Óvirkja tænastuavgjald fyri innanknútsins Lightning gjøld', + ui_management: 'Nýtslumótumsiting', + ui_site_title: 'Síðuheiti', + ui_changing_remove_lnbits_elements: + ' (tillaging elvir til at LNbits-lutir á forsíðuni og síðufótinum verða strikaðir)', + ui_site_tagline: 'Síðuslagorð', + ui_elements_enable: 'Vís lutir á forsíðufótinum', + ui_elements_disable: 'Fjal lutir á forsíðufótinum', + ui_toggle_elements_tip: + "Strikar lutir so sum LNbits-útgávu og 'Koyrir á' frá forsíðuni", + ui_site_description: 'Síðulýsing', + ui_site_description_hint: 'Nýt vanligan tekst, Markdown, ella rátt HTML', + ui_default_wallet_name: 'Forsett mappunavn', + ui_default_theme: 'Forsett snið', + wallet_featured_button_title: 'Tillagaður knøttur á mappusíðuni', + wallet_featured_button_label: 'Tekstur á tillagaum knøtti', + wallet_featured_button_label_hint: 'Vís sermerktan knøtt á mappusíðuni', + wallet_featured_button_url: 'Leinkja ið tillagi knøtturin peikar á', + wallet_featured_button_url_hint: + 'Leinkjan verður latin upp tá trýst verður á knøttin. Lat teigin verða tóman fyri at fjala knøttin.', + wallet_featured_button_icon: 'Ímynd á tillagaða knøttinum', + wallet_featured_button_icon_hint: + 'Quasar-ímyndarnavnið ið skal vísast á knøttinum (t.d. "bolt")', + lnbits_wallet: 'LNbits-mappa', + denomination: 'Heiti', + denomination_hint: 'Heitið á FakeWallet-myntlíkinum', + denomination_error: 'Heitið skal verða 3 stavir, ella `sats`', + ui_qr_code_logo: 'Ímynd á QR-kotum og snarvegum', + ui_qr_code_logo_hint: + 'Leinkja til ímynd ið skal brúkast á QR-kotum og snarvegum', + ui_apple_touch_icon: 'Apple Touch ímynd', + ui_apple_touch_icon_hint: 'Leinkja til Apple touch ímynd', + ui_custom_image: 'Tillagað mynd', + ui_custom_image_label: 'Leinkja til tillagaða mynd', + ui_custom_image_hint: 'Mynd víst á forsíðu/innritanarsíðu', + ui_custom_badge_title: 'Tillaga spjaldur', + ui_custom_badge_desc: 'Vís tillagaðan spjaldratekst ovast á LNbits síðuni', + ui_custom_badge: 'Tillagaður spjaldratekstur', + ui_custom_badge_label: "Tillagaður spjaldratekstur 'BRÚKA VIÐ FYRIVARNI'", + ui_custom_badge_color_label: 'Litur á spjaldrinum', + themes: 'Snið', + themes_hint: 'Tilskilaði snið ið verða tøk fyri brúkarum', + custom_logo: 'Umsitaravalt búmerki', + custom_logo_hint: 'Leinkja ið peikar til búmerkið', + ad_space_section_title: 'Lýsingarteigur', + ad_space_section_desc: 'Tillaga lýsingarteigin á mappusíðuni.', + ad_space_title: 'Tekstur á lýsingarteigi', + ad_space_title_hint: 'Tekstur vístur omanfyri lýsingarteigin', + ad_slots: 'Lýsingar', + ad_slots_hint: + 'Leinkjur og myndaleinkjur í CSV-forsniði. Tað er upp til hvørt ískoytisforrit sær at halda við stillingini.', + ads_enabled: 'Vís lýsingar', + ads_disabled: 'Fjal lýsingar', + user_management: 'Brúkaraumsiting', + admin_users: 'Umsitarir', + admin_users_hint: 'Brúkarar við umsitingarrættindum', + admin_users_label: 'Brúkaraeyðmerki', + allowed_users: 'Loyvdir brúkarar', + allowed_users_hint: 'Einans fylgjandi brúkarar kunnu nýta LNbits', + allowed_users_hint_feature: '{feature} er avmarkað til hesar brúkararnar', + allowed_users_label: 'Brúkaraeyðmerki', + allow_creation_user: 'Loyv skráseting av nýggjum brúkarum', + allow_creation_user_desc: + 'Loyv stovnan av nýggjum brúkarum umvegis forsíðuna', + require_user_activation: 'Krev virkjan av nýggjum brúkarum', + require_user_activation_desc: + 'Nýggir brúkarir verða virktir við at lúka eina av váttanartreytunum. Umsitarir kunnu virkja brúkarir frá umsitanarsíðuni og harvið skúgva váttanartreytirnar til viks fyri brúkarar.', + reusable_activation_code: 'Endurnýtsluvirkjanarkota', + reusable_activation_code_label: 'Endurnýtsluvirkjanarkota', + reusable_activation_code_hint: + 'Hendan virkjanarkotan kann nýtast fleiri ferðir av ymiskum brúkarum.', + one_time_activation_code: 'Einnýtisvirkjanarkotur', + one_time_activation_code_label: 'Legg virkjanarkotu inn', + one_time_activation_code_hint: + 'Einnýtisvirkjanarkotur. Hvør kota kann bert nýtast einaferð og verður strika úr listanum eftir at hon er brúkt.', + invitation_code: 'Innbjóðingarkota', + invitation_code_hint: 'Innbjóðingarkotan ið tú hevur fingið.', + new_user_not_allowed: 'Skráseting av nýggjum brúkarum er óvirkt.', + start_user_impersonation: 'Lát at vera hesin brúkarin', + stop_user_impersonation: 'Lát ikki longur at vera brúkari', + components: 'Forritsliðir', + long_running_endpoints: '5 endapunktini ið hava koyrt longst', + http_request_methods: 'HTTP-umbønarháttir', + http_response_codes: 'HTTP-svarkotur', + request_details: 'Smálutir umbønarinnar', + http_request_details: 'HTTP-umbønarsmálutir', + payment_details: 'Gjaldssmálutir', + payment_details_desc: 'Nágreiniligir staklutir gjaldsins', + payments: 'Gjøld', + payment_show_internal: 'Vís innanhýsis gjøld', + payment_chart_flow: 'Mánaðarligur peningastreymur', + payment_chart_status: 'Gjaldstøður', + payment_chart_tx_per_wallet: 'Flytingar fyri hvørja mappu (upphædd/nøgd)', + payment_details_back: 'Aftur til gjøld', + payment_chart_tags: 'Gjøld eftir spjøldrum', + payments_balance_in_out: 'Inn- og útgjaldsupphæddir', + payments_count_in_out: 'Nøgd av inn- og útgjøldum', + payments_status_chart: 'Støðumynd', + payments_tag_chart: 'Spjaldrasirkulmynd', + payments_balance_chart: 'Saldulinjumynd', + payments_wallets_chart: 'Mappumynd', + payments_balance_in_out_chart: 'Inn- og útgjaldsupphæddir', + payments_count_in_out_chart: 'Nøgd av inn- og útgjøldum', + reset_wallet_keys: 'Endurset lyklar', + reset_wallet_keys_desc: + 'Endurset API lyklarnar fyri mappuna. Hetta ógildar verandi lyklar og framleiður nýggjar lyklar.', + view_list: 'Vís mappur í lista', + view_column: 'Vís mappur í teigum', + filter_payments: 'Filtrera gjøld', + filter_labels: 'Filtrera spjøldur', + filter_date: 'Filtrera út frá tíðarskeiði', + websocket_example: 'Vevsokkul dømi', + client_id: 'Viðskiftaraeyðmerki', + secret_key: 'Loyniligur lykil', + signing_secret: 'Undirritanarlykil', + signing_secret_hint: + 'Undirritanarlykil fyri vevongulin. Boð verða undirritaði við hesum lyklinum.', + webhook_id: 'Vevongulseyðmerki', + webhook_id_hint: 'PayPal-vevongulseyðmerki ið váttar inngangandi hendingar.', + webhook_paypal_description: + 'Uppset ein vevongul ið peikar á tín LNbits-ambætara á PayPal-síðuni.', + square_webhook_signature_key_hint: + 'Square-vevongulsundirritanarlykil ið váttar inngandi hendingar.', + callback_success_url: 'Afturtøkukallsleinkja', + callback_success_url_hint: + 'Eftir avgreitt gjald verður brúkarin víðaribeindur til hesa leinkjuna', + connected: 'Sambundin', + not_connected: 'Ikki sambundin', + free: 'Ókeypis', + paid: 'Til keyps', + funding_source_retries: 'Hámark av endurroyndum', + funding_source_retries_desc: + 'Hámark av endurroyndum av knýta í fíggingarkelduna áðrenn VoidWallet verður virkt.', + add_label: 'Nýtt spjaldur', + label: 'Spjaldur', + labels: 'Spjøldur', + label_filter: 'Spjaldrafiltur', + no_labels_defined: 'Enn eru eingi spjøldur gjørd', + manage_labels: 'Umsit spjøldur', + update_label: 'Broyt spjaldur', + delete_label: 'Strika spjaldur', + add_remove_labels: 'Áset ella strika spøldur', + payment_labels_updated: 'Spjøldur á gjaldi broytt', + color: 'Litur', + sort: 'Raða', + sort_by: 'Raða eftir' +} diff --git a/lnbits/static/i18n/fr.js b/lnbits/static/i18n/fr.js index f99af390e..2ee9373cd 100644 --- a/lnbits/static/i18n/fr.js +++ b/lnbits/static/i18n/fr.js @@ -75,6 +75,10 @@ window.localisation.fr = { view_swagger_docs: "Voir les documentation de l'API Swagger de LNbits", api_docs: "Documentation de l'API", api_keys_api_docs: 'URL du nœud, clés API et documentation API', + api_keys_warning: + 'Ces clés doivent être conservées en lieu sûr ; les partager pourrait entraîner la perte de fonds.', + admin_key_warning: + "Votre clé d'administrateur donne un accès complet à votre portefeuille, y compris la possibilité d'envoyer des paiements. Ne la partagez jamais, sauf si vous faites entièrement confiance au destinataire.", lnbits_version: 'Version de LNbits', runs_on: 'Fonctionne sur', paste: 'Coller', @@ -381,6 +385,16 @@ window.localisation.fr = { auth_keycloak_ci_hint: "Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/keycloak/token", auth_keycloak_cs_label: 'Secret client Keycloak', + auth_keycloak_custom_org_label: 'Organisation personnalisée Keycloak', + auth_keycloak_custom_icon_label: 'Icône personnalisée Keycloak (URL)', + auth_oidc_label: 'URL de découverte OIDC', + auth_oidc_ci_label: 'ID Client OIDC', + auth_oidc_ci_hint: + "Assurez-vous que l'URL de rappel d'autorisation est définie sur https://{domain}/api/v1/auth/oidc/token", + auth_oidc_cs_label: 'Secret client OIDC', + auth_oidc_custom_org_label: + "Nom de l'organisation personnalisée OIDC (par ex. Zitadel, Authentik)", + auth_oidc_custom_icon_label: 'Icône personnalisée OIDC (URL)', currency_settings: 'Paramètres de devise', allowed_currencies: 'Devises autorisées', allowed_currencies_hint: @@ -446,5 +460,48 @@ window.localisation.fr = { http_request_methods: 'Méthodes de requête HTTP', http_response_codes: 'Codes de réponse HTTP', request_details: 'Détails de la demande', - http_request_details: 'Détails de la requête HTTP' + http_request_details: 'Détails de la requête HTTP', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Activer le Block Explorer', + block_explorer_desc: + "Permet aux utilisateurs d'explorer les transactions et adresses Bitcoin via Electrum.", + blockexplorer_public_api: 'Accès API public', + blockexplorer_public_api_desc: + "Autoriser l'accès non authentifié aux endpoints de l'API de l'explorateur de blocs.", + electrum_server_url: 'URL du serveur Electrum', + electrum_server_url_hint: + 'p.ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001', + blockexplorer_search_label: 'Rechercher par TXID ou adresse', + blockexplorer_search_hint: + 'Hex 64 caractères = transaction · autre chose = adresse Bitcoin', + recent_blocks: 'Blocs récents', + chain_tip: 'Sommet de chaîne', + block_height: 'Hauteur de bloc', + block_fee: 'frais de bloc', + fee_estimates: 'Estimations de frais', + confirmed_balance: 'Solde confirmé', + unconfirmed_balance: 'Solde non confirmé', + transaction_history: 'Historique des transactions', + coinbase: 'Coinbase', + inputs: 'Entrées', + outputs: 'Sorties', + confirmations: 'Confirmations', + confirmed: 'Confirmé', + unconfirmed: 'Non confirmé', + history_unavailable: + 'Historique des transactions indisponible (adresse avec trop de transactions)', + address: 'Adresse', + block_number: 'Bloc #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Bloc précédent', + merkle_root: 'Racine de Merkle', + version: 'Version', + bits: 'Bits', + difficulty: 'Difficulté', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Taille virtuelle', + weight: 'Poids', + n_block_fee: 'frais {n} blocs' } diff --git a/lnbits/static/i18n/it.js b/lnbits/static/i18n/it.js index 87efbd3a1..db295faa2 100644 --- a/lnbits/static/i18n/it.js +++ b/lnbits/static/i18n/it.js @@ -73,6 +73,10 @@ window.localisation.it = { view_swagger_docs: "Visualizza i documentazione dell'API Swagger di LNbits", api_docs: "Documentazione dell'API", api_keys_api_docs: 'URL del nodo, chiavi API e documentazione API', + api_keys_warning: + 'Queste chiavi devono essere conservate al sicuro; condividerle potrebbe causare la perdita di fondi.', + admin_key_warning: + 'La tua chiave di amministratore concede accesso completo al tuo portafoglio, inclusa la possibilità di inviare pagamenti. Non condividerla mai, a meno che tu non ti fidi completamente del destinatario.', lnbits_version: 'Versione di LNbits', runs_on: 'Esegue su', paste: 'Incolla', @@ -378,6 +382,16 @@ window.localisation.it = { auth_keycloak_ci_hint: "Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/keycloak/token", auth_keycloak_cs_label: 'Keycloak Client Secret', + auth_keycloak_custom_org_label: 'Organizzazione personalizzata di Keycloak', + auth_keycloak_custom_icon_label: 'Icona personalizzata di Keycloak (URL)', + auth_oidc_label: 'URL di individuazione di OIDC', + auth_oidc_ci_label: 'ID client di OIDC', + auth_oidc_ci_hint: + "Assicurati che l'URL di callback dell'autorizzazione sia impostato su https://{domain}/api/v1/auth/oidc/token", + auth_oidc_cs_label: 'OIDC Client Secret', + auth_oidc_custom_org_label: + 'Nome organizzazione personalizzata OIDC (es. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Icona personalizzata di OIDC (URL)', currency_settings: 'Impostazioni valuta', allowed_currencies: 'Valute consentite', allowed_currencies_hint: 'Limita il numero di valute fiat disponibili', @@ -440,5 +454,48 @@ window.localisation.it = { http_request_methods: 'Metodi di richiesta HTTP', http_response_codes: 'Codici di risposta HTTP', request_details: 'Dettagli della richiesta', - http_request_details: 'Dettagli della richiesta HTTP' + http_request_details: 'Dettagli della richiesta HTTP', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Abilita Block Explorer', + block_explorer_desc: + 'Consenti agli utenti di esplorare transazioni e indirizzi Bitcoin tramite Electrum.', + blockexplorer_public_api: 'Accesso API pubblico', + blockexplorer_public_api_desc: + "Consenti accesso non autenticato agli endpoint API dell'esploratore di blocchi.", + electrum_server_url: 'URL server Electrum', + electrum_server_url_hint: + 'es. ssl://electrum.blockstream.info:50002 o tcp://localhost:50001', + blockexplorer_search_label: 'Cerca per TXID o indirizzo', + blockexplorer_search_hint: + 'Hex 64 caratteri = transazione · altro = indirizzo Bitcoin', + recent_blocks: 'Blocchi recenti', + chain_tip: 'Punta della catena', + block_height: 'Altezza blocco', + block_fee: 'commissione blocco', + fee_estimates: 'Stime delle commissioni', + confirmed_balance: 'Saldo confermato', + unconfirmed_balance: 'Saldo non confermato', + transaction_history: 'Storico transazioni', + coinbase: 'Coinbase', + inputs: 'Input', + outputs: 'Output', + confirmations: 'Conferme', + confirmed: 'Confermato', + unconfirmed: 'Non confermato', + history_unavailable: + "Storico transazioni non disponibile (l'indirizzo ha troppe transazioni)", + address: 'Indirizzo', + block_number: 'Blocco #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Blocco precedente', + merkle_root: 'Radice di Merkle', + version: 'Versione', + bits: 'Bit', + difficulty: 'Difficoltà', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Dimensione virtuale', + weight: 'Peso', + n_block_fee: 'commissione {n} blocchi' } diff --git a/lnbits/static/i18n/jp.js b/lnbits/static/i18n/jp.js index 9bfa65d2e..23f22c9ae 100644 --- a/lnbits/static/i18n/jp.js +++ b/lnbits/static/i18n/jp.js @@ -69,6 +69,10 @@ window.localisation.jp = { view_swagger_docs: 'Swaggerドキュメントを表示', api_docs: 'APIドキュメント', api_keys_api_docs: 'ノードURL、APIキー、APIドキュメント', + api_keys_warning: + 'これらのキーは安全に保管してください。共有すると資金を失うおそれがあります。', + admin_key_warning: + '管理者キーは、支払いの送信を含むウォレットへの完全なアクセスを許可します。受取人を完全に信頼している場合を除き、決して共有しないでください。', lnbits_version: 'LNbits バージョン', runs_on: 'で実行', paste: '貼り付け', @@ -369,6 +373,15 @@ window.localisation.jp = { auth_keycloak_ci_hint: '認証コールバックURLが https://{domain}/api/v1/auth/keycloak/token に設定されていることを確認してください。', auth_keycloak_cs_label: 'キークローククライアントシークレット', + auth_keycloak_custom_org_label: 'Keycloak カスタム組織', + auth_keycloak_custom_icon_label: 'Keycloak カスタムアイコン (URL)', + auth_oidc_label: 'OIDC ディスカバリー URL', + auth_oidc_ci_label: 'OIDC クライアント ID', + auth_oidc_ci_hint: + '認証コールバックURLが https://{domain}/api/v1/auth/oidc/token に設定されていることを確認してください。', + auth_oidc_cs_label: 'OIDC クライアントシークレット', + auth_oidc_custom_org_label: 'OIDC カスタム組織名(例:Zitadel、Authentik)', + auth_oidc_custom_icon_label: 'OIDC カスタムアイコン (URL)', currency_settings: '通貨設定', allowed_currencies: '許可されている通貨', allowed_currencies_hint: '利用可能な法定通貨の数を制限する', @@ -431,5 +444,48 @@ window.localisation.jp = { http_request_methods: 'HTTPリクエストメソッド', http_response_codes: 'HTTPレスポンスコード', request_details: 'リクエストの詳細', - http_request_details: 'HTTPリクエストの詳細' + http_request_details: 'HTTPリクエストの詳細', + block_explorer: 'ブロックエクスプローラー', + enable_block_explorer: 'ブロックエクスプローラーを有効化', + block_explorer_desc: + 'Electrumを介してビットコインのトランザクションとアドレスを探索できます。', + blockexplorer_public_api: 'パブリックAPIアクセス', + blockexplorer_public_api_desc: + 'ブロックエクスプローラーAPIエンドポイントへの非認証アクセスを許可します。', + electrum_server_url: 'ElectrumサーバーURL', + electrum_server_url_hint: + '例: ssl://electrum.blockstream.info:50002 または tcp://localhost:50001', + blockexplorer_search_label: 'TXIDまたはアドレスで検索', + blockexplorer_search_hint: + '64文字の16進数 = トランザクション · それ以外 = ビットコインアドレス', + recent_blocks: '最新ブロック', + chain_tip: 'チェーン先端', + block_height: 'ブロック高さ', + block_fee: 'ブロック手数料', + fee_estimates: '手数料見積もり', + confirmed_balance: '確認済み残高', + unconfirmed_balance: '未確認残高', + transaction_history: 'トランザクション履歴', + coinbase: 'コインベース', + inputs: 'インプット', + outputs: 'アウトプット', + confirmations: '確認数', + confirmed: '確認済み', + unconfirmed: '未確認', + history_unavailable: + 'トランザクション履歴が取得できません(アドレスのトランザクションが多すぎます)', + address: 'アドレス', + block_number: 'ブロック #{height}', + block_diff: 'diff {value}', + block_hash: 'ハッシュ', + previous_block: '前のブロック', + merkle_root: 'マークルルート', + version: 'バージョン', + bits: 'Bits', + difficulty: '難易度', + nonce: 'Nonce', + txid: 'TXID', + vsize: '仮想サイズ', + weight: '重量', + n_block_fee: '{n}ブロック手数料' } diff --git a/lnbits/static/i18n/kr.js b/lnbits/static/i18n/kr.js index 40b7e313e..0bded5c58 100644 --- a/lnbits/static/i18n/kr.js +++ b/lnbits/static/i18n/kr.js @@ -71,6 +71,10 @@ window.localisation.kr = { view_swagger_docs: 'LNbits Swagger API 문서를 봅니다', api_docs: 'API 문서', api_keys_api_docs: '노드 URL, API 키와 API 문서', + api_keys_warning: + '이 키는 안전하게 보관해야 하며, 공유하면 자금을 잃을 위험이 있습니다.', + admin_key_warning: + '관리자 키는 결제 전송을 포함하여 지갑에 대한 모든 권한을 부여합니다. 수신자를 완전히 신뢰하는 경우가 아니라면 절대 공유하지 마세요.', lnbits_version: 'LNbits 버전', runs_on: 'Runs on', paste: '붙여넣기', @@ -365,6 +369,16 @@ window.localisation.kr = { auth_keycloak_ci_hint: '승인 콜백 URL이 https://{domain}/api/v1/auth/keycloak/token으로 설정되어 있는지 확인하십시오.', auth_keycloak_cs_label: 'Keycloak 클라이언트 시크릿', + auth_keycloak_custom_org_label: 'Keycloak 사용자 정의 조직', + auth_keycloak_custom_icon_label: 'Keycloak 사용자 정의 아이콘 (URL)', + auth_oidc_label: 'OIDC 디스커버리 URL', + auth_oidc_ci_label: 'OIDC 클라이언트 ID', + auth_oidc_ci_hint: + '승인 콜백 URL이 https://{domain}/api/v1/auth/oidc/token으로 설정되어 있는지 확인하십시오.', + auth_oidc_cs_label: 'OIDC 클라이언트 시크릿', + auth_oidc_custom_org_label: + 'OIDC 사용자 정의 조직 이름 (예: Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'OIDC 사용자 정의 아이콘 (URL)', currency_settings: '통화 설정', allowed_currencies: '허용되는 통화', allowed_currencies_hint: '사용 가능한 법정 화폐의 수를 제한하십시오.', @@ -425,5 +439,47 @@ window.localisation.kr = { http_request_methods: 'HTTP 요청 메서드', http_response_codes: 'HTTP 응답 코드', request_details: '요청 세부사항', - http_request_details: 'HTTP 요청 세부사항' + http_request_details: 'HTTP 요청 세부사항', + block_explorer: '블록 탐색기', + enable_block_explorer: '블록 탐색기 활성화', + block_explorer_desc: + 'Electrum을 통해 비트코인 거래 및 주소를 탐색할 수 있습니다.', + blockexplorer_public_api: '공개 API 접근', + blockexplorer_public_api_desc: + '블록 탐색기 API 엔드포인트에 대한 비인증 접근을 허용합니다.', + electrum_server_url: 'Electrum 서버 URL', + electrum_server_url_hint: + '예: ssl://electrum.blockstream.info:50002 또는 tcp://localhost:50001', + blockexplorer_search_label: 'TXID 또는 주소로 검색', + blockexplorer_search_hint: '64자 16진수 = 거래 · 그 외 = 비트코인 주소', + recent_blocks: '최근 블록', + chain_tip: '체인 끝', + block_height: '블록 높이', + block_fee: '블록 수수료', + fee_estimates: '수수료 추정', + confirmed_balance: '확인된 잔액', + unconfirmed_balance: '미확인 잔액', + transaction_history: '거래 내역', + coinbase: 'Coinbase', + inputs: '입력', + outputs: '출력', + confirmations: '확인 수', + confirmed: '확인됨', + unconfirmed: '미확인', + history_unavailable: + '거래 내역을 불러올 수 없습니다 (주소의 거래가 너무 많음)', + address: '주소', + block_number: '블록 #{height}', + block_diff: 'diff {value}', + block_hash: '해시', + previous_block: '이전 블록', + merkle_root: '머클 루트', + version: '버전', + bits: 'Bits', + difficulty: '난이도', + nonce: 'Nonce', + txid: 'TXID', + vsize: '가상 크기', + weight: '무게', + n_block_fee: '{n}블록 수수료' } diff --git a/lnbits/static/i18n/nl.js b/lnbits/static/i18n/nl.js index 3c980406f..d103db7ec 100644 --- a/lnbits/static/i18n/nl.js +++ b/lnbits/static/i18n/nl.js @@ -73,6 +73,10 @@ window.localisation.nl = { view_swagger_docs: 'Bekijk LNbits Swagger API-documentatie', api_docs: 'API-documentatie', api_keys_api_docs: 'Node URL, API-sleutels en API-documentatie', + api_keys_warning: + 'Bewaar deze sleutels veilig; het delen ervan kan leiden tot verlies van tegoeden.', + admin_key_warning: + 'Je beheerderssleutel geeft volledige toegang tot je wallet, inclusief de mogelijkheid om betalingen te versturen. Deel deze nooit, tenzij je de ontvanger volledig vertrouwt.', lnbits_version: 'LNbits-versie', runs_on: 'Draait op', paste: 'Plakken', @@ -377,6 +381,16 @@ window.localisation.nl = { auth_keycloak_ci_hint: 'Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Keycloak Clientgeheim', + auth_keycloak_custom_org_label: 'Keycloak Aangepaste Organisatie', + auth_keycloak_custom_icon_label: 'Keycloak Aangepast Pictogram (URL)', + auth_oidc_label: 'OIDC Ontdekking URL', + auth_oidc_ci_label: 'OIDC-client-ID', + auth_oidc_ci_hint: + 'Zorg ervoor dat de autorisatie callback-URL is ingesteld op https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'OIDC Clientgeheim', + auth_oidc_custom_org_label: + 'OIDC Aangepaste Organisatienaam (bijv. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'OIDC Aangepast Pictogram (URL)', currency_settings: 'Valuta-instellingen', allowed_currencies: "Toegestane valuta's", allowed_currencies_hint: "Beperk het aantal beschikbare fiatvaluta's", @@ -440,5 +454,48 @@ window.localisation.nl = { http_request_methods: 'HTTP-aanvraagmethoden', http_response_codes: 'HTTP-responscodes', request_details: 'Aanvraagdetails', - http_request_details: 'HTTP-verzoekdetails' + http_request_details: 'HTTP-verzoekdetails', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Block Explorer inschakelen', + block_explorer_desc: + 'Laat gebruikers Bitcoin-transacties en -adressen verkennen via Electrum.', + blockexplorer_public_api: 'Publieke API-toegang', + blockexplorer_public_api_desc: + 'Niet-geauthenticeerde toegang tot de block explorer API-eindpunten toestaan.', + electrum_server_url: 'Electrum-server-URL', + electrum_server_url_hint: + 'bijv. ssl://electrum.blockstream.info:50002 of tcp://localhost:50001', + blockexplorer_search_label: 'Zoeken op TXID of adres', + blockexplorer_search_hint: + '64-karakter hex = transactie · alles anders = Bitcoin-adres', + recent_blocks: 'Recente blokken', + chain_tip: 'Kettingtop', + block_height: 'Blokhoogte', + block_fee: 'blokvergoeding', + fee_estimates: 'Vergoedingsschattingen', + confirmed_balance: 'Bevestigd saldo', + unconfirmed_balance: 'Onbevestigd saldo', + transaction_history: 'Transactiegeschiedenis', + coinbase: 'Coinbase', + inputs: 'Invoer', + outputs: 'Uitvoer', + confirmations: 'Bevestigingen', + confirmed: 'Bevestigd', + unconfirmed: 'Onbevestigd', + history_unavailable: + 'Transactiegeschiedenis niet beschikbaar (adres heeft te veel transacties)', + address: 'Adres', + block_number: 'Blok #{height}', + block_diff: 'moeil. {value}', + block_hash: 'Hash', + previous_block: 'Vorig blok', + merkle_root: 'Merkle-wortel', + version: 'Versie', + bits: 'Bits', + difficulty: 'Moeilijkheid', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtuele grootte', + weight: 'Gewicht', + n_block_fee: '{n}-blok vergoeding' } diff --git a/lnbits/static/i18n/pi.js b/lnbits/static/i18n/pi.js index 8eda929f1..f3287e6cb 100644 --- a/lnbits/static/i18n/pi.js +++ b/lnbits/static/i18n/pi.js @@ -72,6 +72,10 @@ window.localisation.pi = { view_swagger_docs: 'View LNbits Swagger API docs and learn the secrets', api_docs: 'API docs for the scallywags', api_keys_api_docs: 'Node URL, API keys and API docs', + api_keys_warning: + 'Keep these keys safe, matey; sharing them could lose ye yer doubloons.', + admin_key_warning: + 'Yer admin key gives full access to yer wallet, including sending payments. Never share it unless ye trust the recipient completely.', lnbits_version: 'LNbits version, arr!', runs_on: 'Runs on, matey', paste: 'Stow', @@ -371,6 +375,16 @@ window.localisation.pi = { auth_keycloak_ci_hint: "Make sure thant th' authorization callback URL be set t' https://{domain}/api/v1/auth/keycloak/token", auth_keycloak_cs_label: 'Keycloak Client Secret', + auth_keycloak_custom_org_label: 'Keycloak Custom Organization', + auth_keycloak_custom_icon_label: 'Keycloak Custom Icon (URL)', + auth_oidc_label: 'OIDC Discovery URL', + auth_oidc_ci_label: 'OIDC Client ID', + auth_oidc_ci_hint: + "Make sure thant th' authorization callback URL be set t' https://{domain}/api/v1/auth/oidc/token", + auth_oidc_cs_label: 'OIDC Client Secret', + auth_oidc_custom_org_label: + 'OIDC Custom Organization Name (e.g., Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'OIDC Custom Icon (URL)', currency_settings: "Doubloon Settin's", allowed_currencies: "Allo'ed Doubloons", allowed_currencies_hint: 'Limit the number of available fiat doubloons', @@ -431,5 +445,48 @@ window.localisation.pi = { http_request_methods: 'HTTP Request Methods', http_response_codes: 'HTTP Response Codes', request_details: 'Request Details', - http_request_details: 'HTTP Request Details' + http_request_details: 'HTTP Request Details', + block_explorer: 'Treasure Map', + enable_block_explorer: 'Hoist the Treasure Map', + block_explorer_desc: + "Let scallywags spy on Bitcoin doubloons an' addresses via Electrum.", + blockexplorer_public_api: 'Open Seas API', + blockexplorer_public_api_desc: + 'Allow any landlubber access to the block explorer API ports.', + electrum_server_url: 'Electrum Port URL', + electrum_server_url_hint: + 'e.g. ssl://electrum.blockstream.info:50002 or tcp://localhost:50001', + blockexplorer_search_label: 'Search by TXID or Port', + blockexplorer_search_hint: + '64-char hex = plunder · anything else = Bitcoin port', + recent_blocks: 'Recent Plunder', + chain_tip: "Tip o' the Anchor Chain", + block_height: 'Plunder Height', + block_fee: 'plunder fee', + fee_estimates: 'Booty Estimates', + confirmed_balance: 'Confirmed Booty', + unconfirmed_balance: 'Unconfirmed Booty', + transaction_history: 'Plunder History', + coinbase: 'Coinbase', + inputs: 'Inbound Plunder', + outputs: 'Outbound Plunder', + confirmations: 'Confirmations, arr', + confirmed: 'Confirmed, arr', + unconfirmed: 'Unconfirmed, arr', + history_unavailable: + 'Plunder history lost at sea (too many transactions, matey!)', + address: 'Port', + block_number: 'Block #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Previous Plunder Block', + merkle_root: 'Merkle Root', + version: 'Version', + bits: 'Bits', + difficulty: 'Difficulty', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtual Size', + weight: 'Weight', + n_block_fee: '{n}-block booty' } diff --git a/lnbits/static/i18n/pl.js b/lnbits/static/i18n/pl.js index 242a7572b..363c3cb30 100644 --- a/lnbits/static/i18n/pl.js +++ b/lnbits/static/i18n/pl.js @@ -71,6 +71,10 @@ window.localisation.pl = { view_swagger_docs: 'Dokumentacja Swagger API', api_docs: 'Dokumentacja API', api_keys_api_docs: 'Adres URL węzła, klucze API i dokumentacja API', + api_keys_warning: + 'Te klucze należy przechowywać bezpiecznie; ich udostępnienie może grozić utratą środków.', + admin_key_warning: + 'Twój klucz administratora zapewnia pełny dostęp do portfela, w tym możliwość wysyłania płatności. Nigdy go nie udostępniaj, chyba że całkowicie ufasz odbiorcy.', lnbits_version: 'Wersja LNbits', runs_on: 'Działa na', paste: 'Wklej', @@ -372,6 +376,16 @@ window.localisation.pl = { auth_keycloak_ci_hint: 'Upewnij się, że URL zwrotu autoryzacji jest ustawiony na https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Hasło klienta Keycloak', + auth_keycloak_custom_org_label: 'Własna organizacja Keycloak', + auth_keycloak_custom_icon_label: 'Własna ikona Keycloak (URL)', + auth_oidc_label: 'Adres URL Discovery OIDC', + auth_oidc_ci_label: 'Identyfikator klienta OIDC', + auth_oidc_ci_hint: + 'Upewnij się, że URL zwrotu autoryzacji jest ustawiony na https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Hasło klienta OIDC', + auth_oidc_custom_org_label: + 'Nazwa własnej organizacji OIDC (np. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Własna ikona OIDC (URL)', currency_settings: 'Ustawienia waluty', allowed_currencies: 'Dozwolone waluty', allowed_currencies_hint: 'Ogranicz liczbę dostępnych walut fiducjarnych', @@ -434,5 +448,48 @@ window.localisation.pl = { http_request_methods: 'Metody żądań HTTP', http_response_codes: 'Kody Odpowiedzi HTTP', request_details: 'Szczegóły żądania', - http_request_details: 'Szczegóły żądania HTTP' + http_request_details: 'Szczegóły żądania HTTP', + block_explorer: 'Przeglądarka bloków', + enable_block_explorer: 'Włącz przeglądarkę bloków', + block_explorer_desc: + 'Umożliwia użytkownikom przeglądanie transakcji i adresów Bitcoin przez Electrum.', + blockexplorer_public_api: 'Publiczny dostęp do API', + blockexplorer_public_api_desc: + 'Zezwól na nieuwierzytelniony dostęp do punktów końcowych API przeglądarki bloków.', + electrum_server_url: 'URL serwera Electrum', + electrum_server_url_hint: + 'np. ssl://electrum.blockstream.info:50002 lub tcp://localhost:50001', + blockexplorer_search_label: 'Szukaj po TXID lub adresie', + blockexplorer_search_hint: + '64-znakowy hex = transakcja · cokolwiek innego = adres Bitcoin', + recent_blocks: 'Ostatnie bloki', + chain_tip: 'Wierzchołek łańcucha', + block_height: 'Wysokość bloku', + block_fee: 'opłata bloku', + fee_estimates: 'Szacunki opłat', + confirmed_balance: 'Potwierdzony saldo', + unconfirmed_balance: 'Niepotwierdzony saldo', + transaction_history: 'Historia transakcji', + coinbase: 'Coinbase', + inputs: 'Wejścia', + outputs: 'Wyjścia', + confirmations: 'Potwierdzenia', + confirmed: 'Potwierdzone', + unconfirmed: 'Niepotwierdzone', + history_unavailable: + 'Historia transakcji niedostępna (adres ma zbyt wiele transakcji)', + address: 'Adres', + block_number: 'Blok #{height}', + block_diff: 'trud. {value}', + block_hash: 'Hash', + previous_block: 'Poprzedni blok', + merkle_root: 'Korzeń Merkle', + version: 'Wersja', + bits: 'Bity', + difficulty: 'Trudność', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Rozmiar wirtualny', + weight: 'Waga', + n_block_fee: 'opłata {n} bloków' } diff --git a/lnbits/static/i18n/pt.js b/lnbits/static/i18n/pt.js index f69f491bb..aa11d3993 100644 --- a/lnbits/static/i18n/pt.js +++ b/lnbits/static/i18n/pt.js @@ -72,6 +72,10 @@ window.localisation.pt = { view_swagger_docs: 'Ver a documentação da API do LNbits Swagger', api_docs: 'Documentação da API', api_keys_api_docs: 'URL do Nó, chaves de API e documentação de API', + api_keys_warning: + 'Estas chaves devem ser mantidas em segurança; partilhá-las pode resultar na perda de fundos.', + admin_key_warning: + 'A sua chave de administrador concede acesso total à sua carteira, incluindo a capacidade de enviar pagamentos. Nunca a partilhe, a menos que confie plenamente no destinatário.', lnbits_version: 'Versão do LNbits', runs_on: 'Executa em', paste: 'Colar', @@ -375,6 +379,16 @@ window.localisation.pt = { auth_keycloak_ci_hint: 'Certifique-se de que o URL de retorno de chamada de autorização esteja definido como https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Segredo do Cliente do Keycloak', + auth_keycloak_custom_org_label: 'Organização Personalizada do Keycloak', + auth_keycloak_custom_icon_label: 'Ícone Personalizado do Keycloak (URL)', + auth_oidc_label: 'URL de Descoberta do OIDC', + auth_oidc_ci_label: 'ID do Cliente do OIDC', + auth_oidc_ci_hint: + 'Certifique-se de que o URL de retorno de chamada de autorização esteja definido como https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Segredo do Cliente do OIDC', + auth_oidc_custom_org_label: + 'Nome da Organização Personalizada OIDC (ex. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Ícone Personalizado do OIDC (URL)', currency_settings: 'Configurações de Moeda', allowed_currencies: 'Moedas Permitidas', allowed_currencies_hint: 'Limite o número de moedas fiduciárias disponíveis', @@ -436,5 +450,48 @@ window.localisation.pt = { http_request_methods: 'Métodos de Requisição HTTP', http_response_codes: 'Códigos de Resposta HTTP', request_details: 'Detalhes da solicitação', - http_request_details: 'Detalhes da Solicitação HTTP' + http_request_details: 'Detalhes da Solicitação HTTP', + block_explorer: 'Block Explorer', + enable_block_explorer: 'Ativar Block Explorer', + block_explorer_desc: + 'Permite aos utilizadores explorar transações e endereços Bitcoin via Electrum.', + blockexplorer_public_api: 'Acesso à API pública', + blockexplorer_public_api_desc: + 'Permitir acesso não autenticado aos endpoints da API do explorador de blocos.', + electrum_server_url: 'URL do servidor Electrum', + electrum_server_url_hint: + 'ex. ssl://electrum.blockstream.info:50002 ou tcp://localhost:50001', + blockexplorer_search_label: 'Pesquisar por TXID ou endereço', + blockexplorer_search_hint: + 'Hex de 64 caracteres = transação · qualquer outra coisa = endereço Bitcoin', + recent_blocks: 'Blocos recentes', + chain_tip: 'Ponta da cadeia', + block_height: 'Altura do bloco', + block_fee: 'taxa de bloco', + fee_estimates: 'Estimativas de taxa', + confirmed_balance: 'Saldo confirmado', + unconfirmed_balance: 'Saldo não confirmado', + transaction_history: 'Histórico de transações', + coinbase: 'Coinbase', + inputs: 'Entradas', + outputs: 'Saídas', + confirmations: 'Confirmações', + confirmed: 'Confirmado', + unconfirmed: 'Não confirmado', + history_unavailable: + 'Histórico de transações indisponível (endereço tem demasiadas transações)', + address: 'Endereço', + block_number: 'Bloco #{height}', + block_diff: 'diff {value}', + block_hash: 'Hash', + previous_block: 'Bloco anterior', + merkle_root: 'Raiz de Merkle', + version: 'Versão', + bits: 'Bits', + difficulty: 'Dificuldade', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Tamanho virtual', + weight: 'Peso', + n_block_fee: 'taxa {n} blocos' } diff --git a/lnbits/static/i18n/sk.js b/lnbits/static/i18n/sk.js index 21326a04a..4809a3146 100644 --- a/lnbits/static/i18n/sk.js +++ b/lnbits/static/i18n/sk.js @@ -69,6 +69,10 @@ window.localisation.sk = { view_swagger_docs: 'Zobraziť LNbits Swagger API dokumentáciu', api_docs: 'API dokumentácia', api_keys_api_docs: 'Adresa uzla, API kľúče a API dokumentácia', + api_keys_warning: + 'Tieto kľúče uchovávajte v bezpečí, ich zdieľanie môže viesť k strate prostriedkov.', + admin_key_warning: + 'Váš administrátorský kľúč poskytuje úplný prístup k peňaženke vrátane možnosti odosielať platby. Nikdy ho nezdieľajte, pokiaľ príjemcovi úplne nedôverujete.', lnbits_version: 'Verzia LNbits', runs_on: 'Beží na', paste: 'Vložiť', @@ -371,6 +375,16 @@ window.localisation.sk = { auth_keycloak_ci_hint: 'Uistite sa, že URL spätného volania autorizácie je nastavená na https://{domain}/api/v1/auth/keycloak/token', auth_keycloak_cs_label: 'Tajný kľúč klienta Keycloak', + auth_keycloak_custom_org_label: 'Vlastná organizácia Keycloak', + auth_keycloak_custom_icon_label: 'Vlastná ikona Keycloak (URL)', + auth_oidc_label: 'URL zistenia OIDC', + auth_oidc_ci_label: 'ID klienta OIDC', + auth_oidc_ci_hint: + 'Uistite sa, že URL spätného volania autorizácie je nastavená na https://{domain}/api/v1/auth/oidc/token', + auth_oidc_cs_label: 'Tajný kľúč klienta OIDC', + auth_oidc_custom_org_label: + 'Názov vlastnej organizácie OIDC (napr. Zitadel, Authentik)', + auth_oidc_custom_icon_label: 'Vlastná ikona OIDC (URL)', currency_settings: 'Nastavenia meny', allowed_currencies: 'Povolené meny', allowed_currencies_hint: 'Obmedzte počet dostupných fiat mien', @@ -434,5 +448,48 @@ window.localisation.sk = { http_request_methods: 'Metódy HTTP žiadostí', http_response_codes: 'Kódy odpovedí HTTP', request_details: 'Podrobnosti žiadosti', - http_request_details: 'Podrobnosti požiadavky HTTP' + http_request_details: 'Podrobnosti požiadavky HTTP', + block_explorer: 'Prehliadač blokov', + enable_block_explorer: 'Povoliť prehliadač blokov', + block_explorer_desc: + 'Umožňuje používateľom prehliadať bitcoinové transakcie a adresy cez Electrum.', + blockexplorer_public_api: 'Verejný prístup k API', + blockexplorer_public_api_desc: + 'Povoliť neoverený prístup k API koncovým bodom prieskumníka blokov.', + electrum_server_url: 'URL Electrum servera', + electrum_server_url_hint: + 'napr. ssl://electrum.blockstream.info:50002 alebo tcp://localhost:50001', + blockexplorer_search_label: 'Hľadať podľa TXID alebo adresy', + blockexplorer_search_hint: + '64-znakový hex = transakcia · čokoľvek iné = bitcoinová adresa', + recent_blocks: 'Nedávne bloky', + chain_tip: 'Vrchol reťaze', + block_height: 'Výška bloku', + block_fee: 'poplatok bloku', + fee_estimates: 'Odhady poplatkov', + confirmed_balance: 'Potvrdený zostatok', + unconfirmed_balance: 'Nepotvrdený zostatok', + transaction_history: 'História transakcií', + coinbase: 'Coinbase', + inputs: 'Vstupy', + outputs: 'Výstupy', + confirmations: 'Potvrdenia', + confirmed: 'Potvrdené', + unconfirmed: 'Nepotvrdené', + history_unavailable: + 'História transakcií nedostupná (adresa má príliš veľa transakcií)', + address: 'Adresa', + block_number: 'Blok #{height}', + block_diff: 'obth. {value}', + block_hash: 'Hash', + previous_block: 'Predchádzajúci blok', + merkle_root: 'Merkle koreň', + version: 'Verzia', + bits: 'Bity', + difficulty: 'Obťažnosť', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Virtuálna veľkosť', + weight: 'Váha', + n_block_fee: 'poplatok {n} blokov' } diff --git a/lnbits/static/i18n/we.js b/lnbits/static/i18n/we.js index cf861cd52..75f1f7da6 100644 --- a/lnbits/static/i18n/we.js +++ b/lnbits/static/i18n/we.js @@ -72,6 +72,10 @@ window.localisation.we = { view_swagger_docs: 'Gweld dogfennau API LNbits Swagger', api_docs: 'Dogfennau API', api_keys_api_docs: 'URL y nod, allweddi API a dogfennau API', + api_keys_warning: + "Dylid cadw'r allweddi hyn yn ddiogel; gall eu rhannu arwain at golli arian.", + admin_key_warning: + "Mae eich allwedd weinyddol yn rhoi mynediad llawn i'ch waled, gan gynnwys y gallu i anfon taliadau. Peidiwch byth â'i rhannu oni bai eich bod yn ymddiried yn llwyr yn y derbynnydd.", lnbits_version: 'Fersiwn LNbits', runs_on: 'Yn rhedeg ymlaen', paste: 'Gludo', @@ -370,6 +374,16 @@ window.localisation.we = { auth_keycloak_ci_hint: "Gwnewch yn siŵr bod URL adalw awdurdodiad wedi'i osod i https://{domain}/api/v1/auth/keycloak/token", auth_keycloak_cs_label: 'Cyfrinach Cleient Keycloak', + auth_keycloak_custom_org_label: "Sefydliad Wedi'i Addasu Keycloak", + auth_keycloak_custom_icon_label: "Eicon Wedi'i Addasu Keycloak (URL)", + auth_oidc_label: 'URL Darganfod OIDC', + auth_oidc_ci_label: 'ID Cleient OIDC', + auth_oidc_ci_hint: + "Gwnewch yn siŵr bod URL adalw awdurdodiad wedi'i osod i https://{domain}/api/v1/auth/oidc/token", + auth_oidc_cs_label: 'Cyfrinach Cleient OIDC', + auth_oidc_custom_org_label: + "Enw Sefydliad Wedi'i Addasu OIDC (e.e. Zitadel, Authentik)", + auth_oidc_custom_icon_label: "Eicon Wedi'i Addasu OIDC (URL)", currency_settings: 'Gosodiadau Arian Cyfred', allowed_currencies: 'Ariannau a Ganiateir', allowed_currencies_hint: 'Cyfyngu nifer yr arian cyfred fiat sydd ar gael', @@ -432,5 +446,48 @@ window.localisation.we = { http_request_methods: 'Dulliau Cais HTTP', http_response_codes: 'Codau Ymateb HTTP', request_details: 'Manylion y Cais', - http_request_details: 'Manylion Cais HTTP' + http_request_details: 'Manylion Cais HTTP', + block_explorer: 'Archwiliwr Bloc', + enable_block_explorer: "Galluogi'r Archwiliwr Bloc", + block_explorer_desc: + 'Caniatáu i ddefnyddwyr archwilio trafodion a chyfeiriadau Bitcoin drwy Electrum.', + blockexplorer_public_api: 'Mynediad API Cyhoeddus', + blockexplorer_public_api_desc: + 'Caniatáu mynediad heb ddilysu i bwyntiau terfyn API yr archwiliwr bloc.', + electrum_server_url: 'URL Gweinydd Electrum', + electrum_server_url_hint: + 'e.e. ssl://electrum.blockstream.info:50002 neu tcp://localhost:50001', + blockexplorer_search_label: 'Chwilio yn ôl TXID neu Gyfeiriad', + blockexplorer_search_hint: + 'Hex 64 nod = trafodiad · unrhyw beth arall = cyfeiriad Bitcoin', + recent_blocks: 'Blociau Diweddar', + chain_tip: 'Blaen y Gadwyn', + block_height: 'Uchder Bloc', + block_fee: 'ffi bloc', + fee_estimates: 'Amcangyfrifon Ffi', + confirmed_balance: 'Balans Cadarnhawyd', + unconfirmed_balance: 'Balans Heb ei Gadarnhau', + transaction_history: 'Hanes Trafodion', + coinbase: 'Coinbase', + inputs: 'Mewnbynnau', + outputs: 'Allbynnau', + confirmations: 'Cadarnhadau', + confirmed: 'Cadarnhawyd', + unconfirmed: 'Heb ei Gadarnhau', + history_unavailable: + 'Hanes trafodion ar goll (mae cyfeiriad â gormod o drafodion)', + address: 'Cyfeiriad', + block_number: 'Bloc #{height}', + block_diff: 'anhawster {value}', + block_hash: 'Hash', + previous_block: 'Bloc Blaenorol', + merkle_root: 'Gwreiddyn Merkle', + version: 'Fersiwn', + bits: 'Bits', + difficulty: 'Anhawster', + nonce: 'Nonce', + txid: 'TXID', + vsize: 'Maint Rhithwir', + weight: 'Pwysau', + n_block_fee: 'ffi {n} bloc' } diff --git a/lnbits/static/images/authelia.png b/lnbits/static/images/authelia.png new file mode 100644 index 000000000..134afbb1c Binary files /dev/null and b/lnbits/static/images/authelia.png differ diff --git a/lnbits/static/images/authentik.png b/lnbits/static/images/authentik.png new file mode 100644 index 000000000..791d37039 Binary files /dev/null and b/lnbits/static/images/authentik.png differ diff --git a/lnbits/static/images/generic-oidc-logo.svg b/lnbits/static/images/generic-oidc-logo.svg new file mode 100644 index 000000000..abc3f0572 --- /dev/null +++ b/lnbits/static/images/generic-oidc-logo.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + ID + diff --git a/lnbits/static/images/okta.png b/lnbits/static/images/okta.png new file mode 100644 index 000000000..73e1b9b01 Binary files /dev/null and b/lnbits/static/images/okta.png differ diff --git a/lnbits/static/images/oktal.png b/lnbits/static/images/oktal.png new file mode 100644 index 000000000..666065483 Binary files /dev/null and b/lnbits/static/images/oktal.png differ diff --git a/lnbits/static/images/open-sats.png b/lnbits/static/images/open-sats.png deleted file mode 100644 index daa051c4f..000000000 Binary files a/lnbits/static/images/open-sats.png and /dev/null differ diff --git a/lnbits/static/images/zitadel.png b/lnbits/static/images/zitadel.png new file mode 100644 index 000000000..926f2a2b4 Binary files /dev/null and b/lnbits/static/images/zitadel.png differ diff --git a/lnbits/static/images/zitadell.png b/lnbits/static/images/zitadell.png new file mode 100644 index 000000000..f6fa8634d Binary files /dev/null and b/lnbits/static/images/zitadell.png differ diff --git a/lnbits/static/js/api.js b/lnbits/static/js/api.js index ba1936790..abc590801 100644 --- a/lnbits/static/js/api.js +++ b/lnbits/static/js/api.js @@ -175,6 +175,9 @@ window._lnbitsApi = { wallet.inkey ) }, + getPaymentTotalBreakdown(wallet) { + return this.request('get', '/api/v1/payments/stats/breakdown', wallet.inkey) + }, getPayment(wallet, paymentHash) { return this.request('get', '/api/v1/payments/' + paymentHash, wallet.inkey) }, @@ -193,5 +196,14 @@ window._lnbitsApi = { return LNbits.api .request('GET', `/admin/api/v1/settings/default?field_name=${fieldName}`) .catch(LNbits.utils.notifyApiError) + }, + getBlockexplorerAddress(address) { + return this.request('get', `/blockexplorer/api/v1/address/${address}`) + }, + getBlockexplorerTransaction(txid) { + return this.request('get', `/blockexplorer/api/v1/tx/${txid}`) + }, + getBlockexplorerUtxos(address) { + return this.request('get', `/blockexplorer/api/v1/utxos/${address}`) } } diff --git a/lnbits/static/js/base.js b/lnbits/static/js/base.js index b5677b91c..614a5f03f 100644 --- a/lnbits/static/js/base.js +++ b/lnbits/static/js/base.js @@ -47,6 +47,7 @@ window.LNbits = { adminkey: data.adminkey, inkey: data.inkey, currency: data.currency, + lightningAddress: data.lightning_address, extra: data.extra, canReceivePayments: true, canSendPayments: true @@ -59,6 +60,9 @@ window.LNbits = { newWallet.canSendPayments = perms.includes('send-payments') } newWallet.url = `/wallet?&wal=${data.id}` + newWallet.lightningAddressFull = newWallet.lightningAddress + ? `${newWallet.lightningAddress}@${window.location.host}` + : null newWallet.storedPaylinks = data.stored_paylinks.links return newWallet } diff --git a/lnbits/static/js/components.js b/lnbits/static/js/components.js index 69082e469..ea716bb31 100644 --- a/lnbits/static/js/components.js +++ b/lnbits/static/js/components.js @@ -442,7 +442,8 @@ window.app.component('username-password', { 'nostr-auth-nip98', 'google-auth', 'github-auth', - 'keycloak-auth' + 'keycloak-auth', + 'oidc-auth' ], username: this.userName, password: this.password_1, @@ -451,7 +452,9 @@ window.app.component('username-password', { confirmationMethod: 'code', confirmationEmail: '', confirmationCode: this.invitationCode || '', - showConfirmationCode: false + showConfirmationCode: false, + showPwd: false, + showPwdRepeat: false } }, methods: { @@ -691,12 +694,10 @@ window.app.component('lnbits-node-qrcode', {
- + :value="info.addresses[0]" + >
No addresses available
diff --git a/lnbits/static/js/components/admin/lnbits-admin-blockexplorer.js b/lnbits/static/js/components/admin/lnbits-admin-blockexplorer.js new file mode 100644 index 000000000..f92d3c388 --- /dev/null +++ b/lnbits/static/js/components/admin/lnbits-admin-blockexplorer.js @@ -0,0 +1,40 @@ +window.app.component('lnbits-admin-blockexplorer', { + props: ['form-data'], + template: '#lnbits-admin-blockexplorer', + data() { + return { + electrumServers: [ + 'ssl://fulcrum.lnbits.com:50002', + 'ssl://mainnet.nunchuk.io:52002', + 'ssl://fulcrum.grey.pw:50002', + 'ssl://electrum2.bluewallet.io:443', + 'ssl://electrum.acinq.co:50002', + 'ssl://electrum.blockstream.info:50002', + 'ssl://bitcoin.mullvad.net:5010' + ] + } + }, + computed: { + electrumServerOptions() { + return [...this.electrumServers, 'Custom'] + }, + electrumServerPreset: { + get() { + return this.electrumServers.includes( + this.formData.lnbits_blockexplorer_electrum_url + ) + ? this.formData.lnbits_blockexplorer_electrum_url + : 'Custom' + }, + set(value) { + if (value === 'Custom') { + if (this.electrumServerPreset !== 'Custom') { + this.formData.lnbits_blockexplorer_electrum_url = '' + } + return + } + this.formData.lnbits_blockexplorer_electrum_url = value + } + } + } +}) diff --git a/lnbits/static/js/components/admin/lnbits-admin-exchange-providers.js b/lnbits/static/js/components/admin/lnbits-admin-exchange-providers.js index 1be7a0f8d..e8b0f729c 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-exchange-providers.js +++ b/lnbits/static/js/components/admin/lnbits-admin-exchange-providers.js @@ -62,12 +62,6 @@ window.app.component('lnbits-admin-exchange-providers', { mounted() { this.getExchangeRateHistory() }, - created() { - const hash = window.location.hash.replace('#', '') - if (hash === 'exchange_providers') { - this.showExchangeProvidersTab(hash) - } - }, methods: { getDefaultSetting(fieldName) { LNbits.api.getDefaultSetting(fieldName).then(response => { @@ -127,18 +121,21 @@ window.app.component('lnbits-admin-exchange-providers', { this.exchangeData.showTickerConversion = true }, initExchangeChart(data) { + if (this.exchangeRatesChart) { + this.exchangeRatesChart.destroy() + this.exchangeRatesChart = null + } const xValues = data.map(d => this.utils.formatTimestamp(d.timestamp, 'HH:mm') ) - const exchanges = [ - ...this.formData.lnbits_exchange_rate_providers, - {name: 'LNbits'} - ] + const exchanges = this.formData.lnbits_price_aggregator_enabled + ? [{name: 'Aggregator'}] + : [...this.formData.lnbits_exchange_rate_providers, {name: 'LNbits'}] const datasets = exchanges.map(exchange => ({ label: exchange.name, data: data.map(d => d.rates[exchange.name]), pointStyle: true, - borderWidth: exchange.name === 'LNbits' ? 4 : 1, + borderWidth: exchange.name === 'LNbits' ? 4 : 2, tension: 0.4 })) this.exchangeRatesChart = new Chart( @@ -148,7 +145,11 @@ window.app.component('lnbits-admin-exchange-providers', { options: { plugins: { legend: { - display: false + display: true + }, + title: { + display: true, + text: 'Bitcoin Price History' } } }, diff --git a/lnbits/static/js/components/admin/lnbits-admin-extensions.js b/lnbits/static/js/components/admin/lnbits-admin-extensions.js index 9245c71b5..f70de66a5 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-extensions.js +++ b/lnbits/static/js/components/admin/lnbits-admin-extensions.js @@ -3,27 +3,44 @@ window.app.component('lnbits-admin-extensions', { template: '#lnbits-admin-extensions', data() { return { - formAddExtensionsManifest: '' + formAddExtensionsManifest: '', + formAddWasmManifest: '' } }, methods: { addExtensionsManifest() { - const addManifest = this.formAddExtensionsManifest.trim() - const manifests = this.formData.lnbits_extensions_manifests + this.addManifest( + 'lnbits_extensions_manifests', + 'formAddExtensionsManifest' + ) + }, + addWasmManifest() { + this.addManifest( + 'lnbits_wasm_extensions_manifests', + 'formAddWasmManifest' + ) + }, + addManifest(manifestField, inputField) { + const addManifest = this[inputField].trim() + const manifests = this.formData[manifestField] || [] if ( addManifest && addManifest.length && !manifests.includes(addManifest) ) { - this.formData.lnbits_extensions_manifests = [...manifests, addManifest] - this.formAddExtensionsManifest = '' + this.formData[manifestField] = [...manifests, addManifest] + this[inputField] = '' } }, removeExtensionsManifest(manifest) { - const manifests = this.formData.lnbits_extensions_manifests - this.formData.lnbits_extensions_manifests = manifests.filter( - m => m !== manifest - ) + this.removeManifest('lnbits_extensions_manifests', manifest) + }, + removeWasmManifest(manifest) { + this.removeManifest('lnbits_wasm_extensions_manifests', manifest) + }, + removeManifest(manifestField, manifest) { + const manifests = this.formData[manifestField] || [] + this.formData[manifestField] = manifests.filter(m => m !== manifest) } } }) diff --git a/lnbits/static/js/components/admin/lnbits-admin-fiat-providers.js b/lnbits/static/js/components/admin/lnbits-admin-fiat-providers.js index 8449752f4..ecf37ab73 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-fiat-providers.js +++ b/lnbits/static/js/components/admin/lnbits-admin-fiat-providers.js @@ -5,6 +5,9 @@ window.app.component('lnbits-admin-fiat-providers', { return { formAddStripeUser: '', formAddPaypalUser: '', + formAddSquareUser: '', + formAddRevolutUser: '', + creatingRevolutWebhook: false, hideInputToggle: true } }, @@ -20,6 +23,12 @@ window.app.component('lnbits-admin-fiat-providers', { this.formData?.paypal_payment_webhook_url || this.calculateWebhookUrl('paypal') ) + }, + revolutWebhookUrl() { + return ( + this.formData?.revolut_payment_webhook_url || + this.calculateWebhookUrl('revolut') + ) } }, watch: { @@ -58,6 +67,8 @@ window.app.component('lnbits-admin-fiat-providers', { syncWebhookUrls() { this.maybeSetWebhookUrl('stripe_payment_webhook_url', 'stripe') this.maybeSetWebhookUrl('paypal_payment_webhook_url', 'paypal') + this.maybeSetWebhookUrl('square_payment_webhook_url', 'square') + this.maybeSetWebhookUrl('revolut_payment_webhook_url', 'revolut') }, maybeSetWebhookUrl(fieldName, provider) { if (!this.formData) { @@ -77,6 +88,47 @@ window.app.component('lnbits-admin-fiat-providers', { } this.copyText(url) }, + isClearnetWebhookUrl(url) { + let parsedUrl + try { + parsedUrl = new URL(url) + } catch (e) { + return false + } + + const host = parsedUrl.hostname.toLowerCase() + if (!['http:', 'https:'].includes(parsedUrl.protocol)) { + return false + } + if ( + host === 'localhost' || + host.endsWith('.localhost') || + host.endsWith('.local') || + host.endsWith('.onion') + ) { + return false + } + if ( + /^127\./.test(host) || + /^10\./.test(host) || + /^192\.168\./.test(host) || + /^169\.254\./.test(host) || + /^172\.(1[6-9]|2\d|3[0-1])\./.test(host) || + host === '0.0.0.0' || + host === '::1' + ) { + return false + } + return true + }, + notifyRevolutWebhookWarning(message) { + Quasar.Notify.create({ + type: 'warning', + message, + icon: null, + closeBtn: true + }) + }, addStripeAllowedUser() { const addUser = this.formAddStripeUser || '' if ( @@ -111,6 +163,40 @@ window.app.component('lnbits-admin-fiat-providers', { this.formData.paypal_limits.allowed_users = this.formData.paypal_limits.allowed_users.filter(u => u !== user) }, + addSquareAllowedUser() { + const addUser = this.formAddSquareUser || '' + if ( + addUser.length && + !this.formData.square_limits.allowed_users.includes(addUser) + ) { + this.formData.square_limits.allowed_users = [ + ...this.formData.square_limits.allowed_users, + addUser + ] + this.formAddSquareUser = '' + } + }, + removeSquareAllowedUser(user) { + this.formData.square_limits.allowed_users = + this.formData.square_limits.allowed_users.filter(u => u !== user) + }, + addRevolutAllowedUser() { + const addUser = this.formAddRevolutUser || '' + if ( + addUser.length && + !this.formData.revolut_limits.allowed_users.includes(addUser) + ) { + this.formData.revolut_limits.allowed_users = [ + ...this.formData.revolut_limits.allowed_users, + addUser + ] + this.formAddRevolutUser = '' + } + }, + removeRevolutAllowedUser(user) { + this.formData.revolut_limits.allowed_users = + this.formData.revolut_limits.allowed_users.filter(u => u !== user) + }, checkFiatProvider(providerName) { LNbits.api .request('PUT', `/api/v1/fiat/check/${providerName}`) @@ -124,6 +210,48 @@ window.app.component('lnbits-admin-fiat-providers', { }) }) .catch(LNbits.utils.notifyApiError) + }, + createRevolutWebhook() { + const webhookUrl = this.calculateWebhookUrl('revolut') + this.formData.revolut_payment_webhook_url = webhookUrl + + if (!this.formData.revolut_api_secret_key) { + this.notifyRevolutWebhookWarning( + 'Add your Revolut API secret key before creating a webhook.' + ) + return + } + if (!this.isClearnetWebhookUrl(webhookUrl)) { + this.notifyRevolutWebhookWarning( + 'Revolut webhook URL must be a clearnet URL.' + ) + return + } + + this.creatingRevolutWebhook = true + LNbits.api + .request('POST', '/api/v1/fiat/revolut/webhook', null, { + url: webhookUrl, + endpoint: this.formData.revolut_api_endpoint, + api_secret_key: this.formData.revolut_api_secret_key, + api_version: this.formData.revolut_api_version + }) + .then(response => { + const data = response.data + this.formData.revolut_payment_webhook_url = data.url + this.formData.revolut_webhook_signing_secret = data.signing_secret + Quasar.Notify.create({ + type: 'positive', + message: `Revolut webhook ${ + data.already_exists ? 'already exists' : 'created' + }${data.id ? `: ${data.id}` : ''}.`, + icon: null + }) + }) + .catch(LNbits.utils.notifyApiError) + .finally(() => { + this.creatingRevolutWebhook = false + }) } } }) diff --git a/lnbits/static/js/components/admin/lnbits-admin-funding-seed-backup.js b/lnbits/static/js/components/admin/lnbits-admin-funding-seed-backup.js new file mode 100644 index 000000000..6c1102c4d --- /dev/null +++ b/lnbits/static/js/components/admin/lnbits-admin-funding-seed-backup.js @@ -0,0 +1,151 @@ +window.app.component('lnbits-admin-funding-seed-backup', { + props: ['active', 'is-super-user', 'form-data', 'settings'], + template: '#lnbits-admin-funding-seed-backup', + data() { + return { + dialog: { + show: false, + step: 1, + seed: '', + visible: false, + challenge: [], + answers: {}, + error: '', + confirmField: '' + } + } + }, + watch: { + active(isActive) { + if (isActive) { + this.openIfRequired() + } + }, + 'formData.lnbits_backend_wallet_class'(walletClass, previousWalletClass) { + const source = this.seedBackupSource(walletClass) + if (previousWalletClass && source && this.formData[source.seedField]) { + this.formData[source.confirmField] = false + } + this.openIfRequired() + }, + 'formData.boltz_mnemonic'() { + this.formData.boltz_mnemonic_backup_confirmed = + this.formData.boltz_mnemonic === this.settings.boltz_mnemonic + ? this.settings.boltz_mnemonic_backup_confirmed + : false + this.openIfRequired() + }, + 'formData.phoenixd_mnemonic'() { + this.formData.phoenixd_mnemonic_backup_confirmed = + this.formData.phoenixd_mnemonic === this.settings.phoenixd_mnemonic + ? this.settings.phoenixd_mnemonic_backup_confirmed + : false + this.openIfRequired() + }, + 'formData.spark_l2_mnemonic'() { + this.formData.spark_l2_mnemonic_backup_confirmed = + this.formData.spark_l2_mnemonic === this.settings.spark_l2_mnemonic + ? this.settings.spark_l2_mnemonic_backup_confirmed + : false + this.openIfRequired() + } + }, + computed: { + seedWords() { + return this.dialog.seed + .split(/\s+/) + .filter(Boolean) + .map((word, index) => ({index, word})) + } + }, + created() { + this.openIfRequired() + }, + methods: { + seedBackupSource(walletClass = this.formData.lnbits_backend_wallet_class) { + if (walletClass === 'BoltzWallet') { + return { + seedField: 'boltz_mnemonic', + confirmField: 'boltz_mnemonic_backup_confirmed' + } + } + if (walletClass === 'PhoenixdWallet') { + return { + seedField: 'phoenixd_mnemonic', + confirmField: 'phoenixd_mnemonic_backup_confirmed' + } + } + if (walletClass === 'SparkL2Wallet') { + return { + seedField: 'spark_l2_mnemonic', + confirmField: 'spark_l2_mnemonic_backup_confirmed' + } + } + }, + openIfRequired() { + if (!this.active || !this.isSuperUser) return + + const source = this.seedBackupSource() + if (!source) return + + const seed = (this.formData[source.seedField] || '').trim() + const confirmed = this.formData[source.confirmField] + if (!seed || confirmed || this.dialog.show) return + + this.dialog = { + show: true, + step: 1, + seed, + visible: false, + challenge: [], + answers: {}, + error: '', + confirmField: source.confirmField + } + }, + prepareChallenge() { + const words = this.dialog.seed.split(/\s+/).filter(Boolean) + const count = Math.min(4, words.length) + const indexes = _.shuffle([...Array(words.length).keys()]).slice(0, count) + this.dialog.challenge = indexes + .sort((a, b) => a - b) + .map(index => ({index, word: words[index]})) + this.dialog.answers = {} + this.dialog.error = '' + this.dialog.step = 2 + }, + submitChallenge() { + const isValid = this.dialog.challenge.every(({index, word}) => { + const answer = this.dialog.answers[index] || '' + return answer.trim().toLowerCase() === word.toLowerCase() + }) + if (!isValid) { + this.dialog.error = + 'One or more words are incorrect. Check your backup and try again.' + return + } + + const field = this.dialog.confirmField + LNbits.api + .request( + 'PATCH', + '/admin/api/v1/settings', + this.g.user.wallets[0].adminkey, + { + [field]: true + } + ) + .then(() => { + this.formData[field] = true + this.settings[field] = true + this.dialog.show = false + Quasar.Notify.create({ + type: 'positive', + message: 'Seed backup confirmed', + icon: 'check' + }) + }) + .catch(LNbits.utils.notifyApiError) + } + } +}) diff --git a/lnbits/static/js/components/admin/lnbits-admin-funding-sources.js b/lnbits/static/js/components/admin/lnbits-admin-funding-sources.js index 1cd98ff81..9a97f596b 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-funding-sources.js +++ b/lnbits/static/js/components/admin/lnbits-admin-funding-sources.js @@ -108,7 +108,11 @@ window.app.component('lnbits-admin-funding-sources', { lnd_grpc_macaroon: 'GRPC Macaroon', lnd_grpc_invoice_macaroon: 'GRPC Invoice Macaroon', lnd_grpc_admin_macaroon: 'GRPC Admin Macaroon', - lnd_grpc_macaroon_encrypted: 'Encrypted Macaroon' + lnd_grpc_macaroon_encrypted: 'Encrypted Macaroon', + lnd_grpc_allow_self_payment: { + advanced: true, + label: 'Allow Self Payment' + } } ], [ @@ -150,7 +154,12 @@ window.app.component('lnbits-admin-funding-sources', { { blink_api_endpoint: 'Endpoint', blink_ws_endpoint: 'WebSocket', - blink_token: 'Key' + blink_token: 'Key', + blink_send_without_probe: { + advanced: true, + label: 'Send payment if fee probe fails', + hint: 'If enabled (default), payments to destinations that cannot be probed (e.g. fedimints) are still sent. If disabled, such payments fail.' + } } ], [ @@ -161,6 +170,17 @@ window.app.component('lnbits-admin-funding-sources', { alby_access_token: 'Key' } ], + [ + 'BarkWallet', + 'Bark', + { + bark_api_endpoint: { + label: 'Endpoint', + value: 'http://localhost:3000' + }, + bark_api_token: 'auth_token' + } + ], [ 'BoltzWallet', 'Boltz', @@ -202,7 +222,18 @@ window.app.component('lnbits-admin-funding-sources', { 'Phoenixd', { phoenixd_api_endpoint: 'Endpoint', - phoenixd_api_password: 'Key' + phoenixd_api_password: 'Key', + phoenixd_data_dir: { + label: 'Data Directory', + hint: 'Directory where phoenixd stores its data, including the seed phrase.' + }, + phoenixd_mnemonic: { + label: 'Phoenixd Seed Phrase', + hint: 'Only available if phoenixd data-dir is specified', + readonly: true, + copy: true, + qrcode: true + } } ], [ diff --git a/lnbits/static/js/components/admin/lnbits-admin-funding.js b/lnbits/static/js/components/admin/lnbits-admin-funding.js index 6710a8dd4..1474490d5 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-funding.js +++ b/lnbits/static/js/components/admin/lnbits-admin-funding.js @@ -1,5 +1,5 @@ window.app.component('lnbits-admin-funding', { - props: ['is-super-user', 'form-data', 'settings'], + props: ['active', 'is-super-user', 'form-data', 'settings'], template: '#lnbits-admin-funding', data() { return { diff --git a/lnbits/static/js/components/admin/lnbits-admin-server.js b/lnbits/static/js/components/admin/lnbits-admin-server.js index 552f5e142..1da53e79c 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-server.js +++ b/lnbits/static/js/components/admin/lnbits-admin-server.js @@ -1,4 +1,18 @@ window.app.component('lnbits-admin-server', { props: ['form-data'], - template: '#lnbits-admin-server' + template: '#lnbits-admin-server', + computed: { + lightningAddressBlacklistText: { + get() { + const value = this.formData.lnbits_wallet_lightning_address_blacklist + return Array.isArray(value) ? value.join('\n') : value || '' + }, + set(value) { + this.formData.lnbits_wallet_lightning_address_blacklist = value + .split(/[\n,]/) + .map(word => word.trim().toLowerCase()) + .filter(word => word.length) + } + } + } }) diff --git a/lnbits/static/js/components/admin/lnbits-admin-site-customisation.js b/lnbits/static/js/components/admin/lnbits-admin-site-customisation.js index 799d7cf9e..f63e9958a 100644 --- a/lnbits/static/js/components/admin/lnbits-admin-site-customisation.js +++ b/lnbits/static/js/components/admin/lnbits-admin-site-customisation.js @@ -31,7 +31,8 @@ window.app.component('lnbits-admin-site-customisation', { 'confettiBothSides', 'confettiFireworks', 'confettiStars', - 'confettiTop' + 'confettiTop', + 'lightningStrike' ], globalBorderOptions: [ 'retro-border', @@ -41,5 +42,37 @@ window.app.component('lnbits-admin-site-customisation', { ] } }, - methods: {} + methods: { + onBackgroundImageInput(e) { + const file = e.target.files[0] + if (file) { + this.uploadBackgroundImage(file) + } + e.target.value = null + }, + async uploadBackgroundImage(file) { + const formData = new FormData() + formData.append('file', file) + try { + const {data} = await LNbits.api.request( + 'POST', + '/api/v1/assets?public_asset=true', + null, + formData, + { + headers: {'Content-Type': 'multipart/form-data'} + } + ) + const assetUrl = `${window.location.origin}/api/v1/assets/${data.id}/thumbnail` + this.formData.lnbits_default_bgimage = assetUrl + Quasar.Notify.create({ + type: 'positive', + message: 'Background image uploaded.', + icon: null + }) + } catch (e) { + LNbits.utils.notifyApiError(e) + } + } + } }) diff --git a/lnbits/static/js/components/admin/lnbits-admin-wasm-limit-config.js b/lnbits/static/js/components/admin/lnbits-admin-wasm-limit-config.js new file mode 100644 index 000000000..9dd6e6452 --- /dev/null +++ b/lnbits/static/js/components/admin/lnbits-admin-wasm-limit-config.js @@ -0,0 +1,380 @@ +window.app.component('lnbits-admin-wasm-limit-config', { + props: ['form-data'], + template: '#lnbits-admin-wasm-limit-config', + data() { + return { + selectedWasmExtensionId: null, + wasmExtensionLimitDraft: {}, + wasmExtensionLimitsSaving: false, + wasmRuntimeLimitExtensions: [], + wasmRuntimeLimitExtensionsLoading: false, + wasmLimitInfoDialog: { + show: false, + title: '', + details: '' + }, + wasmRuntimeLimitGroups: [ + { + title: 'Execution', + fields: [ + { + name: 'wasm_runtime_max_execution_ms', + label: 'Max execution time (ms)', + description: + 'Maximum wall-clock time allowed for one WASM invocation.', + details: + 'This is the elapsed time from starting the invocation until the export returns. When the limit is reached LNbits requests an interrupt and records the invocation as timed out if it cannot finish quickly. Use this to stop long sleeps, slow host calls, and CPU loops that run for too long.' + }, + { + name: 'wasm_runtime_max_fuel', + label: 'Max fuel', + description: + 'Maximum Wasmtime instruction budget for one invocation.', + details: + 'Fuel is Wasmtime instruction budgeting. It is more deterministic than wall-clock time for CPU-heavy loops because each executed instruction consumes budget. Set this low enough to stop busy loops, but high enough for legitimate extension startup and JSON processing.' + }, + { + name: 'wasm_runtime_max_wasm_stack_bytes', + label: 'Max WASM stack (bytes)', + description: 'Maximum stack space for WASM calls and recursion.', + details: + 'This limits stack used by WebAssembly function calls. It protects the server from deep recursion or very large call chains in extension code. If legitimate extensions fail with stack overflow traps, raise this carefully.' + } + ] + }, + { + title: 'Memory and Data Size', + fields: [ + { + name: 'wasm_runtime_max_memory_bytes', + label: 'Max memory (bytes)', + description: 'Maximum WASM linear memory per invocation.', + details: + 'This caps the linear memory visible to the WASM module. It limits memory.grow and can make instantiation fail if the module asks for too much memory up front. This does not include every byte used by the Python process or Wasmtime engine internals.' + }, + { + name: 'wasm_runtime_max_request_bytes', + label: 'Max request size (bytes)', + description: + 'Maximum serialized input payload accepted before execution.', + details: + 'This caps the serialized payload passed into a WASM export before execution starts. It protects against huge HTTP bodies, oversized event data, and expensive JSON parsing. Requests above this limit should be rejected before invoking the extension.' + }, + { + name: 'wasm_runtime_max_response_bytes', + label: 'Max response size (bytes)', + description: + 'Maximum serialized response returned by a WASM export.', + details: + 'This caps the JSON or string response returned by the WASM export. It prevents extensions from returning huge responses that consume memory, slow down API calls, or overload the browser. Responses above this limit are treated as invalid.' + } + ] + }, + { + title: 'Wasmtime Objects', + fields: [ + { + name: 'wasm_runtime_max_table_elements', + label: 'Max table elements', + description: 'Maximum total elements allowed in WASM tables.', + details: + 'Tables store references used by WebAssembly, commonly function references. Limiting table elements prevents a module from allocating very large reference tables. Each table element also has host memory overhead.' + }, + { + name: 'wasm_runtime_max_instances', + label: 'Max instances', + description: + 'Maximum WebAssembly instances allowed inside one store.', + details: + 'This limits how many WebAssembly instances can be created inside one Wasmtime store. LNbits normally needs one instance per invocation, so a low value is expected. Raising it should only be needed if the runtime starts supporting modules that instantiate other modules.' + }, + { + name: 'wasm_runtime_max_tables', + label: 'Max tables', + description: + 'Maximum WebAssembly tables allowed inside one store.', + details: + 'This limits the number of WebAssembly tables in the store. It is separate from table elements: one setting limits the number of tables, the other limits their total size. Keep this small unless a component model module legitimately needs more tables.' + }, + { + name: 'wasm_runtime_max_memories', + label: 'Max memories', + description: + 'Maximum WebAssembly linear memories allowed inside one store.', + details: + 'This limits how many separate linear memories a module can create. Most extensions should need only one memory. Keep this small to reduce memory accounting complexity and prevent multi-memory abuse.' + } + ] + }, + { + title: 'Concurrency', + fields: [ + { + name: 'wasm_runtime_max_concurrent_invocations', + label: 'Max concurrent invocations', + description: + 'Maximum running WASM invocations across the server.', + details: + 'This is the global cap for running WASM invocations across all extensions and users. It protects the LNbits process from thread exhaustion, CPU pressure, and too many simultaneous stores. New invocations should be rejected or queued once this is reached.' + }, + { + name: 'wasm_runtime_max_concurrent_invocations_per_extension', + label: 'Max concurrent per extension', + description: + 'Maximum running WASM invocations for one extension.', + details: + 'This caps how many invocations a single extension can run at once. It prevents one malicious or buggy extension from consuming the whole global concurrency budget. Set it lower than the global limit.' + }, + { + name: 'wasm_runtime_max_concurrent_invocations_per_user', + label: 'Max concurrent per user', + description: 'Maximum running WASM invocations for one user.', + details: + 'This caps concurrent invocations attributed to one user. It helps protect against a user repeatedly clicking, refreshing, or scripting extension calls. Invocations without a user can still be governed by the global and per-extension limits.' + } + ] + }, + { + title: 'Host Calls', + fields: [ + { + name: 'wasm_runtime_max_host_calls', + label: 'Max host calls', + description: + 'Maximum total calls from WASM into LNbits host APIs.', + details: + 'This is the total budget for calls from the WASM module into LNbits host APIs during one invocation. It should count all categories together. It limits chatty extensions and prevents tight loops that repeatedly call back into Python.' + }, + { + name: 'wasm_runtime_max_http_calls', + label: 'Max HTTP calls', + description: 'Maximum outbound HTTP host calls per invocation.', + details: + 'This caps outbound HTTP requests made through the host API during one invocation. It reduces SSRF blast radius, protects network resources, and limits slow external dependencies. It should be enforced together with HTTP timeout and response-size limits.' + }, + { + name: 'wasm_runtime_max_storage_calls', + label: 'Max storage calls', + description: 'Maximum storage host calls per invocation.', + details: + 'This caps extension storage operations during one invocation. It protects the database from excessive reads and writes triggered by malicious loops. Use it with storage payload-size limits if those are added later.' + }, + { + name: 'wasm_runtime_max_wallet_calls', + label: 'Max wallet calls', + description: 'Maximum wallet/payment host calls per invocation.', + details: + 'This caps wallet and payment-related host calls during one invocation. These calls are security-sensitive and may touch balances, invoices, or payments. Keep this conservative and rely on explicit permissions for what the extension is allowed to do.' + } + ] + }, + { + title: 'HTTP', + fields: [ + { + name: 'wasm_runtime_http_timeout_ms', + label: 'HTTP timeout (ms)', + description: 'Maximum time allowed for one WASM HTTP request.', + details: + 'This is the per-request timeout for HTTP calls made through the WASM host API. It prevents a slow remote server from holding an invocation open indefinitely. The total invocation timeout still applies across all work.' + }, + { + name: 'wasm_runtime_max_http_response_bytes', + label: 'Max HTTP response size (bytes)', + description: + 'Maximum response body size accepted from one WASM HTTP request.', + details: + 'This caps the response body accepted from each HTTP call made by an extension. It protects memory and parsing time when a remote server returns a very large body. Responses above the limit should fail the host call.' + } + ] + } + ] + } + }, + computed: { + adminKey() { + return this.g.user.wallets[0].adminkey + }, + isExtensionLimitRoute() { + return this.$route.path.startsWith('/admin/extensions/wasm/limits/') + }, + routeWasmExtensionId() { + return this.isExtensionLimitRoute ? this.$route.params.extId : null + }, + backRoute() { + return this.isExtensionLimitRoute + ? '/admin/extensions/wasm/limits' + : '/admin#extensions' + }, + backTooltip() { + return this.isExtensionLimitRoute + ? 'Wasm Limit Config' + : 'Extensions Settings' + }, + pageDescription() { + if (this.isExtensionLimitRoute) { + return 'Customize limits for one installed WASM extension.' + } + return 'These values are global defaults. Use 0 to disable a global limit.' + }, + wasmRuntimeLimitExtensionOptions() { + return this.wasmRuntimeLimitExtensions.map(extension => ({ + label: `${extension.name || extension.id} (${extension.id})`, + value: extension.id + })) + }, + selectedWasmRuntimeLimitExtension() { + return ( + this.wasmRuntimeLimitExtensions.find( + extension => extension.id === this.selectedWasmExtensionId + ) || null + ) + }, + customWasmLimitCount() { + const extension = this.selectedWasmRuntimeLimitExtension + if (!extension || !extension.wasm_runtime_limits) { + return 0 + } + return Object.keys(extension.wasm_runtime_limits).length + } + }, + watch: { + selectedWasmExtensionId() { + this.loadSelectedWasmRuntimeLimitExtension() + }, + routeWasmExtensionId() { + this.syncWasmExtensionLimitRoute() + } + }, + created() { + this.fetchWasmRuntimeLimitExtensions() + }, + methods: { + async fetchWasmRuntimeLimitExtensions() { + this.wasmRuntimeLimitExtensionsLoading = true + try { + const {data} = await LNbits.api.request( + 'GET', + '/api/v1/extension/wasm/runtime-limits/extensions', + this.adminKey + ) + this.wasmRuntimeLimitExtensions = data || [] + if ( + this.selectedWasmExtensionId && + !this.wasmRuntimeLimitExtensions.some( + extension => extension.id === this.selectedWasmExtensionId + ) + ) { + this.selectedWasmExtensionId = null + } + this.syncWasmExtensionLimitRoute() + } catch (error) { + LNbits.utils.notifyApiError(error) + } finally { + this.wasmRuntimeLimitExtensionsLoading = false + } + }, + syncWasmExtensionLimitRoute() { + this.selectedWasmExtensionId = this.routeWasmExtensionId + this.loadSelectedWasmRuntimeLimitExtension() + }, + openWasmExtensionLimit(extensionId) { + this.$router.push( + `/admin/extensions/wasm/limits/${encodeURIComponent(extensionId)}` + ) + }, + loadSelectedWasmRuntimeLimitExtension() { + const extension = this.selectedWasmRuntimeLimitExtension + this.wasmExtensionLimitDraft = extension + ? {...(extension.wasm_runtime_limits || {})} + : {} + }, + wasmExtensionLimitHint(field) { + const globalValue = this.formData[field.name] + return `Inherited global value: ${globalValue}. ${field.description}` + }, + wasmExtensionLimitPlaceholder(field) { + const globalValue = this.formData[field.name] + return globalValue === undefined || globalValue === null + ? '' + : String(globalValue) + }, + normalizedWasmExtensionLimitDraft() { + const limits = {} + this.wasmRuntimeLimitGroups.forEach(group => { + group.fields.forEach(field => { + const value = this.wasmExtensionLimitDraft[field.name] + const cleanValue = typeof value === 'string' ? value.trim() : value + if ( + cleanValue === '' || + cleanValue === null || + cleanValue === undefined + ) { + return + } + const numericValue = Number(cleanValue) + if ( + !Number.isFinite(numericValue) || + !Number.isInteger(numericValue) || + numericValue < 0 + ) { + throw new Error(`${field.label} must be a non-negative integer.`) + } + limits[field.name] = numericValue + }) + }) + return limits + }, + async clearWasmExtensionLimits() { + this.wasmExtensionLimitDraft = {} + await this.saveWasmExtensionLimits() + }, + async saveWasmExtensionLimits() { + if (!this.selectedWasmExtensionId) { + return + } + this.wasmExtensionLimitsSaving = true + try { + const {data} = await LNbits.api.request( + 'PUT', + `/api/v1/extension/wasm/runtime-limits/${encodeURIComponent( + this.selectedWasmExtensionId + )}`, + this.adminKey, + { + limits: this.normalizedWasmExtensionLimitDraft() + } + ) + const index = this.wasmRuntimeLimitExtensions.findIndex( + extension => extension.id === data.id + ) + if (index >= 0) { + this.wasmRuntimeLimitExtensions.splice(index, 1, data) + } + this.loadSelectedWasmRuntimeLimitExtension() + Quasar.Notify.create({ + type: 'positive', + message: 'WASM extension limits saved.' + }) + } catch (error) { + if (error instanceof Error && !error.response) { + Quasar.Notify.create({ + type: 'negative', + message: error.message + }) + } else { + LNbits.utils.notifyApiError(error) + } + } finally { + this.wasmExtensionLimitsSaving = false + } + }, + showWasmLimitInfo(field) { + this.wasmLimitInfoDialog = { + show: true, + title: field.label, + details: field.details + } + } + } +}) diff --git a/lnbits/static/js/components/admin/lnbits-admin-wasm-runtime.js b/lnbits/static/js/components/admin/lnbits-admin-wasm-runtime.js new file mode 100644 index 000000000..9700be4cb --- /dev/null +++ b/lnbits/static/js/components/admin/lnbits-admin-wasm-runtime.js @@ -0,0 +1,380 @@ +window.app.component('lnbits-admin-wasm-runtime', { + props: ['form-data'], + template: '#lnbits-admin-wasm-runtime', + data() { + return { + wasmRuntimeLoading: false, + wasmHistoryLoading: false, + wasmRuntimeTimer: null, + wasmStats: {}, + wasmCurrentInvocations: [], + wasmInvocationHistory: [], + wasmStatItems: [ + {key: 'total', label: 'Total', icon: 'data_usage', color: 'primary'}, + {key: 'running', label: 'Running', icon: 'play_circle', color: 'green'}, + {key: 'completed', label: 'Completed', icon: 'task_alt', color: 'teal'}, + {key: 'failed', label: 'Failed', icon: 'error', color: 'red'}, + { + key: 'stopped', + label: 'Stopped', + icon: 'stop_circle', + color: 'orange' + }, + {key: 'timeout', label: 'Timeouts', icon: 'timer_off', color: 'purple'} + ], + wasmCurrentColumns: [ + { + name: 'extension_id', + label: 'Extension', + field: 'extension_id', + align: 'left', + sortable: true + }, + { + name: 'export_name', + label: 'Export', + field: 'export_name', + align: 'left', + sortable: true + }, + { + name: 'trigger_type', + label: 'Trigger', + field: 'trigger_type', + align: 'left', + sortable: true + }, + { + name: 'status', + label: 'Status', + field: 'status', + align: 'left', + sortable: true + }, + { + name: 'user_id', + label: 'User', + field: 'user_id', + align: 'left', + sortable: true + }, + { + name: 'started_at', + label: 'Started', + field: 'started_at', + align: 'left', + sortable: true + }, + { + name: 'duration_ms', + label: 'Duration', + field: row => row.duration_ms || 0, + align: 'right', + sortable: true + }, + { + name: 'context', + label: 'Context', + field: row => this.wasmContextValue(row), + align: 'left', + sortable: true + }, + {name: 'actions', label: '', field: 'actions', align: 'right'} + ], + wasmHistoryColumns: [ + { + name: 'extension_id', + label: 'Extension', + field: 'extension_id', + align: 'left', + sortable: true + }, + { + name: 'export_name', + label: 'Export', + field: 'export_name', + align: 'left', + sortable: true + }, + { + name: 'trigger_type', + label: 'Trigger', + field: 'trigger_type', + align: 'left', + sortable: true + }, + { + name: 'status', + label: 'Status', + field: 'status', + align: 'left', + sortable: true + }, + { + name: 'user_id', + label: 'User', + field: 'user_id', + align: 'left', + sortable: true + }, + { + name: 'started_at', + label: 'Started', + field: 'started_at', + align: 'left', + sortable: true + }, + { + name: 'duration_ms', + label: 'Duration', + field: row => row.duration_ms || 0, + align: 'right', + sortable: true + }, + { + name: 'calls', + label: 'Calls', + field: row => this.wasmCallCount(row), + align: 'left', + sortable: true + }, + { + name: 'context', + label: 'Context', + field: row => this.wasmContextValue(row), + align: 'left', + sortable: true + }, + { + name: 'error_message', + label: 'Error/Stop Reason', + field: row => row.error_message || row.stop_reason || '', + align: 'left', + sortable: true + } + ] + } + }, + computed: { + adminKey() { + return this.g.user.wallets[0].adminkey + }, + wasmExtensionId() { + return this.$route.params.extId || null + }, + wasmExtensionQuery() { + if (!this.wasmExtensionId) { + return '' + } + return `extension_id=${encodeURIComponent(this.wasmExtensionId)}` + } + }, + watch: { + wasmExtensionId() { + this.fetchWasmRuntime() + } + }, + methods: { + async fetchWasmRuntime() { + await Promise.all([ + this.fetchWasmCurrentInvocations(), + this.fetchWasmInvocationHistory(), + this.fetchWasmInvocationStats() + ]) + }, + async fetchWasmCurrentInvocations() { + this.wasmRuntimeLoading = true + try { + const query = this.wasmExtensionQuery + ? `?${this.wasmExtensionQuery}` + : '' + const {data} = await LNbits.api.request( + 'GET', + `/api/v1/extension/wasm/invocations/current${query}`, + this.adminKey + ) + this.wasmCurrentInvocations = data || [] + } catch (error) { + LNbits.utils.notifyApiError(error) + } finally { + this.wasmRuntimeLoading = false + } + }, + async fetchWasmInvocationHistory() { + this.wasmHistoryLoading = true + try { + const params = ['limit=50'] + if (this.wasmExtensionQuery) { + params.push(this.wasmExtensionQuery) + } + const {data} = await LNbits.api.request( + 'GET', + `/api/v1/extension/wasm/invocations?${params.join('&')}`, + this.adminKey + ) + this.wasmInvocationHistory = data || [] + } catch (error) { + LNbits.utils.notifyApiError(error) + } finally { + this.wasmHistoryLoading = false + } + }, + async fetchWasmInvocationStats() { + try { + const params = ['hours=24'] + if (this.wasmExtensionQuery) { + params.push(this.wasmExtensionQuery) + } + const {data} = await LNbits.api.request( + 'GET', + `/api/v1/extension/wasm/invocations/stats?${params.join('&')}`, + this.adminKey + ) + this.wasmStats = data || {} + } catch (error) { + LNbits.utils.notifyApiError(error) + } + }, + async stopWasmInvocation(invocationId) { + try { + await LNbits.api.request( + 'POST', + `/api/v1/extension/wasm/invocations/${encodeURIComponent(invocationId)}/stop`, + this.adminKey + ) + Quasar.Notify.create({ + type: 'positive', + message: 'WASM invocation stop requested.' + }) + await this.fetchWasmRuntime() + } catch (error) { + LNbits.utils.notifyApiError(error) + } + }, + deactivateWasmExtension(extensionId) { + LNbits.utils + .confirmDialog( + `Deactivate extension '${extensionId}'?`, + 'Deactivate Extension' + ) + .onOk(async () => { + try { + await LNbits.api.request( + 'PUT', + `/api/v1/extension/${encodeURIComponent(extensionId)}/deactivate`, + this.adminKey + ) + Quasar.Notify.create({ + type: 'positive', + message: `Extension '${extensionId}' deactivated.` + }) + await this.fetchWasmRuntime() + } catch (error) { + LNbits.utils.notifyApiError(error) + } + }) + }, + formatWasmStat(key) { + const value = this.wasmStats[key] + return value === undefined || value === null ? '0' : String(value) + }, + formatWasmDate(value) { + return value ? this.utils.formatDate(value) : '' + }, + wasmStatusColor(status) { + return ( + { + running: 'green', + stopping: 'orange', + completed: 'teal', + failed: 'red', + stopped: 'orange', + timeout: 'purple', + abandoned: 'grey' + }[status] || 'grey' + ) + }, + wasmTriggerColor(triggerType) { + return ( + { + http: 'primary', + event: 'purple' + }[triggerType] || 'grey' + ) + }, + formatWasmDuration(row) { + let duration = row.duration_ms + if ( + (row.status === 'running' || row.status === 'stopping') && + row.started_at + ) { + duration = Date.now() - new Date(row.started_at).getTime() + } + if (duration === undefined || duration === null) { + return '' + } + if (duration >= 1000) { + return `${(duration / 1000).toFixed(1)}s` + } + return `${duration}ms` + }, + formatWasmCalls(row) { + return [ + `host ${row.host_call_count || 0}`, + `http ${row.http_call_count || 0}`, + `storage ${row.storage_call_count || 0}`, + `wallet ${row.wallet_call_count || 0}` + ].join(' / ') + }, + wasmCallCount(row) { + return ( + (row.host_call_count || 0) + + (row.http_call_count || 0) + + (row.storage_call_count || 0) + + (row.wallet_call_count || 0) + ) + }, + wasmContextValue(row) { + return [ + row.method, + row.path, + row.event_type, + row.wallet_id, + row.payment_hash + ] + .filter(Boolean) + .join(' ') + }, + formatWasmContext(row) { + const items = [ + row.method, + row.path, + row.event_type, + row.wallet_id ? `wallet ${row.wallet_id}` : '', + row.payment_hash ? `payment ${row.payment_hash.slice(0, 12)}...` : '' + ].filter(Boolean) + return items.join(' | ') + }, + formatWasmUserId(userId) { + if (!userId) { + return '-' + } + const value = String(userId) + if (value.length <= 12) { + return value + } + return `${value.slice(0, 3)}...${value.slice(-3)}` + } + }, + created() { + this.fetchWasmRuntime() + this.wasmRuntimeTimer = setInterval(() => { + this.fetchWasmCurrentInvocations() + }, 5000) + }, + unmounted() { + if (this.wasmRuntimeTimer) { + clearInterval(this.wasmRuntimeTimer) + } + } +}) diff --git a/lnbits/static/js/components/lnbits-extension-permissions.js b/lnbits/static/js/components/lnbits-extension-permissions.js new file mode 100644 index 000000000..1556a70a1 --- /dev/null +++ b/lnbits/static/js/components/lnbits-extension-permissions.js @@ -0,0 +1,474 @@ +;(function () { + function translate(translateFn, key) { + return translateFn ? translateFn(key) : key + } + + function permissionI18nKey(permission) { + return `extension_permission_${permission.id.replace(/[^A-Za-z0-9]/g, '_')}` + } + + function permissionLabel(permission, translateFn) { + const key = permissionI18nKey(permission) + const label = translate(translateFn, key) + return label === key ? permission.id : label + } + + function permissionManifestDescription(permission) { + return typeof permission.description === 'string' + ? permission.description + : '' + } + + function lowRisk(translateFn) { + return { + level: 'low', + color: 'grey-6', + label: translate(translateFn, 'extension_permission_risk_low'), + warning: '' + } + } + + function mediumRisk(translateFn, warningKey) { + return { + level: 'medium', + color: 'warning', + label: translate(translateFn, 'extension_permission_risk_medium'), + warning: warningKey ? translate(translateFn, warningKey) : '' + } + } + + function highRisk(translateFn, warningKey) { + return { + level: 'high', + color: 'negative', + label: translate(translateFn, 'extension_permission_risk_high'), + warning: translate(translateFn, warningKey) + } + } + + function extensionDisplayName(extensions, extensionId) { + const extension = (extensions || []).find( + extension => extension.id === extensionId + ) + return extension?.name || extensionId + } + + function extensionApiPermissionTargets(permission, extensions) { + const extensionPolicies = permission.policies + if (!Array.isArray(extensionPolicies)) return [] + return extensionPolicies + .map(extension => { + const extensionId = + typeof extension === 'string' ? extension : extension?.id + if (!extensionId) return null + const access = + typeof extension === 'string' + ? ['read'] + : Array.isArray(extension.access) && extension.access.length + ? extension.access + : ['read'] + return { + id: extensionId, + name: extensionDisplayName(extensions, extensionId), + access + } + }) + .filter(Boolean) + } + + function permissionRiskForPermission(permission, extensions, translateFn) { + if ( + ['wallet.pay_invoice', 'wallet.pay_invoice_background'].includes( + permission.id + ) + ) { + return highRisk( + translateFn, + permission.id === 'wallet.pay_invoice_background' + ? 'extension_permission_warning_wallet_pay_invoice_background' + : 'extension_permission_warning_wallet_pay_invoice' + ) + } + if (permission.id === 'extension.api.request') { + const hasWriteAccess = extensionApiPermissionTargets( + permission, + extensions + ).some(target => target.access.includes('write')) + return hasWriteAccess + ? highRisk( + translateFn, + 'extension_permission_warning_extension_api_request_write' + ) + : mediumRisk(translateFn) + } + if (permission.id === 'http.request') { + return mediumRisk(translateFn) + } + if (permission.id === 'wallet.payments.watch') { + return mediumRisk( + translateFn, + 'extension_permission_warning_wallet_payments_watch' + ) + } + if (['websocket.publish', 'websocket.subscribe'].includes(permission.id)) { + return mediumRisk(translateFn) + } + if ( + [ + 'wallet.list', + 'wallet.balance.read', + 'wallet.create_invoice_public', + 'ext.storage.append_public', + 'ext.storage.read_public' + ].includes(permission.id) + ) { + return mediumRisk(translateFn) + } + return lowRisk(translateFn) + } + + function permissionRisk(permissions, extensions, translateFn) { + const risks = permissions.map(permission => + permissionRiskForPermission(permission, extensions, translateFn) + ) + const highestRisk = risks.find(risk => risk.level === 'high') + if (highestRisk) return highestRisk + return risks.find(risk => risk.level === 'medium') || lowRisk(translateFn) + } + + function permissionOrderIndex(permissionId) { + const order = [ + 'wallet.pay_invoice', + 'wallet.pay_invoice_background', + 'wallet.payments.watch', + 'wallet.list', + 'wallet.balance.read', + 'extension.api.request', + 'http.request', + 'ui.camera.scan_qr', + 'websocket', + 'websocket.publish', + 'websocket.subscribe', + 'ext.storage.read', + 'ext.storage.write', + 'ext.storage.read_public', + 'ext.storage.append_public', + 'wallet.create_invoice_public', + 'wallet.create_invoice', + 'utils.basic' + ] + const index = order.indexOf(permissionId) + return index === -1 ? order.length : index + } + + function publicStorageFieldGroups(permission) { + const tables = permission.policies + if (!Array.isArray(tables)) return [] + return tables + .map(table => { + const tableName = + typeof table === 'string' ? table : table?.table_name || '' + const fields = + typeof table === 'string' || !Array.isArray(table?.public_fields) + ? [] + : table.public_fields.filter( + field => typeof field === 'string' && field + ) + const sourceIdField = + typeof table === 'string' || + typeof table?.source_id_field !== 'string' + ? '' + : table.source_id_field + return tableName ? {table: tableName, fields, sourceIdField} : null + }) + .filter(Boolean) + } + + function httpRequestPermissionHosts(permission) { + const hosts = permission.policies + if (!Array.isArray(hosts)) return [] + return hosts + .map(host => (typeof host === 'string' ? host : host?.host || '')) + .filter(host => typeof host === 'string' && host) + } + + function publicInvoicePolicies(permission) { + const policies = permission.policies + if (!Array.isArray(policies)) return [] + return policies + .map(policy => { + if (!policy || typeof policy !== 'object') return null + const table = policy.table + const walletField = policy.wallet_field + if (typeof table !== 'string' || !table) return null + if (typeof walletField !== 'string' || !walletField) return null + return {table, walletField} + }) + .filter(Boolean) + } + + function publicAppendPolicies(permission) { + const policies = permission.policies + if (!Array.isArray(policies)) return [] + return policies + .map(policy => { + if (!policy || typeof policy !== 'object') return null + const table = policy.table + const sourceTable = policy.source_table + const sourceIdField = policy.source_id_field + const allowedFields = Array.isArray(policy.allowed_fields) + ? policy.allowed_fields.filter( + field => typeof field === 'string' && field + ) + : [] + const maxRowsPerSource = Number.isInteger(policy.max_rows_per_source) + ? policy.max_rows_per_source + : 10000 + if (typeof table !== 'string' || !table) return null + if (typeof sourceTable !== 'string' || !sourceTable) return null + if (typeof sourceIdField !== 'string' || !sourceIdField) return null + return { + table, + sourceTable, + sourceIdField, + allowedFields, + maxRowsPerSource, + rawPolicy: policy + } + }) + .filter(Boolean) + } + + function websocketPublishPolicies(permission) { + const policies = permission.policies + if (!Array.isArray(policies)) return [] + return policies + .map(policy => { + if (!policy || typeof policy !== 'object') return null + const maxMessagesPerSecond = Number.isInteger( + policy.max_messages_per_second + ) + ? policy.max_messages_per_second + : 0 + return { + maxMessagesPerSecond, + rawPolicy: policy + } + }) + .filter(Boolean) + } + + function permissionDisplayItem(permissions, extensions, translateFn) { + const permission = permissions[0] + const isReadWriteStorage = + permissions.length === 2 && + permissions.some(permission => permission.id === 'ext.storage.read') && + permissions.some(permission => permission.id === 'ext.storage.write') + const isWebsocket = + permissions.every(permission => + ['websocket.publish', 'websocket.subscribe'].includes(permission.id) + ) && + permissions.some(permission => permission.id === 'websocket.publish') && + permissions.some(permission => permission.id === 'websocket.subscribe') + const descriptions = permissions + .map(permission => permissionManifestDescription(permission)) + .filter(Boolean) + const item = { + id: isReadWriteStorage + ? 'ext.storage.read_write' + : isWebsocket + ? 'websocket' + : permission.id, + label: isReadWriteStorage + ? translate(translateFn, 'extension_permission_ext_storage_read_write') + : isWebsocket + ? translate(translateFn, 'extension_permission_websocket') + : permissionLabel(permission, translateFn), + risk: permissionRisk(permissions, extensions, translateFn), + badges: [], + descriptions, + fieldGroups: [], + appendPolicies: [], + websocketPublishPolicies: [], + invoicePolicies: [], + extensionAccess: [], + httpHosts: [] + } + + if (permission.id === 'ext.storage.read_public') { + item.fieldGroups = publicStorageFieldGroups(permission) + item.badges = item.fieldGroups.map(group => ({ + key: group.table, + label: group.table + })) + } + + if (permission.id === 'extension.api.request') { + item.extensionAccess = extensionApiPermissionTargets( + permission, + extensions + ) + item.badges = item.extensionAccess.map(target => ({ + key: target.id, + label: target.name + })) + } + + if (permission.id === 'http.request') { + item.httpHosts = httpRequestPermissionHosts(permission) + } + + if (permission.id === 'wallet.create_invoice_public') { + item.invoicePolicies = publicInvoicePolicies(permission) + } + + if (permission.id === 'ext.storage.append_public') { + item.appendPolicies = publicAppendPolicies(permission) + item.badges = item.appendPolicies.map(policy => ({ + key: + policy.table + ':' + policy.sourceTable + ':' + policy.sourceIdField, + label: policy.table + })) + } + + const websocketPublishPermission = permissions.find( + permission => permission.id === 'websocket.publish' + ) + if (websocketPublishPermission) { + item.websocketPublishPolicies = websocketPublishPolicies( + websocketPublishPermission + ) + } + + return item + } + + function displayItems({permissions, extensions, translate}) { + const permissionList = permissions || [] + const permissionsById = new Map( + permissionList.map(permission => [permission.id, permission]) + ) + const hasReadWriteStorage = + permissionsById.has('ext.storage.read') && + permissionsById.has('ext.storage.write') + const hasWebsocket = + permissionsById.has('websocket.publish') && + permissionsById.has('websocket.subscribe') + let addedReadWriteStorage = false + let addedWebsocket = false + + return permissionList + .map((permission, index) => { + if ( + hasReadWriteStorage && + ['ext.storage.read', 'ext.storage.write'].includes(permission.id) + ) { + if (addedReadWriteStorage) return null + addedReadWriteStorage = true + return { + index, + orderId: 'ext.storage.read', + permissions: [ + permissionsById.get('ext.storage.read'), + permissionsById.get('ext.storage.write') + ] + } + } + if ( + hasWebsocket && + ['websocket.publish', 'websocket.subscribe'].includes(permission.id) + ) { + if (addedWebsocket) return null + addedWebsocket = true + return { + index, + orderId: 'websocket', + permissions: [ + permissionsById.get('websocket.publish'), + permissionsById.get('websocket.subscribe') + ] + } + } + return { + index, + orderId: permission.id, + permissions: [permission] + } + }) + .filter(Boolean) + .sort((left, right) => { + const leftOrder = permissionOrderIndex(left.orderId) + const rightOrder = permissionOrderIndex(right.orderId) + return leftOrder === rightOrder + ? left.index - right.index + : leftOrder - rightOrder + }) + .map(group => + permissionDisplayItem(group.permissions, extensions || [], translate) + ) + } + + window.LNbitsExtensionPermissions = { + displayItems, + hasHighRisk({permissions, extensions, translate}) { + return displayItems({permissions, extensions, translate}).some( + permission => permission.risk.level === 'high' + ) + } + } + + window.app.component('lnbits-extension-permissions', { + template: '#lnbits-extension-permissions', + props: { + permissions: { + type: Array, + default: () => [] + }, + extensions: { + type: Array, + default: () => [] + }, + editableAppendPublicLimits: { + type: Boolean, + default: false + }, + maxRowsPerSourceLimit: { + type: Number, + default: 1000000 + }, + editableWebsocketPublishLimits: { + type: Boolean, + default: false + }, + maxMessagesPerSecondLimit: { + type: Number, + default: 100 + } + }, + computed: { + displayItems() { + return window.LNbitsExtensionPermissions.displayItems({ + permissions: this.permissions, + extensions: this.extensions, + translate: key => this.$t(key) + }) + } + }, + methods: { + publicInvoicePolicySentence(policy) { + return `Invoices will be created using ${policy.walletField} from ${policy.table}.` + }, + publicAppendPolicySentence(policy) { + return `${policy.table} rows can be appended for ${policy.sourceTable} using ${policy.sourceIdField}. Limit: ${policy.maxRowsPerSource} rows per source.` + }, + websocketPublishPolicySentence(policy) { + return `Limit: ${policy.maxMessagesPerSecond} messages per second.` + }, + permissionAccessLabel(access) { + const key = `extension_permission_access_${access}` + const label = this.$t(key) + return label === key ? access : label + } + } + }) +})() diff --git a/lnbits/static/js/components/lnbits-language-dropdown.js b/lnbits/static/js/components/lnbits-language-dropdown.js index 53d0fe862..7f73b5fac 100644 --- a/lnbits/static/js/components/lnbits-language-dropdown.js +++ b/lnbits/static/js/components/lnbits-language-dropdown.js @@ -41,7 +41,8 @@ window.app.component('lnbits-language-dropdown', { {value: 'cs', label: 'Česky', display: '🇨🇿 CS'}, {value: 'sk', label: 'Slovensky', display: '🇸🇰 SK'}, {value: 'kr', label: '한국어', display: '🇰🇷 KR'}, - {value: 'fi', label: 'Suomi', display: '🇫🇮 FI'} + {value: 'fi', label: 'Suomi', display: '🇫🇮 FI'}, + {value: 'fo', label: 'Føroyskt', display: '🇫🇴 FO'} ] } } diff --git a/lnbits/static/js/components/lnbits-manage-extension-list.js b/lnbits/static/js/components/lnbits-manage-extension-list.js index 77d6a834f..4e41de6a6 100644 --- a/lnbits/static/js/components/lnbits-manage-extension-list.js +++ b/lnbits/static/js/components/lnbits-manage-extension-list.js @@ -35,6 +35,18 @@ window.app.component('lnbits-manage-extension-list', { .toLocaleLowerCase() .includes(this.searchTerm.toLocaleLowerCase()) }) + }, + extensionUrl(extension) { + if (extension.is_wasm) { + return `/ext/${extension.code}` + } + return `/${extension.code}/` + }, + extensionActive(extension) { + const extensionPath = extension.is_wasm + ? `/ext/${extension.code}` + : `/${extension.code}` + return this.$route.path.startsWith(extensionPath) } }, async created() { diff --git a/lnbits/static/js/components/lnbits-payment-list.js b/lnbits/static/js/components/lnbits-payment-list.js index 766ecec16..11b9f056d 100644 --- a/lnbits/static/js/components/lnbits-payment-list.js +++ b/lnbits/static/js/components/lnbits-payment-list.js @@ -360,18 +360,37 @@ window.app.component('lnbits-payment-list', { paymentTableRowKey(row) { return row.payment_hash + row.amount }, - exportCSV(detailed = false) { + async exportCSV(detailed = false) { // status is important for export but it is not in paymentsTable // because it is manually added with payment detail link and icons // and would cause duplication in the list const pagination = this.paymentsTable.pagination - const query = { - sortby: pagination.sortBy ?? 'time', - direction: pagination.descending ? 'desc' : 'asc' - } - const params = new URLSearchParams(query) - LNbits.api.getPayments(this.wallet, params).then(response => { - let payments = response.data.data.map(this.mapPayment) + const maxPages = 100 + const limit = 1000 + let payments = [] + + this.paymentsCSV.loading = true + try { + for (let page = 0; page < maxPages; page++) { + const query = { + sortby: pagination.sortBy ?? 'time', + direction: pagination.descending ? 'desc' : 'asc', + limit, + offset: page * limit + } + const params = new URLSearchParams(query) + const response = await LNbits.api.getPayments(this.wallet, params) + const pagePayments = response.data.data || [] + payments = payments.concat(pagePayments.map(this.mapPayment)) + + if ( + pagePayments.length < limit || + payments.length >= response.data.total + ) { + break + } + } + let columns = this.paymentsCSV.columns if (detailed) { @@ -400,7 +419,11 @@ window.app.component('lnbits-payment-list', { payments, this.wallet.name + '-payments' ) - }) + } catch (err) { + LNbits.utils.notifyApiError(err) + } finally { + this.paymentsCSV.loading = false + } }, addFilterTag() { if (!this.exportTagName) return diff --git a/lnbits/static/js/components/lnbits-qrcode-lnurl.js b/lnbits/static/js/components/lnbits-qrcode-lnurl.js index 16308a452..2b5474e47 100644 --- a/lnbits/static/js/components/lnbits-qrcode-lnurl.js +++ b/lnbits/static/js/components/lnbits-qrcode-lnurl.js @@ -8,6 +8,10 @@ window.app.component('lnbits-qrcode-lnurl', { prefix: { type: String, default: 'lnurlp' + }, + href: { + type: String, + default: '' } }, data() { @@ -21,7 +25,10 @@ window.app.component('lnbits-qrcode-lnurl', { if (this.tab == 'bech32') { const bytes = new TextEncoder().encode(this.url) const bech32 = NostrTools.nip19.encodeBytes('lnurl', bytes) - this.lnurl = `lightning:${bech32.toUpperCase()}` + this.lnurl = + this.href && this.href.trim() !== '' + ? `${this.href}?lightning=${bech32.toUpperCase()}` + : `lightning:${bech32.toUpperCase()}` } else if (this.tab == 'lud17') { if (this.url.startsWith('http://')) { this.lnurl = this.url.replace('http://', this.prefix + '://') diff --git a/lnbits/static/js/components/lnbits-qrcode.js b/lnbits/static/js/components/lnbits-qrcode.js index 8247fe306..55d36f21c 100644 --- a/lnbits/static/js/components/lnbits-qrcode.js +++ b/lnbits/static/js/components/lnbits-qrcode.js @@ -85,6 +85,9 @@ window.app.component('lnbits-qrcode', { event.preventDefault() event.stopPropagation() return false + } else if (this.href && this.href.startsWith('http')) { + window.open(this.href, '_blank') + event.preventDefault() } }, async writeNfcTag() { @@ -165,5 +168,26 @@ window.app.component('lnbits-qrcode', { this.$refs.qrCode.$el.style.maxWidth = this.maxWidth + 'px' this.$refs.qrCode.$el.setAttribute('width', '100%') this.$refs.qrCode.$el.removeAttribute('height') + }, + computed: { + optimizedValue() { + const separatorIndex = this.value.indexOf(':') + const type = + separatorIndex === -1 ? '' : this.value.substring(0, separatorIndex) + const value = + separatorIndex === -1 + ? this.value + : this.value.substring(separatorIndex + 1) + + if (this.utils.isValidBech32(value)) { + const normalizedValue = value.toUpperCase() + if (type) { + return `${type.toUpperCase()}:${normalizedValue}` + } + return normalizedValue + } + + return this.value + } } }) diff --git a/lnbits/static/js/components/lnbits-theme.js b/lnbits/static/js/components/lnbits-theme.js index 67624e713..54ca6f093 100644 --- a/lnbits/static/js/components/lnbits-theme.js +++ b/lnbits/static/js/components/lnbits-theme.js @@ -69,6 +69,14 @@ window.app.component('lnbits-theme', { document.body.classList.remove('card-shadow') } }, + 'g.burgerMenuChoice'(val) { + this.$q.localStorage.set('lnbits.burgerMenu', val) + if (val === true) { + document.body.classList.remove('no-burger-background') + } else { + document.body.classList.add('no-burger-background') + } + }, 'g.mobileSimple'(val) { this.$q.localStorage.set('lnbits.mobileSimple', val) if (val === true) { @@ -150,6 +158,9 @@ window.app.component('lnbits-theme', { if (this.g.cardShadowChoice === true) { document.body.classList.add('card-shadow') } + if (this.g.burgerMenuChoice !== true) { + document.body.classList.add('no-burger-background') + } if (this.g.bgimageChoice !== '') { document.body.classList.add('bg-image') document.body.style.setProperty( diff --git a/lnbits/static/js/components/lnbits-wallet-api-docs.js b/lnbits/static/js/components/lnbits-wallet-api-docs.js index b2c857335..3072b94d1 100644 --- a/lnbits/static/js/components/lnbits-wallet-api-docs.js +++ b/lnbits/static/js/components/lnbits-wallet-api-docs.js @@ -1,6 +1,11 @@ window.app.component('lnbits-wallet-api-docs', { template: '#lnbits-wallet-api-docs', methods: { + copyAdminKey() { + LNbits.utils + .confirmDialog(this.$t('admin_key_warning')) + .onOk(() => LNbits.utils.copyText(this.g.wallet.adminkey)) + }, resetKeys() { LNbits.utils .confirmDialog('Are you sure you want to reset your API keys?') diff --git a/lnbits/static/js/components/lnbits-wallet-extra.js b/lnbits/static/js/components/lnbits-wallet-extra.js index 1d5e0cabf..53e0a9da7 100644 --- a/lnbits/static/js/components/lnbits-wallet-extra.js +++ b/lnbits/static/js/components/lnbits-wallet-extra.js @@ -1,12 +1,46 @@ window.app.component('lnbits-wallet-extra', { template: '#lnbits-wallet-extra', props: ['chartConfig'], + data() { + return { + lightningAddressInput: '' + } + }, computed: { exportUrl() { return `${window.location.origin}/wallet?usr=${this.g.user.id}&wal=${this.g.wallet.id}` + }, + canEditLightningAddress() { + return ( + this.g.settings.enableWalletLightningAddresses && + this.g.settings.allowCustomWalletLightningAddresses && + this.g.wallet.walletType === 'lightning' + ) + }, + lightningAddressSuffix() { + return `@${window.location.host}` + }, + lightningAddressChanged() { + return ( + this.lightningAddressInput !== (this.g.wallet.lightningAddress || '') + ) + }, + lightningAddressFeeHint() { + if (!this.g.settings.chargeWalletLightningAddresses) return '' + return `Fee: ${this.g.settings.walletLightningAddressPriceSats} sats` } }, + watch: { + 'g.wallet.id': 'resetLightningAddressInput', + 'g.wallet.lightningAddress': 'resetLightningAddressInput' + }, methods: { + resetLightningAddressInput() { + this.lightningAddressInput = this.g.wallet.lightningAddress || '' + }, + saveLightningAddress() { + this.updateWallet({lightning_address: this.lightningAddressInput}) + }, handleSendLnurl(lnurl) { this.$emit('send-lnurl', lnurl) }, @@ -80,6 +114,7 @@ window.app.component('lnbits-wallet-extra', { } }, created() { + this.resetLightningAddressInput() if (this.g.wallet.currency !== '' && this.g.isSatsDenomination) { this.g.fiatTracking = true this.updateFiatBalance() diff --git a/lnbits/static/js/event-reactions.js b/lnbits/static/js/event-reactions.js index ebd50f7c2..2a80c5ed0 100644 --- a/lnbits/static/js/event-reactions.js +++ b/lnbits/static/js/event-reactions.js @@ -1,16 +1,17 @@ function eventReaction(amount) { localUrl = '' - reaction = localStorage.getItem('lnbits.reactions') - if (!reaction || reaction === 'None') { + const reaction = + Quasar.LocalStorage.getItem('lnbits.reactions') || SETTINGS.defaultReaction + if (!reaction || reaction.toLowerCase() === 'none') { return } + try { if (amount < 0) { return } - reaction = localStorage.getItem('lnbits.reactions') - if (reaction) { - window[reaction.split('|')[1]]() + if (typeof window[reaction] === 'function') { + window[reaction]() } } catch (e) { console.log(e) @@ -153,6 +154,99 @@ function confettiStars() { setTimeout(shoot, 100) setTimeout(shoot, 200) } +function lightningStrike() { + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d') + const dpr = window.devicePixelRatio || 1 + + canvas.style.position = 'fixed' + canvas.style.inset = '0' + canvas.style.pointerEvents = 'none' + canvas.style.zIndex = 999999 + canvas.width = Math.floor(window.innerWidth * dpr) + canvas.height = Math.floor(window.innerHeight * dpr) + ctx.scale(dpr, dpr) + document.body.appendChild(canvas) + + const startX = Math.random() * window.innerWidth + const endY = window.innerHeight * (0.45 + Math.random() * 0.35) + const segments = 18 + Math.floor(Math.random() * 10) + const points = [{x: startX, y: -20}] + + for (let i = 1; i <= segments; i++) { + const progress = i / segments + const previous = points[i - 1] + points.push({ + x: previous.x + (Math.random() - 0.5) * (34 + progress * 42), + y: progress * endY + }) + } + + const branches = [] + for ( + let i = 4; + i < points.length - 3; + i += 3 + Math.floor(Math.random() * 3) + ) { + const base = points[i] + const branch = [{...base}] + const direction = Math.random() > 0.5 ? 1 : -1 + const length = 3 + Math.floor(Math.random() * 4) + + for (let j = 1; j <= length; j++) { + branch.push({ + x: base.x + direction * j * (18 + Math.random() * 22), + y: base.y + j * (14 + Math.random() * 18) + }) + } + branches.push(branch) + } + + let frame = 0 + const maxFrames = 48 + + function drawBolt(path, width, alpha) { + ctx.beginPath() + ctx.moveTo(path[0].x, path[0].y) + path.slice(1).forEach(point => ctx.lineTo(point.x, point.y)) + ctx.strokeStyle = `rgba(170, 220, 255, ${alpha})` + ctx.lineWidth = width + ctx.lineJoin = 'round' + ctx.lineCap = 'round' + ctx.shadowBlur = 18 + ctx.shadowColor = '#7dd3fc' + ctx.stroke() + + ctx.strokeStyle = `rgba(255, 255, 255, ${Math.min(1, alpha + 0.2)})` + ctx.lineWidth = Math.max(1, width * 0.35) + ctx.shadowBlur = 4 + ctx.stroke() + } + + function animate() { + const alpha = 1 - frame / maxFrames + ctx.clearRect(0, 0, window.innerWidth, window.innerHeight) + + if (frame < 3) { + ctx.fillStyle = `rgba(255, 255, 255, ${0.22 - frame * 0.06})` + ctx.fillRect(0, 0, window.innerWidth, window.innerHeight) + } + + drawBolt(points, 5 * alpha + 1, alpha) + branches.forEach(branch => + drawBolt(branch, 2.5 * alpha + 0.5, alpha * 0.75) + ) + + frame += 1 + if (frame <= maxFrames) { + requestAnimationFrame(animate) + } else { + canvas.remove() + } + } + + animate() +} !(function (t, e) { ;(!(function t(e, n, a, i) { var o = !!( diff --git a/lnbits/static/js/globals.js b/lnbits/static/js/globals.js index e45fb54a5..990eb32ee 100644 --- a/lnbits/static/js/globals.js +++ b/lnbits/static/js/globals.js @@ -29,6 +29,10 @@ window.g = Vue.reactive({ SETTINGS.defaultCardGradient ), cardShadowChoice: localStore('lnbits.cardShadow', SETTINGS.defaultCardShadow), + burgerMenuChoice: localStore( + 'lnbits.burgerMenu', + SETTINGS.defaultBurgerMenuBackground + ), reactionChoice: localStore('lnbits.reactions', SETTINGS.defaultReaction), bgimageChoice: localStore( 'lnbits.backgroundImage', diff --git a/lnbits/static/js/init-app.js b/lnbits/static/js/init-app.js index 457b016bc..b57af295b 100644 --- a/lnbits/static/js/init-app.js +++ b/lnbits/static/js/init-app.js @@ -27,6 +27,14 @@ const DynamicComponent = { name: r.name, component: async () => { await LNbits.utils.loadTemplate(r.template) + if (r.i18n) { + const locale = + window.i18n?.global?.locale?.value ?? + window.i18n?.global?.locale ?? + window.g.locale ?? + 'en' + await LNbits.utils.loadExtI18n(r.i18n, locale) + } await LNbits.utils.loadScript(r.component) return window[r.name] } @@ -58,6 +66,12 @@ const routes = [ name: 'NodePublic', component: PageNodePublic }, + { + path: '/blockexplorer/:type(tx|address|block)?/:id?', + name: 'BlockExplorer', + component: PageBlockExplorer, + meta: {stableKey: true} + }, { path: '/payments', name: 'Payments', @@ -91,6 +105,26 @@ const routes = [ name: 'Users', component: PageUsers }, + { + path: '/admin/extensions/wasm', + name: 'AdminWasmRuntime', + component: PageAdmin + }, + { + path: '/admin/extensions/wasm/limits', + name: 'AdminWasmLimitConfig', + component: PageAdmin + }, + { + path: '/admin/extensions/wasm/limits/:extId', + name: 'AdminWasmLimitConfigDetail', + component: PageAdmin + }, + { + path: '/admin/extensions/wasm/:extId', + name: 'AdminWasmRuntimeDetail', + component: PageAdmin + }, { path: '/admin', name: 'Admin', @@ -131,6 +165,16 @@ const routes = [ name: 'PageError', component: PageError }, + { + path: '/ext/:extId', + name: 'WasmExtensionRoot', + component: window.WasmExtensionComponent + }, + { + path: '/ext/:extId/:pathMatch(.*)*', + name: 'WasmExtension', + component: window.WasmExtensionComponent + }, { path: '/:pathMatch(.*)*', name: 'DynamicComponent', @@ -151,6 +195,30 @@ window.i18n = new VueI18n.createI18n({ fallbackLocale: 'en', messages: window.localisation }) +;(function () { + let _applying = false + let _target = null + Vue.watch( + () => window.i18n.global.locale, + async (locale, prevLocale) => { + if (_applying || !LNbits.utils._extI18nDirs.size) return + _target = locale + _applying = true + window.i18n.global.locale = prevLocale + _applying = false + await Promise.all( + [...LNbits.utils._extI18nDirs].map(dir => + LNbits.utils.loadExtI18n(dir, locale) + ) + ) + if (_target !== locale) return + _applying = true + window.i18n.global.locale = locale + _applying = false + }, + {flush: 'sync'} + ) +})() window.app.mixin({ data() { diff --git a/lnbits/static/js/pages/account.js b/lnbits/static/js/pages/account.js index 7b12884b2..2edff32bc 100644 --- a/lnbits/static/js/pages/account.js +++ b/lnbits/static/js/pages/account.js @@ -10,6 +10,10 @@ window.PageAccount = { name: 'bitcoin', color: 'deep-orange' }, + { + name: 'classic', + color: 'purple' + }, { name: 'mint', color: 'green' @@ -47,7 +51,8 @@ window.PageAccount = { 'confettiBothSides', 'confettiFireworks', 'confettiStars', - 'confettiTop' + 'confettiTop', + 'lightningStrike' ], borderOptions: [ 'retro-border', @@ -213,6 +218,35 @@ window.PageAccount = { computed: { isUserTouched() { return !_.isEqual(this.g.user, this.untouchedUser) + }, + selectedApiToken() { + return this.selectedApiAcl.token_id_list.find( + token => token.id === this.apiAcl.selectedTokenId + ) + }, + expiryAt() { + if (this.selectedApiToken.expires_at) { + return `${this.$t('expiry')}: ${LNbits.utils.formatTimestamp(this.selectedApiToken.expires_at)}` + } else { + return '' + } + }, + tokenStatus() { + if (this.selectedApiToken.expires_at) { + const now = new Date() + const expiresAt = new Date(this.selectedApiToken.expires_at * 1000) + let status = '' + let badgeColor = 'positive' + if (expiresAt < now) { + status = this.$t('acl_token_expired') + badgeColor = 'negative' + } else { + status = this.$t('acl_token_active') + } + return {status, badgeColor} + } else { + return '' + } } }, methods: { @@ -541,31 +575,56 @@ window.PageAccount = { if (file) { this.uploadAsset(file) } + e.target.value = null }, - async uploadAsset(file) { + onBackgroundImageInput(e) { + const file = e.target.files[0] + if (file) { + this.uploadBackgroundImage(file) + } + e.target.value = null + }, + async uploadAsset( + file, + {isPublic = this.assetsUploadToPublic, notifySuccess = true} = {} + ) { const formData = new FormData() formData.append('file', file) try { - await LNbits.api.request( + const {data} = await LNbits.api.request( 'POST', - `/api/v1/assets?public_asset=${this.assetsUploadToPublic}`, + `/api/v1/assets?public_asset=${isPublic}`, null, formData, { headers: {'Content-Type': 'multipart/form-data'} } ) - this.$q.notify({ - type: 'positive', - message: 'Upload successful!', - icon: null - }) + if (notifySuccess) { + this.$q.notify({ + type: 'positive', + message: 'Upload successful!', + icon: null + }) + } await this.getUserAssets() + return data } catch (e) { console.warn(e) LNbits.utils.notifyApiError(e) } }, + async uploadBackgroundImage(file) { + const asset = await this.uploadAsset(file, { + isPublic: false, + notifySuccess: false + }) + if (!asset) { + return + } + const assetUrl = `${window.location.origin}/api/v1/assets/${asset.id}/thumbnail` + await this.siteCustomisationChanged({bgimageChoice: assetUrl}) + }, async deleteAsset(asset) { LNbits.utils .confirmDialog('Are you sure you want to delete this asset?') @@ -703,7 +762,8 @@ window.PageAccount = { darkChoice: this.g.settings.defaultDark, cardRoundedChoice: this.g.settings.defaultCardRounded, cardGradientChoice: this.g.settings.defaultCardGradient, - cardShadowChoice: this.g.settings.defaultCardShadow + cardShadowChoice: this.g.settings.defaultCardShadow, + burgerMenuChoice: this.g.settings.defaultBurgerMenuBackground } this.siteCustomisationChanged(defaults) } diff --git a/lnbits/static/js/pages/admin.js b/lnbits/static/js/pages/admin.js index 233740883..1368d0141 100644 --- a/lnbits/static/js/pages/admin.js +++ b/lnbits/static/js/pages/admin.js @@ -16,18 +16,26 @@ window.PageAdmin = { }, watch: { tab(tab) { - this.$router.push(`/admin#${tab}`) + if ( + ['wasm-runtime', 'wasm-limit-config'].includes(tab) && + this.$route.path.startsWith('/admin/extensions/wasm') + ) { + return + } + const target = this.adminRouteForTab(tab) + if (this.$route.fullPath !== target) { + this.$router.push(target) + } }, $route(to) { - if (to.hash.length > 1) { - this.tab = to.hash.replace('#', '') + const tab = this.adminTabFromRoute(to) + if (this.tab !== tab) { + this.tab = tab } } }, async created() { - if (this.$route.hash.length > 1) { - this.tab = this.$route.hash.replace('#', '') - } + this.tab = this.adminTabFromRoute(this.$route) await this.getSettings() }, computed: { @@ -36,6 +44,27 @@ window.PageAdmin = { } }, methods: { + adminTabFromRoute(route) { + if (route.path.startsWith('/admin/extensions/wasm/limits')) { + return 'wasm-limit-config' + } + if (route.path.startsWith('/admin/extensions/wasm')) { + return 'wasm-runtime' + } + if (route.hash.length > 1) { + return route.hash.replace('#', '') + } + return 'funding' + }, + adminRouteForTab(tab) { + if (tab === 'wasm-runtime') { + return '/admin/extensions/wasm' + } + if (tab === 'wasm-limit-config') { + return '/admin/extensions/wasm/limits' + } + return `/admin#${tab}` + }, getDefaultSetting(fieldName) { LNbits.api.getDefaultSetting(fieldName).then(response => { this.formData[fieldName] = response.data.default_value diff --git a/lnbits/static/js/pages/blockexplorer.js b/lnbits/static/js/pages/blockexplorer.js new file mode 100644 index 000000000..d16eae97b --- /dev/null +++ b/lnbits/static/js/pages/blockexplorer.js @@ -0,0 +1,233 @@ +window.PageBlockExplorer = { + template: '#page-blockexplorer', + data() { + return { + query: '', + loading: false, + tip: null, + fees: null, + blocks: [], + selectedBlock: null, + blockDialog: false, + txResult: null, + txStatus: null, + addressResult: null, + currentAddress: '' + } + }, + computed: { + feeList() { + if (!this.fees || !this.fees.estimates) return [] + return Object.entries(this.fees.estimates).map(([blocks, rate]) => ({ + label: this.$t('n_block_fee', {n: blocks}), + rate: (rate * 100000).toFixed(1) + ' sat/vB' + })) + }, + formattedBlocks() { + const now = Math.floor(Date.now() / 1000) + return this.blocks.map(b => ({ + ...b, + shortHash: b.hash.slice(0, 8) + '...' + b.hash.slice(-4), + timeAgo: this._timeAgo(now - b.timestamp), + utcTime: new Date(b.timestamp * 1000).toUTCString(), + difficulty: this._difficulty(b.bits) + })) + } + }, + async created() { + await Promise.all([this.loadTip(), this.loadFees(), this.loadBlocks()]) + this._blockWsActive = true + this._connectBlocksWs() + this._loadFromRoute() + }, + beforeUnmount() { + this._blockWsActive = false + if (this._blockWs) this._blockWs.close() + if (this._searchWs) this._searchWs.close() + }, + watch: { + $route(to) { + this._loadFromRoute(to) + }, + blockDialog(val) { + if (!val && this.$route.params.type === 'block') { + this.$router.push('/blockexplorer') + } + } + }, + methods: { + _loadFromRoute(route) { + route = route || this.$route + const {type, id} = route.params + if (type === 'tx') { + this.query = id + this._fetchTx(id) + } else if (type === 'address') { + this.query = id + this._fetchAddress(id) + } else if (type === 'block') { + this._openBlockByHeight(id) + } else { + this._resetResults() + this.blockDialog = false + } + }, + _openBlockByHeight(height) { + const h = parseInt(height, 10) + const block = + this.formattedBlocks.find(b => b.height === h) || + this.blocks.find(b => b.height === h) + if (block) { + this.selectedBlock = block + this.blockDialog = true + } else { + this.selectedBlock = null + this.blockDialog = false + } + }, + _resetResults() { + this.txResult = null + this.txStatus = null + this.addressResult = null + if (this._searchWs) { + this._searchWs.close() + this._searchWs = null + } + }, + _wsUrl(path) { + const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:' + return `${proto}//${window.location.host}/blockexplorer/api/v1${path}` + }, + _connectBlocksWs() { + const ws = new WebSocket(this._wsUrl('/ws/blocks')) + ws.onmessage = e => { + const block = JSON.parse(e.data) + const rest = this.blocks.filter(b => b.height !== block.height) + this.blocks = [block, ...rest].slice(0, 5) + } + ws.onerror = () => ws.close() + ws.onclose = () => { + if (this._blockWsActive) setTimeout(() => this._connectBlocksWs(), 5000) + } + this._blockWs = ws + }, + _connectSearchWs(path, onMessage) { + if (this._searchWs) { + this._searchWs.close() + this._searchWs = null + } + const ws = new WebSocket(this._wsUrl(path)) + ws.onmessage = e => { + try { + onMessage(JSON.parse(e.data)) + } catch (_) {} + } + ws.onerror = () => ws.close() + this._searchWs = ws + }, + _timeAgo(seconds) { + if (seconds < 60) return seconds + 's ago' + if (seconds < 3600) return Math.floor(seconds / 60) + 'm ago' + return Math.floor(seconds / 3600) + 'h ago' + }, + _difficulty(bitsHex) { + const exp = parseInt(bitsHex.slice(0, 2), 16) + const mantissa = parseInt(bitsHex.slice(2), 16) + const diff1 = 0xffff * Math.pow(2, 208) + const target = mantissa * Math.pow(2, 8 * (exp - 3)) + const d = diff1 / target + if (d >= 1e12) return (d / 1e12).toFixed(2) + 'T' + if (d >= 1e9) return (d / 1e9).toFixed(2) + 'G' + if (d >= 1e6) return (d / 1e6).toFixed(2) + 'M' + return d.toFixed(0) + }, + openBlock(b) { + this.$router.push(`/blockexplorer/block/${b.height}`) + }, + async loadBlocks() { + try { + const r = await LNbits.api.request( + 'GET', + '/blockexplorer/api/v1/blocks' + ) + this.blocks = r.data + } catch (_) {} + }, + async loadTip() { + try { + const r = await LNbits.api.request('GET', '/blockexplorer/api/v1/tip') + this.tip = r.data + } catch (e) { + LNbits.utils.notifyApiError(e) + } + }, + async loadFees() { + try { + const r = await LNbits.api.request('GET', '/blockexplorer/api/v1/fees') + this.fees = r.data + } catch (_) {} + }, + clearResult() { + this.query = '' + if (this.$route.path !== '/blockexplorer') { + this.$router.push('/blockexplorer') + } else { + this._resetResults() + } + }, + search() { + const q = this.query.trim() + if (!q) return + if (/^[0-9a-fA-F]{64}$/.test(q)) { + this.loadTx(q) + } else { + this.loadAddress(q) + } + }, + loadTx(txid) { + this.$router.push(`/blockexplorer/tx/${txid}`) + }, + loadAddress(address) { + this.$router.push(`/blockexplorer/address/${address}`) + }, + async _fetchTx(txid) { + this.loading = true + try { + const r = await LNbits.api.request( + 'GET', + '/blockexplorer/api/v1/tx/' + txid + ) + this.txResult = r.data + this.txStatus = null + this.addressResult = null + this._connectSearchWs(`/ws/tx/${txid}`, data => { + if (!data.error) this.txStatus = data + }) + } catch (e) { + LNbits.utils.notifyApiError(e) + } finally { + this.loading = false + } + }, + async _fetchAddress(address) { + this.loading = true + try { + const r = await LNbits.api.request( + 'GET', + '/blockexplorer/api/v1/address/' + address + ) + this.addressResult = r.data + this.txResult = null + this.txStatus = null + this.currentAddress = address + this._connectSearchWs(`/ws/address/${address}`, data => { + if (!data.error) this.addressResult = data + }) + } catch (e) { + LNbits.utils.notifyApiError(e) + } finally { + this.loading = false + } + } + } +} diff --git a/lnbits/static/js/pages/extensions.js b/lnbits/static/js/pages/extensions.js index a71160d54..b4a14848e 100644 --- a/lnbits/static/js/pages/extensions.js +++ b/lnbits/static/js/pages/extensions.js @@ -1,3 +1,7 @@ +const EXTENSION_PERMISSION_DEFAULT_MAX_ROWS_PER_SOURCE = 10000 +const EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT = 1000000 +const EXTENSION_PERMISSION_MAX_MESSAGES_PER_SECOND_LIMIT = 100 + window.PageExtensions = { template: '#page-extensions', data() { @@ -10,6 +14,7 @@ window.PageExtensions = { tab: 'installed', manageExtensionTab: 'releases', filteredExtensions: [], + categories: new Set(), updatableExtensions: [], showUninstallDialog: false, showManageExtensionDialog: false, @@ -21,8 +26,36 @@ window.PageExtensions = { selectedExtension: null, selectedImage: null, selectedExtensionDetails: null, + selectedExtensionDetailsDescription: '', selectedExtensionRepos: null, selectedRelease: null, + permissionGrant: { + show: false, + permissions: [], + resolve: null + }, + extensionPermissionMaxRowsPerSourceLimit: + EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT, + extensionPermissionMaxMessagesPerSecondLimit: + EXTENSION_PERMISSION_MAX_MESSAGES_PER_SECOND_LIMIT, + managedExtensionPermissions: { + loading: false, + extensionPermissions: [], + userPermissions: {}, + savingExtensionPermissions: false, + savingKey: '', + deletingKey: '' + }, + backgroundPaymentDestinationOptions: [ + { + label: 'Only transfers to my wallets', + value: 'own_wallets_only' + }, + { + label: 'Allow external payments', + value: 'external_allowed' + } + ], uninstallAndDropDb: false, maxStars: 5, paylinkWebsocket: null, @@ -92,6 +125,32 @@ window.PageExtensions = { this.filterExtensions(this.searchTerm, val) } }, + computed: { + managedUserPermissionRows() { + const rows = [] + const userPermissions = + this.managedExtensionPermissions.userPermissions || {} + Object.entries(userPermissions).forEach(([permissionId, grants]) => { + if (!Array.isArray(grants)) return + grants.forEach(grant => { + if (!grant || typeof grant !== 'object') return + const grantId = String(grant.id || '') + const walletId = String(grant.wallet_id || '') + if (!grantId || !walletId) return + rows.push({ + key: grantId, + permissionId, + label: this.permissionLabelById(permissionId), + grantId, + walletId, + walletName: this.walletName(walletId), + grant + }) + }) + }) + return rows + } + }, methods: { filterExtensions(term, tab) { // Filter the extensions list @@ -106,6 +165,10 @@ window.PageExtensions = { } } + const isCategoryTab = !['installed', 'all', 'featured'].includes(tab) + const isInSelectedCategory = extension => + extension.categories?.includes(tab) ?? false + this.filteredExtensions = this.extensions .filter(e => (tab === 'all' ? !e.isInstalled : true)) .filter(e => (tab === 'installed' ? e.isInstalled : true)) @@ -113,6 +176,7 @@ window.PageExtensions = { tab === 'installed' ? (e.isActive ? true : !!this.g.user.admin) : true ) .filter(e => (tab === 'featured' ? e.isFeatured : true)) + .filter(e => (isCategoryTab ? isInSelectedCategory(e) : true)) .filter(extensionNameContains(term)) .map(e => ({ ...e, @@ -126,6 +190,12 @@ window.PageExtensions = { // the install logic has been triggered one way or another this.unsubscribeFromPaylinkWs() + const grantedPermissions = + await this.resolveExtensionPermissionGrant(release) + if (grantedPermissions === null) { + return + } + this.selectedExtension.inProgress = true this.showManageExtensionDialog = false release.payment_hash = @@ -137,7 +207,8 @@ window.PageExtensions = { archive: release.archive, source_repo: release.source_repo, payment_hash: release.payment_hash, - version: release.version + version: release.version, + permissions: grantedPermissions }) .then(response => { this.selectedExtension.inProgress = false @@ -146,6 +217,12 @@ window.PageExtensions = { ) extension.isAvailable = true extension.isInstalled = true + extension.isWasm = + response.data.is_wasm === true || + response.data.isWasm === true || + release.extension_type === 'wasm' || + extension.isWasm === true + extension.icon = response.data.icon || extension.icon extension.installedRelease = release this.toggleExtension(extension) extension.inProgress = false @@ -333,8 +410,18 @@ window.PageExtensions = { this.selectedExtension = extension this.selectedRelease = null this.selectedExtensionRepos = null - this.manageExtensionTab = 'releases' + this.resetManagedExtensionPermissions() + this.manageExtensionTab = this.g.user.admin + ? 'releases' + : 'extension-permissions' this.showManageExtensionDialog = true + if (this.canManageExtensionPermissions(extension)) { + this.loadManagedExtensionPermissions(extension) + } + + if (!this.g.user.admin) { + return + } try { const {data} = await LNbits.api.request( @@ -372,6 +459,195 @@ window.PageExtensions = { extension.inProgress = false } }, + canShowManageExtensionButton(extension) { + return ( + this.g.user.admin || + (extension?.isWasm === true && extension?.isInstalled === true) + ) + }, + canManageExtensionPermissions(extension = this.selectedExtension) { + return extension?.isWasm === true && extension?.isInstalled === true + }, + canShowAdminManageTabs() { + return this.g.user.admin === true + }, + resetManagedExtensionPermissions() { + this.managedExtensionPermissions = { + loading: false, + extensionPermissions: [], + userPermissions: {}, + savingExtensionPermissions: false, + savingKey: '', + deletingKey: '' + } + }, + async loadManagedExtensionPermissions(extension = this.selectedExtension) { + if (!this.canManageExtensionPermissions(extension)) return + this.managedExtensionPermissions.loading = true + try { + const {data} = await LNbits.api.request( + 'GET', + `/api/v1/extension/${extension.id}/permissions` + ) + this.managedExtensionPermissions.extensionPermissions = + this.cloneEditableExtensionPermissions( + data.extension_permissions || [] + ) + this.managedExtensionPermissions.userPermissions = + this.cloneUserPermissions(data.user_permissions || {}) + } catch (error) { + console.warn(error) + LNbits.utils.notifyApiError(error) + } finally { + this.managedExtensionPermissions.loading = false + } + }, + cloneEditableExtensionPermissions(permissions) { + return (permissions || []) + .filter(permission => permission && typeof permission === 'object') + .map(permission => ({ + ...permission, + policies: Array.isArray(permission.policies) + ? permission.policies.map(policy => + this.cloneEditablePermissionPolicy(permission.id, policy) + ) + : permission.policies + })) + }, + cloneEditablePermissionPolicy(permissionId, policy) { + if (!policy || typeof policy !== 'object' || Array.isArray(policy)) { + return policy + } + const clonedPolicy = Object.entries(policy).reduce( + (copy, [key, value]) => ({ + ...copy, + [key]: Array.isArray(value) ? value.slice() : value + }), + {} + ) + if (permissionId === 'ext.storage.append_public') { + clonedPolicy.max_rows_per_source = this.maxRowsPerSourceValue( + clonedPolicy.max_rows_per_source, + EXTENSION_PERMISSION_DEFAULT_MAX_ROWS_PER_SOURCE + ) + } + if (permissionId === 'websocket.publish') { + clonedPolicy.max_messages_per_second = Number( + clonedPolicy.max_messages_per_second + ) + } + return clonedPolicy + }, + maxRowsPerSourceValue(value, fallback) { + const number = Number(value) + if (!Number.isInteger(number) || number <= 0) return fallback + return Math.min(number, EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT) + }, + extensionPermissionLimitError(permissions) { + const appendPermission = (permissions || []).find( + permission => permission?.id === 'ext.storage.append_public' + ) + if (!appendPermission || !Array.isArray(appendPermission.policies)) { + return this.websocketPublishLimitError(permissions) + } + for (const policy of appendPermission.policies) { + if (!policy || typeof policy !== 'object') continue + const number = Number(policy.max_rows_per_source) + if (!Number.isInteger(number) || number <= 0) { + return 'Max rows per source must be a positive integer.' + } + if (number > EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT) { + return `Max rows per source cannot exceed ${EXTENSION_PERMISSION_MAX_ROWS_PER_SOURCE_LIMIT}.` + } + } + return this.websocketPublishLimitError(permissions) + }, + websocketPublishLimitError(permissions) { + const publishPermission = (permissions || []).find( + permission => permission?.id === 'websocket.publish' + ) + if (!publishPermission) return '' + if ( + !Array.isArray(publishPermission.policies) || + publishPermission.policies.length !== 1 + ) { + return 'Websocket publish requires a max messages per second policy.' + } + const policy = publishPermission.policies[0] + if (!policy || typeof policy !== 'object') { + return 'Websocket publish requires a max messages per second policy.' + } + const number = Number(policy.max_messages_per_second) + if (!Number.isInteger(number) || number <= 0) { + return 'Max messages per second must be a positive integer.' + } + if (number > EXTENSION_PERMISSION_MAX_MESSAGES_PER_SECOND_LIMIT) { + return `Max messages per second cannot exceed ${EXTENSION_PERMISSION_MAX_MESSAGES_PER_SECOND_LIMIT}.` + } + return '' + }, + validateExtensionPermissionLimits(permissions) { + const error = this.extensionPermissionLimitError(permissions) + if (!error) return true + Quasar.Notify.create({ + type: 'negative', + message: error + }) + return false + }, + extensionPermissionsHaveEditableLimits(permissions) { + return (permissions || []).some( + permission => + (permission?.id === 'ext.storage.append_public' && + Array.isArray(permission.policies) && + permission.policies.length > 0) || + permission?.id === 'websocket.publish' + ) + }, + async saveManagedExtensionPermissions() { + const permissions = this.managedExtensionPermissions.extensionPermissions + if (!this.validateExtensionPermissionLimits(permissions)) return + + this.managedExtensionPermissions.savingExtensionPermissions = true + try { + const {data} = await LNbits.api.request( + 'PUT', + `/api/v1/extension/${this.selectedExtension.id}/permissions`, + this.g.user.wallets[0].adminkey, + { + permissions: this.cloneEditableExtensionPermissions(permissions) + } + ) + this.managedExtensionPermissions.extensionPermissions = + this.cloneEditableExtensionPermissions( + data.extension_permissions || [] + ) + Quasar.Notify.create({ + type: 'positive', + message: 'Permission updated.' + }) + } catch (error) { + console.warn(error) + LNbits.utils.notifyApiError(error) + } finally { + this.managedExtensionPermissions.savingExtensionPermissions = false + } + }, + cloneUserPermissions(userPermissions) { + const permissions = {} + Object.entries(userPermissions || {}).forEach( + ([permissionId, grants]) => { + if (!Array.isArray(grants)) return + permissions[permissionId] = grants + .filter(grant => grant && typeof grant === 'object') + .map(grant => ({ + ...grant, + _original: {...grant} + })) + } + ) + return permissions + }, async showExtensionDetails(extId, detailsLink) { if (!detailsLink) { @@ -381,6 +657,7 @@ window.PageExtensions = { this.selectedExtension = this.extensions.find(ext => ext.id === extId) || this.selectedExtension this.selectedExtensionDetails = null + this.selectedExtensionDetailsDescription = '' this.showExtensionDetailsDialog = true this.slide = 0 this.fullscreen = false @@ -392,14 +669,95 @@ window.PageExtensions = { ) this.selectedExtensionDetails = data - this.selectedExtensionDetails.description_md = - LNbits.utils.convertMarkdown(data.description_md) + this.selectedExtensionDetailsDescription = + this.extensionDescriptionDocument(data.description_md) } catch (error) { console.warn(error) } }, + extensionDescriptionDocument(markdown) { + const source = typeof markdown === 'string' ? markdown : '' + const rendered = LNbits.utils.convertMarkdown(source) + const parsed = new DOMParser().parseFromString(rendered, 'text/html') + + parsed.body + .querySelectorAll( + 'applet, base, embed, form, frame, iframe, link, meta, object, portal, script' + ) + .forEach(element => element.remove()) + parsed.body.querySelectorAll('*').forEach(element => { + for (const attribute of [...element.attributes]) { + const attributeName = attribute.name.toLowerCase() + if ( + attributeName.startsWith('on') || + attributeName === 'srcdoc' || + attributeName === 'xlink:href' + ) { + element.removeAttribute(attribute.name) + } + } + }) + parsed.body.querySelectorAll('a[href], area[href]').forEach(link => { + try { + const url = new URL(link.getAttribute('href'), window.location.origin) + if ( + !['http:', 'https:'].includes(url.protocol) || + url.username || + url.password + ) { + link.removeAttribute('href') + return + } + link.setAttribute('href', url.href) + link.setAttribute('target', '_blank') + link.setAttribute('rel', 'noopener noreferrer') + } catch (_error) { + link.removeAttribute('href') + } + }) + + const csp = [ + "default-src 'none'", + 'img-src https: data:', + "style-src 'unsafe-inline'", + "script-src 'none'", + "script-src-attr 'none'", + "base-uri 'none'", + "form-action 'none'", + "frame-src 'none'", + "object-src 'none'" + ].join('; ') + const styles = ` + :root { color-scheme: light dark; font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } + body { margin: 0; color: CanvasText; background: Canvas; line-height: 1.5; overflow-wrap: anywhere; } + img { max-width: 100%; height: auto; } + pre { overflow: auto; padding: 0.75rem; background: color-mix(in srgb, CanvasText 8%, Canvas); } + code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; } + table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; } + th, td { padding: 0.35rem 0.6rem; border: 1px solid color-mix(in srgb, CanvasText 20%, Canvas); } + a[href] { color: LinkText; cursor: pointer; } + ` + + return ` + + + + + + + + + + ${parsed.body.innerHTML} + + ` + }, async payAndInstall(release) { try { + if ((await this.resolveExtensionPermissionGrant(release)) === null) { + return + } + this.selectedExtension.inProgress = true this.showManageExtensionDialog = false const paymentInfo = await this.requestPaymentForInstall( @@ -445,6 +803,10 @@ window.PageExtensions = { } }, async showInstallQRCode(release) { + if ((await this.resolveExtensionPermissionGrant(release)) === null) { + return + } + this.selectedRelease = release try { @@ -607,6 +969,138 @@ window.PageExtensions = { return '' }, + extensionOpenUrl(extension) { + return extension.isWasm ? `/ext/${extension.id}` : `/${extension.id}` + }, + permissionLabelById(permissionId) { + const key = `extension_permission_${String(permissionId).replace( + /[^A-Za-z0-9]/g, + '_' + )}` + const label = this.$t(key) + return label === key ? permissionId : label + }, + walletName(walletId) { + const wallet = (this.g.user.wallets || []).find( + wallet => wallet.id === walletId + ) + return wallet ? wallet.name || wallet.id : walletId + }, + userPermissionRowCaption(row) { + return `${row.walletName} (${row.walletId.slice(0, 8)}...)` + }, + isBackgroundPaymentPermission(row) { + return row.permissionId === 'wallet.pay_invoice_background' + }, + userPermissionGrantPayload(row) { + return { + wallet_id: row.walletId, + max_amount: this.positiveInteger(row.grant.max_amount, 0), + destination_policy: this.backgroundPaymentDestinationPolicy( + row.grant.destination_policy + ) + } + }, + positiveInteger(value, fallback) { + const number = Number(value) + if (!Number.isFinite(number) || number <= 0) return fallback + return Math.floor(number) + }, + backgroundPaymentDestinationPolicy(value) { + return value === 'external_allowed' + ? 'external_allowed' + : 'own_wallets_only' + }, + backgroundPaymentGrantIncreased(row, payload) { + const original = row.grant._original || {} + const originalAmount = this.positiveInteger(original.max_amount, 0) + const originalPolicy = this.backgroundPaymentDestinationPolicy( + original.destination_policy + ) + return ( + payload.max_amount > originalAmount || + (originalPolicy === 'own_wallets_only' && + payload.destination_policy === 'external_allowed') + ) + }, + confirmUserPermissionIncrease() { + return new Promise(resolve => { + let resolved = false + const finish = value => { + if (resolved) return + resolved = true + resolve(value) + } + LNbits.utils + .confirmDialog( + 'This increases what the extension can do with this wallet. Continue?' + ) + .onOk(() => finish(true)) + .onCancel(() => finish(false)) + .onDismiss(() => finish(false)) + }) + }, + async saveUserPermissionGrant(row) { + if (!this.isBackgroundPaymentPermission(row)) return + const payload = this.userPermissionGrantPayload(row) + if (!payload.max_amount) { + Quasar.Notify.create({ + type: 'negative', + message: 'Max payment amount must be greater than zero.' + }) + return + } + if ( + this.backgroundPaymentGrantIncreased(row, payload) && + !(await this.confirmUserPermissionIncrease()) + ) { + return + } + + this.managedExtensionPermissions.savingKey = row.key + try { + await LNbits.api.request( + 'POST', + `/api/v1/extension/${this.selectedExtension.id}/permissions/background-payment`, + null, + payload + ) + Quasar.Notify.create({ + type: 'positive', + message: 'Permission updated.' + }) + await this.loadManagedExtensionPermissions() + } catch (error) { + console.warn(error) + LNbits.utils.notifyApiError(error) + } finally { + this.managedExtensionPermissions.savingKey = '' + } + }, + deleteUserPermissionGrant(row) { + LNbits.utils + .confirmDialog('Remove this permission grant?') + .onOk(async () => { + this.managedExtensionPermissions.deletingKey = row.key + try { + const grantId = encodeURIComponent(row.grantId) + await LNbits.api.request( + 'DELETE', + `/api/v1/extension/${this.selectedExtension.id}/permissions/user/${grantId}` + ) + Quasar.Notify.create({ + type: 'positive', + message: 'Permission removed.' + }) + await this.loadManagedExtensionPermissions() + } catch (error) { + console.warn(error) + LNbits.utils.notifyApiError(error) + } finally { + this.managedExtensionPermissions.deletingKey = '' + } + }) + }, async getGitHubReleaseDetails(release) { if (!release.is_github_release || release.loaded) { return @@ -622,6 +1116,8 @@ window.PageExtensions = { release.is_version_compatible = data.is_version_compatible release.min_lnbits_version = data.min_lnbits_version release.warning = data.warning + release.extension_type = data.extension_type + release.permissions = data.permissions || [] } catch (error) { console.warn(error) release.error = error @@ -630,6 +1126,84 @@ window.PageExtensions = { release.inProgress = false } }, + async resolveExtensionPermissionGrant(release) { + const permissions = this.extensionPermissionsForRelease(release) + if ( + !this.releaseRequiresPermissionGrant(release) || + !permissions.length + ) { + return [] + } + if (release.grantedPermissions) { + return release.grantedPermissions + } + const grantedPermissions = + await this.confirmExtensionPermissions(permissions) + if (!grantedPermissions) { + return null + } + release.grantedPermissions = grantedPermissions + return grantedPermissions + }, + extensionPermissionsForRelease(release) { + return release.permissions || this.selectedExtension?.permissions || [] + }, + releaseRequiresPermissionGrant(release) { + return ( + release.extension_type === 'wasm' || + this.selectedExtension?.isWasm === true + ) + }, + confirmExtensionPermissions(permissions) { + return new Promise(resolve => { + this.selectedRelease = null + this.permissionGrant = { + show: true, + permissions: this.cloneEditableExtensionPermissions(permissions), + resolve + } + this.showManageExtensionDialog = true + }) + }, + grantExtensionPermissions() { + if ( + !this.validateExtensionPermissionLimits( + this.permissionGrant.permissions + ) + ) { + return + } + this.resolveExtensionPermissionDialog( + this.cloneEditableExtensionPermissions(this.permissionGrant.permissions) + ) + }, + cancelExtensionPermissions() { + this.resolveExtensionPermissionDialog(null) + }, + onManageExtensionDialogHide() { + if (this.permissionGrant.show) { + this.resolveExtensionPermissionDialog(null) + } + }, + resolveExtensionPermissionDialog(grantedPermissions) { + const resolve = this.permissionGrant.resolve + this.permissionGrant = { + show: false, + permissions: [], + resolve: null + } + this.showManageExtensionDialog = false + if (resolve) { + resolve(grantedPermissions) + } + }, + permissionGrantHasHighRisk() { + return window.LNbitsExtensionPermissions.hasHighRisk({ + permissions: this.permissionGrant.permissions, + extensions: this.extensions, + translate: key => this.$t(key) + }) + }, async selectAllUpdatableExtensionss() { this.updatableExtensions.forEach(e => (e.selectedForUpdate = true)) }, @@ -640,6 +1214,13 @@ window.PageExtensions = { if (!ext.selectedForUpdate) { continue } + if (ext.isWasm) { + Quasar.Notify.create({ + type: 'warning', + message: `Skipping ${ext.id}; this extension update requires permission approval.` + }) + continue + } ext.inProgress = true await LNbits.api.request('POST', `/api/v1/extension`, null, { ext_id: ext.id, @@ -832,6 +1413,9 @@ window.PageExtensions = { async fetchAllExtensions() { try { const {data} = await LNbits.api.request('GET', `/api/v1/extension/all`) + data.forEach(ext => { + ext.categories?.forEach(category => this.categories.add(category)) + }) return data } catch (error) { console.warn(error) diff --git a/lnbits/static/js/pages/home.js b/lnbits/static/js/pages/home.js index ed8dd52c0..413fb44c6 100644 --- a/lnbits/static/js/pages/home.js +++ b/lnbits/static/js/pages/home.js @@ -21,7 +21,7 @@ window.PageHome = { return ( this.lnurl !== '' && this.g.settings.allowRegister && - 'user-id-only' in this.g.settings.authMethods + this.g.settings.authMethods.includes('user-id-only') ) }, formatDescription() { diff --git a/lnbits/static/js/pages/users.js b/lnbits/static/js/pages/users.js index 00bef033d..3686cceca 100644 --- a/lnbits/static/js/pages/users.js +++ b/lnbits/static/js/pages/users.js @@ -29,6 +29,11 @@ window.PageUsers = { data: {}, show: false }, + lightningAddressDialog: { + wallet: null, + lightningAddress: '', + show: false + }, walletTable: { columns: [ { @@ -173,6 +178,11 @@ window.PageUsers = { created() { this.fetchUsers() }, + computed: { + lightningAddressSuffix() { + return `@${window.location.host}` + } + }, methods: { formatSat(value) { @@ -348,6 +358,35 @@ window.PageUsers = { const url = `${window.location.origin}/wallet?usr=${this.activeWallet.userId}&wal=${walletId}` this.utils.copyText(url) }, + showLightningAddressDialog(wallet) { + this.lightningAddressDialog.wallet = wallet + this.lightningAddressDialog.lightningAddress = + wallet.lightning_address || '' + this.lightningAddressDialog.show = true + }, + saveLightningAddress() { + const wallet = this.lightningAddressDialog.wallet + if (!wallet) return + LNbits.api + .request( + 'PUT', + `/users/api/v1/user/${wallet.user}/wallet/${wallet.id}/lightning-address`, + null, + { + lightning_address: this.lightningAddressDialog.lightningAddress + } + ) + .then(response => { + Object.assign(wallet, response.data) + this.lightningAddressDialog.show = false + Quasar.Notify.create({ + type: 'positive', + message: this.$t('lightning_address_updated'), + icon: null + }) + }) + .catch(LNbits.utils.notifyApiError) + }, fetchUsers(props) { this.relaxFilterForFields(['username', 'email']) const params = LNbits.utils.prepareFilterQuery(this.usersTable, props) diff --git a/lnbits/static/js/pages/wallet.js b/lnbits/static/js/pages/wallet.js index e71ec651e..2d775d768 100644 --- a/lnbits/static/js/pages/wallet.js +++ b/lnbits/static/js/pages/wallet.js @@ -7,6 +7,7 @@ window.PageWallet = { invoice: null, lnurlpay: null, lnurlauth: null, + sending: false, data: { request: '', amount: 0, @@ -48,6 +49,13 @@ window.PageWallet = { hasNfc: false, nfcReaderAbortController: null, formattedFiatAmount: 0, + totalBreakdown: { + show: false, + loading: false, + rows: [], + selectedTypes: ['bitcoin', 'fiat'], + selectedTags: [] + }, paymentFilter: { 'status[ne]': 'failed' }, @@ -84,9 +92,116 @@ window.PageWallet = { }, formattedSatAmount() { return LNbits.utils.formatMsat(this.receive.amountMsat) + ' sat' + }, + totalBreakdownTags() { + const tags = this.totalBreakdown.rows.map(row => row.tag || null) + return [...new Set(tags)].sort((a, b) => + this.totalBreakdownTagLabel(a).localeCompare( + this.totalBreakdownTagLabel(b) + ) + ) + }, + hasFiatTotalBreakdown() { + return this.totalBreakdown.rows.some(row => row.is_fiat) + }, + selectedTotalBreakdownRows() { + return this.totalBreakdown.rows.filter(row => { + const type = row.is_fiat ? 'fiat' : 'bitcoin' + return ( + this.totalBreakdown.selectedTypes.includes(type) && + this.totalBreakdown.selectedTags.includes( + this.totalBreakdownTagKey(row.tag) + ) + ) + }) + }, + selectedTotalBreakdownMsat() { + return this.selectedTotalBreakdownRows.reduce( + (total, row) => total + row.total, + 0 + ) + }, + selectedTotalBreakdownSat() { + return Math.round(this.selectedTotalBreakdownMsat / 1000) + }, + selectedTotalBreakdownCount() { + return this.selectedTotalBreakdownRows.reduce( + (total, row) => total + row.payments_count, + 0 + ) + }, + formattedTotalBreakdown() { + return this.utils.formatBalance( + this.selectedTotalBreakdownSat, + this.g.denomination + ) + }, + formattedTotalBreakdownFiat() { + if (!this.g.fiatTracking) return null + const amount = + (this.selectedTotalBreakdownSat / 100000000) * this.g.exchangeRate + return LNbits.utils.formatCurrency(amount, this.g.wallet.currency) + }, + primaryTotalBreakdownValue() { + if (this.g.isFiatPriority && this.g.fiatTracking) { + return this.formattedTotalBreakdownFiat || this.formattedTotalBreakdown + } + return this.formattedTotalBreakdown + }, + secondaryTotalBreakdownValue() { + if (!this.g.fiatTracking) return null + if (this.g.isFiatPriority) { + return this.formattedTotalBreakdown + } + return this.formattedTotalBreakdownFiat } }, methods: { + showWalletTotalBreakdown() { + this.totalBreakdown.show = true + if (!this.totalBreakdown.rows.length) { + this.fetchTotalBreakdown() + } + }, + fetchTotalBreakdown() { + this.totalBreakdown.loading = true + LNbits.api + .getPaymentTotalBreakdown(this.g.wallet) + .then(response => { + this.totalBreakdown.rows = response.data + this.totalBreakdown.selectedTypes = ['bitcoin', 'fiat'] + this.totalBreakdown.selectedTags = this.totalBreakdownTags.map( + this.totalBreakdownTagKey + ) + this.totalBreakdown.loading = false + }) + .catch(err => { + this.totalBreakdown.loading = false + LNbits.utils.notifyApiError(err) + }) + }, + totalBreakdownTagLabel(tag) { + return tag || 'No tag' + }, + totalBreakdownTagKey(tag) { + return tag || '__untagged__' + }, + totalBreakdownTagCount(tag) { + return this.totalBreakdown.rows + .filter(row => (row.tag || null) === tag) + .reduce((total, row) => total + row.payments_count, 0) + }, + totalBreakdownTagMsat(tag) { + return this.totalBreakdown.rows + .filter(row => (row.tag || null) === tag) + .reduce((total, row) => total + row.total, 0) + }, + formatTotalBreakdownMsat(msat) { + return this.utils.formatBalance( + Math.round(msat / 1000), + this.g.denomination + ) + }, handleSendLnurl(lnurl) { this.parse.data.request = lnurl this.parse.show = true @@ -131,6 +246,7 @@ window.PageWallet = { this.parse.data.request = '' this.parse.data.comment = '' this.parse.data.internalMemo = null + this.parse.sending = false this.parse.data.paymentChecker = null this.parse.camera.show = false }, @@ -223,6 +339,12 @@ window.PageWallet = { if (data.tag === 'payRequest') { this.parse.lnurlpay = Object.freeze(data) this.parse.data.amount = data.minSendable / 1000 + this.receive.units = [ + 'sats', + ...(this.g.allowedCurrencies.length > 0 + ? this.g.allowedCurrencies + : this.g.currencies) + ] } else if (data.tag === 'login') { this.parse.lnurlauth = Object.freeze(data) } else if (data.tag === 'withdrawRequest') { @@ -356,6 +478,9 @@ window.PageWallet = { this.parse.invoice = Object.freeze(cleanInvoice) }, payInvoice() { + if (this.parse.sending) return + + this.parse.sending = true const dismissPaymentMsg = Quasar.Notify.create({ timeout: 0, message: this.$t('payment_processing') @@ -368,6 +493,7 @@ window.PageWallet = { this.parse.data.internalMemo ) .then(response => { + this.parse.sending = false dismissPaymentMsg() this.g.updatePayments = !this.g.updatePayments this.parse.show = false @@ -385,13 +511,16 @@ window.PageWallet = { } }) .catch(err => { + this.parse.sending = false dismissPaymentMsg() LNbits.utils.notifyApiError(err) this.g.updatePayments = !this.g.updatePayments - this.parse.show = false }) }, payLnurl() { + if (this.parse.sending) return + + this.parse.sending = true LNbits.api .request('post', '/api/v1/payments/lnurl', this.g.wallet.adminkey, { res: this.parse.lnurlpay, @@ -402,18 +531,26 @@ window.PageWallet = { internalMemo: this.parse.data.internalMemo }) .then(response => { + this.parse.sending = false this.parse.show = false if (response.data.extra.success_action) { const action = JSON.parse(response.data.extra.success_action) switch (action.tag) { case 'url': Quasar.Notify.create({ - message: `${action.url}`, + message: action.url, caption: action.description, - html: true, + html: false, type: 'positive', timeout: 0, - closeBtn: true + closeBtn: true, + actions: [ + { + label: 'Open link', + color: 'white', + handler: () => this.utils.openUrlInNewTab(action.url) + } + ] }) break case 'message': @@ -425,19 +562,36 @@ window.PageWallet = { }) break case 'aes': - this.utils.decryptLnurlPayAES(action, response.data.preimage) - Quasar.Notify.create({ - message: value, - caption: extra.success_action.description, - html: true, - type: 'positive', - timeout: 0, - closeBtn: true - }) + this.utils + .decryptLnurlPayAES(action, response.data.preimage) + .then(value => { + Quasar.Notify.create({ + message: value, + caption: action.description, + html: false, + type: 'positive', + timeout: 0, + closeBtn: true + }) + }) + .catch(error => { + Quasar.Notify.create({ + message: action.description || 'Payment successful.', + caption: 'Could not decrypt success action.', + html: false, + type: 'warning', + timeout: 0, + closeBtn: true + }) + }) + break } } }) - .catch(LNbits.utils.notifyApiError) + .catch(err => { + this.parse.sending = false + LNbits.utils.notifyApiError(err) + }) }, authLnurl() { const dismissAuthMsg = Quasar.Notify.create({ @@ -477,14 +631,19 @@ window.PageWallet = { LNbits.api .request('PATCH', '/api/v1/wallet', this.g.wallet.adminkey, data) .then(response => { - this.g.wallet = {...this.g.wallet, ...response.data} + const walletData = {...response.data} + if (walletData.lightning_address) { + walletData.lightningAddress = walletData.lightning_address + walletData.lightningAddressFull = `${walletData.lightning_address}@${window.location.host}` + } + this.g.wallet = {...this.g.wallet, ...walletData} const walletIndex = this.g.user.wallets.findIndex( wallet => wallet.id === response.data.id ) if (walletIndex !== -1) { this.g.user.wallets[walletIndex] = { ...this.g.user.wallets[walletIndex], - ...response.data + ...walletData } } Quasar.Notify.create({ @@ -570,7 +729,7 @@ window.PageWallet = { const dismissPaymentMsg = Quasar.Notify.create({ timeout: 0, spinner: true, - message: this.$t('processing_payment') + message: this.$t('payment_processing') }) LNbits.api diff --git a/lnbits/static/js/utils.js b/lnbits/static/js/utils.js index e2ba1d265..7937c9e02 100644 --- a/lnbits/static/js/utils.js +++ b/lnbits/static/js/utils.js @@ -160,6 +160,46 @@ window._lnbitsUtils = { return null } }, + isValidBech32(value) { + if (typeof value !== 'string') { + return false + } + + const candidate = value.trim() + if ( + !candidate || + (candidate !== candidate.toLowerCase() && + candidate !== candidate.toUpperCase()) + ) { + return false + } + + const normalized = candidate.toLowerCase() + const splitPosition = normalized.lastIndexOf('1') + if (splitPosition <= 0) { + return false + } + + const humanReadablePart = normalized.substring(0, splitPosition) + const data = normalized.substring(splitPosition + 1) + if (data.length < 6) { + return false + } + + if ( + typeof bech32ToFiveBitArray !== 'function' || + typeof verify_checksum !== 'function' + ) { + return false + } + + const words = bech32ToFiveBitArray(data) + if (words.some(word => word < 0)) { + return false + } + + return verify_checksum(humanReadablePart, words) + }, async notifyApiError(error) { if (!error.response) { return console.error(error) @@ -283,6 +323,20 @@ window._lnbitsUtils = { converter.setOption('simpleLineBreaks', true) return converter.makeHtml(text) }, + _extI18nDirs: new Set(), + _extI18nLoaded: {}, + loadExtI18n(dir, locale) { + this._extI18nDirs.add(dir) + const loaded = (this._extI18nLoaded[dir] ??= {}) + if (loaded[locale]) return loaded[locale] + loaded[locale] = this.loadScript(`${dir}/${locale}.js`).catch(() => { + if (locale !== 'en') { + loaded['en'] ??= this.loadScript(`${dir}/en.js`).catch(() => {}) + return loaded['en'] + } + }) + return loaded[locale] + }, async decryptLnurlPayAES(success_action, preimage) { let keyb = new Uint8Array( preimage.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16)) @@ -311,5 +365,27 @@ window._lnbitsUtils = { let decoder = new TextDecoder('utf-8') return decoder.decode(valueb) }) + }, + validateBrowsableUrl(urlString, allowLoopback = false) { + const url = new URL(urlString) + if (url.protocol !== 'http:' && url.protocol !== 'https:') { + throw new Error('Invalid protocol') + } + if (!allowLoopback) { + const host = url.hostname + if ( + host === 'localhost' || + host === '[::1]' || + host === '::1' || + host.startsWith('127.') || + host.startsWith('::ffff:127.') + ) { + throw new Error('Loopback addresses are not allowed') + } + } + }, + openUrlInNewTab(urlString, allowLoopback = false) { + this.validateBrowsableUrl(urlString, allowLoopback) + window.open(urlString, '_blank', 'noopener,noreferrer') } } diff --git a/lnbits/static/js/wasm-extension-component.js b/lnbits/static/js/wasm-extension-component.js new file mode 100644 index 000000000..9829415c0 --- /dev/null +++ b/lnbits/static/js/wasm-extension-component.js @@ -0,0 +1,1420 @@ +window.WasmExtensionComponent = { + template: ` +
+ + + + + {{ error }} + + + + + +
Camera access
+
+ + {{ cameraPrompt.extensionName }} wants to access the camera to scan a QR code. + + + + + + +
+
+ + + +
Background payments
+
+ +
+ {{ backgroundPaymentPrompt.extensionName }} wants permission to make + background payments from + {{ backgroundPaymentPrompt.walletName }}. +
+ + This permission can move funds later without an active click. + + + +
+ + + + +
+
+ + + +
Watch wallet payments
+
+ +
+ {{ walletPaymentWatchPrompt.extensionName }} wants permission to receive + payment notifications for + {{ walletPaymentWatchPrompt.walletName }}. +
+ + This permission exposes payment metadata for this wallet to the extension. + +
+ + + + +
+
+ + + +
Open link
+
+ +
+ {{ newTabPrompt.extensionName }} wants to open this link in a new + tab. +
+
+ {{ newTabPrompt.url }} +
+ + This link is not on the same domain as this LNbits page. + +
+ + + + + +
+
+
+ `, + data() { + return { + allowedPaymentHashes: new Set(), + bridge: { + apiRoutes: [], + extensionId: '', + permissions: [], + public: false, + query: {}, + routeParams: {} + }, + bridgePort: null, + cameraPrompt: { + extensionName: '', + reject: null, + resolve: null, + show: false + }, + backgroundPaymentDestinationOptions: [ + { + label: 'Only transfers to my wallets', + value: 'own_wallets_only' + }, + { + label: 'Allow external payments', + value: 'external_allowed' + } + ], + backgroundPaymentPrompt: { + extensionName: '', + form: { + destinationPolicy: 'own_wallets_only', + maxAmount: 0 + }, + reject: null, + resolve: null, + show: false, + walletId: '', + walletName: '' + }, + walletPaymentWatchPrompt: { + extensionName: '', + reject: null, + resolve: null, + show: false, + walletId: '', + walletName: '' + }, + newTabPrompt: { + extensionName: '', + external: false, + reject: null, + resolve: null, + show: false, + url: '' + }, + error: '', + extensionName: '', + frameUrl: '', + handleWindowMessage: null, + loading: false, + loadId: 0, + paymentSubscriptions: new Map(), + websocketSubscriptions: new Map() + } + }, + created() { + this.handleWindowMessage = event => this.onWindowMessage(event) + window.addEventListener('message', this.handleWindowMessage) + }, + unmounted() { + window.removeEventListener('message', this.handleWindowMessage) + this.rejectCameraPrompt('Camera scan cancelled.') + this.rejectBackgroundPaymentPrompt( + 'Background payment permission cancelled.' + ) + this.rejectWalletPaymentWatchPrompt( + 'Wallet payment watch permission cancelled.' + ) + this.rejectNewTabPrompt('Open link cancelled.') + this.closeBridgePort() + }, + watch: { + '$route.fullPath': { + immediate: true, + handler() { + this.loadFrameConfig() + } + } + }, + methods: { + emptyBridge() { + return { + apiRoutes: [], + extensionId: '', + permissions: [], + public: false, + query: {}, + routeParams: {} + } + }, + plainBridgeContext() { + return { + extensionId: String(this.bridge.extensionId || ''), + public: Boolean(this.bridge.public), + routeParams: this.plainValue(this.bridge.routeParams || {}), + query: this.plainValue(this.bridge.query || {}) + } + }, + hasBridgePermission(permission) { + return (this.bridge.permissions || []).includes(permission) + }, + cameraPromptStorageKey() { + return `lnbits.ext.permissions.${this.bridge.extensionId}.ui.camera.scan_qr` + }, + emptyBackgroundPaymentPrompt() { + return { + extensionName: '', + form: { + destinationPolicy: 'own_wallets_only', + maxAmount: 0 + }, + reject: null, + resolve: null, + show: false, + walletId: '', + walletName: '' + } + }, + emptyCameraPrompt() { + return { + extensionName: '', + reject: null, + resolve: null, + show: false + } + }, + emptyWalletPaymentWatchPrompt() { + return { + extensionName: '', + reject: null, + resolve: null, + show: false, + walletId: '', + walletName: '' + } + }, + emptyNewTabPrompt() { + return { + extensionName: '', + external: false, + reject: null, + resolve: null, + show: false, + url: '' + } + }, + plainValue(value) { + try { + return JSON.parse(JSON.stringify(value)) + } catch (_error) { + return {} + } + }, + async loadFrameConfig() { + const extId = String(this.$route.params.extId || '') + const loadId = ++this.loadId + this.loading = true + this.error = '' + this.frameUrl = '' + this.bridge = this.emptyBridge() + this.allowedPaymentHashes.clear() + this.rejectCameraPrompt('Camera scan cancelled.') + this.rejectBackgroundPaymentPrompt( + 'Background payment permission cancelled.' + ) + this.rejectWalletPaymentWatchPrompt( + 'Wallet payment watch permission cancelled.' + ) + this.rejectNewTabPrompt('Open link cancelled.') + this.closeBridgePort() + + try { + const response = await fetch( + `/api/v1/ext/${encodeURIComponent(extId)}/_ui/frame`, + { + method: 'POST', + headers: {'content-type': 'application/json'}, + credentials: 'same-origin', + body: JSON.stringify({ + path: this.$route.path, + query: this.$route.query || {} + }) + } + ) + const text = await response.text() + let data = {} + if (text) { + try { + data = JSON.parse(text) + } catch (_error) { + data = {detail: text} + } + } + if (!response.ok) { + throw new Error(data?.detail || 'Failed to load extension page.') + } + if (loadId !== this.loadId) return + + this.bridge = data.bridge || this.emptyBridge() + this.extensionName = data.extension?.name || extId + this.frameUrl = data.frameUrl + } catch (error) { + if (loadId !== this.loadId) return + console.error('[lnbits wasm extension] Failed to load frame.', error) + this.error = error instanceof Error ? error.message : String(error) + } finally { + if (loadId === this.loadId) { + this.loading = false + } + } + }, + extensionFrameWindow() { + return this.$refs.frame?.contentWindow + }, + sendResponse(reply, id, payload) { + reply({ + type: 'lnbits-extension:response', + id, + ...payload + }) + }, + allowedApiRoute(method, path) { + let url + try { + url = new URL(path, window.location.origin) + } catch (_error) { + return false + } + if (url.origin !== window.location.origin) return false + + method = String(method || 'GET').toUpperCase() + return (this.bridge.apiRoutes || []).some(route => { + return ( + route.method === method && + new RegExp(route.pattern).test(url.pathname) + ) + }) + }, + extensionRoute(path) { + let url + try { + url = new URL(String(path || ''), window.location.origin) + } catch (_error) { + throw new Error('Invalid extension route.') + } + if (url.origin !== window.location.origin) { + throw new Error('Extension route must stay on this server.') + } + + const basePath = `/ext/${encodeURIComponent(this.bridge.extensionId)}` + if ( + url.pathname !== basePath && + !url.pathname.startsWith(`${basePath}/`) + ) { + throw new Error('Extension route must stay inside this extension.') + } + return `${url.pathname}${url.search}${url.hash}` + }, + replaceExtensionRoute(message) { + return this.$router.replace(this.extensionRoute(message.path)) + }, + newTabUrl(rawUrl) { + const raw = String(rawUrl || '').trim() + if (!raw) { + throw new Error('Open link needs a URL.') + } + + let url + try { + url = new URL(raw, window.location.href) + } catch (_error) { + throw new Error('Invalid open link URL.') + } + + if (!['http:', 'https:'].includes(url.protocol)) { + throw new Error('Only HTTP and HTTPS links can be opened.') + } + if (url.username || url.password) { + throw new Error('Links with embedded credentials cannot be opened.') + } + + return { + external: url.origin !== window.location.origin, + url: url.href + } + }, + openNewTab(message) { + return this.promptNewTabOpen(this.newTabUrl(message.url || message.href)) + }, + promptNewTabOpen(link) { + if (this.newTabPrompt.show) { + throw new Error('Open link prompt is already open.') + } + + return new Promise((resolve, reject) => { + this.newTabPrompt = { + extensionName: + this.extensionName || this.bridge.extensionId || 'This extension', + external: link.external, + reject, + resolve, + show: true, + url: link.url + } + }) + }, + resolveNewTabPrompt(approved) { + const prompt = this.newTabPrompt + if (!prompt.show) return + this.newTabPrompt = this.emptyNewTabPrompt() + + if (!approved) { + prompt.reject?.(new Error('Open link denied by user.')) + return + } + + try { + window.open(prompt.url, '_blank', 'noopener,noreferrer') + prompt.resolve?.({ + external: prompt.external, + opened: true, + url: prompt.url + }) + } catch (error) { + prompt.reject?.(error) + } + }, + rejectNewTabPrompt(message) { + const reject = this.newTabPrompt.reject + this.newTabPrompt = this.emptyNewTabPrompt() + reject?.(new Error(message)) + }, + async copyNewTabLink() { + const prompt = this.newTabPrompt + if (!prompt.show || !prompt.url) return + + try { + await navigator.clipboard.writeText(prompt.url) + this.notify({ + level: 'positive', + message: 'Link copied.' + }) + } catch (_error) { + this.notify({ + level: 'negative', + message: 'Could not copy link.' + }) + } + }, + bridgeSessionStorageKey(rawKey) { + const key = String(rawKey || '').trim() + if (!key || key.length > 128 || !/^[A-Za-z0-9._:-]+$/.test(key)) { + throw new Error('Invalid extension session key.') + } + return `lnbits.ext.session.${this.bridge.extensionId}.${key}` + }, + getBridgeSessionValue(message) { + const key = this.bridgeSessionStorageKey(message.key) + return {value: window.sessionStorage.getItem(key) || ''} + }, + setBridgeSessionValue(message) { + const key = this.bridgeSessionStorageKey(message.key) + const value = String(message.value || '') + if (value.length > 4096) { + throw new Error('Extension session value is too large.') + } + window.sessionStorage.setItem(key, value) + return {ok: true} + }, + async callApi(message) { + const method = String(message.method || 'GET').toUpperCase() + const path = String(message.path || '') + if (!this.allowedApiRoute(method, path)) { + throw new Error('Extension API route is not allowed.') + } + + const options = { + method, + headers: {}, + credentials: 'same-origin' + } + if (message.body !== undefined && message.body !== null) { + options.headers['content-type'] = 'application/json' + options.body = JSON.stringify(message.body) + } + + const response = await fetch(path, options) + const text = await response.text() + let data = text + if (text) { + try { + data = JSON.parse(text) + } catch (_error) { + data = text + } + } + if (!response.ok) { + throw new Error( + typeof data === 'object' && data.detail ? data.detail : text + ) + } + this.rememberPaymentHashes(data) + return data + }, + notify(message) { + const level = ['positive', 'negative', 'warning', 'info'].includes( + message.level + ) + ? message.level + : 'info' + if (window.Quasar?.Notify) { + window.Quasar.Notify.create({ + color: level, + message: String(message.message || '') + }) + } + }, + async scanQrCode() { + if (!this.hasBridgePermission('ui.camera.scan_qr')) { + throw new Error('Extension is missing scanner permission.') + } + if (!this.g) { + throw new Error('LNbits scanner is not available.') + } + if (this.g.scanner) { + throw new Error('A scanner is already active.') + } + await this.requireCameraScanApproval() + if (this.g.scanner) { + throw new Error('A scanner is already active.') + } + + return new Promise((resolve, reject) => { + let completed = false + + const cleanup = () => { + window.clearTimeout(timeout) + window.clearInterval(cancelPoll) + if (this.g.scanner === onScan) { + this.g.scanner = null + } + } + + const complete = callback => value => { + if (completed) return + completed = true + cleanup() + callback(value) + } + + const onScan = value => { + complete(resolve)({value: String(value || '')}) + } + + const timeout = window.setTimeout(() => { + complete(reject)(new Error('QR scan timed out.')) + }, 120000) + + const cancelPoll = window.setInterval(() => { + if (!completed && this.g.scanner !== onScan) { + complete(reject)(new Error('QR scan cancelled.')) + } + }, 250) + + this.g.scanner = onScan + }) + }, + async requestBackgroundPaymentPermission(message) { + const response = await this.requestExtensionPermissions({ + forcePrompt: message?.forcePrompt === true, + permissions: [ + { + id: 'wallet.pay_invoice_background', + grant: message?.grant || {} + } + ] + }) + return response.permissions?.[0] || response + }, + async requestWalletPaymentWatchPermission(message) { + const response = await this.requestExtensionPermissions({ + permissions: [ + { + id: 'wallet.payments.watch', + grant: message?.grant || {} + } + ] + }) + return response.permissions?.[0] || response + }, + async requestExtensionPermissions(message) { + if (this.bridge.public) { + throw new Error('Public pages cannot request permissions.') + } + const permissions = Array.isArray(message.permissions) + ? message.permissions + : [] + if (!permissions.length) { + throw new Error('No permissions requested.') + } + const forcePrompt = message.forcePrompt === true + + const requestedPermissions = permissions.map(permission => + this.normalizePermissionRequest(permission) + ) + const checkResult = await this.checkExtensionPermissions( + requestedPermissions.map(permission => ({ + id: permission.id, + grant: permission.grant + })) + ) + const checks = Array.isArray(checkResult?.permissions) + ? checkResult.permissions + : [] + const approvedLabels = [] + const results = [] + + for (const [index, permission] of requestedPermissions.entries()) { + const check = checks[index] || {} + if (check.id && check.id !== permission.id) { + throw new Error('Permission check response did not match request.') + } + + if (check.approved && !forcePrompt) { + approvedLabels.push(permission.label) + results.push({ + id: permission.id, + approved: true, + grant: check.grant || permission.grant + }) + continue + } + + const promptPermission = check.grant + ? {...permission, grant: check.grant} + : permission + const granted = await this.promptExtensionPermission(promptPermission) + results.push({ + id: permission.id, + approved: true, + grant: granted?.grant || permission.grant + }) + } + + this.notifyApprovedPermissionUse(approvedLabels) + return {permissions: results} + }, + normalizePermissionRequest(permission) { + const id = String(permission?.id || '') + const grant = permission?.grant || {} + if (id === 'wallet.pay_invoice_background') { + return this.normalizeBackgroundPaymentPermission(grant) + } + if (id === 'wallet.payments.watch') { + return this.normalizeWalletPaymentWatchPermission(grant) + } + throw new Error(`Unsupported permission request: ${id}.`) + }, + normalizeBackgroundPaymentPermission(grant) { + if (!this.hasBridgePermission('wallet.pay_invoice_background')) { + throw new Error('Extension is missing background payment permission.') + } + + const walletId = String(grant.walletId || grant.wallet_id || '') + const wallet = this.walletById(walletId) + if (!wallet) { + throw new Error('Selected wallet is not available.') + } + if (wallet.walletType === 'lightning-shared') { + throw new Error( + 'Background payments are not allowed from shared wallets.' + ) + } + + const requestedGrant = { + wallet_id: walletId, + max_amount: this.positiveInteger( + grant.maxAmount || grant.max_amount, + 1000 + ), + destination_policy: this.backgroundPaymentDestinationPolicy( + grant.destinationPolicy || grant.destination_policy + ) + } + if (!requestedGrant.max_amount) { + throw new Error('Max payment amount must be greater than zero.') + } + + return { + id: 'wallet.pay_invoice_background', + grant: requestedGrant, + label: `Background payments from ${wallet.name || walletId}`, + wallet + } + }, + normalizeWalletPaymentWatchPermission(grant) { + if (!this.hasBridgePermission('wallet.payments.watch')) { + throw new Error('Extension is missing wallet payment watch permission.') + } + + const walletId = String(grant.walletId || grant.wallet_id || '') + const wallet = this.walletById(walletId) + if (!wallet) { + throw new Error('Selected wallet is not available.') + } + + return { + id: 'wallet.payments.watch', + grant: {wallet_id: walletId}, + label: `Watch wallet payments for ${wallet.name || walletId}`, + wallet + } + }, + walletById(walletId) { + return ( + (this.g?.user?.wallets || []).find(wallet => wallet.id === walletId) || + null + ) + }, + async checkExtensionPermissions(permissions) { + return await this.postExtensionPermission( + 'check', + {permissions}, + 'Could not check extension permissions.' + ) + }, + promptExtensionPermission(permission) { + if (permission.id === 'wallet.pay_invoice_background') { + return this.promptBackgroundPaymentPermission(permission) + } + if (permission.id === 'wallet.payments.watch') { + return this.promptWalletPaymentWatchPermission(permission) + } + throw new Error(`Unsupported permission request: ${permission.id}.`) + }, + promptBackgroundPaymentPermission(permission) { + if (this.backgroundPaymentPrompt.show) { + throw new Error('Background payment prompt is already open.') + } + + return new Promise((resolve, reject) => { + this.backgroundPaymentPrompt = { + extensionName: + this.extensionName || this.bridge.extensionId || 'This extension', + form: { + destinationPolicy: permission.grant.destination_policy, + maxAmount: permission.grant.max_amount + }, + reject, + resolve, + show: true, + walletId: permission.grant.wallet_id, + walletName: permission.wallet.name || permission.grant.wallet_id + } + }) + }, + async resolveBackgroundPaymentPrompt(approved) { + const prompt = this.backgroundPaymentPrompt + if (!prompt.show) return + + if (!approved) { + this.backgroundPaymentPrompt = this.emptyBackgroundPaymentPrompt() + prompt.reject?.(new Error('Background payment permission denied.')) + return + } + + try { + const grant = { + wallet_id: prompt.walletId, + max_amount: this.positiveInteger(prompt.form.maxAmount, 0), + destination_policy: this.backgroundPaymentDestinationPolicy( + prompt.form.destinationPolicy + ) + } + if (!grant.max_amount) { + throw new Error('Max payment amount must be greater than zero.') + } + + const data = await this.postExtensionPermission( + 'background-payment', + grant, + 'Could not save permission.' + ) + + this.backgroundPaymentPrompt = this.emptyBackgroundPaymentPrompt() + prompt.resolve?.(data) + } catch (error) { + prompt.reject?.(error) + this.backgroundPaymentPrompt = this.emptyBackgroundPaymentPrompt() + } + }, + rejectBackgroundPaymentPrompt(message) { + const reject = this.backgroundPaymentPrompt.reject + this.backgroundPaymentPrompt = this.emptyBackgroundPaymentPrompt() + reject?.(new Error(message)) + }, + promptWalletPaymentWatchPermission(permission) { + if (this.walletPaymentWatchPrompt.show) { + throw new Error('Wallet payment watch prompt is already open.') + } + + return new Promise((resolve, reject) => { + this.walletPaymentWatchPrompt = { + extensionName: + this.extensionName || this.bridge.extensionId || 'This extension', + reject, + resolve, + show: true, + walletId: permission.grant.wallet_id, + walletName: permission.wallet.name || permission.grant.wallet_id + } + }) + }, + async resolveWalletPaymentWatchPrompt(approved) { + const prompt = this.walletPaymentWatchPrompt + if (!prompt.show) return + + if (!approved) { + this.walletPaymentWatchPrompt = this.emptyWalletPaymentWatchPrompt() + prompt.reject?.(new Error('Wallet payment watch permission denied.')) + return + } + + try { + const data = await this.postExtensionPermission( + 'wallet-payments-watch', + {wallet_id: prompt.walletId}, + 'Could not save permission.' + ) + + this.walletPaymentWatchPrompt = this.emptyWalletPaymentWatchPrompt() + prompt.resolve?.(data) + } catch (error) { + prompt.reject?.(error) + this.walletPaymentWatchPrompt = this.emptyWalletPaymentWatchPrompt() + } + }, + rejectWalletPaymentWatchPrompt(message) { + const reject = this.walletPaymentWatchPrompt.reject + this.walletPaymentWatchPrompt = this.emptyWalletPaymentWatchPrompt() + reject?.(new Error(message)) + }, + positiveInteger(value, fallback) { + const number = Number(value) + if (!Number.isFinite(number) || number <= 0) return fallback + return Math.floor(number) + }, + backgroundPaymentDestinationPolicy(value) { + return value === 'external_allowed' + ? 'external_allowed' + : 'own_wallets_only' + }, + async postExtensionPermission(path, body, fallbackMessage) { + const response = await fetch( + `/api/v1/extension/${encodeURIComponent( + this.bridge.extensionId + )}/permissions/${path}`, + { + method: 'POST', + headers: {'content-type': 'application/json'}, + credentials: 'same-origin', + body: JSON.stringify(body) + } + ) + const text = await response.text() + let data = {} + if (text) { + try { + data = JSON.parse(text) + } catch (_error) { + data = {detail: text} + } + } + if (!response.ok) { + throw new Error(data?.detail || fallbackMessage) + } + return data + }, + notifyApprovedPermissionUse(permissions) { + const permissionList = permissions.filter(Boolean).join(', ') + if (!permissionList) return + this.notify({ + level: 'info', + message: `Using approved permissions: ${permissionList}.` + }) + }, + requireCameraScanApproval() { + if (this.isCameraScanRemembered()) return Promise.resolve() + if (this.cameraPrompt.show) { + return Promise.reject( + new Error('Camera access prompt is already open.') + ) + } + + return new Promise((resolve, reject) => { + this.cameraPrompt = { + extensionName: + this.extensionName || this.bridge.extensionId || 'This extension', + reject, + resolve, + show: true + } + }) + }, + isCameraScanRemembered() { + try { + return ( + this.$q.localStorage.getItem(this.cameraPromptStorageKey()) === + 'allow' + ) + } catch (_error) { + return false + } + }, + rememberCameraScanApproval() { + try { + this.$q.localStorage.set(this.cameraPromptStorageKey(), 'allow') + } catch (_error) {} + }, + resolveCameraPrompt(decision) { + const resolve = this.cameraPrompt.resolve + const reject = this.cameraPrompt.reject + this.cameraPrompt = this.emptyCameraPrompt() + + if (decision === 'allow_remember') { + this.rememberCameraScanApproval() + resolve?.() + return + } + if (decision === 'allow') { + resolve?.() + return + } + reject?.(new Error('Camera scan denied by user.')) + }, + rejectCameraPrompt(message) { + const reject = this.cameraPrompt.reject + this.cameraPrompt = this.emptyCameraPrompt() + reject?.(new Error(message)) + }, + rememberPaymentHashes(value) { + if (!value || typeof value !== 'object') return + + if (Array.isArray(value)) { + value.forEach(item => this.rememberPaymentHashes(item)) + return + } + + for (const [key, item] of Object.entries(value)) { + if ( + ['paymentHash', 'payment_hash'].includes(key) && + this.isPaymentHash(item) + ) { + this.allowedPaymentHashes.add(item) + } + this.rememberPaymentHashes(item) + } + }, + isPaymentHash(value) { + return typeof value === 'string' && /^[a-f0-9]{64}$/i.test(value) + }, + isWebsocketItemId(value) { + return ( + typeof value === 'string' && + /^[A-Za-z0-9][A-Za-z0-9:_-]{0,127}$/.test(value) + ) + }, + websocketUrl(path) { + const url = new URL(window.location.href) + url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:' + url.pathname = path + url.search = '' + url.hash = '' + return url.toString() + }, + sendBridgeEvent(message) { + if (!this.bridgePort) return + this.bridgePort.postMessage({ + type: 'lnbits-extension:event', + ...message + }) + }, + closePaymentSubscription(subscriptionId) { + const subscription = this.paymentSubscriptions.get(subscriptionId) + if (!subscription) return + this.paymentSubscriptions.delete(subscriptionId) + try { + subscription.socket.close() + } catch (_error) {} + }, + closePaymentSubscriptions() { + for (const subscriptionId of Array.from( + this.paymentSubscriptions.keys() + )) { + this.closePaymentSubscription(subscriptionId) + } + }, + closeWebsocketSubscription(subscriptionId) { + const subscription = this.websocketSubscriptions.get(subscriptionId) + if (!subscription) return + this.websocketSubscriptions.delete(subscriptionId) + try { + subscription.socket.close() + } catch (_error) {} + }, + closeWebsocketSubscriptions() { + for (const subscriptionId of Array.from( + this.websocketSubscriptions.keys() + )) { + this.closeWebsocketSubscription(subscriptionId) + } + }, + closeBridgePort() { + this.closePaymentSubscriptions() + this.closeWebsocketSubscriptions() + this.bridgePort?.close() + this.bridgePort = null + }, + subscribePayment(message) { + const subscriptionId = String(message.subscriptionId || '') + const paymentHash = String(message.paymentHash || '') + + if (!subscriptionId || !this.isPaymentHash(paymentHash)) { + throw new Error('Invalid payment subscription.') + } + if (!this.allowedPaymentHashes.has(paymentHash)) { + throw new Error('Payment subscription is not allowed.') + } + + this.closePaymentSubscription(subscriptionId) + + const socket = new WebSocket( + this.websocketUrl(`/api/v1/ws/${encodeURIComponent(paymentHash)}`) + ) + this.paymentSubscriptions.set(subscriptionId, {paymentHash, socket}) + + socket.addEventListener('message', event => { + let data = event.data + try { + data = JSON.parse(event.data) + } catch (_error) {} + + this.sendBridgeEvent({ + event: 'payment.update', + subscriptionId, + paymentHash, + data + }) + + if ( + data && + typeof data === 'object' && + (data.pending === false || + ['success', 'settled', 'paid'].includes(String(data.status || ''))) + ) { + this.sendBridgeEvent({ + event: 'payment.settled', + subscriptionId, + paymentHash, + data + }) + this.closePaymentSubscription(subscriptionId) + } + }) + socket.addEventListener('error', () => { + this.sendBridgeEvent({ + event: 'payment.error', + subscriptionId, + paymentHash + }) + this.closePaymentSubscription(subscriptionId) + }) + socket.addEventListener('close', () => { + this.paymentSubscriptions.delete(subscriptionId) + }) + }, + subscribeWebsocket(message) { + if (!this.hasBridgePermission('websocket.subscribe')) { + throw new Error('Extension is missing websocket subscribe permission.') + } + + const subscriptionId = String(message.subscriptionId || '') + const itemId = String(message.itemId || '') + + if ( + !subscriptionId || + subscriptionId.length > 128 || + !this.isWebsocketItemId(itemId) + ) { + throw new Error('Invalid websocket subscription.') + } + + this.closeWebsocketSubscription(subscriptionId) + + const socket = new WebSocket( + this.websocketUrl( + `/api/v1/ext/ws/${encodeURIComponent( + this.bridge.extensionId + )}/${encodeURIComponent(itemId)}` + ) + ) + this.websocketSubscriptions.set(subscriptionId, {itemId, socket}) + + socket.addEventListener('message', event => { + let data = event.data + try { + data = JSON.parse(event.data) + } catch (_error) {} + + this.sendBridgeEvent({ + event: 'websocket.message', + subscriptionId, + itemId, + data + }) + }) + socket.addEventListener('error', () => { + this.sendBridgeEvent({ + event: 'websocket.error', + subscriptionId, + itemId + }) + this.closeWebsocketSubscription(subscriptionId) + }) + socket.addEventListener('close', () => { + this.websocketSubscriptions.delete(subscriptionId) + }) + }, + sendWebsocket(message) { + if (!this.hasBridgePermission('websocket.subscribe')) { + throw new Error('Extension is missing websocket subscribe permission.') + } + + const subscriptionId = String(message.subscriptionId || '') + if (!subscriptionId) { + throw new Error('Invalid websocket subscription.') + } + + const subscription = this.websocketSubscriptions.get(subscriptionId) + if (!subscription) { + return + } + + if (subscription.socket.readyState !== WebSocket.OPEN) { + if ( + subscription.socket.readyState === WebSocket.CLOSING || + subscription.socket.readyState === WebSocket.CLOSED + ) { + this.closeWebsocketSubscription(subscriptionId) + } + return + } + + const data = + typeof message.data === 'string' + ? message.data + : JSON.stringify(message.data ?? {}) + subscription.socket.send(data) + }, + async handleBridgeRequest(message, reply) { + if (!message || message.type !== 'lnbits-extension:request') return + + try { + if (message.action === 'context') { + this.sendResponse(reply, message.id, { + ok: true, + data: this.plainBridgeContext() + }) + return + } + + if (message.action === 'api') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.callApi(message) + }) + return + } + + if (message.action === 'ui.notify') { + this.notify(message) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'navigation.replace') { + await this.replaceExtensionRoute(message) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'navigation.open_new_tab') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.openNewTab(message) + }) + return + } + + if (message.action === 'storage.session.get') { + this.sendResponse(reply, message.id, { + ok: true, + data: this.getBridgeSessionValue(message) + }) + return + } + + if (message.action === 'storage.session.set') { + this.sendResponse(reply, message.id, { + ok: true, + data: this.setBridgeSessionValue(message) + }) + return + } + + if (message.action === 'ui.scan_qr') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.scanQrCode() + }) + return + } + + if (message.action === 'permissions.request') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.requestExtensionPermissions(message) + }) + return + } + + if (message.action === 'permissions.request_background_payment') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.requestBackgroundPaymentPermission(message) + }) + return + } + + if (message.action === 'permissions.request_wallet_payment_watch') { + this.sendResponse(reply, message.id, { + ok: true, + data: await this.requestWalletPaymentWatchPermission(message) + }) + return + } + + if (message.action === 'payment.subscribe') { + this.subscribePayment(message) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'payment.unsubscribe') { + this.closePaymentSubscription(String(message.subscriptionId || '')) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'websocket.subscribe') { + this.subscribeWebsocket(message) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'websocket.unsubscribe') { + this.closeWebsocketSubscription(String(message.subscriptionId || '')) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + if (message.action === 'websocket.send') { + this.sendWebsocket(message) + this.sendResponse(reply, message.id, { + ok: true, + data: {ok: true} + }) + return + } + + throw new Error('Unknown extension bridge action.') + } catch (error) { + this.sendResponse(reply, message.id, { + ok: false, + error: error instanceof Error ? error.message : String(error) + }) + } + }, + onWindowMessage(event) { + if (event.source !== this.extensionFrameWindow()) return + const message = event.data + if (!message || message.type !== 'lnbits-extension:connect') return + + const port = event.ports?.[0] + if (!port) return + + this.closeBridgePort() + this.bridgePort = port + this.bridgePort.addEventListener('message', portEvent => { + this.handleBridgeRequest(portEvent.data, response => { + port.postMessage(response) + }) + }) + this.bridgePort.start() + this.bridgePort.postMessage({ + type: 'lnbits-extension:connected', + id: message.id + }) + } + } +} diff --git a/lnbits/static/scss/background.scss b/lnbits/static/scss/background.scss index 63acc3c84..ca4bb83c4 100644 --- a/lnbits/static/scss/background.scss +++ b/lnbits/static/scss/background.scss @@ -58,11 +58,15 @@ body.bg-image { } // transparent background for specific elements body.body--dark { - .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark), + .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { + --q-dark: #{color.adjust(#1d1d1d, $alpha: -0.7)}; + background-color: var(--q-dark); + } + .q-header, .q-drawer { --q-dark: #{color.adjust(#1d1d1d, $alpha: -0.7)}; background-color: var(--q-dark); - backdrop-filter: blur(6px) brightness(0.8); + backdrop-filter: brightness(0.8); } } diff --git a/lnbits/static/scss/cards.scss b/lnbits/static/scss/cards.scss index 6b190ec50..b0d931ad9 100644 --- a/lnbits/static/scss/cards.scss +++ b/lnbits/static/scss/cards.scss @@ -61,12 +61,21 @@ body.rounded-ui { body.card-shadow { .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { - filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.18)); + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.18); } } body.card-shadow.body--dark { .q-card:not(.q-dialog .q-card, .lnbits__dialog-card, .q-dialog-plugin--dark) { - filter: drop-shadow(0 12px 28px rgba(0, 0, 0, 0.45)); + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45); + } +} + +body.no-burger-background { + .q-drawer { + background-color: transparent !important; + background-image: none !important; + backdrop-filter: none !important; + box-shadow: none !important; } } diff --git a/lnbits/static/vendor.json b/lnbits/static/vendor.json index 41751b9b7..1fc80b98c 100644 --- a/lnbits/static/vendor.json +++ b/lnbits/static/vendor.json @@ -33,6 +33,7 @@ "i18n/sk.js", "i18n/kr.js", "i18n/fi.js", + "i18n/fo.js", "js/utils.js", "js/api.js", "js/globals.js", @@ -58,6 +59,7 @@ "js/pages/users.js", "js/pages/account.js", "js/pages/admin.js", + "js/components/admin/lnbits-admin-funding-seed-backup.js", "js/components/admin/lnbits-admin-funding.js", "js/components/admin/lnbits-admin-funding-sources.js", "js/components/admin/lnbits-admin-fiat-providers.js", @@ -66,10 +68,14 @@ "js/components/admin/lnbits-admin-users.js", "js/components/admin/lnbits-admin-server.js", "js/components/admin/lnbits-admin-extensions.js", + "js/components/admin/lnbits-admin-wasm-runtime.js", + "js/components/admin/lnbits-admin-wasm-limit-config.js", "js/components/admin/lnbits-admin-notifications.js", "js/components/admin/lnbits-admin-site-customisation.js", "js/components/admin/lnbits-admin-assets-config.js", "js/components/admin/lnbits-admin-audit.js", + "js/components/admin/lnbits-admin-blockexplorer.js", + "js/pages/blockexplorer.js", "js/components/lnbits-wallet-charts.js", "js/components/lnbits-wallet-api-docs.js", "js/components/lnbits-wallet-icon.js", @@ -89,6 +95,7 @@ "js/components/lnbits-theme.js", "js/components/lnbits-qrcode-scanner.js", "js/components/lnbits-manage-extension-list.js", + "js/components/lnbits-extension-permissions.js", "js/components/lnbits-manage-wallet-list.js", "js/components/lnbits-language-dropdown.js", "js/components/lnbits-payment-list.js", @@ -96,6 +103,7 @@ "js/components/extension-settings.js", "js/components/data-fields.js", "js/components.js", + "js/wasm-extension-component.js", "js/init-app.js" ], "css": ["vendor/quasar.css", "css/base.css"] diff --git a/lnbits/static/vendor/Chart.bundle.js b/lnbits/static/vendor/Chart.bundle.js deleted file mode 100755 index c852f5b8f..000000000 --- a/lnbits/static/vendor/Chart.bundle.js +++ /dev/null @@ -1,20776 +0,0 @@ -/*! - * Chart.js v2.9.4 - * https://www.chartjs.org - * (c) 2020 Chart.js Contributors - * Released under the MIT License - */ -(function (global, factory) { -typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : -typeof define === 'function' && define.amd ? define(factory) : -(global = global || self, global.Chart = factory()); -}(this, (function () { 'use strict'; - -var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - -function commonjsRequire () { - throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); -} - -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} - -function getCjsExportFromNamespace (n) { - return n && n['default'] || n; -} - -var colorName = { - "aliceblue": [240, 248, 255], - "antiquewhite": [250, 235, 215], - "aqua": [0, 255, 255], - "aquamarine": [127, 255, 212], - "azure": [240, 255, 255], - "beige": [245, 245, 220], - "bisque": [255, 228, 196], - "black": [0, 0, 0], - "blanchedalmond": [255, 235, 205], - "blue": [0, 0, 255], - "blueviolet": [138, 43, 226], - "brown": [165, 42, 42], - "burlywood": [222, 184, 135], - "cadetblue": [95, 158, 160], - "chartreuse": [127, 255, 0], - "chocolate": [210, 105, 30], - "coral": [255, 127, 80], - "cornflowerblue": [100, 149, 237], - "cornsilk": [255, 248, 220], - "crimson": [220, 20, 60], - "cyan": [0, 255, 255], - "darkblue": [0, 0, 139], - "darkcyan": [0, 139, 139], - "darkgoldenrod": [184, 134, 11], - "darkgray": [169, 169, 169], - "darkgreen": [0, 100, 0], - "darkgrey": [169, 169, 169], - "darkkhaki": [189, 183, 107], - "darkmagenta": [139, 0, 139], - "darkolivegreen": [85, 107, 47], - "darkorange": [255, 140, 0], - "darkorchid": [153, 50, 204], - "darkred": [139, 0, 0], - "darksalmon": [233, 150, 122], - "darkseagreen": [143, 188, 143], - "darkslateblue": [72, 61, 139], - "darkslategray": [47, 79, 79], - "darkslategrey": [47, 79, 79], - "darkturquoise": [0, 206, 209], - "darkviolet": [148, 0, 211], - "deeppink": [255, 20, 147], - "deepskyblue": [0, 191, 255], - "dimgray": [105, 105, 105], - "dimgrey": [105, 105, 105], - "dodgerblue": [30, 144, 255], - "firebrick": [178, 34, 34], - "floralwhite": [255, 250, 240], - "forestgreen": [34, 139, 34], - "fuchsia": [255, 0, 255], - "gainsboro": [220, 220, 220], - "ghostwhite": [248, 248, 255], - "gold": [255, 215, 0], - "goldenrod": [218, 165, 32], - "gray": [128, 128, 128], - "green": [0, 128, 0], - "greenyellow": [173, 255, 47], - "grey": [128, 128, 128], - "honeydew": [240, 255, 240], - "hotpink": [255, 105, 180], - "indianred": [205, 92, 92], - "indigo": [75, 0, 130], - "ivory": [255, 255, 240], - "khaki": [240, 230, 140], - "lavender": [230, 230, 250], - "lavenderblush": [255, 240, 245], - "lawngreen": [124, 252, 0], - "lemonchiffon": [255, 250, 205], - "lightblue": [173, 216, 230], - "lightcoral": [240, 128, 128], - "lightcyan": [224, 255, 255], - "lightgoldenrodyellow": [250, 250, 210], - "lightgray": [211, 211, 211], - "lightgreen": [144, 238, 144], - "lightgrey": [211, 211, 211], - "lightpink": [255, 182, 193], - "lightsalmon": [255, 160, 122], - "lightseagreen": [32, 178, 170], - "lightskyblue": [135, 206, 250], - "lightslategray": [119, 136, 153], - "lightslategrey": [119, 136, 153], - "lightsteelblue": [176, 196, 222], - "lightyellow": [255, 255, 224], - "lime": [0, 255, 0], - "limegreen": [50, 205, 50], - "linen": [250, 240, 230], - "magenta": [255, 0, 255], - "maroon": [128, 0, 0], - "mediumaquamarine": [102, 205, 170], - "mediumblue": [0, 0, 205], - "mediumorchid": [186, 85, 211], - "mediumpurple": [147, 112, 219], - "mediumseagreen": [60, 179, 113], - "mediumslateblue": [123, 104, 238], - "mediumspringgreen": [0, 250, 154], - "mediumturquoise": [72, 209, 204], - "mediumvioletred": [199, 21, 133], - "midnightblue": [25, 25, 112], - "mintcream": [245, 255, 250], - "mistyrose": [255, 228, 225], - "moccasin": [255, 228, 181], - "navajowhite": [255, 222, 173], - "navy": [0, 0, 128], - "oldlace": [253, 245, 230], - "olive": [128, 128, 0], - "olivedrab": [107, 142, 35], - "orange": [255, 165, 0], - "orangered": [255, 69, 0], - "orchid": [218, 112, 214], - "palegoldenrod": [238, 232, 170], - "palegreen": [152, 251, 152], - "paleturquoise": [175, 238, 238], - "palevioletred": [219, 112, 147], - "papayawhip": [255, 239, 213], - "peachpuff": [255, 218, 185], - "peru": [205, 133, 63], - "pink": [255, 192, 203], - "plum": [221, 160, 221], - "powderblue": [176, 224, 230], - "purple": [128, 0, 128], - "rebeccapurple": [102, 51, 153], - "red": [255, 0, 0], - "rosybrown": [188, 143, 143], - "royalblue": [65, 105, 225], - "saddlebrown": [139, 69, 19], - "salmon": [250, 128, 114], - "sandybrown": [244, 164, 96], - "seagreen": [46, 139, 87], - "seashell": [255, 245, 238], - "sienna": [160, 82, 45], - "silver": [192, 192, 192], - "skyblue": [135, 206, 235], - "slateblue": [106, 90, 205], - "slategray": [112, 128, 144], - "slategrey": [112, 128, 144], - "snow": [255, 250, 250], - "springgreen": [0, 255, 127], - "steelblue": [70, 130, 180], - "tan": [210, 180, 140], - "teal": [0, 128, 128], - "thistle": [216, 191, 216], - "tomato": [255, 99, 71], - "turquoise": [64, 224, 208], - "violet": [238, 130, 238], - "wheat": [245, 222, 179], - "white": [255, 255, 255], - "whitesmoke": [245, 245, 245], - "yellow": [255, 255, 0], - "yellowgreen": [154, 205, 50] -}; - -var conversions = createCommonjsModule(function (module) { -/* MIT license */ - - -// NOTE: conversions should only return primitive values (i.e. arrays, or -// values that give correct `typeof` results). -// do not use box values types (i.e. Number(), String(), etc.) - -var reverseKeywords = {}; -for (var key in colorName) { - if (colorName.hasOwnProperty(key)) { - reverseKeywords[colorName[key]] = key; - } -} - -var convert = module.exports = { - rgb: {channels: 3, labels: 'rgb'}, - hsl: {channels: 3, labels: 'hsl'}, - hsv: {channels: 3, labels: 'hsv'}, - hwb: {channels: 3, labels: 'hwb'}, - cmyk: {channels: 4, labels: 'cmyk'}, - xyz: {channels: 3, labels: 'xyz'}, - lab: {channels: 3, labels: 'lab'}, - lch: {channels: 3, labels: 'lch'}, - hex: {channels: 1, labels: ['hex']}, - keyword: {channels: 1, labels: ['keyword']}, - ansi16: {channels: 1, labels: ['ansi16']}, - ansi256: {channels: 1, labels: ['ansi256']}, - hcg: {channels: 3, labels: ['h', 'c', 'g']}, - apple: {channels: 3, labels: ['r16', 'g16', 'b16']}, - gray: {channels: 1, labels: ['gray']} -}; - -// hide .channels and .labels properties -for (var model in convert) { - if (convert.hasOwnProperty(model)) { - if (!('channels' in convert[model])) { - throw new Error('missing channels property: ' + model); - } - - if (!('labels' in convert[model])) { - throw new Error('missing channel labels property: ' + model); - } - - if (convert[model].labels.length !== convert[model].channels) { - throw new Error('channel and label counts mismatch: ' + model); - } - - var channels = convert[model].channels; - var labels = convert[model].labels; - delete convert[model].channels; - delete convert[model].labels; - Object.defineProperty(convert[model], 'channels', {value: channels}); - Object.defineProperty(convert[model], 'labels', {value: labels}); - } -} - -convert.rgb.hsl = function (rgb) { - var r = rgb[0] / 255; - var g = rgb[1] / 255; - var b = rgb[2] / 255; - var min = Math.min(r, g, b); - var max = Math.max(r, g, b); - var delta = max - min; - var h; - var s; - var l; - - if (max === min) { - h = 0; - } else if (r === max) { - h = (g - b) / delta; - } else if (g === max) { - h = 2 + (b - r) / delta; - } else if (b === max) { - h = 4 + (r - g) / delta; - } - - h = Math.min(h * 60, 360); - - if (h < 0) { - h += 360; - } - - l = (min + max) / 2; - - if (max === min) { - s = 0; - } else if (l <= 0.5) { - s = delta / (max + min); - } else { - s = delta / (2 - max - min); - } - - return [h, s * 100, l * 100]; -}; - -convert.rgb.hsv = function (rgb) { - var rdif; - var gdif; - var bdif; - var h; - var s; - - var r = rgb[0] / 255; - var g = rgb[1] / 255; - var b = rgb[2] / 255; - var v = Math.max(r, g, b); - var diff = v - Math.min(r, g, b); - var diffc = function (c) { - return (v - c) / 6 / diff + 1 / 2; - }; - - if (diff === 0) { - h = s = 0; - } else { - s = diff / v; - rdif = diffc(r); - gdif = diffc(g); - bdif = diffc(b); - - if (r === v) { - h = bdif - gdif; - } else if (g === v) { - h = (1 / 3) + rdif - bdif; - } else if (b === v) { - h = (2 / 3) + gdif - rdif; - } - if (h < 0) { - h += 1; - } else if (h > 1) { - h -= 1; - } - } - - return [ - h * 360, - s * 100, - v * 100 - ]; -}; - -convert.rgb.hwb = function (rgb) { - var r = rgb[0]; - var g = rgb[1]; - var b = rgb[2]; - var h = convert.rgb.hsl(rgb)[0]; - var w = 1 / 255 * Math.min(r, Math.min(g, b)); - - b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); - - return [h, w * 100, b * 100]; -}; - -convert.rgb.cmyk = function (rgb) { - var r = rgb[0] / 255; - var g = rgb[1] / 255; - var b = rgb[2] / 255; - var c; - var m; - var y; - var k; - - k = Math.min(1 - r, 1 - g, 1 - b); - c = (1 - r - k) / (1 - k) || 0; - m = (1 - g - k) / (1 - k) || 0; - y = (1 - b - k) / (1 - k) || 0; - - return [c * 100, m * 100, y * 100, k * 100]; -}; - -/** - * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance - * */ -function comparativeDistance(x, y) { - return ( - Math.pow(x[0] - y[0], 2) + - Math.pow(x[1] - y[1], 2) + - Math.pow(x[2] - y[2], 2) - ); -} - -convert.rgb.keyword = function (rgb) { - var reversed = reverseKeywords[rgb]; - if (reversed) { - return reversed; - } - - var currentClosestDistance = Infinity; - var currentClosestKeyword; - - for (var keyword in colorName) { - if (colorName.hasOwnProperty(keyword)) { - var value = colorName[keyword]; - - // Compute comparative distance - var distance = comparativeDistance(rgb, value); - - // Check if its less, if so set as closest - if (distance < currentClosestDistance) { - currentClosestDistance = distance; - currentClosestKeyword = keyword; - } - } - } - - return currentClosestKeyword; -}; - -convert.keyword.rgb = function (keyword) { - return colorName[keyword]; -}; - -convert.rgb.xyz = function (rgb) { - var r = rgb[0] / 255; - var g = rgb[1] / 255; - var b = rgb[2] / 255; - - // assume sRGB - r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); - g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); - b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); - - var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); - var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); - var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); - - return [x * 100, y * 100, z * 100]; -}; - -convert.rgb.lab = function (rgb) { - var xyz = convert.rgb.xyz(rgb); - var x = xyz[0]; - var y = xyz[1]; - var z = xyz[2]; - var l; - var a; - var b; - - x /= 95.047; - y /= 100; - z /= 108.883; - - x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); - y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); - z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); - - l = (116 * y) - 16; - a = 500 * (x - y); - b = 200 * (y - z); - - return [l, a, b]; -}; - -convert.hsl.rgb = function (hsl) { - var h = hsl[0] / 360; - var s = hsl[1] / 100; - var l = hsl[2] / 100; - var t1; - var t2; - var t3; - var rgb; - var val; - - if (s === 0) { - val = l * 255; - return [val, val, val]; - } - - if (l < 0.5) { - t2 = l * (1 + s); - } else { - t2 = l + s - l * s; - } - - t1 = 2 * l - t2; - - rgb = [0, 0, 0]; - for (var i = 0; i < 3; i++) { - t3 = h + 1 / 3 * -(i - 1); - if (t3 < 0) { - t3++; - } - if (t3 > 1) { - t3--; - } - - if (6 * t3 < 1) { - val = t1 + (t2 - t1) * 6 * t3; - } else if (2 * t3 < 1) { - val = t2; - } else if (3 * t3 < 2) { - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; - } else { - val = t1; - } - - rgb[i] = val * 255; - } - - return rgb; -}; - -convert.hsl.hsv = function (hsl) { - var h = hsl[0]; - var s = hsl[1] / 100; - var l = hsl[2] / 100; - var smin = s; - var lmin = Math.max(l, 0.01); - var sv; - var v; - - l *= 2; - s *= (l <= 1) ? l : 2 - l; - smin *= lmin <= 1 ? lmin : 2 - lmin; - v = (l + s) / 2; - sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s); - - return [h, sv * 100, v * 100]; -}; - -convert.hsv.rgb = function (hsv) { - var h = hsv[0] / 60; - var s = hsv[1] / 100; - var v = hsv[2] / 100; - var hi = Math.floor(h) % 6; - - var f = h - Math.floor(h); - var p = 255 * v * (1 - s); - var q = 255 * v * (1 - (s * f)); - var t = 255 * v * (1 - (s * (1 - f))); - v *= 255; - - switch (hi) { - case 0: - return [v, t, p]; - case 1: - return [q, v, p]; - case 2: - return [p, v, t]; - case 3: - return [p, q, v]; - case 4: - return [t, p, v]; - case 5: - return [v, p, q]; - } -}; - -convert.hsv.hsl = function (hsv) { - var h = hsv[0]; - var s = hsv[1] / 100; - var v = hsv[2] / 100; - var vmin = Math.max(v, 0.01); - var lmin; - var sl; - var l; - - l = (2 - s) * v; - lmin = (2 - s) * vmin; - sl = s * vmin; - sl /= (lmin <= 1) ? lmin : 2 - lmin; - sl = sl || 0; - l /= 2; - - return [h, sl * 100, l * 100]; -}; - -// http://dev.w3.org/csswg/css-color/#hwb-to-rgb -convert.hwb.rgb = function (hwb) { - var h = hwb[0] / 360; - var wh = hwb[1] / 100; - var bl = hwb[2] / 100; - var ratio = wh + bl; - var i; - var v; - var f; - var n; - - // wh + bl cant be > 1 - if (ratio > 1) { - wh /= ratio; - bl /= ratio; - } - - i = Math.floor(6 * h); - v = 1 - bl; - f = 6 * h - i; - - if ((i & 0x01) !== 0) { - f = 1 - f; - } - - n = wh + f * (v - wh); // linear interpolation - - var r; - var g; - var b; - switch (i) { - default: - case 6: - case 0: r = v; g = n; b = wh; break; - case 1: r = n; g = v; b = wh; break; - case 2: r = wh; g = v; b = n; break; - case 3: r = wh; g = n; b = v; break; - case 4: r = n; g = wh; b = v; break; - case 5: r = v; g = wh; b = n; break; - } - - return [r * 255, g * 255, b * 255]; -}; - -convert.cmyk.rgb = function (cmyk) { - var c = cmyk[0] / 100; - var m = cmyk[1] / 100; - var y = cmyk[2] / 100; - var k = cmyk[3] / 100; - var r; - var g; - var b; - - r = 1 - Math.min(1, c * (1 - k) + k); - g = 1 - Math.min(1, m * (1 - k) + k); - b = 1 - Math.min(1, y * (1 - k) + k); - - return [r * 255, g * 255, b * 255]; -}; - -convert.xyz.rgb = function (xyz) { - var x = xyz[0] / 100; - var y = xyz[1] / 100; - var z = xyz[2] / 100; - var r; - var g; - var b; - - r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); - g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); - b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); - - // assume sRGB - r = r > 0.0031308 - ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) - : r * 12.92; - - g = g > 0.0031308 - ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) - : g * 12.92; - - b = b > 0.0031308 - ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) - : b * 12.92; - - r = Math.min(Math.max(0, r), 1); - g = Math.min(Math.max(0, g), 1); - b = Math.min(Math.max(0, b), 1); - - return [r * 255, g * 255, b * 255]; -}; - -convert.xyz.lab = function (xyz) { - var x = xyz[0]; - var y = xyz[1]; - var z = xyz[2]; - var l; - var a; - var b; - - x /= 95.047; - y /= 100; - z /= 108.883; - - x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); - y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); - z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); - - l = (116 * y) - 16; - a = 500 * (x - y); - b = 200 * (y - z); - - return [l, a, b]; -}; - -convert.lab.xyz = function (lab) { - var l = lab[0]; - var a = lab[1]; - var b = lab[2]; - var x; - var y; - var z; - - y = (l + 16) / 116; - x = a / 500 + y; - z = y - b / 200; - - var y2 = Math.pow(y, 3); - var x2 = Math.pow(x, 3); - var z2 = Math.pow(z, 3); - y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787; - x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787; - z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787; - - x *= 95.047; - y *= 100; - z *= 108.883; - - return [x, y, z]; -}; - -convert.lab.lch = function (lab) { - var l = lab[0]; - var a = lab[1]; - var b = lab[2]; - var hr; - var h; - var c; - - hr = Math.atan2(b, a); - h = hr * 360 / 2 / Math.PI; - - if (h < 0) { - h += 360; - } - - c = Math.sqrt(a * a + b * b); - - return [l, c, h]; -}; - -convert.lch.lab = function (lch) { - var l = lch[0]; - var c = lch[1]; - var h = lch[2]; - var a; - var b; - var hr; - - hr = h / 360 * 2 * Math.PI; - a = c * Math.cos(hr); - b = c * Math.sin(hr); - - return [l, a, b]; -}; - -convert.rgb.ansi16 = function (args) { - var r = args[0]; - var g = args[1]; - var b = args[2]; - var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization - - value = Math.round(value / 50); - - if (value === 0) { - return 30; - } - - var ansi = 30 - + ((Math.round(b / 255) << 2) - | (Math.round(g / 255) << 1) - | Math.round(r / 255)); - - if (value === 2) { - ansi += 60; - } - - return ansi; -}; - -convert.hsv.ansi16 = function (args) { - // optimization here; we already know the value and don't need to get - // it converted for us. - return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]); -}; - -convert.rgb.ansi256 = function (args) { - var r = args[0]; - var g = args[1]; - var b = args[2]; - - // we use the extended greyscale palette here, with the exception of - // black and white. normal palette only has 4 greyscale shades. - if (r === g && g === b) { - if (r < 8) { - return 16; - } - - if (r > 248) { - return 231; - } - - return Math.round(((r - 8) / 247) * 24) + 232; - } - - var ansi = 16 - + (36 * Math.round(r / 255 * 5)) - + (6 * Math.round(g / 255 * 5)) - + Math.round(b / 255 * 5); - - return ansi; -}; - -convert.ansi16.rgb = function (args) { - var color = args % 10; - - // handle greyscale - if (color === 0 || color === 7) { - if (args > 50) { - color += 3.5; - } - - color = color / 10.5 * 255; - - return [color, color, color]; - } - - var mult = (~~(args > 50) + 1) * 0.5; - var r = ((color & 1) * mult) * 255; - var g = (((color >> 1) & 1) * mult) * 255; - var b = (((color >> 2) & 1) * mult) * 255; - - return [r, g, b]; -}; - -convert.ansi256.rgb = function (args) { - // handle greyscale - if (args >= 232) { - var c = (args - 232) * 10 + 8; - return [c, c, c]; - } - - args -= 16; - - var rem; - var r = Math.floor(args / 36) / 5 * 255; - var g = Math.floor((rem = args % 36) / 6) / 5 * 255; - var b = (rem % 6) / 5 * 255; - - return [r, g, b]; -}; - -convert.rgb.hex = function (args) { - var integer = ((Math.round(args[0]) & 0xFF) << 16) - + ((Math.round(args[1]) & 0xFF) << 8) - + (Math.round(args[2]) & 0xFF); - - var string = integer.toString(16).toUpperCase(); - return '000000'.substring(string.length) + string; -}; - -convert.hex.rgb = function (args) { - var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); - if (!match) { - return [0, 0, 0]; - } - - var colorString = match[0]; - - if (match[0].length === 3) { - colorString = colorString.split('').map(function (char) { - return char + char; - }).join(''); - } - - var integer = parseInt(colorString, 16); - var r = (integer >> 16) & 0xFF; - var g = (integer >> 8) & 0xFF; - var b = integer & 0xFF; - - return [r, g, b]; -}; - -convert.rgb.hcg = function (rgb) { - var r = rgb[0] / 255; - var g = rgb[1] / 255; - var b = rgb[2] / 255; - var max = Math.max(Math.max(r, g), b); - var min = Math.min(Math.min(r, g), b); - var chroma = (max - min); - var grayscale; - var hue; - - if (chroma < 1) { - grayscale = min / (1 - chroma); - } else { - grayscale = 0; - } - - if (chroma <= 0) { - hue = 0; - } else - if (max === r) { - hue = ((g - b) / chroma) % 6; - } else - if (max === g) { - hue = 2 + (b - r) / chroma; - } else { - hue = 4 + (r - g) / chroma + 4; - } - - hue /= 6; - hue %= 1; - - return [hue * 360, chroma * 100, grayscale * 100]; -}; - -convert.hsl.hcg = function (hsl) { - var s = hsl[1] / 100; - var l = hsl[2] / 100; - var c = 1; - var f = 0; - - if (l < 0.5) { - c = 2.0 * s * l; - } else { - c = 2.0 * s * (1.0 - l); - } - - if (c < 1.0) { - f = (l - 0.5 * c) / (1.0 - c); - } - - return [hsl[0], c * 100, f * 100]; -}; - -convert.hsv.hcg = function (hsv) { - var s = hsv[1] / 100; - var v = hsv[2] / 100; - - var c = s * v; - var f = 0; - - if (c < 1.0) { - f = (v - c) / (1 - c); - } - - return [hsv[0], c * 100, f * 100]; -}; - -convert.hcg.rgb = function (hcg) { - var h = hcg[0] / 360; - var c = hcg[1] / 100; - var g = hcg[2] / 100; - - if (c === 0.0) { - return [g * 255, g * 255, g * 255]; - } - - var pure = [0, 0, 0]; - var hi = (h % 1) * 6; - var v = hi % 1; - var w = 1 - v; - var mg = 0; - - switch (Math.floor(hi)) { - case 0: - pure[0] = 1; pure[1] = v; pure[2] = 0; break; - case 1: - pure[0] = w; pure[1] = 1; pure[2] = 0; break; - case 2: - pure[0] = 0; pure[1] = 1; pure[2] = v; break; - case 3: - pure[0] = 0; pure[1] = w; pure[2] = 1; break; - case 4: - pure[0] = v; pure[1] = 0; pure[2] = 1; break; - default: - pure[0] = 1; pure[1] = 0; pure[2] = w; - } - - mg = (1.0 - c) * g; - - return [ - (c * pure[0] + mg) * 255, - (c * pure[1] + mg) * 255, - (c * pure[2] + mg) * 255 - ]; -}; - -convert.hcg.hsv = function (hcg) { - var c = hcg[1] / 100; - var g = hcg[2] / 100; - - var v = c + g * (1.0 - c); - var f = 0; - - if (v > 0.0) { - f = c / v; - } - - return [hcg[0], f * 100, v * 100]; -}; - -convert.hcg.hsl = function (hcg) { - var c = hcg[1] / 100; - var g = hcg[2] / 100; - - var l = g * (1.0 - c) + 0.5 * c; - var s = 0; - - if (l > 0.0 && l < 0.5) { - s = c / (2 * l); - } else - if (l >= 0.5 && l < 1.0) { - s = c / (2 * (1 - l)); - } - - return [hcg[0], s * 100, l * 100]; -}; - -convert.hcg.hwb = function (hcg) { - var c = hcg[1] / 100; - var g = hcg[2] / 100; - var v = c + g * (1.0 - c); - return [hcg[0], (v - c) * 100, (1 - v) * 100]; -}; - -convert.hwb.hcg = function (hwb) { - var w = hwb[1] / 100; - var b = hwb[2] / 100; - var v = 1 - b; - var c = v - w; - var g = 0; - - if (c < 1) { - g = (v - c) / (1 - c); - } - - return [hwb[0], c * 100, g * 100]; -}; - -convert.apple.rgb = function (apple) { - return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255]; -}; - -convert.rgb.apple = function (rgb) { - return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535]; -}; - -convert.gray.rgb = function (args) { - return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]; -}; - -convert.gray.hsl = convert.gray.hsv = function (args) { - return [0, 0, args[0]]; -}; - -convert.gray.hwb = function (gray) { - return [0, 100, gray[0]]; -}; - -convert.gray.cmyk = function (gray) { - return [0, 0, 0, gray[0]]; -}; - -convert.gray.lab = function (gray) { - return [gray[0], 0, 0]; -}; - -convert.gray.hex = function (gray) { - var val = Math.round(gray[0] / 100 * 255) & 0xFF; - var integer = (val << 16) + (val << 8) + val; - - var string = integer.toString(16).toUpperCase(); - return '000000'.substring(string.length) + string; -}; - -convert.rgb.gray = function (rgb) { - var val = (rgb[0] + rgb[1] + rgb[2]) / 3; - return [val / 255 * 100]; -}; -}); -var conversions_1 = conversions.rgb; -var conversions_2 = conversions.hsl; -var conversions_3 = conversions.hsv; -var conversions_4 = conversions.hwb; -var conversions_5 = conversions.cmyk; -var conversions_6 = conversions.xyz; -var conversions_7 = conversions.lab; -var conversions_8 = conversions.lch; -var conversions_9 = conversions.hex; -var conversions_10 = conversions.keyword; -var conversions_11 = conversions.ansi16; -var conversions_12 = conversions.ansi256; -var conversions_13 = conversions.hcg; -var conversions_14 = conversions.apple; -var conversions_15 = conversions.gray; - -/* - this function routes a model to all other models. - - all functions that are routed have a property `.conversion` attached - to the returned synthetic function. This property is an array - of strings, each with the steps in between the 'from' and 'to' - color models (inclusive). - - conversions that are not possible simply are not included. -*/ - -function buildGraph() { - var graph = {}; - // https://jsperf.com/object-keys-vs-for-in-with-closure/3 - var models = Object.keys(conversions); - - for (var len = models.length, i = 0; i < len; i++) { - graph[models[i]] = { - // http://jsperf.com/1-vs-infinity - // micro-opt, but this is simple. - distance: -1, - parent: null - }; - } - - return graph; -} - -// https://en.wikipedia.org/wiki/Breadth-first_search -function deriveBFS(fromModel) { - var graph = buildGraph(); - var queue = [fromModel]; // unshift -> queue -> pop - - graph[fromModel].distance = 0; - - while (queue.length) { - var current = queue.pop(); - var adjacents = Object.keys(conversions[current]); - - for (var len = adjacents.length, i = 0; i < len; i++) { - var adjacent = adjacents[i]; - var node = graph[adjacent]; - - if (node.distance === -1) { - node.distance = graph[current].distance + 1; - node.parent = current; - queue.unshift(adjacent); - } - } - } - - return graph; -} - -function link(from, to) { - return function (args) { - return to(from(args)); - }; -} - -function wrapConversion(toModel, graph) { - var path = [graph[toModel].parent, toModel]; - var fn = conversions[graph[toModel].parent][toModel]; - - var cur = graph[toModel].parent; - while (graph[cur].parent) { - path.unshift(graph[cur].parent); - fn = link(conversions[graph[cur].parent][cur], fn); - cur = graph[cur].parent; - } - - fn.conversion = path; - return fn; -} - -var route = function (fromModel) { - var graph = deriveBFS(fromModel); - var conversion = {}; - - var models = Object.keys(graph); - for (var len = models.length, i = 0; i < len; i++) { - var toModel = models[i]; - var node = graph[toModel]; - - if (node.parent === null) { - // no possible conversion, or this node is the source model. - continue; - } - - conversion[toModel] = wrapConversion(toModel, graph); - } - - return conversion; -}; - -var convert = {}; - -var models = Object.keys(conversions); - -function wrapRaw(fn) { - var wrappedFn = function (args) { - if (args === undefined || args === null) { - return args; - } - - if (arguments.length > 1) { - args = Array.prototype.slice.call(arguments); - } - - return fn(args); - }; - - // preserve .conversion property if there is one - if ('conversion' in fn) { - wrappedFn.conversion = fn.conversion; - } - - return wrappedFn; -} - -function wrapRounded(fn) { - var wrappedFn = function (args) { - if (args === undefined || args === null) { - return args; - } - - if (arguments.length > 1) { - args = Array.prototype.slice.call(arguments); - } - - var result = fn(args); - - // we're assuming the result is an array here. - // see notice in conversions.js; don't use box types - // in conversion functions. - if (typeof result === 'object') { - for (var len = result.length, i = 0; i < len; i++) { - result[i] = Math.round(result[i]); - } - } - - return result; - }; - - // preserve .conversion property if there is one - if ('conversion' in fn) { - wrappedFn.conversion = fn.conversion; - } - - return wrappedFn; -} - -models.forEach(function (fromModel) { - convert[fromModel] = {}; - - Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels}); - Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels}); - - var routes = route(fromModel); - var routeModels = Object.keys(routes); - - routeModels.forEach(function (toModel) { - var fn = routes[toModel]; - - convert[fromModel][toModel] = wrapRounded(fn); - convert[fromModel][toModel].raw = wrapRaw(fn); - }); -}); - -var colorConvert = convert; - -var colorName$1 = { - "aliceblue": [240, 248, 255], - "antiquewhite": [250, 235, 215], - "aqua": [0, 255, 255], - "aquamarine": [127, 255, 212], - "azure": [240, 255, 255], - "beige": [245, 245, 220], - "bisque": [255, 228, 196], - "black": [0, 0, 0], - "blanchedalmond": [255, 235, 205], - "blue": [0, 0, 255], - "blueviolet": [138, 43, 226], - "brown": [165, 42, 42], - "burlywood": [222, 184, 135], - "cadetblue": [95, 158, 160], - "chartreuse": [127, 255, 0], - "chocolate": [210, 105, 30], - "coral": [255, 127, 80], - "cornflowerblue": [100, 149, 237], - "cornsilk": [255, 248, 220], - "crimson": [220, 20, 60], - "cyan": [0, 255, 255], - "darkblue": [0, 0, 139], - "darkcyan": [0, 139, 139], - "darkgoldenrod": [184, 134, 11], - "darkgray": [169, 169, 169], - "darkgreen": [0, 100, 0], - "darkgrey": [169, 169, 169], - "darkkhaki": [189, 183, 107], - "darkmagenta": [139, 0, 139], - "darkolivegreen": [85, 107, 47], - "darkorange": [255, 140, 0], - "darkorchid": [153, 50, 204], - "darkred": [139, 0, 0], - "darksalmon": [233, 150, 122], - "darkseagreen": [143, 188, 143], - "darkslateblue": [72, 61, 139], - "darkslategray": [47, 79, 79], - "darkslategrey": [47, 79, 79], - "darkturquoise": [0, 206, 209], - "darkviolet": [148, 0, 211], - "deeppink": [255, 20, 147], - "deepskyblue": [0, 191, 255], - "dimgray": [105, 105, 105], - "dimgrey": [105, 105, 105], - "dodgerblue": [30, 144, 255], - "firebrick": [178, 34, 34], - "floralwhite": [255, 250, 240], - "forestgreen": [34, 139, 34], - "fuchsia": [255, 0, 255], - "gainsboro": [220, 220, 220], - "ghostwhite": [248, 248, 255], - "gold": [255, 215, 0], - "goldenrod": [218, 165, 32], - "gray": [128, 128, 128], - "green": [0, 128, 0], - "greenyellow": [173, 255, 47], - "grey": [128, 128, 128], - "honeydew": [240, 255, 240], - "hotpink": [255, 105, 180], - "indianred": [205, 92, 92], - "indigo": [75, 0, 130], - "ivory": [255, 255, 240], - "khaki": [240, 230, 140], - "lavender": [230, 230, 250], - "lavenderblush": [255, 240, 245], - "lawngreen": [124, 252, 0], - "lemonchiffon": [255, 250, 205], - "lightblue": [173, 216, 230], - "lightcoral": [240, 128, 128], - "lightcyan": [224, 255, 255], - "lightgoldenrodyellow": [250, 250, 210], - "lightgray": [211, 211, 211], - "lightgreen": [144, 238, 144], - "lightgrey": [211, 211, 211], - "lightpink": [255, 182, 193], - "lightsalmon": [255, 160, 122], - "lightseagreen": [32, 178, 170], - "lightskyblue": [135, 206, 250], - "lightslategray": [119, 136, 153], - "lightslategrey": [119, 136, 153], - "lightsteelblue": [176, 196, 222], - "lightyellow": [255, 255, 224], - "lime": [0, 255, 0], - "limegreen": [50, 205, 50], - "linen": [250, 240, 230], - "magenta": [255, 0, 255], - "maroon": [128, 0, 0], - "mediumaquamarine": [102, 205, 170], - "mediumblue": [0, 0, 205], - "mediumorchid": [186, 85, 211], - "mediumpurple": [147, 112, 219], - "mediumseagreen": [60, 179, 113], - "mediumslateblue": [123, 104, 238], - "mediumspringgreen": [0, 250, 154], - "mediumturquoise": [72, 209, 204], - "mediumvioletred": [199, 21, 133], - "midnightblue": [25, 25, 112], - "mintcream": [245, 255, 250], - "mistyrose": [255, 228, 225], - "moccasin": [255, 228, 181], - "navajowhite": [255, 222, 173], - "navy": [0, 0, 128], - "oldlace": [253, 245, 230], - "olive": [128, 128, 0], - "olivedrab": [107, 142, 35], - "orange": [255, 165, 0], - "orangered": [255, 69, 0], - "orchid": [218, 112, 214], - "palegoldenrod": [238, 232, 170], - "palegreen": [152, 251, 152], - "paleturquoise": [175, 238, 238], - "palevioletred": [219, 112, 147], - "papayawhip": [255, 239, 213], - "peachpuff": [255, 218, 185], - "peru": [205, 133, 63], - "pink": [255, 192, 203], - "plum": [221, 160, 221], - "powderblue": [176, 224, 230], - "purple": [128, 0, 128], - "rebeccapurple": [102, 51, 153], - "red": [255, 0, 0], - "rosybrown": [188, 143, 143], - "royalblue": [65, 105, 225], - "saddlebrown": [139, 69, 19], - "salmon": [250, 128, 114], - "sandybrown": [244, 164, 96], - "seagreen": [46, 139, 87], - "seashell": [255, 245, 238], - "sienna": [160, 82, 45], - "silver": [192, 192, 192], - "skyblue": [135, 206, 235], - "slateblue": [106, 90, 205], - "slategray": [112, 128, 144], - "slategrey": [112, 128, 144], - "snow": [255, 250, 250], - "springgreen": [0, 255, 127], - "steelblue": [70, 130, 180], - "tan": [210, 180, 140], - "teal": [0, 128, 128], - "thistle": [216, 191, 216], - "tomato": [255, 99, 71], - "turquoise": [64, 224, 208], - "violet": [238, 130, 238], - "wheat": [245, 222, 179], - "white": [255, 255, 255], - "whitesmoke": [245, 245, 245], - "yellow": [255, 255, 0], - "yellowgreen": [154, 205, 50] -}; - -/* MIT license */ - - -var colorString = { - getRgba: getRgba, - getHsla: getHsla, - getRgb: getRgb, - getHsl: getHsl, - getHwb: getHwb, - getAlpha: getAlpha, - - hexString: hexString, - rgbString: rgbString, - rgbaString: rgbaString, - percentString: percentString, - percentaString: percentaString, - hslString: hslString, - hslaString: hslaString, - hwbString: hwbString, - keyword: keyword -}; - -function getRgba(string) { - if (!string) { - return; - } - var abbr = /^#([a-fA-F0-9]{3,4})$/i, - hex = /^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i, - rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i, - per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i, - keyword = /(\w+)/; - - var rgb = [0, 0, 0], - a = 1, - match = string.match(abbr), - hexAlpha = ""; - if (match) { - match = match[1]; - hexAlpha = match[3]; - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match[i] + match[i], 16); - } - if (hexAlpha) { - a = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100; - } - } - else if (match = string.match(hex)) { - hexAlpha = match[2]; - match = match[1]; - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16); - } - if (hexAlpha) { - a = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100; - } - } - else if (match = string.match(rgba)) { - for (var i = 0; i < rgb.length; i++) { - rgb[i] = parseInt(match[i + 1]); - } - a = parseFloat(match[4]); - } - else if (match = string.match(per)) { - for (var i = 0; i < rgb.length; i++) { - rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55); - } - a = parseFloat(match[4]); - } - else if (match = string.match(keyword)) { - if (match[1] == "transparent") { - return [0, 0, 0, 0]; - } - rgb = colorName$1[match[1]]; - if (!rgb) { - return; - } - } - - for (var i = 0; i < rgb.length; i++) { - rgb[i] = scale(rgb[i], 0, 255); - } - if (!a && a != 0) { - a = 1; - } - else { - a = scale(a, 0, 1); - } - rgb[3] = a; - return rgb; -} - -function getHsla(string) { - if (!string) { - return; - } - var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; - var match = string.match(hsl); - if (match) { - var alpha = parseFloat(match[4]); - var h = scale(parseInt(match[1]), 0, 360), - s = scale(parseFloat(match[2]), 0, 100), - l = scale(parseFloat(match[3]), 0, 100), - a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); - return [h, s, l, a]; - } -} - -function getHwb(string) { - if (!string) { - return; - } - var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/; - var match = string.match(hwb); - if (match) { - var alpha = parseFloat(match[4]); - var h = scale(parseInt(match[1]), 0, 360), - w = scale(parseFloat(match[2]), 0, 100), - b = scale(parseFloat(match[3]), 0, 100), - a = scale(isNaN(alpha) ? 1 : alpha, 0, 1); - return [h, w, b, a]; - } -} - -function getRgb(string) { - var rgba = getRgba(string); - return rgba && rgba.slice(0, 3); -} - -function getHsl(string) { - var hsla = getHsla(string); - return hsla && hsla.slice(0, 3); -} - -function getAlpha(string) { - var vals = getRgba(string); - if (vals) { - return vals[3]; - } - else if (vals = getHsla(string)) { - return vals[3]; - } - else if (vals = getHwb(string)) { - return vals[3]; - } -} - -// generators -function hexString(rgba, a) { - var a = (a !== undefined && rgba.length === 3) ? a : rgba[3]; - return "#" + hexDouble(rgba[0]) - + hexDouble(rgba[1]) - + hexDouble(rgba[2]) - + ( - (a >= 0 && a < 1) - ? hexDouble(Math.round(a * 255)) - : "" - ); -} - -function rgbString(rgba, alpha) { - if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { - return rgbaString(rgba, alpha); - } - return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")"; -} - -function rgbaString(rgba, alpha) { - if (alpha === undefined) { - alpha = (rgba[3] !== undefined ? rgba[3] : 1); - } - return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] - + ", " + alpha + ")"; -} - -function percentString(rgba, alpha) { - if (alpha < 1 || (rgba[3] && rgba[3] < 1)) { - return percentaString(rgba, alpha); - } - var r = Math.round(rgba[0]/255 * 100), - g = Math.round(rgba[1]/255 * 100), - b = Math.round(rgba[2]/255 * 100); - - return "rgb(" + r + "%, " + g + "%, " + b + "%)"; -} - -function percentaString(rgba, alpha) { - var r = Math.round(rgba[0]/255 * 100), - g = Math.round(rgba[1]/255 * 100), - b = Math.round(rgba[2]/255 * 100); - return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")"; -} - -function hslString(hsla, alpha) { - if (alpha < 1 || (hsla[3] && hsla[3] < 1)) { - return hslaString(hsla, alpha); - } - return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)"; -} - -function hslaString(hsla, alpha) { - if (alpha === undefined) { - alpha = (hsla[3] !== undefined ? hsla[3] : 1); - } - return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, " - + alpha + ")"; -} - -// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax -// (hwb have alpha optional & 1 is default value) -function hwbString(hwb, alpha) { - if (alpha === undefined) { - alpha = (hwb[3] !== undefined ? hwb[3] : 1); - } - return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%" - + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")"; -} - -function keyword(rgb) { - return reverseNames[rgb.slice(0, 3)]; -} - -// helpers -function scale(num, min, max) { - return Math.min(Math.max(min, num), max); -} - -function hexDouble(num) { - var str = num.toString(16).toUpperCase(); - return (str.length < 2) ? "0" + str : str; -} - - -//create a list of reverse color names -var reverseNames = {}; -for (var name in colorName$1) { - reverseNames[colorName$1[name]] = name; -} - -/* MIT license */ - - - -var Color = function (obj) { - if (obj instanceof Color) { - return obj; - } - if (!(this instanceof Color)) { - return new Color(obj); - } - - this.valid = false; - this.values = { - rgb: [0, 0, 0], - hsl: [0, 0, 0], - hsv: [0, 0, 0], - hwb: [0, 0, 0], - cmyk: [0, 0, 0, 0], - alpha: 1 - }; - - // parse Color() argument - var vals; - if (typeof obj === 'string') { - vals = colorString.getRgba(obj); - if (vals) { - this.setValues('rgb', vals); - } else if (vals = colorString.getHsla(obj)) { - this.setValues('hsl', vals); - } else if (vals = colorString.getHwb(obj)) { - this.setValues('hwb', vals); - } - } else if (typeof obj === 'object') { - vals = obj; - if (vals.r !== undefined || vals.red !== undefined) { - this.setValues('rgb', vals); - } else if (vals.l !== undefined || vals.lightness !== undefined) { - this.setValues('hsl', vals); - } else if (vals.v !== undefined || vals.value !== undefined) { - this.setValues('hsv', vals); - } else if (vals.w !== undefined || vals.whiteness !== undefined) { - this.setValues('hwb', vals); - } else if (vals.c !== undefined || vals.cyan !== undefined) { - this.setValues('cmyk', vals); - } - } -}; - -Color.prototype = { - isValid: function () { - return this.valid; - }, - rgb: function () { - return this.setSpace('rgb', arguments); - }, - hsl: function () { - return this.setSpace('hsl', arguments); - }, - hsv: function () { - return this.setSpace('hsv', arguments); - }, - hwb: function () { - return this.setSpace('hwb', arguments); - }, - cmyk: function () { - return this.setSpace('cmyk', arguments); - }, - - rgbArray: function () { - return this.values.rgb; - }, - hslArray: function () { - return this.values.hsl; - }, - hsvArray: function () { - return this.values.hsv; - }, - hwbArray: function () { - var values = this.values; - if (values.alpha !== 1) { - return values.hwb.concat([values.alpha]); - } - return values.hwb; - }, - cmykArray: function () { - return this.values.cmyk; - }, - rgbaArray: function () { - var values = this.values; - return values.rgb.concat([values.alpha]); - }, - hslaArray: function () { - var values = this.values; - return values.hsl.concat([values.alpha]); - }, - alpha: function (val) { - if (val === undefined) { - return this.values.alpha; - } - this.setValues('alpha', val); - return this; - }, - - red: function (val) { - return this.setChannel('rgb', 0, val); - }, - green: function (val) { - return this.setChannel('rgb', 1, val); - }, - blue: function (val) { - return this.setChannel('rgb', 2, val); - }, - hue: function (val) { - if (val) { - val %= 360; - val = val < 0 ? 360 + val : val; - } - return this.setChannel('hsl', 0, val); - }, - saturation: function (val) { - return this.setChannel('hsl', 1, val); - }, - lightness: function (val) { - return this.setChannel('hsl', 2, val); - }, - saturationv: function (val) { - return this.setChannel('hsv', 1, val); - }, - whiteness: function (val) { - return this.setChannel('hwb', 1, val); - }, - blackness: function (val) { - return this.setChannel('hwb', 2, val); - }, - value: function (val) { - return this.setChannel('hsv', 2, val); - }, - cyan: function (val) { - return this.setChannel('cmyk', 0, val); - }, - magenta: function (val) { - return this.setChannel('cmyk', 1, val); - }, - yellow: function (val) { - return this.setChannel('cmyk', 2, val); - }, - black: function (val) { - return this.setChannel('cmyk', 3, val); - }, - - hexString: function () { - return colorString.hexString(this.values.rgb); - }, - rgbString: function () { - return colorString.rgbString(this.values.rgb, this.values.alpha); - }, - rgbaString: function () { - return colorString.rgbaString(this.values.rgb, this.values.alpha); - }, - percentString: function () { - return colorString.percentString(this.values.rgb, this.values.alpha); - }, - hslString: function () { - return colorString.hslString(this.values.hsl, this.values.alpha); - }, - hslaString: function () { - return colorString.hslaString(this.values.hsl, this.values.alpha); - }, - hwbString: function () { - return colorString.hwbString(this.values.hwb, this.values.alpha); - }, - keyword: function () { - return colorString.keyword(this.values.rgb, this.values.alpha); - }, - - rgbNumber: function () { - var rgb = this.values.rgb; - return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; - }, - - luminosity: function () { - // http://www.w3.org/TR/WCAG20/#relativeluminancedef - var rgb = this.values.rgb; - var lum = []; - for (var i = 0; i < rgb.length; i++) { - var chan = rgb[i] / 255; - lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4); - } - return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]; - }, - - contrast: function (color2) { - // http://www.w3.org/TR/WCAG20/#contrast-ratiodef - var lum1 = this.luminosity(); - var lum2 = color2.luminosity(); - if (lum1 > lum2) { - return (lum1 + 0.05) / (lum2 + 0.05); - } - return (lum2 + 0.05) / (lum1 + 0.05); - }, - - level: function (color2) { - var contrastRatio = this.contrast(color2); - if (contrastRatio >= 7.1) { - return 'AAA'; - } - - return (contrastRatio >= 4.5) ? 'AA' : ''; - }, - - dark: function () { - // YIQ equation from http://24ways.org/2010/calculating-color-contrast - var rgb = this.values.rgb; - var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; - return yiq < 128; - }, - - light: function () { - return !this.dark(); - }, - - negate: function () { - var rgb = []; - for (var i = 0; i < 3; i++) { - rgb[i] = 255 - this.values.rgb[i]; - } - this.setValues('rgb', rgb); - return this; - }, - - lighten: function (ratio) { - var hsl = this.values.hsl; - hsl[2] += hsl[2] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - darken: function (ratio) { - var hsl = this.values.hsl; - hsl[2] -= hsl[2] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - saturate: function (ratio) { - var hsl = this.values.hsl; - hsl[1] += hsl[1] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - desaturate: function (ratio) { - var hsl = this.values.hsl; - hsl[1] -= hsl[1] * ratio; - this.setValues('hsl', hsl); - return this; - }, - - whiten: function (ratio) { - var hwb = this.values.hwb; - hwb[1] += hwb[1] * ratio; - this.setValues('hwb', hwb); - return this; - }, - - blacken: function (ratio) { - var hwb = this.values.hwb; - hwb[2] += hwb[2] * ratio; - this.setValues('hwb', hwb); - return this; - }, - - greyscale: function () { - var rgb = this.values.rgb; - // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale - var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; - this.setValues('rgb', [val, val, val]); - return this; - }, - - clearer: function (ratio) { - var alpha = this.values.alpha; - this.setValues('alpha', alpha - (alpha * ratio)); - return this; - }, - - opaquer: function (ratio) { - var alpha = this.values.alpha; - this.setValues('alpha', alpha + (alpha * ratio)); - return this; - }, - - rotate: function (degrees) { - var hsl = this.values.hsl; - var hue = (hsl[0] + degrees) % 360; - hsl[0] = hue < 0 ? 360 + hue : hue; - this.setValues('hsl', hsl); - return this; - }, - - /** - * Ported from sass implementation in C - * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 - */ - mix: function (mixinColor, weight) { - var color1 = this; - var color2 = mixinColor; - var p = weight === undefined ? 0.5 : weight; - - var w = 2 * p - 1; - var a = color1.alpha() - color2.alpha(); - - var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; - var w2 = 1 - w1; - - return this - .rgb( - w1 * color1.red() + w2 * color2.red(), - w1 * color1.green() + w2 * color2.green(), - w1 * color1.blue() + w2 * color2.blue() - ) - .alpha(color1.alpha() * p + color2.alpha() * (1 - p)); - }, - - toJSON: function () { - return this.rgb(); - }, - - clone: function () { - // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify, - // making the final build way to big to embed in Chart.js. So let's do it manually, - // assuming that values to clone are 1 dimension arrays containing only numbers, - // except 'alpha' which is a number. - var result = new Color(); - var source = this.values; - var target = result.values; - var value, type; - - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - value = source[prop]; - type = ({}).toString.call(value); - if (type === '[object Array]') { - target[prop] = value.slice(0); - } else if (type === '[object Number]') { - target[prop] = value; - } else { - console.error('unexpected color value:', value); - } - } - } - - return result; - } -}; - -Color.prototype.spaces = { - rgb: ['red', 'green', 'blue'], - hsl: ['hue', 'saturation', 'lightness'], - hsv: ['hue', 'saturation', 'value'], - hwb: ['hue', 'whiteness', 'blackness'], - cmyk: ['cyan', 'magenta', 'yellow', 'black'] -}; - -Color.prototype.maxes = { - rgb: [255, 255, 255], - hsl: [360, 100, 100], - hsv: [360, 100, 100], - hwb: [360, 100, 100], - cmyk: [100, 100, 100, 100] -}; - -Color.prototype.getValues = function (space) { - var values = this.values; - var vals = {}; - - for (var i = 0; i < space.length; i++) { - vals[space.charAt(i)] = values[space][i]; - } - - if (values.alpha !== 1) { - vals.a = values.alpha; - } - - // {r: 255, g: 255, b: 255, a: 0.4} - return vals; -}; - -Color.prototype.setValues = function (space, vals) { - var values = this.values; - var spaces = this.spaces; - var maxes = this.maxes; - var alpha = 1; - var i; - - this.valid = true; - - if (space === 'alpha') { - alpha = vals; - } else if (vals.length) { - // [10, 10, 10] - values[space] = vals.slice(0, space.length); - alpha = vals[space.length]; - } else if (vals[space.charAt(0)] !== undefined) { - // {r: 10, g: 10, b: 10} - for (i = 0; i < space.length; i++) { - values[space][i] = vals[space.charAt(i)]; - } - - alpha = vals.a; - } else if (vals[spaces[space][0]] !== undefined) { - // {red: 10, green: 10, blue: 10} - var chans = spaces[space]; - - for (i = 0; i < space.length; i++) { - values[space][i] = vals[chans[i]]; - } - - alpha = vals.alpha; - } - - values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha))); - - if (space === 'alpha') { - return false; - } - - var capped; - - // cap values of the space prior converting all values - for (i = 0; i < space.length; i++) { - capped = Math.max(0, Math.min(maxes[space][i], values[space][i])); - values[space][i] = Math.round(capped); - } - - // convert to all the other color spaces - for (var sname in spaces) { - if (sname !== space) { - values[sname] = colorConvert[space][sname](values[space]); - } - } - - return true; -}; - -Color.prototype.setSpace = function (space, args) { - var vals = args[0]; - - if (vals === undefined) { - // color.rgb() - return this.getValues(space); - } - - // color.rgb(10, 10, 10) - if (typeof vals === 'number') { - vals = Array.prototype.slice.call(args); - } - - this.setValues(space, vals); - return this; -}; - -Color.prototype.setChannel = function (space, index, val) { - var svalues = this.values[space]; - if (val === undefined) { - // color.red() - return svalues[index]; - } else if (val === svalues[index]) { - // color.red(color.red()) - return this; - } - - // color.red(100) - svalues[index] = val; - this.setValues(space, svalues); - - return this; -}; - -if (typeof window !== 'undefined') { - window.Color = Color; -} - -var chartjsColor = Color; - -function isValidKey(key) { - return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1; -} - -/** - * @namespace Chart.helpers - */ -var helpers = { - /** - * An empty function that can be used, for example, for optional callback. - */ - noop: function() {}, - - /** - * Returns a unique id, sequentially generated from a global variable. - * @returns {number} - * @function - */ - uid: (function() { - var id = 0; - return function() { - return id++; - }; - }()), - - /** - * Returns true if `value` is neither null nor undefined, else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @since 2.7.0 - */ - isNullOrUndef: function(value) { - return value === null || typeof value === 'undefined'; - }, - - /** - * Returns true if `value` is an array (including typed arrays), else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @function - */ - isArray: function(value) { - if (Array.isArray && Array.isArray(value)) { - return true; - } - var type = Object.prototype.toString.call(value); - if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { - return true; - } - return false; - }, - - /** - * Returns true if `value` is an object (excluding null), else returns false. - * @param {*} value - The value to test. - * @returns {boolean} - * @since 2.7.0 - */ - isObject: function(value) { - return value !== null && Object.prototype.toString.call(value) === '[object Object]'; - }, - - /** - * Returns true if `value` is a finite number, else returns false - * @param {*} value - The value to test. - * @returns {boolean} - */ - isFinite: function(value) { - return (typeof value === 'number' || value instanceof Number) && isFinite(value); - }, - - /** - * Returns `value` if defined, else returns `defaultValue`. - * @param {*} value - The value to return if defined. - * @param {*} defaultValue - The value to return if `value` is undefined. - * @returns {*} - */ - valueOrDefault: function(value, defaultValue) { - return typeof value === 'undefined' ? defaultValue : value; - }, - - /** - * Returns value at the given `index` in array if defined, else returns `defaultValue`. - * @param {Array} value - The array to lookup for value at `index`. - * @param {number} index - The index in `value` to lookup for value. - * @param {*} defaultValue - The value to return if `value[index]` is undefined. - * @returns {*} - */ - valueAtIndexOrDefault: function(value, index, defaultValue) { - return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue); - }, - - /** - * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the - * value returned by `fn`. If `fn` is not a function, this method returns undefined. - * @param {function} fn - The function to call. - * @param {Array|undefined|null} args - The arguments with which `fn` should be called. - * @param {object} [thisArg] - The value of `this` provided for the call to `fn`. - * @returns {*} - */ - callback: function(fn, args, thisArg) { - if (fn && typeof fn.call === 'function') { - return fn.apply(thisArg, args); - } - }, - - /** - * Note(SB) for performance sake, this method should only be used when loopable type - * is unknown or in none intensive code (not called often and small loopable). Else - * it's preferable to use a regular for() loop and save extra function calls. - * @param {object|Array} loopable - The object or array to be iterated. - * @param {function} fn - The function to call for each item. - * @param {object} [thisArg] - The value of `this` provided for the call to `fn`. - * @param {boolean} [reverse] - If true, iterates backward on the loopable. - */ - each: function(loopable, fn, thisArg, reverse) { - var i, len, keys; - if (helpers.isArray(loopable)) { - len = loopable.length; - if (reverse) { - for (i = len - 1; i >= 0; i--) { - fn.call(thisArg, loopable[i], i); - } - } else { - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[i], i); - } - } - } else if (helpers.isObject(loopable)) { - keys = Object.keys(loopable); - len = keys.length; - for (i = 0; i < len; i++) { - fn.call(thisArg, loopable[keys[i]], keys[i]); - } - } - }, - - /** - * Returns true if the `a0` and `a1` arrays have the same content, else returns false. - * @see https://stackoverflow.com/a/14853974 - * @param {Array} a0 - The array to compare - * @param {Array} a1 - The array to compare - * @returns {boolean} - */ - arrayEquals: function(a0, a1) { - var i, ilen, v0, v1; - - if (!a0 || !a1 || a0.length !== a1.length) { - return false; - } - - for (i = 0, ilen = a0.length; i < ilen; ++i) { - v0 = a0[i]; - v1 = a1[i]; - - if (v0 instanceof Array && v1 instanceof Array) { - if (!helpers.arrayEquals(v0, v1)) { - return false; - } - } else if (v0 !== v1) { - // NOTE: two different object instances will never be equal: {x:20} != {x:20} - return false; - } - } - - return true; - }, - - /** - * Returns a deep copy of `source` without keeping references on objects and arrays. - * @param {*} source - The value to clone. - * @returns {*} - */ - clone: function(source) { - if (helpers.isArray(source)) { - return source.map(helpers.clone); - } - - if (helpers.isObject(source)) { - var target = Object.create(source); - var keys = Object.keys(source); - var klen = keys.length; - var k = 0; - - for (; k < klen; ++k) { - target[keys[k]] = helpers.clone(source[keys[k]]); - } - - return target; - } - - return source; - }, - - /** - * The default merger when Chart.helpers.merge is called without merger option. - * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback. - * @private - */ - _merger: function(key, target, source, options) { - if (!isValidKey(key)) { - // We want to ensure we do not copy prototypes over - // as this can pollute global namespaces - return; - } - - var tval = target[key]; - var sval = source[key]; - - if (helpers.isObject(tval) && helpers.isObject(sval)) { - helpers.merge(tval, sval, options); - } else { - target[key] = helpers.clone(sval); - } - }, - - /** - * Merges source[key] in target[key] only if target[key] is undefined. - * @private - */ - _mergerIf: function(key, target, source) { - if (!isValidKey(key)) { - // We want to ensure we do not copy prototypes over - // as this can pollute global namespaces - return; - } - - var tval = target[key]; - var sval = source[key]; - - if (helpers.isObject(tval) && helpers.isObject(sval)) { - helpers.mergeIf(tval, sval); - } else if (!target.hasOwnProperty(key)) { - target[key] = helpers.clone(sval); - } - }, - - /** - * Recursively deep copies `source` properties into `target` with the given `options`. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param {object} target - The target object in which all sources are merged into. - * @param {object|object[]} source - Object(s) to merge into `target`. - * @param {object} [options] - Merging options: - * @param {function} [options.merger] - The merge method (key, target, source, options) - * @returns {object} The `target` object. - */ - merge: function(target, source, options) { - var sources = helpers.isArray(source) ? source : [source]; - var ilen = sources.length; - var merge, i, keys, klen, k; - - if (!helpers.isObject(target)) { - return target; - } - - options = options || {}; - merge = options.merger || helpers._merger; - - for (i = 0; i < ilen; ++i) { - source = sources[i]; - if (!helpers.isObject(source)) { - continue; - } - - keys = Object.keys(source); - for (k = 0, klen = keys.length; k < klen; ++k) { - merge(keys[k], target, source, options); - } - } - - return target; - }, - - /** - * Recursively deep copies `source` properties into `target` *only* if not defined in target. - * IMPORTANT: `target` is not cloned and will be updated with `source` properties. - * @param {object} target - The target object in which all sources are merged into. - * @param {object|object[]} source - Object(s) to merge into `target`. - * @returns {object} The `target` object. - */ - mergeIf: function(target, source) { - return helpers.merge(target, source, {merger: helpers._mergerIf}); - }, - - /** - * Applies the contents of two or more objects together into the first object. - * @param {object} target - The target object in which all objects are merged into. - * @param {object} arg1 - Object containing additional properties to merge in target. - * @param {object} argN - Additional objects containing properties to merge in target. - * @returns {object} The `target` object. - */ - extend: Object.assign || function(target) { - return helpers.merge(target, [].slice.call(arguments, 1), { - merger: function(key, dst, src) { - dst[key] = src[key]; - } - }); - }, - - /** - * Basic javascript inheritance based on the model created in Backbone.js - */ - inherits: function(extensions) { - var me = this; - var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() { - return me.apply(this, arguments); - }; - - var Surrogate = function() { - this.constructor = ChartElement; - }; - - Surrogate.prototype = me.prototype; - ChartElement.prototype = new Surrogate(); - ChartElement.extend = helpers.inherits; - - if (extensions) { - helpers.extend(ChartElement.prototype, extensions); - } - - ChartElement.__super__ = me.prototype; - return ChartElement; - }, - - _deprecated: function(scope, value, previous, current) { - if (value !== undefined) { - console.warn(scope + ': "' + previous + - '" is deprecated. Please use "' + current + '" instead'); - } - } -}; - -var helpers_core = helpers; - -// DEPRECATIONS - -/** - * Provided for backward compatibility, use Chart.helpers.callback instead. - * @function Chart.helpers.callCallback - * @deprecated since version 2.6.0 - * @todo remove at version 3 - * @private - */ -helpers.callCallback = helpers.callback; - -/** - * Provided for backward compatibility, use Array.prototype.indexOf instead. - * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+ - * @function Chart.helpers.indexOf - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers.indexOf = function(array, item, fromIndex) { - return Array.prototype.indexOf.call(array, item, fromIndex); -}; - -/** - * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead. - * @function Chart.helpers.getValueOrDefault - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers.getValueOrDefault = helpers.valueOrDefault; - -/** - * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead. - * @function Chart.helpers.getValueAtIndexOrDefault - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault; - -/** - * Easing functions adapted from Robert Penner's easing equations. - * @namespace Chart.helpers.easingEffects - * @see http://www.robertpenner.com/easing/ - */ -var effects = { - linear: function(t) { - return t; - }, - - easeInQuad: function(t) { - return t * t; - }, - - easeOutQuad: function(t) { - return -t * (t - 2); - }, - - easeInOutQuad: function(t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t; - } - return -0.5 * ((--t) * (t - 2) - 1); - }, - - easeInCubic: function(t) { - return t * t * t; - }, - - easeOutCubic: function(t) { - return (t = t - 1) * t * t + 1; - }, - - easeInOutCubic: function(t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t; - } - return 0.5 * ((t -= 2) * t * t + 2); - }, - - easeInQuart: function(t) { - return t * t * t * t; - }, - - easeOutQuart: function(t) { - return -((t = t - 1) * t * t * t - 1); - }, - - easeInOutQuart: function(t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t * t; - } - return -0.5 * ((t -= 2) * t * t * t - 2); - }, - - easeInQuint: function(t) { - return t * t * t * t * t; - }, - - easeOutQuint: function(t) { - return (t = t - 1) * t * t * t * t + 1; - }, - - easeInOutQuint: function(t) { - if ((t /= 0.5) < 1) { - return 0.5 * t * t * t * t * t; - } - return 0.5 * ((t -= 2) * t * t * t * t + 2); - }, - - easeInSine: function(t) { - return -Math.cos(t * (Math.PI / 2)) + 1; - }, - - easeOutSine: function(t) { - return Math.sin(t * (Math.PI / 2)); - }, - - easeInOutSine: function(t) { - return -0.5 * (Math.cos(Math.PI * t) - 1); - }, - - easeInExpo: function(t) { - return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)); - }, - - easeOutExpo: function(t) { - return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1; - }, - - easeInOutExpo: function(t) { - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if ((t /= 0.5) < 1) { - return 0.5 * Math.pow(2, 10 * (t - 1)); - } - return 0.5 * (-Math.pow(2, -10 * --t) + 2); - }, - - easeInCirc: function(t) { - if (t >= 1) { - return t; - } - return -(Math.sqrt(1 - t * t) - 1); - }, - - easeOutCirc: function(t) { - return Math.sqrt(1 - (t = t - 1) * t); - }, - - easeInOutCirc: function(t) { - if ((t /= 0.5) < 1) { - return -0.5 * (Math.sqrt(1 - t * t) - 1); - } - return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); - }, - - easeInElastic: function(t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if (!p) { - p = 0.3; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); - }, - - easeOutElastic: function(t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if (t === 1) { - return 1; - } - if (!p) { - p = 0.3; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1; - }, - - easeInOutElastic: function(t) { - var s = 1.70158; - var p = 0; - var a = 1; - if (t === 0) { - return 0; - } - if ((t /= 0.5) === 2) { - return 1; - } - if (!p) { - p = 0.45; - } - if (a < 1) { - a = 1; - s = p / 4; - } else { - s = p / (2 * Math.PI) * Math.asin(1 / a); - } - if (t < 1) { - return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); - } - return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1; - }, - easeInBack: function(t) { - var s = 1.70158; - return t * t * ((s + 1) * t - s); - }, - - easeOutBack: function(t) { - var s = 1.70158; - return (t = t - 1) * t * ((s + 1) * t + s) + 1; - }, - - easeInOutBack: function(t) { - var s = 1.70158; - if ((t /= 0.5) < 1) { - return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); - } - return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); - }, - - easeInBounce: function(t) { - return 1 - effects.easeOutBounce(1 - t); - }, - - easeOutBounce: function(t) { - if (t < (1 / 2.75)) { - return 7.5625 * t * t; - } - if (t < (2 / 2.75)) { - return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; - } - if (t < (2.5 / 2.75)) { - return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; - } - return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; - }, - - easeInOutBounce: function(t) { - if (t < 0.5) { - return effects.easeInBounce(t * 2) * 0.5; - } - return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5; - } -}; - -var helpers_easing = { - effects: effects -}; - -// DEPRECATIONS - -/** - * Provided for backward compatibility, use Chart.helpers.easing.effects instead. - * @function Chart.helpers.easingEffects - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers_core.easingEffects = effects; - -var PI = Math.PI; -var RAD_PER_DEG = PI / 180; -var DOUBLE_PI = PI * 2; -var HALF_PI = PI / 2; -var QUARTER_PI = PI / 4; -var TWO_THIRDS_PI = PI * 2 / 3; - -/** - * @namespace Chart.helpers.canvas - */ -var exports$1 = { - /** - * Clears the entire canvas associated to the given `chart`. - * @param {Chart} chart - The chart for which to clear the canvas. - */ - clear: function(chart) { - chart.ctx.clearRect(0, 0, chart.width, chart.height); - }, - - /** - * Creates a "path" for a rectangle with rounded corners at position (x, y) with a - * given size (width, height) and the same `radius` for all corners. - * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context. - * @param {number} x - The x axis of the coordinate for the rectangle starting point. - * @param {number} y - The y axis of the coordinate for the rectangle starting point. - * @param {number} width - The rectangle's width. - * @param {number} height - The rectangle's height. - * @param {number} radius - The rounded amount (in pixels) for the four corners. - * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object? - */ - roundedRect: function(ctx, x, y, width, height, radius) { - if (radius) { - var r = Math.min(radius, height / 2, width / 2); - var left = x + r; - var top = y + r; - var right = x + width - r; - var bottom = y + height - r; - - ctx.moveTo(x, top); - if (left < right && top < bottom) { - ctx.arc(left, top, r, -PI, -HALF_PI); - ctx.arc(right, top, r, -HALF_PI, 0); - ctx.arc(right, bottom, r, 0, HALF_PI); - ctx.arc(left, bottom, r, HALF_PI, PI); - } else if (left < right) { - ctx.moveTo(left, y); - ctx.arc(right, top, r, -HALF_PI, HALF_PI); - ctx.arc(left, top, r, HALF_PI, PI + HALF_PI); - } else if (top < bottom) { - ctx.arc(left, top, r, -PI, 0); - ctx.arc(left, bottom, r, 0, PI); - } else { - ctx.arc(left, top, r, -PI, PI); - } - ctx.closePath(); - ctx.moveTo(x, y); - } else { - ctx.rect(x, y, width, height); - } - }, - - drawPoint: function(ctx, style, radius, x, y, rotation) { - var type, xOffset, yOffset, size, cornerRadius; - var rad = (rotation || 0) * RAD_PER_DEG; - - if (style && typeof style === 'object') { - type = style.toString(); - if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { - ctx.save(); - ctx.translate(x, y); - ctx.rotate(rad); - ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); - ctx.restore(); - return; - } - } - - if (isNaN(radius) || radius <= 0) { - return; - } - - ctx.beginPath(); - - switch (style) { - // Default includes circle - default: - ctx.arc(x, y, radius, 0, DOUBLE_PI); - ctx.closePath(); - break; - case 'triangle': - ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - rad += TWO_THIRDS_PI; - ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); - ctx.closePath(); - break; - case 'rectRounded': - // NOTE: the rounded rect implementation changed to use `arc` instead of - // `quadraticCurveTo` since it generates better results when rect is - // almost a circle. 0.516 (instead of 0.5) produces results with visually - // closer proportion to the previous impl and it is inscribed in the - // circle with `radius`. For more details, see the following PRs: - // https://github.com/chartjs/Chart.js/issues/5597 - // https://github.com/chartjs/Chart.js/issues/5858 - cornerRadius = radius * 0.516; - size = radius - cornerRadius; - xOffset = Math.cos(rad + QUARTER_PI) * size; - yOffset = Math.sin(rad + QUARTER_PI) * size; - ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); - ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); - ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); - ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); - ctx.closePath(); - break; - case 'rect': - if (!rotation) { - size = Math.SQRT1_2 * radius; - ctx.rect(x - size, y - size, 2 * size, 2 * size); - break; - } - rad += QUARTER_PI; - /* falls through */ - case 'rectRot': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + yOffset, y - xOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.lineTo(x - yOffset, y + xOffset); - ctx.closePath(); - break; - case 'crossRot': - rad += QUARTER_PI; - /* falls through */ - case 'cross': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'star': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - rad += QUARTER_PI; - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x + yOffset, y - xOffset); - ctx.lineTo(x - yOffset, y + xOffset); - break; - case 'line': - xOffset = Math.cos(rad) * radius; - yOffset = Math.sin(rad) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - break; - case 'dash': - ctx.moveTo(x, y); - ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); - break; - } - - ctx.fill(); - ctx.stroke(); - }, - - /** - * Returns true if the point is inside the rectangle - * @param {object} point - The point to test - * @param {object} area - The rectangle - * @returns {boolean} - * @private - */ - _isPointInArea: function(point, area) { - var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error. - - return point.x > area.left - epsilon && point.x < area.right + epsilon && - point.y > area.top - epsilon && point.y < area.bottom + epsilon; - }, - - clipArea: function(ctx, area) { - ctx.save(); - ctx.beginPath(); - ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); - ctx.clip(); - }, - - unclipArea: function(ctx) { - ctx.restore(); - }, - - lineTo: function(ctx, previous, target, flip) { - var stepped = target.steppedLine; - if (stepped) { - if (stepped === 'middle') { - var midpoint = (previous.x + target.x) / 2.0; - ctx.lineTo(midpoint, flip ? target.y : previous.y); - ctx.lineTo(midpoint, flip ? previous.y : target.y); - } else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) { - ctx.lineTo(previous.x, target.y); - } else { - ctx.lineTo(target.x, previous.y); - } - ctx.lineTo(target.x, target.y); - return; - } - - if (!target.tension) { - ctx.lineTo(target.x, target.y); - return; - } - - ctx.bezierCurveTo( - flip ? previous.controlPointPreviousX : previous.controlPointNextX, - flip ? previous.controlPointPreviousY : previous.controlPointNextY, - flip ? target.controlPointNextX : target.controlPointPreviousX, - flip ? target.controlPointNextY : target.controlPointPreviousY, - target.x, - target.y); - } -}; - -var helpers_canvas = exports$1; - -// DEPRECATIONS - -/** - * Provided for backward compatibility, use Chart.helpers.canvas.clear instead. - * @namespace Chart.helpers.clear - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers_core.clear = exports$1.clear; - -/** - * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead. - * @namespace Chart.helpers.drawRoundedRectangle - * @deprecated since version 2.7.0 - * @todo remove at version 3 - * @private - */ -helpers_core.drawRoundedRectangle = function(ctx) { - ctx.beginPath(); - exports$1.roundedRect.apply(exports$1, arguments); -}; - -var defaults = { - /** - * @private - */ - _set: function(scope, values) { - return helpers_core.merge(this[scope] || (this[scope] = {}), values); - } -}; - -// TODO(v3): remove 'global' from namespace. all default are global and -// there's inconsistency around which options are under 'global' -defaults._set('global', { - defaultColor: 'rgba(0,0,0,0.1)', - defaultFontColor: '#666', - defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - defaultFontSize: 12, - defaultFontStyle: 'normal', - defaultLineHeight: 1.2, - showLines: true -}); - -var core_defaults = defaults; - -var valueOrDefault = helpers_core.valueOrDefault; - -/** - * Converts the given font object into a CSS font string. - * @param {object} font - A font object. - * @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font - * @private - */ -function toFontString(font) { - if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) { - return null; - } - - return (font.style ? font.style + ' ' : '') - + (font.weight ? font.weight + ' ' : '') - + font.size + 'px ' - + font.family; -} - -/** - * @alias Chart.helpers.options - * @namespace - */ -var helpers_options = { - /** - * Converts the given line height `value` in pixels for a specific font `size`. - * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). - * @param {number} size - The font size (in pixels) used to resolve relative `value`. - * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid). - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height - * @since 2.7.0 - */ - toLineHeight: function(value, size) { - var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); - if (!matches || matches[1] === 'normal') { - return size * 1.2; - } - - value = +matches[2]; - - switch (matches[3]) { - case 'px': - return value; - case '%': - value /= 100; - break; - } - - return size * value; - }, - - /** - * Converts the given value into a padding object with pre-computed width/height. - * @param {number|object} value - If a number, set the value to all TRBL component, - * else, if and object, use defined properties and sets undefined ones to 0. - * @returns {object} The padding values (top, right, bottom, left, width, height) - * @since 2.7.0 - */ - toPadding: function(value) { - var t, r, b, l; - - if (helpers_core.isObject(value)) { - t = +value.top || 0; - r = +value.right || 0; - b = +value.bottom || 0; - l = +value.left || 0; - } else { - t = r = b = l = +value || 0; - } - - return { - top: t, - right: r, - bottom: b, - left: l, - height: t + b, - width: l + r - }; - }, - - /** - * Parses font options and returns the font object. - * @param {object} options - A object that contains font options to be parsed. - * @return {object} The font object. - * @todo Support font.* options and renamed to toFont(). - * @private - */ - _parseFont: function(options) { - var globalDefaults = core_defaults.global; - var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize); - var font = { - family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily), - lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size), - size: size, - style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle), - weight: null, - string: '' - }; - - font.string = toFontString(font); - return font; - }, - - /** - * Evaluates the given `inputs` sequentially and returns the first defined value. - * @param {Array} inputs - An array of values, falling back to the last value. - * @param {object} [context] - If defined and the current value is a function, the value - * is called with `context` as first argument and the result becomes the new input. - * @param {number} [index] - If defined and the current value is an array, the value - * at `index` become the new input. - * @param {object} [info] - object to return information about resolution in - * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable. - * @since 2.7.0 - */ - resolve: function(inputs, context, index, info) { - var cacheable = true; - var i, ilen, value; - - for (i = 0, ilen = inputs.length; i < ilen; ++i) { - value = inputs[i]; - if (value === undefined) { - continue; - } - if (context !== undefined && typeof value === 'function') { - value = value(context); - cacheable = false; - } - if (index !== undefined && helpers_core.isArray(value)) { - value = value[index]; - cacheable = false; - } - if (value !== undefined) { - if (info && !cacheable) { - info.cacheable = false; - } - return value; - } - } - } -}; - -/** - * @alias Chart.helpers.math - * @namespace - */ -var exports$2 = { - /** - * Returns an array of factors sorted from 1 to sqrt(value) - * @private - */ - _factorize: function(value) { - var result = []; - var sqrt = Math.sqrt(value); - var i; - - for (i = 1; i < sqrt; i++) { - if (value % i === 0) { - result.push(i); - result.push(value / i); - } - } - if (sqrt === (sqrt | 0)) { // if value is a square number - result.push(sqrt); - } - - result.sort(function(a, b) { - return a - b; - }).pop(); - return result; - }, - - log10: Math.log10 || function(x) { - var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10. - // Check for whole powers of 10, - // which due to floating point rounding error should be corrected. - var powerOf10 = Math.round(exponent); - var isPowerOf10 = x === Math.pow(10, powerOf10); - - return isPowerOf10 ? powerOf10 : exponent; - } -}; - -var helpers_math = exports$2; - -// DEPRECATIONS - -/** - * Provided for backward compatibility, use Chart.helpers.math.log10 instead. - * @namespace Chart.helpers.log10 - * @deprecated since version 2.9.0 - * @todo remove at version 3 - * @private - */ -helpers_core.log10 = exports$2.log10; - -var getRtlAdapter = function(rectX, width) { - return { - x: function(x) { - return rectX + rectX + width - x; - }, - setWidth: function(w) { - width = w; - }, - textAlign: function(align) { - if (align === 'center') { - return align; - } - return align === 'right' ? 'left' : 'right'; - }, - xPlus: function(x, value) { - return x - value; - }, - leftForLtr: function(x, itemWidth) { - return x - itemWidth; - }, - }; -}; - -var getLtrAdapter = function() { - return { - x: function(x) { - return x; - }, - setWidth: function(w) { // eslint-disable-line no-unused-vars - }, - textAlign: function(align) { - return align; - }, - xPlus: function(x, value) { - return x + value; - }, - leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars - return x; - }, - }; -}; - -var getAdapter = function(rtl, rectX, width) { - return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter(); -}; - -var overrideTextDirection = function(ctx, direction) { - var style, original; - if (direction === 'ltr' || direction === 'rtl') { - style = ctx.canvas.style; - original = [ - style.getPropertyValue('direction'), - style.getPropertyPriority('direction'), - ]; - - style.setProperty('direction', direction, 'important'); - ctx.prevTextDirection = original; - } -}; - -var restoreTextDirection = function(ctx) { - var original = ctx.prevTextDirection; - if (original !== undefined) { - delete ctx.prevTextDirection; - ctx.canvas.style.setProperty('direction', original[0], original[1]); - } -}; - -var helpers_rtl = { - getRtlAdapter: getAdapter, - overrideTextDirection: overrideTextDirection, - restoreTextDirection: restoreTextDirection, -}; - -var helpers$1 = helpers_core; -var easing = helpers_easing; -var canvas = helpers_canvas; -var options = helpers_options; -var math = helpers_math; -var rtl = helpers_rtl; -helpers$1.easing = easing; -helpers$1.canvas = canvas; -helpers$1.options = options; -helpers$1.math = math; -helpers$1.rtl = rtl; - -function interpolate(start, view, model, ease) { - var keys = Object.keys(model); - var i, ilen, key, actual, origin, target, type, c0, c1; - - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - - target = model[key]; - - // if a value is added to the model after pivot() has been called, the view - // doesn't contain it, so let's initialize the view to the target value. - if (!view.hasOwnProperty(key)) { - view[key] = target; - } - - actual = view[key]; - - if (actual === target || key[0] === '_') { - continue; - } - - if (!start.hasOwnProperty(key)) { - start[key] = actual; - } - - origin = start[key]; - - type = typeof target; - - if (type === typeof origin) { - if (type === 'string') { - c0 = chartjsColor(origin); - if (c0.valid) { - c1 = chartjsColor(target); - if (c1.valid) { - view[key] = c1.mix(c0, ease).rgbString(); - continue; - } - } - } else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) { - view[key] = origin + (target - origin) * ease; - continue; - } - } - - view[key] = target; - } -} - -var Element = function(configuration) { - helpers$1.extend(this, configuration); - this.initialize.apply(this, arguments); -}; - -helpers$1.extend(Element.prototype, { - _type: undefined, - - initialize: function() { - this.hidden = false; - }, - - pivot: function() { - var me = this; - if (!me._view) { - me._view = helpers$1.extend({}, me._model); - } - me._start = {}; - return me; - }, - - transition: function(ease) { - var me = this; - var model = me._model; - var start = me._start; - var view = me._view; - - // No animation -> No Transition - if (!model || ease === 1) { - me._view = helpers$1.extend({}, model); - me._start = null; - return me; - } - - if (!view) { - view = me._view = {}; - } - - if (!start) { - start = me._start = {}; - } - - interpolate(start, view, model, ease); - - return me; - }, - - tooltipPosition: function() { - return { - x: this._model.x, - y: this._model.y - }; - }, - - hasValue: function() { - return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y); - } -}); - -Element.extend = helpers$1.inherits; - -var core_element = Element; - -var exports$3 = core_element.extend({ - chart: null, // the animation associated chart instance - currentStep: 0, // the current animation step - numSteps: 60, // default number of steps - easing: '', // the easing to use for this animation - render: null, // render function used by the animation service - - onAnimationProgress: null, // user specified callback to fire on each step of the animation - onAnimationComplete: null, // user specified callback to fire when the animation finishes -}); - -var core_animation = exports$3; - -// DEPRECATIONS - -/** - * Provided for backward compatibility, use Chart.Animation instead - * @prop Chart.Animation#animationObject - * @deprecated since version 2.6.0 - * @todo remove at version 3 - */ -Object.defineProperty(exports$3.prototype, 'animationObject', { - get: function() { - return this; - } -}); - -/** - * Provided for backward compatibility, use Chart.Animation#chart instead - * @prop Chart.Animation#chartInstance - * @deprecated since version 2.6.0 - * @todo remove at version 3 - */ -Object.defineProperty(exports$3.prototype, 'chartInstance', { - get: function() { - return this.chart; - }, - set: function(value) { - this.chart = value; - } -}); - -core_defaults._set('global', { - animation: { - duration: 1000, - easing: 'easeOutQuart', - onProgress: helpers$1.noop, - onComplete: helpers$1.noop - } -}); - -var core_animations = { - animations: [], - request: null, - - /** - * @param {Chart} chart - The chart to animate. - * @param {Chart.Animation} animation - The animation that we will animate. - * @param {number} duration - The animation duration in ms. - * @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions - */ - addAnimation: function(chart, animation, duration, lazy) { - var animations = this.animations; - var i, ilen; - - animation.chart = chart; - animation.startTime = Date.now(); - animation.duration = duration; - - if (!lazy) { - chart.animating = true; - } - - for (i = 0, ilen = animations.length; i < ilen; ++i) { - if (animations[i].chart === chart) { - animations[i] = animation; - return; - } - } - - animations.push(animation); - - // If there are no animations queued, manually kickstart a digest, for lack of a better word - if (animations.length === 1) { - this.requestAnimationFrame(); - } - }, - - cancelAnimation: function(chart) { - var index = helpers$1.findIndex(this.animations, function(animation) { - return animation.chart === chart; - }); - - if (index !== -1) { - this.animations.splice(index, 1); - chart.animating = false; - } - }, - - requestAnimationFrame: function() { - var me = this; - if (me.request === null) { - // Skip animation frame requests until the active one is executed. - // This can happen when processing mouse events, e.g. 'mousemove' - // and 'mouseout' events will trigger multiple renders. - me.request = helpers$1.requestAnimFrame.call(window, function() { - me.request = null; - me.startDigest(); - }); - } - }, - - /** - * @private - */ - startDigest: function() { - var me = this; - - me.advance(); - - // Do we have more stuff to animate? - if (me.animations.length > 0) { - me.requestAnimationFrame(); - } - }, - - /** - * @private - */ - advance: function() { - var animations = this.animations; - var animation, chart, numSteps, nextStep; - var i = 0; - - // 1 animation per chart, so we are looping charts here - while (i < animations.length) { - animation = animations[i]; - chart = animation.chart; - numSteps = animation.numSteps; - - // Make sure that currentStep starts at 1 - // https://github.com/chartjs/Chart.js/issues/6104 - nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1; - animation.currentStep = Math.min(nextStep, numSteps); - - helpers$1.callback(animation.render, [chart, animation], chart); - helpers$1.callback(animation.onAnimationProgress, [animation], chart); - - if (animation.currentStep >= numSteps) { - helpers$1.callback(animation.onAnimationComplete, [animation], chart); - chart.animating = false; - animations.splice(i, 1); - } else { - ++i; - } - } - } -}; - -var resolve = helpers$1.options.resolve; - -var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; - -/** - * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', - * 'unshift') and notify the listener AFTER the array has been altered. Listeners are - * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments. - */ -function listenArrayEvents(array, listener) { - if (array._chartjs) { - array._chartjs.listeners.push(listener); - return; - } - - Object.defineProperty(array, '_chartjs', { - configurable: true, - enumerable: false, - value: { - listeners: [listener] - } - }); - - arrayEvents.forEach(function(key) { - var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1); - var base = array[key]; - - Object.defineProperty(array, key, { - configurable: true, - enumerable: false, - value: function() { - var args = Array.prototype.slice.call(arguments); - var res = base.apply(this, args); - - helpers$1.each(array._chartjs.listeners, function(object) { - if (typeof object[method] === 'function') { - object[method].apply(object, args); - } - }); - - return res; - } - }); - }); -} - -/** - * Removes the given array event listener and cleanup extra attached properties (such as - * the _chartjs stub and overridden methods) if array doesn't have any more listeners. - */ -function unlistenArrayEvents(array, listener) { - var stub = array._chartjs; - if (!stub) { - return; - } - - var listeners = stub.listeners; - var index = listeners.indexOf(listener); - if (index !== -1) { - listeners.splice(index, 1); - } - - if (listeners.length > 0) { - return; - } - - arrayEvents.forEach(function(key) { - delete array[key]; - }); - - delete array._chartjs; -} - -// Base class for all dataset controllers (line, bar, etc) -var DatasetController = function(chart, datasetIndex) { - this.initialize(chart, datasetIndex); -}; - -helpers$1.extend(DatasetController.prototype, { - - /** - * Element type used to generate a meta dataset (e.g. Chart.element.Line). - * @type {Chart.core.element} - */ - datasetElementType: null, - - /** - * Element type used to generate a meta data (e.g. Chart.element.Point). - * @type {Chart.core.element} - */ - dataElementType: null, - - /** - * Dataset element option keys to be resolved in _resolveDatasetElementOptions. - * A derived controller may override this to resolve controller-specific options. - * The keys defined here are for backward compatibility for legend styles. - * @private - */ - _datasetElementOptions: [ - 'backgroundColor', - 'borderCapStyle', - 'borderColor', - 'borderDash', - 'borderDashOffset', - 'borderJoinStyle', - 'borderWidth' - ], - - /** - * Data element option keys to be resolved in _resolveDataElementOptions. - * A derived controller may override this to resolve controller-specific options. - * The keys defined here are for backward compatibility for legend styles. - * @private - */ - _dataElementOptions: [ - 'backgroundColor', - 'borderColor', - 'borderWidth', - 'pointStyle' - ], - - initialize: function(chart, datasetIndex) { - var me = this; - me.chart = chart; - me.index = datasetIndex; - me.linkScales(); - me.addElements(); - me._type = me.getMeta().type; - }, - - updateIndex: function(datasetIndex) { - this.index = datasetIndex; - }, - - linkScales: function() { - var me = this; - var meta = me.getMeta(); - var chart = me.chart; - var scales = chart.scales; - var dataset = me.getDataset(); - var scalesOpts = chart.options.scales; - - if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) { - meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id; - } - if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) { - meta.yAxisID = dataset.yAxisID || scalesOpts.yAxes[0].id; - } - }, - - getDataset: function() { - return this.chart.data.datasets[this.index]; - }, - - getMeta: function() { - return this.chart.getDatasetMeta(this.index); - }, - - getScaleForId: function(scaleID) { - return this.chart.scales[scaleID]; - }, - - /** - * @private - */ - _getValueScaleId: function() { - return this.getMeta().yAxisID; - }, - - /** - * @private - */ - _getIndexScaleId: function() { - return this.getMeta().xAxisID; - }, - - /** - * @private - */ - _getValueScale: function() { - return this.getScaleForId(this._getValueScaleId()); - }, - - /** - * @private - */ - _getIndexScale: function() { - return this.getScaleForId(this._getIndexScaleId()); - }, - - reset: function() { - this._update(true); - }, - - /** - * @private - */ - destroy: function() { - if (this._data) { - unlistenArrayEvents(this._data, this); - } - }, - - createMetaDataset: function() { - var me = this; - var type = me.datasetElementType; - return type && new type({ - _chart: me.chart, - _datasetIndex: me.index - }); - }, - - createMetaData: function(index) { - var me = this; - var type = me.dataElementType; - return type && new type({ - _chart: me.chart, - _datasetIndex: me.index, - _index: index - }); - }, - - addElements: function() { - var me = this; - var meta = me.getMeta(); - var data = me.getDataset().data || []; - var metaData = meta.data; - var i, ilen; - - for (i = 0, ilen = data.length; i < ilen; ++i) { - metaData[i] = metaData[i] || me.createMetaData(i); - } - - meta.dataset = meta.dataset || me.createMetaDataset(); - }, - - addElementAndReset: function(index) { - var element = this.createMetaData(index); - this.getMeta().data.splice(index, 0, element); - this.updateElement(element, index, true); - }, - - buildOrUpdateElements: function() { - var me = this; - var dataset = me.getDataset(); - var data = dataset.data || (dataset.data = []); - - // In order to correctly handle data addition/deletion animation (an thus simulate - // real-time charts), we need to monitor these data modifications and synchronize - // the internal meta data accordingly. - if (me._data !== data) { - if (me._data) { - // This case happens when the user replaced the data array instance. - unlistenArrayEvents(me._data, me); - } - - if (data && Object.isExtensible(data)) { - listenArrayEvents(data, me); - } - me._data = data; - } - - // Re-sync meta data in case the user replaced the data array or if we missed - // any updates and so make sure that we handle number of datapoints changing. - me.resyncElements(); - }, - - /** - * Returns the merged user-supplied and default dataset-level options - * @private - */ - _configure: function() { - var me = this; - me._config = helpers$1.merge(Object.create(null), [ - me.chart.options.datasets[me._type], - me.getDataset(), - ], { - merger: function(key, target, source) { - if (key !== '_meta' && key !== 'data') { - helpers$1._merger(key, target, source); - } - } - }); - }, - - _update: function(reset) { - var me = this; - me._configure(); - me._cachedDataOpts = null; - me.update(reset); - }, - - update: helpers$1.noop, - - transition: function(easingValue) { - var meta = this.getMeta(); - var elements = meta.data || []; - var ilen = elements.length; - var i = 0; - - for (; i < ilen; ++i) { - elements[i].transition(easingValue); - } - - if (meta.dataset) { - meta.dataset.transition(easingValue); - } - }, - - draw: function() { - var meta = this.getMeta(); - var elements = meta.data || []; - var ilen = elements.length; - var i = 0; - - if (meta.dataset) { - meta.dataset.draw(); - } - - for (; i < ilen; ++i) { - elements[i].draw(); - } - }, - - /** - * Returns a set of predefined style properties that should be used to represent the dataset - * or the data if the index is specified - * @param {number} index - data index - * @return {IStyleInterface} style object - */ - getStyle: function(index) { - var me = this; - var meta = me.getMeta(); - var dataset = meta.dataset; - var style; - - me._configure(); - if (dataset && index === undefined) { - style = me._resolveDatasetElementOptions(dataset || {}); - } else { - index = index || 0; - style = me._resolveDataElementOptions(meta.data[index] || {}, index); - } - - if (style.fill === false || style.fill === null) { - style.backgroundColor = style.borderColor; - } - - return style; - }, - - /** - * @private - */ - _resolveDatasetElementOptions: function(element, hover) { - var me = this; - var chart = me.chart; - var datasetOpts = me._config; - var custom = element.custom || {}; - var options = chart.options.elements[me.datasetElementType.prototype._type] || {}; - var elementOptions = me._datasetElementOptions; - var values = {}; - var i, ilen, key, readKey; - - // Scriptable options - var context = { - chart: chart, - dataset: me.getDataset(), - datasetIndex: me.index, - hover: hover - }; - - for (i = 0, ilen = elementOptions.length; i < ilen; ++i) { - key = elementOptions[i]; - readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key; - values[key] = resolve([ - custom[readKey], - datasetOpts[readKey], - options[readKey] - ], context); - } - - return values; - }, - - /** - * @private - */ - _resolveDataElementOptions: function(element, index) { - var me = this; - var custom = element && element.custom; - var cached = me._cachedDataOpts; - if (cached && !custom) { - return cached; - } - var chart = me.chart; - var datasetOpts = me._config; - var options = chart.options.elements[me.dataElementType.prototype._type] || {}; - var elementOptions = me._dataElementOptions; - var values = {}; - - // Scriptable options - var context = { - chart: chart, - dataIndex: index, - dataset: me.getDataset(), - datasetIndex: me.index - }; - - // `resolve` sets cacheable to `false` if any option is indexed or scripted - var info = {cacheable: !custom}; - - var keys, i, ilen, key; - - custom = custom || {}; - - if (helpers$1.isArray(elementOptions)) { - for (i = 0, ilen = elementOptions.length; i < ilen; ++i) { - key = elementOptions[i]; - values[key] = resolve([ - custom[key], - datasetOpts[key], - options[key] - ], context, index, info); - } - } else { - keys = Object.keys(elementOptions); - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - values[key] = resolve([ - custom[key], - datasetOpts[elementOptions[key]], - datasetOpts[key], - options[key] - ], context, index, info); - } - } - - if (info.cacheable) { - me._cachedDataOpts = Object.freeze(values); - } - - return values; - }, - - removeHoverStyle: function(element) { - helpers$1.merge(element._model, element.$previousStyle || {}); - delete element.$previousStyle; - }, - - setHoverStyle: function(element) { - var dataset = this.chart.data.datasets[element._datasetIndex]; - var index = element._index; - var custom = element.custom || {}; - var model = element._model; - var getHoverColor = helpers$1.getHoverColor; - - element.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth - }; - - model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index); - model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index); - model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index); - }, - - /** - * @private - */ - _removeDatasetHoverStyle: function() { - var element = this.getMeta().dataset; - - if (element) { - this.removeHoverStyle(element); - } - }, - - /** - * @private - */ - _setDatasetHoverStyle: function() { - var element = this.getMeta().dataset; - var prev = {}; - var i, ilen, key, keys, hoverOptions, model; - - if (!element) { - return; - } - - model = element._model; - hoverOptions = this._resolveDatasetElementOptions(element, true); - - keys = Object.keys(hoverOptions); - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; - prev[key] = model[key]; - model[key] = hoverOptions[key]; - } - - element.$previousStyle = prev; - }, - - /** - * @private - */ - resyncElements: function() { - var me = this; - var meta = me.getMeta(); - var data = me.getDataset().data; - var numMeta = meta.data.length; - var numData = data.length; - - if (numData < numMeta) { - meta.data.splice(numData, numMeta - numData); - } else if (numData > numMeta) { - me.insertElements(numMeta, numData - numMeta); - } - }, - - /** - * @private - */ - insertElements: function(start, count) { - for (var i = 0; i < count; ++i) { - this.addElementAndReset(start + i); - } - }, - - /** - * @private - */ - onDataPush: function() { - var count = arguments.length; - this.insertElements(this.getDataset().data.length - count, count); - }, - - /** - * @private - */ - onDataPop: function() { - this.getMeta().data.pop(); - }, - - /** - * @private - */ - onDataShift: function() { - this.getMeta().data.shift(); - }, - - /** - * @private - */ - onDataSplice: function(start, count) { - this.getMeta().data.splice(start, count); - this.insertElements(start, arguments.length - 2); - }, - - /** - * @private - */ - onDataUnshift: function() { - this.insertElements(0, arguments.length); - } -}); - -DatasetController.extend = helpers$1.inherits; - -var core_datasetController = DatasetController; - -var TAU = Math.PI * 2; - -core_defaults._set('global', { - elements: { - arc: { - backgroundColor: core_defaults.global.defaultColor, - borderColor: '#fff', - borderWidth: 2, - borderAlign: 'center' - } - } -}); - -function clipArc(ctx, arc) { - var startAngle = arc.startAngle; - var endAngle = arc.endAngle; - var pixelMargin = arc.pixelMargin; - var angleMargin = pixelMargin / arc.outerRadius; - var x = arc.x; - var y = arc.y; - - // Draw an inner border by cliping the arc and drawing a double-width border - // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders - ctx.beginPath(); - ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin); - if (arc.innerRadius > pixelMargin) { - angleMargin = pixelMargin / arc.innerRadius; - ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true); - } else { - ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); - } - ctx.closePath(); - ctx.clip(); -} - -function drawFullCircleBorders(ctx, vm, arc, inner) { - var endAngle = arc.endAngle; - var i; - - if (inner) { - arc.endAngle = arc.startAngle + TAU; - clipArc(ctx, arc); - arc.endAngle = endAngle; - if (arc.endAngle === arc.startAngle && arc.fullCircles) { - arc.endAngle += TAU; - arc.fullCircles--; - } - } - - ctx.beginPath(); - ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true); - for (i = 0; i < arc.fullCircles; ++i) { - ctx.stroke(); - } - - ctx.beginPath(); - ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU); - for (i = 0; i < arc.fullCircles; ++i) { - ctx.stroke(); - } -} - -function drawBorder(ctx, vm, arc) { - var inner = vm.borderAlign === 'inner'; - - if (inner) { - ctx.lineWidth = vm.borderWidth * 2; - ctx.lineJoin = 'round'; - } else { - ctx.lineWidth = vm.borderWidth; - ctx.lineJoin = 'bevel'; - } - - if (arc.fullCircles) { - drawFullCircleBorders(ctx, vm, arc, inner); - } - - if (inner) { - clipArc(ctx, arc); - } - - ctx.beginPath(); - ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle); - ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); - ctx.closePath(); - ctx.stroke(); -} - -var element_arc = core_element.extend({ - _type: 'arc', - - inLabelRange: function(mouseX) { - var vm = this._view; - - if (vm) { - return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2)); - } - return false; - }, - - inRange: function(chartX, chartY) { - var vm = this._view; - - if (vm) { - var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY}); - var angle = pointRelativePosition.angle; - var distance = pointRelativePosition.distance; - - // Sanitise angle range - var startAngle = vm.startAngle; - var endAngle = vm.endAngle; - while (endAngle < startAngle) { - endAngle += TAU; - } - while (angle > endAngle) { - angle -= TAU; - } - while (angle < startAngle) { - angle += TAU; - } - - // Check if within the range of the open/close angle - var betweenAngles = (angle >= startAngle && angle <= endAngle); - var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius); - - return (betweenAngles && withinRadius); - } - return false; - }, - - getCenterPoint: function() { - var vm = this._view; - var halfAngle = (vm.startAngle + vm.endAngle) / 2; - var halfRadius = (vm.innerRadius + vm.outerRadius) / 2; - return { - x: vm.x + Math.cos(halfAngle) * halfRadius, - y: vm.y + Math.sin(halfAngle) * halfRadius - }; - }, - - getArea: function() { - var vm = this._view; - return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2)); - }, - - tooltipPosition: function() { - var vm = this._view; - var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2); - var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius; - - return { - x: vm.x + (Math.cos(centreAngle) * rangeFromCentre), - y: vm.y + (Math.sin(centreAngle) * rangeFromCentre) - }; - }, - - draw: function() { - var ctx = this._chart.ctx; - var vm = this._view; - var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0; - var arc = { - x: vm.x, - y: vm.y, - innerRadius: vm.innerRadius, - outerRadius: Math.max(vm.outerRadius - pixelMargin, 0), - pixelMargin: pixelMargin, - startAngle: vm.startAngle, - endAngle: vm.endAngle, - fullCircles: Math.floor(vm.circumference / TAU) - }; - var i; - - ctx.save(); - - ctx.fillStyle = vm.backgroundColor; - ctx.strokeStyle = vm.borderColor; - - if (arc.fullCircles) { - arc.endAngle = arc.startAngle + TAU; - ctx.beginPath(); - ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); - ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); - ctx.closePath(); - for (i = 0; i < arc.fullCircles; ++i) { - ctx.fill(); - } - arc.endAngle = arc.startAngle + vm.circumference % TAU; - } - - ctx.beginPath(); - ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle); - ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true); - ctx.closePath(); - ctx.fill(); - - if (vm.borderWidth) { - drawBorder(ctx, vm, arc); - } - - ctx.restore(); - } -}); - -var valueOrDefault$1 = helpers$1.valueOrDefault; - -var defaultColor = core_defaults.global.defaultColor; - -core_defaults._set('global', { - elements: { - line: { - tension: 0.4, - backgroundColor: defaultColor, - borderWidth: 3, - borderColor: defaultColor, - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - capBezierPoints: true, - fill: true, // do we fill in the area between the line and its base axis - } - } -}); - -var element_line = core_element.extend({ - _type: 'line', - - draw: function() { - var me = this; - var vm = me._view; - var ctx = me._chart.ctx; - var spanGaps = vm.spanGaps; - var points = me._children.slice(); // clone array - var globalDefaults = core_defaults.global; - var globalOptionLineElements = globalDefaults.elements.line; - var lastDrawnIndex = -1; - var closePath = me._loop; - var index, previous, currentVM; - - if (!points.length) { - return; - } - - if (me._loop) { - for (index = 0; index < points.length; ++index) { - previous = helpers$1.previousItem(points, index); - // If the line has an open path, shift the point array - if (!points[index]._view.skip && previous._view.skip) { - points = points.slice(index).concat(points.slice(0, index)); - closePath = spanGaps; - break; - } - } - // If the line has a close path, add the first point again - if (closePath) { - points.push(points[0]); - } - } - - ctx.save(); - - // Stroke Line Options - ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle; - - // IE 9 and 10 do not support line dash - if (ctx.setLineDash) { - ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash); - } - - ctx.lineDashOffset = valueOrDefault$1(vm.borderDashOffset, globalOptionLineElements.borderDashOffset); - ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle; - ctx.lineWidth = valueOrDefault$1(vm.borderWidth, globalOptionLineElements.borderWidth); - ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor; - - // Stroke Line - ctx.beginPath(); - - // First point moves to it's starting position no matter what - currentVM = points[0]._view; - if (!currentVM.skip) { - ctx.moveTo(currentVM.x, currentVM.y); - lastDrawnIndex = 0; - } - - for (index = 1; index < points.length; ++index) { - currentVM = points[index]._view; - previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : points[lastDrawnIndex]; - - if (!currentVM.skip) { - if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) { - // There was a gap and this is the first point after the gap - ctx.moveTo(currentVM.x, currentVM.y); - } else { - // Line to next point - helpers$1.canvas.lineTo(ctx, previous._view, currentVM); - } - lastDrawnIndex = index; - } - } - - if (closePath) { - ctx.closePath(); - } - - ctx.stroke(); - ctx.restore(); - } -}); - -var valueOrDefault$2 = helpers$1.valueOrDefault; - -var defaultColor$1 = core_defaults.global.defaultColor; - -core_defaults._set('global', { - elements: { - point: { - radius: 3, - pointStyle: 'circle', - backgroundColor: defaultColor$1, - borderColor: defaultColor$1, - borderWidth: 1, - // Hover - hitRadius: 1, - hoverRadius: 4, - hoverBorderWidth: 1 - } - } -}); - -function xRange(mouseX) { - var vm = this._view; - return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false; -} - -function yRange(mouseY) { - var vm = this._view; - return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false; -} - -var element_point = core_element.extend({ - _type: 'point', - - inRange: function(mouseX, mouseY) { - var vm = this._view; - return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false; - }, - - inLabelRange: xRange, - inXRange: xRange, - inYRange: yRange, - - getCenterPoint: function() { - var vm = this._view; - return { - x: vm.x, - y: vm.y - }; - }, - - getArea: function() { - return Math.PI * Math.pow(this._view.radius, 2); - }, - - tooltipPosition: function() { - var vm = this._view; - return { - x: vm.x, - y: vm.y, - padding: vm.radius + vm.borderWidth - }; - }, - - draw: function(chartArea) { - var vm = this._view; - var ctx = this._chart.ctx; - var pointStyle = vm.pointStyle; - var rotation = vm.rotation; - var radius = vm.radius; - var x = vm.x; - var y = vm.y; - var globalDefaults = core_defaults.global; - var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow - - if (vm.skip) { - return; - } - - // Clipping for Points. - if (chartArea === undefined || helpers$1.canvas._isPointInArea(vm, chartArea)) { - ctx.strokeStyle = vm.borderColor || defaultColor; - ctx.lineWidth = valueOrDefault$2(vm.borderWidth, globalDefaults.elements.point.borderWidth); - ctx.fillStyle = vm.backgroundColor || defaultColor; - helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation); - } - } -}); - -var defaultColor$2 = core_defaults.global.defaultColor; - -core_defaults._set('global', { - elements: { - rectangle: { - backgroundColor: defaultColor$2, - borderColor: defaultColor$2, - borderSkipped: 'bottom', - borderWidth: 0 - } - } -}); - -function isVertical(vm) { - return vm && vm.width !== undefined; -} - -/** - * Helper function to get the bounds of the bar regardless of the orientation - * @param bar {Chart.Element.Rectangle} the bar - * @return {Bounds} bounds of the bar - * @private - */ -function getBarBounds(vm) { - var x1, x2, y1, y2, half; - - if (isVertical(vm)) { - half = vm.width / 2; - x1 = vm.x - half; - x2 = vm.x + half; - y1 = Math.min(vm.y, vm.base); - y2 = Math.max(vm.y, vm.base); - } else { - half = vm.height / 2; - x1 = Math.min(vm.x, vm.base); - x2 = Math.max(vm.x, vm.base); - y1 = vm.y - half; - y2 = vm.y + half; - } - - return { - left: x1, - top: y1, - right: x2, - bottom: y2 - }; -} - -function swap(orig, v1, v2) { - return orig === v1 ? v2 : orig === v2 ? v1 : orig; -} - -function parseBorderSkipped(vm) { - var edge = vm.borderSkipped; - var res = {}; - - if (!edge) { - return res; - } - - if (vm.horizontal) { - if (vm.base > vm.x) { - edge = swap(edge, 'left', 'right'); - } - } else if (vm.base < vm.y) { - edge = swap(edge, 'bottom', 'top'); - } - - res[edge] = true; - return res; -} - -function parseBorderWidth(vm, maxW, maxH) { - var value = vm.borderWidth; - var skip = parseBorderSkipped(vm); - var t, r, b, l; - - if (helpers$1.isObject(value)) { - t = +value.top || 0; - r = +value.right || 0; - b = +value.bottom || 0; - l = +value.left || 0; - } else { - t = r = b = l = +value || 0; - } - - return { - t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t, - r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r, - b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b, - l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l - }; -} - -function boundingRects(vm) { - var bounds = getBarBounds(vm); - var width = bounds.right - bounds.left; - var height = bounds.bottom - bounds.top; - var border = parseBorderWidth(vm, width / 2, height / 2); - - return { - outer: { - x: bounds.left, - y: bounds.top, - w: width, - h: height - }, - inner: { - x: bounds.left + border.l, - y: bounds.top + border.t, - w: width - border.l - border.r, - h: height - border.t - border.b - } - }; -} - -function inRange(vm, x, y) { - var skipX = x === null; - var skipY = y === null; - var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm); - - return bounds - && (skipX || x >= bounds.left && x <= bounds.right) - && (skipY || y >= bounds.top && y <= bounds.bottom); -} - -var element_rectangle = core_element.extend({ - _type: 'rectangle', - - draw: function() { - var ctx = this._chart.ctx; - var vm = this._view; - var rects = boundingRects(vm); - var outer = rects.outer; - var inner = rects.inner; - - ctx.fillStyle = vm.backgroundColor; - ctx.fillRect(outer.x, outer.y, outer.w, outer.h); - - if (outer.w === inner.w && outer.h === inner.h) { - return; - } - - ctx.save(); - ctx.beginPath(); - ctx.rect(outer.x, outer.y, outer.w, outer.h); - ctx.clip(); - ctx.fillStyle = vm.borderColor; - ctx.rect(inner.x, inner.y, inner.w, inner.h); - ctx.fill('evenodd'); - ctx.restore(); - }, - - height: function() { - var vm = this._view; - return vm.base - vm.y; - }, - - inRange: function(mouseX, mouseY) { - return inRange(this._view, mouseX, mouseY); - }, - - inLabelRange: function(mouseX, mouseY) { - var vm = this._view; - return isVertical(vm) - ? inRange(vm, mouseX, null) - : inRange(vm, null, mouseY); - }, - - inXRange: function(mouseX) { - return inRange(this._view, mouseX, null); - }, - - inYRange: function(mouseY) { - return inRange(this._view, null, mouseY); - }, - - getCenterPoint: function() { - var vm = this._view; - var x, y; - if (isVertical(vm)) { - x = vm.x; - y = (vm.y + vm.base) / 2; - } else { - x = (vm.x + vm.base) / 2; - y = vm.y; - } - - return {x: x, y: y}; - }, - - getArea: function() { - var vm = this._view; - - return isVertical(vm) - ? vm.width * Math.abs(vm.y - vm.base) - : vm.height * Math.abs(vm.x - vm.base); - }, - - tooltipPosition: function() { - var vm = this._view; - return { - x: vm.x, - y: vm.y - }; - } -}); - -var elements = {}; -var Arc = element_arc; -var Line = element_line; -var Point = element_point; -var Rectangle = element_rectangle; -elements.Arc = Arc; -elements.Line = Line; -elements.Point = Point; -elements.Rectangle = Rectangle; - -var deprecated = helpers$1._deprecated; -var valueOrDefault$3 = helpers$1.valueOrDefault; - -core_defaults._set('bar', { - hover: { - mode: 'label' - }, - - scales: { - xAxes: [{ - type: 'category', - offset: true, - gridLines: { - offsetGridLines: true - } - }], - - yAxes: [{ - type: 'linear' - }] - } -}); - -core_defaults._set('global', { - datasets: { - bar: { - categoryPercentage: 0.8, - barPercentage: 0.9 - } - } -}); - -/** - * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap. - * @private - */ -function computeMinSampleSize(scale, pixels) { - var min = scale._length; - var prev, curr, i, ilen; - - for (i = 1, ilen = pixels.length; i < ilen; ++i) { - min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1])); - } - - for (i = 0, ilen = scale.getTicks().length; i < ilen; ++i) { - curr = scale.getPixelForTick(i); - min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min; - prev = curr; - } - - return min; -} - -/** - * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null, - * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This - * mode currently always generates bars equally sized (until we introduce scriptable options?). - * @private - */ -function computeFitCategoryTraits(index, ruler, options) { - var thickness = options.barThickness; - var count = ruler.stackCount; - var curr = ruler.pixels[index]; - var min = helpers$1.isNullOrUndef(thickness) - ? computeMinSampleSize(ruler.scale, ruler.pixels) - : -1; - var size, ratio; - - if (helpers$1.isNullOrUndef(thickness)) { - size = min * options.categoryPercentage; - ratio = options.barPercentage; - } else { - // When bar thickness is enforced, category and bar percentages are ignored. - // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%') - // and deprecate barPercentage since this value is ignored when thickness is absolute. - size = thickness * count; - ratio = 1; - } - - return { - chunk: size / count, - ratio: ratio, - start: curr - (size / 2) - }; -} - -/** - * Computes an "optimal" category that globally arranges bars side by side (no gap when - * percentage options are 1), based on the previous and following categories. This mode - * generates bars with different widths when data are not evenly spaced. - * @private - */ -function computeFlexCategoryTraits(index, ruler, options) { - var pixels = ruler.pixels; - var curr = pixels[index]; - var prev = index > 0 ? pixels[index - 1] : null; - var next = index < pixels.length - 1 ? pixels[index + 1] : null; - var percent = options.categoryPercentage; - var start, size; - - if (prev === null) { - // first data: its size is double based on the next point or, - // if it's also the last data, we use the scale size. - prev = curr - (next === null ? ruler.end - ruler.start : next - curr); - } - - if (next === null) { - // last data: its size is also double based on the previous point. - next = curr + curr - prev; - } - - start = curr - (curr - Math.min(prev, next)) / 2 * percent; - size = Math.abs(next - prev) / 2 * percent; - - return { - chunk: size / ruler.stackCount, - ratio: options.barPercentage, - start: start - }; -} - -var controller_bar = core_datasetController.extend({ - - dataElementType: elements.Rectangle, - - /** - * @private - */ - _dataElementOptions: [ - 'backgroundColor', - 'borderColor', - 'borderSkipped', - 'borderWidth', - 'barPercentage', - 'barThickness', - 'categoryPercentage', - 'maxBarThickness', - 'minBarLength' - ], - - initialize: function() { - var me = this; - var meta, scaleOpts; - - core_datasetController.prototype.initialize.apply(me, arguments); - - meta = me.getMeta(); - meta.stack = me.getDataset().stack; - meta.bar = true; - - scaleOpts = me._getIndexScale().options; - deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage'); - deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness'); - deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage'); - deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength'); - deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness'); - }, - - update: function(reset) { - var me = this; - var rects = me.getMeta().data; - var i, ilen; - - me._ruler = me.getRuler(); - - for (i = 0, ilen = rects.length; i < ilen; ++i) { - me.updateElement(rects[i], i, reset); - } - }, - - updateElement: function(rectangle, index, reset) { - var me = this; - var meta = me.getMeta(); - var dataset = me.getDataset(); - var options = me._resolveDataElementOptions(rectangle, index); - - rectangle._xScale = me.getScaleForId(meta.xAxisID); - rectangle._yScale = me.getScaleForId(meta.yAxisID); - rectangle._datasetIndex = me.index; - rectangle._index = index; - rectangle._model = { - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderSkipped: options.borderSkipped, - borderWidth: options.borderWidth, - datasetLabel: dataset.label, - label: me.chart.data.labels[index] - }; - - if (helpers$1.isArray(dataset.data[index])) { - rectangle._model.borderSkipped = null; - } - - me._updateElementGeometry(rectangle, index, reset, options); - - rectangle.pivot(); - }, - - /** - * @private - */ - _updateElementGeometry: function(rectangle, index, reset, options) { - var me = this; - var model = rectangle._model; - var vscale = me._getValueScale(); - var base = vscale.getBasePixel(); - var horizontal = vscale.isHorizontal(); - var ruler = me._ruler || me.getRuler(); - var vpixels = me.calculateBarValuePixels(me.index, index, options); - var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options); - - model.horizontal = horizontal; - model.base = reset ? base : vpixels.base; - model.x = horizontal ? reset ? base : vpixels.head : ipixels.center; - model.y = horizontal ? ipixels.center : reset ? base : vpixels.head; - model.height = horizontal ? ipixels.size : undefined; - model.width = horizontal ? undefined : ipixels.size; - }, - - /** - * Returns the stacks based on groups and bar visibility. - * @param {number} [last] - The dataset index - * @returns {string[]} The list of stack IDs - * @private - */ - _getStacks: function(last) { - var me = this; - var scale = me._getIndexScale(); - var metasets = scale._getMatchingVisibleMetas(me._type); - var stacked = scale.options.stacked; - var ilen = metasets.length; - var stacks = []; - var i, meta; - - for (i = 0; i < ilen; ++i) { - meta = metasets[i]; - // stacked | meta.stack - // | found | not found | undefined - // false | x | x | x - // true | | x | - // undefined | | x | x - if (stacked === false || stacks.indexOf(meta.stack) === -1 || - (stacked === undefined && meta.stack === undefined)) { - stacks.push(meta.stack); - } - if (meta.index === last) { - break; - } - } - - return stacks; - }, - - /** - * Returns the effective number of stacks based on groups and bar visibility. - * @private - */ - getStackCount: function() { - return this._getStacks().length; - }, - - /** - * Returns the stack index for the given dataset based on groups and bar visibility. - * @param {number} [datasetIndex] - The dataset index - * @param {string} [name] - The stack name to find - * @returns {number} The stack index - * @private - */ - getStackIndex: function(datasetIndex, name) { - var stacks = this._getStacks(datasetIndex); - var index = (name !== undefined) - ? stacks.indexOf(name) - : -1; // indexOf returns -1 if element is not present - - return (index === -1) - ? stacks.length - 1 - : index; - }, - - /** - * @private - */ - getRuler: function() { - var me = this; - var scale = me._getIndexScale(); - var pixels = []; - var i, ilen; - - for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) { - pixels.push(scale.getPixelForValue(null, i, me.index)); - } - - return { - pixels: pixels, - start: scale._startPixel, - end: scale._endPixel, - stackCount: me.getStackCount(), - scale: scale - }; - }, - - /** - * Note: pixel values are not clamped to the scale area. - * @private - */ - calculateBarValuePixels: function(datasetIndex, index, options) { - var me = this; - var chart = me.chart; - var scale = me._getValueScale(); - var isHorizontal = scale.isHorizontal(); - var datasets = chart.data.datasets; - var metasets = scale._getMatchingVisibleMetas(me._type); - var value = scale._parseValue(datasets[datasetIndex].data[index]); - var minBarLength = options.minBarLength; - var stacked = scale.options.stacked; - var stack = me.getMeta().stack; - var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max; - var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max; - var ilen = metasets.length; - var i, imeta, ivalue, base, head, size, stackLength; - - if (stacked || (stacked === undefined && stack !== undefined)) { - for (i = 0; i < ilen; ++i) { - imeta = metasets[i]; - - if (imeta.index === datasetIndex) { - break; - } - - if (imeta.stack === stack) { - stackLength = scale._parseValue(datasets[imeta.index].data[index]); - ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min; - - if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) { - start += ivalue; - } - } - } - } - - base = scale.getPixelForValue(start); - head = scale.getPixelForValue(start + length); - size = head - base; - - if (minBarLength !== undefined && Math.abs(size) < minBarLength) { - size = minBarLength; - if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) { - head = base - minBarLength; - } else { - head = base + minBarLength; - } - } - - return { - size: size, - base: base, - head: head, - center: head + size / 2 - }; - }, - - /** - * @private - */ - calculateBarIndexPixels: function(datasetIndex, index, ruler, options) { - var me = this; - var range = options.barThickness === 'flex' - ? computeFlexCategoryTraits(index, ruler, options) - : computeFitCategoryTraits(index, ruler, options); - - var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack); - var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); - var size = Math.min( - valueOrDefault$3(options.maxBarThickness, Infinity), - range.chunk * range.ratio); - - return { - base: center - size / 2, - head: center + size / 2, - center: center, - size: size - }; - }, - - draw: function() { - var me = this; - var chart = me.chart; - var scale = me._getValueScale(); - var rects = me.getMeta().data; - var dataset = me.getDataset(); - var ilen = rects.length; - var i = 0; - - helpers$1.canvas.clipArea(chart.ctx, chart.chartArea); - - for (; i < ilen; ++i) { - var val = scale._parseValue(dataset.data[i]); - if (!isNaN(val.min) && !isNaN(val.max)) { - rects[i].draw(); - } - } - - helpers$1.canvas.unclipArea(chart.ctx); - }, - - /** - * @private - */ - _resolveDataElementOptions: function() { - var me = this; - var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments)); - var indexOpts = me._getIndexScale().options; - var valueOpts = me._getValueScale().options; - - values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage); - values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness); - values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage); - values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness); - values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength); - - return values; - } - -}); - -var valueOrDefault$4 = helpers$1.valueOrDefault; -var resolve$1 = helpers$1.options.resolve; - -core_defaults._set('bubble', { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - type: 'linear', // bubble should probably use a linear scale by default - position: 'bottom', - id: 'x-axis-0' // need an ID so datasets can reference the scale - }], - yAxes: [{ - type: 'linear', - position: 'left', - id: 'y-axis-0' - }] - }, - - tooltips: { - callbacks: { - title: function() { - // Title doesn't make sense for scatter since we format the data as a point - return ''; - }, - label: function(item, data) { - var datasetLabel = data.datasets[item.datasetIndex].label || ''; - var dataPoint = data.datasets[item.datasetIndex].data[item.index]; - return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')'; - } - } - } -}); - -var controller_bubble = core_datasetController.extend({ - /** - * @protected - */ - dataElementType: elements.Point, - - /** - * @private - */ - _dataElementOptions: [ - 'backgroundColor', - 'borderColor', - 'borderWidth', - 'hoverBackgroundColor', - 'hoverBorderColor', - 'hoverBorderWidth', - 'hoverRadius', - 'hitRadius', - 'pointStyle', - 'rotation' - ], - - /** - * @protected - */ - update: function(reset) { - var me = this; - var meta = me.getMeta(); - var points = meta.data; - - // Update Points - helpers$1.each(points, function(point, index) { - me.updateElement(point, index, reset); - }); - }, - - /** - * @protected - */ - updateElement: function(point, index, reset) { - var me = this; - var meta = me.getMeta(); - var custom = point.custom || {}; - var xScale = me.getScaleForId(meta.xAxisID); - var yScale = me.getScaleForId(meta.yAxisID); - var options = me._resolveDataElementOptions(point, index); - var data = me.getDataset().data[index]; - var dsIndex = me.index; - - var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex); - var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex); - - point._xScale = xScale; - point._yScale = yScale; - point._options = options; - point._datasetIndex = dsIndex; - point._index = index; - point._model = { - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - hitRadius: options.hitRadius, - pointStyle: options.pointStyle, - rotation: options.rotation, - radius: reset ? 0 : options.radius, - skip: custom.skip || isNaN(x) || isNaN(y), - x: x, - y: y, - }; - - point.pivot(); - }, - - /** - * @protected - */ - setHoverStyle: function(point) { - var model = point._model; - var options = point._options; - var getHoverColor = helpers$1.getHoverColor; - - point.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth, - radius: model.radius - }; - - model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor)); - model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor)); - model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth); - model.radius = options.radius + options.hoverRadius; - }, - - /** - * @private - */ - _resolveDataElementOptions: function(point, index) { - var me = this; - var chart = me.chart; - var dataset = me.getDataset(); - var custom = point.custom || {}; - var data = dataset.data[index] || {}; - var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments); - - // Scriptable options - var context = { - chart: chart, - dataIndex: index, - dataset: dataset, - datasetIndex: me.index - }; - - // In case values were cached (and thus frozen), we need to clone the values - if (me._cachedDataOpts === values) { - values = helpers$1.extend({}, values); - } - - // Custom radius resolution - values.radius = resolve$1([ - custom.radius, - data.r, - me._config.radius, - chart.options.elements.point.radius - ], context, index); - - return values; - } -}); - -var valueOrDefault$5 = helpers$1.valueOrDefault; - -var PI$1 = Math.PI; -var DOUBLE_PI$1 = PI$1 * 2; -var HALF_PI$1 = PI$1 / 2; - -core_defaults._set('doughnut', { - animation: { - // Boolean - Whether we animate the rotation of the Doughnut - animateRotate: true, - // Boolean - Whether we animate scaling the Doughnut from the centre - animateScale: false - }, - hover: { - mode: 'single' - }, - legendCallback: function(chart) { - var list = document.createElement('ul'); - var data = chart.data; - var datasets = data.datasets; - var labels = data.labels; - var i, ilen, listItem, listItemSpan; - - list.setAttribute('class', chart.id + '-legend'); - if (datasets.length) { - for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) { - listItem = list.appendChild(document.createElement('li')); - listItemSpan = listItem.appendChild(document.createElement('span')); - listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i]; - if (labels[i]) { - listItem.appendChild(document.createTextNode(labels[i])); - } - } - } - - return list.outerHTML; - }, - legend: { - labels: { - generateLabels: function(chart) { - var data = chart.data; - if (data.labels.length && data.datasets.length) { - return data.labels.map(function(label, i) { - var meta = chart.getDatasetMeta(0); - var style = meta.controller.getStyle(i); - - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden, - - // Extra data used for toggling the correct item - index: i - }; - }); - } - return []; - } - }, - - onClick: function(e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - // toggle visibility of index if exists - if (meta.data[index]) { - meta.data[index].hidden = !meta.data[index].hidden; - } - } - - chart.update(); - } - }, - - // The percentage of the chart that we cut out of the middle. - cutoutPercentage: 50, - - // The rotation of the chart, where the first data arc begins. - rotation: -HALF_PI$1, - - // The total circumference of the chart. - circumference: DOUBLE_PI$1, - - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function() { - return ''; - }, - label: function(tooltipItem, data) { - var dataLabel = data.labels[tooltipItem.index]; - var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; - - if (helpers$1.isArray(dataLabel)) { - // show value on first line of multiline label - // need to clone because we are changing the value - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - - return dataLabel; - } - } - } -}); - -var controller_doughnut = core_datasetController.extend({ - - dataElementType: elements.Arc, - - linkScales: helpers$1.noop, - - /** - * @private - */ - _dataElementOptions: [ - 'backgroundColor', - 'borderColor', - 'borderWidth', - 'borderAlign', - 'hoverBackgroundColor', - 'hoverBorderColor', - 'hoverBorderWidth', - ], - - // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly - getRingIndex: function(datasetIndex) { - var ringIndex = 0; - - for (var j = 0; j < datasetIndex; ++j) { - if (this.chart.isDatasetVisible(j)) { - ++ringIndex; - } - } - - return ringIndex; - }, - - update: function(reset) { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var opts = chart.options; - var ratioX = 1; - var ratioY = 1; - var offsetX = 0; - var offsetY = 0; - var meta = me.getMeta(); - var arcs = meta.data; - var cutout = opts.cutoutPercentage / 100 || 0; - var circumference = opts.circumference; - var chartWeight = me._getRingWeight(me.index); - var maxWidth, maxHeight, i, ilen; - - // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc - if (circumference < DOUBLE_PI$1) { - var startAngle = opts.rotation % DOUBLE_PI$1; - startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0; - var endAngle = startAngle + circumference; - var startX = Math.cos(startAngle); - var startY = Math.sin(startAngle); - var endX = Math.cos(endAngle); - var endY = Math.sin(endAngle); - var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1; - var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1; - var contains180 = startAngle === -PI$1 || endAngle >= PI$1; - var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1; - var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout); - var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout); - var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout); - var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout); - ratioX = (maxX - minX) / 2; - ratioY = (maxY - minY) / 2; - offsetX = -(maxX + minX) / 2; - offsetY = -(maxY + minY) / 2; - } - - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - arcs[i]._options = me._resolveDataElementOptions(arcs[i], i); - } - - chart.borderWidth = me.getMaxBorderWidth(); - maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX; - maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY; - chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); - chart.innerRadius = Math.max(chart.outerRadius * cutout, 0); - chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1); - chart.offsetX = offsetX * chart.outerRadius; - chart.offsetY = offsetY * chart.outerRadius; - - meta.total = me.calculateTotal(); - - me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index); - me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0); - - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - me.updateElement(arcs[i], i, reset); - } - }, - - updateElement: function(arc, index, reset) { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var opts = chart.options; - var animationOpts = opts.animation; - var centerX = (chartArea.left + chartArea.right) / 2; - var centerY = (chartArea.top + chartArea.bottom) / 2; - var startAngle = opts.rotation; // non reset case handled later - var endAngle = opts.rotation; // non reset case handled later - var dataset = me.getDataset(); - var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI$1); - var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius; - var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius; - var options = arc._options || {}; - - helpers$1.extend(arc, { - // Utility - _datasetIndex: me.index, - _index: index, - - // Desired view properties - _model: { - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - borderAlign: options.borderAlign, - x: centerX + chart.offsetX, - y: centerY + chart.offsetY, - startAngle: startAngle, - endAngle: endAngle, - circumference: circumference, - outerRadius: outerRadius, - innerRadius: innerRadius, - label: helpers$1.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) - } - }); - - var model = arc._model; - - // Set correct angles if not resetting - if (!reset || !animationOpts.animateRotate) { - if (index === 0) { - model.startAngle = opts.rotation; - } else { - model.startAngle = me.getMeta().data[index - 1]._model.endAngle; - } - - model.endAngle = model.startAngle + model.circumference; - } - - arc.pivot(); - }, - - calculateTotal: function() { - var dataset = this.getDataset(); - var meta = this.getMeta(); - var total = 0; - var value; - - helpers$1.each(meta.data, function(element, index) { - value = dataset.data[index]; - if (!isNaN(value) && !element.hidden) { - total += Math.abs(value); - } - }); - - /* if (total === 0) { - total = NaN; - }*/ - - return total; - }, - - calculateCircumference: function(value) { - var total = this.getMeta().total; - if (total > 0 && !isNaN(value)) { - return DOUBLE_PI$1 * (Math.abs(value) / total); - } - return 0; - }, - - // gets the max border or hover width to properly scale pie charts - getMaxBorderWidth: function(arcs) { - var me = this; - var max = 0; - var chart = me.chart; - var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth; - - if (!arcs) { - // Find the outmost visible dataset - for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { - if (chart.isDatasetVisible(i)) { - meta = chart.getDatasetMeta(i); - arcs = meta.data; - if (i !== me.index) { - controller = meta.controller; - } - break; - } - } - } - - if (!arcs) { - return 0; - } - - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - arc = arcs[i]; - if (controller) { - controller._configure(); - options = controller._resolveDataElementOptions(arc, i); - } else { - options = arc._options; - } - if (options.borderAlign !== 'inner') { - borderWidth = options.borderWidth; - hoverWidth = options.hoverBorderWidth; - - max = borderWidth > max ? borderWidth : max; - max = hoverWidth > max ? hoverWidth : max; - } - } - return max; - }, - - /** - * @protected - */ - setHoverStyle: function(arc) { - var model = arc._model; - var options = arc._options; - var getHoverColor = helpers$1.getHoverColor; - - arc.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth, - }; - - model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor)); - model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor)); - model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth); - }, - - /** - * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly - * @private - */ - _getRingWeightOffset: function(datasetIndex) { - var ringWeightOffset = 0; - - for (var i = 0; i < datasetIndex; ++i) { - if (this.chart.isDatasetVisible(i)) { - ringWeightOffset += this._getRingWeight(i); - } - } - - return ringWeightOffset; - }, - - /** - * @private - */ - _getRingWeight: function(dataSetIndex) { - return Math.max(valueOrDefault$5(this.chart.data.datasets[dataSetIndex].weight, 1), 0); - }, - - /** - * Returns the sum of all visibile data set weights. This value can be 0. - * @private - */ - _getVisibleDatasetWeightTotal: function() { - return this._getRingWeightOffset(this.chart.data.datasets.length); - } -}); - -core_defaults._set('horizontalBar', { - hover: { - mode: 'index', - axis: 'y' - }, - - scales: { - xAxes: [{ - type: 'linear', - position: 'bottom' - }], - - yAxes: [{ - type: 'category', - position: 'left', - offset: true, - gridLines: { - offsetGridLines: true - } - }] - }, - - elements: { - rectangle: { - borderSkipped: 'left' - } - }, - - tooltips: { - mode: 'index', - axis: 'y' - } -}); - -core_defaults._set('global', { - datasets: { - horizontalBar: { - categoryPercentage: 0.8, - barPercentage: 0.9 - } - } -}); - -var controller_horizontalBar = controller_bar.extend({ - /** - * @private - */ - _getValueScaleId: function() { - return this.getMeta().xAxisID; - }, - - /** - * @private - */ - _getIndexScaleId: function() { - return this.getMeta().yAxisID; - } -}); - -var valueOrDefault$6 = helpers$1.valueOrDefault; -var resolve$2 = helpers$1.options.resolve; -var isPointInArea = helpers$1.canvas._isPointInArea; - -core_defaults._set('line', { - showLines: true, - spanGaps: false, - - hover: { - mode: 'label' - }, - - scales: { - xAxes: [{ - type: 'category', - id: 'x-axis-0' - }], - yAxes: [{ - type: 'linear', - id: 'y-axis-0' - }] - } -}); - -function scaleClip(scale, halfBorderWidth) { - var tickOpts = scale && scale.options.ticks || {}; - var reverse = tickOpts.reverse; - var min = tickOpts.min === undefined ? halfBorderWidth : 0; - var max = tickOpts.max === undefined ? halfBorderWidth : 0; - return { - start: reverse ? max : min, - end: reverse ? min : max - }; -} - -function defaultClip(xScale, yScale, borderWidth) { - var halfBorderWidth = borderWidth / 2; - var x = scaleClip(xScale, halfBorderWidth); - var y = scaleClip(yScale, halfBorderWidth); - - return { - top: y.end, - right: x.end, - bottom: y.start, - left: x.start - }; -} - -function toClip(value) { - var t, r, b, l; - - if (helpers$1.isObject(value)) { - t = value.top; - r = value.right; - b = value.bottom; - l = value.left; - } else { - t = r = b = l = value; - } - - return { - top: t, - right: r, - bottom: b, - left: l - }; -} - - -var controller_line = core_datasetController.extend({ - - datasetElementType: elements.Line, - - dataElementType: elements.Point, - - /** - * @private - */ - _datasetElementOptions: [ - 'backgroundColor', - 'borderCapStyle', - 'borderColor', - 'borderDash', - 'borderDashOffset', - 'borderJoinStyle', - 'borderWidth', - 'cubicInterpolationMode', - 'fill' - ], - - /** - * @private - */ - _dataElementOptions: { - backgroundColor: 'pointBackgroundColor', - borderColor: 'pointBorderColor', - borderWidth: 'pointBorderWidth', - hitRadius: 'pointHitRadius', - hoverBackgroundColor: 'pointHoverBackgroundColor', - hoverBorderColor: 'pointHoverBorderColor', - hoverBorderWidth: 'pointHoverBorderWidth', - hoverRadius: 'pointHoverRadius', - pointStyle: 'pointStyle', - radius: 'pointRadius', - rotation: 'pointRotation' - }, - - update: function(reset) { - var me = this; - var meta = me.getMeta(); - var line = meta.dataset; - var points = meta.data || []; - var options = me.chart.options; - var config = me._config; - var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines); - var i, ilen; - - me._xScale = me.getScaleForId(meta.xAxisID); - me._yScale = me.getScaleForId(meta.yAxisID); - - // Update Line - if (showLine) { - // Compatibility: If the properties are defined with only the old name, use those values - if (config.tension !== undefined && config.lineTension === undefined) { - config.lineTension = config.tension; - } - - // Utility - line._scale = me._yScale; - line._datasetIndex = me.index; - // Data - line._children = points; - // Model - line._model = me._resolveDatasetElementOptions(line); - - line.pivot(); - } - - // Update Points - for (i = 0, ilen = points.length; i < ilen; ++i) { - me.updateElement(points[i], i, reset); - } - - if (showLine && line._model.tension !== 0) { - me.updateBezierControlPoints(); - } - - // Now pivot the point for animation - for (i = 0, ilen = points.length; i < ilen; ++i) { - points[i].pivot(); - } - }, - - updateElement: function(point, index, reset) { - var me = this; - var meta = me.getMeta(); - var custom = point.custom || {}; - var dataset = me.getDataset(); - var datasetIndex = me.index; - var value = dataset.data[index]; - var xScale = me._xScale; - var yScale = me._yScale; - var lineModel = meta.dataset._model; - var x, y; - - var options = me._resolveDataElementOptions(point, index); - - x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex); - y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex); - - // Utility - point._xScale = xScale; - point._yScale = yScale; - point._options = options; - point._datasetIndex = datasetIndex; - point._index = index; - - // Desired view properties - point._model = { - x: x, - y: y, - skip: custom.skip || isNaN(x) || isNaN(y), - // Appearance - radius: options.radius, - pointStyle: options.pointStyle, - rotation: options.rotation, - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0), - steppedLine: lineModel ? lineModel.steppedLine : false, - // Tooltip - hitRadius: options.hitRadius - }; - }, - - /** - * @private - */ - _resolveDatasetElementOptions: function(element) { - var me = this; - var config = me._config; - var custom = element.custom || {}; - var options = me.chart.options; - var lineOptions = options.elements.line; - var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments); - - // The default behavior of lines is to break at null values, according - // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158 - // This option gives lines the ability to span gaps - values.spanGaps = valueOrDefault$6(config.spanGaps, options.spanGaps); - values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension); - values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]); - values.clip = toClip(valueOrDefault$6(config.clip, defaultClip(me._xScale, me._yScale, values.borderWidth))); - - return values; - }, - - calculatePointY: function(value, index, datasetIndex) { - var me = this; - var chart = me.chart; - var yScale = me._yScale; - var sumPos = 0; - var sumNeg = 0; - var i, ds, dsMeta, stackedRightValue, rightValue, metasets, ilen; - - if (yScale.options.stacked) { - rightValue = +yScale.getRightValue(value); - metasets = chart._getSortedVisibleDatasetMetas(); - ilen = metasets.length; - - for (i = 0; i < ilen; ++i) { - dsMeta = metasets[i]; - if (dsMeta.index === datasetIndex) { - break; - } - - ds = chart.data.datasets[dsMeta.index]; - if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) { - stackedRightValue = +yScale.getRightValue(ds.data[index]); - if (stackedRightValue < 0) { - sumNeg += stackedRightValue || 0; - } else { - sumPos += stackedRightValue || 0; - } - } - } - - if (rightValue < 0) { - return yScale.getPixelForValue(sumNeg + rightValue); - } - return yScale.getPixelForValue(sumPos + rightValue); - } - return yScale.getPixelForValue(value); - }, - - updateBezierControlPoints: function() { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var lineModel = meta.dataset._model; - var area = chart.chartArea; - var points = meta.data || []; - var i, ilen, model, controlPoints; - - // Only consider points that are drawn in case the spanGaps option is used - if (lineModel.spanGaps) { - points = points.filter(function(pt) { - return !pt._model.skip; - }); - } - - function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); - } - - if (lineModel.cubicInterpolationMode === 'monotone') { - helpers$1.splineCurveMonotone(points); - } else { - for (i = 0, ilen = points.length; i < ilen; ++i) { - model = points[i]._model; - controlPoints = helpers$1.splineCurve( - helpers$1.previousItem(points, i)._model, - model, - helpers$1.nextItem(points, i)._model, - lineModel.tension - ); - model.controlPointPreviousX = controlPoints.previous.x; - model.controlPointPreviousY = controlPoints.previous.y; - model.controlPointNextX = controlPoints.next.x; - model.controlPointNextY = controlPoints.next.y; - } - } - - if (chart.options.elements.line.capBezierPoints) { - for (i = 0, ilen = points.length; i < ilen; ++i) { - model = points[i]._model; - if (isPointInArea(model, area)) { - if (i > 0 && isPointInArea(points[i - 1]._model, area)) { - model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right); - model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom); - } - if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) { - model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right); - model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom); - } - } - } - } - }, - - draw: function() { - var me = this; - var chart = me.chart; - var meta = me.getMeta(); - var points = meta.data || []; - var area = chart.chartArea; - var canvas = chart.canvas; - var i = 0; - var ilen = points.length; - var clip; - - if (me._showLine) { - clip = meta.dataset._model.clip; - - helpers$1.canvas.clipArea(chart.ctx, { - left: clip.left === false ? 0 : area.left - clip.left, - right: clip.right === false ? canvas.width : area.right + clip.right, - top: clip.top === false ? 0 : area.top - clip.top, - bottom: clip.bottom === false ? canvas.height : area.bottom + clip.bottom - }); - - meta.dataset.draw(); - - helpers$1.canvas.unclipArea(chart.ctx); - } - - // Draw the points - for (; i < ilen; ++i) { - points[i].draw(area); - } - }, - - /** - * @protected - */ - setHoverStyle: function(point) { - var model = point._model; - var options = point._options; - var getHoverColor = helpers$1.getHoverColor; - - point.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth, - radius: model.radius - }; - - model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor)); - model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor)); - model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth); - model.radius = valueOrDefault$6(options.hoverRadius, options.radius); - }, -}); - -var resolve$3 = helpers$1.options.resolve; - -core_defaults._set('polarArea', { - scale: { - type: 'radialLinear', - angleLines: { - display: false - }, - gridLines: { - circular: true - }, - pointLabels: { - display: false - }, - ticks: { - beginAtZero: true - } - }, - - // Boolean - Whether to animate the rotation of the chart - animation: { - animateRotate: true, - animateScale: true - }, - - startAngle: -0.5 * Math.PI, - legendCallback: function(chart) { - var list = document.createElement('ul'); - var data = chart.data; - var datasets = data.datasets; - var labels = data.labels; - var i, ilen, listItem, listItemSpan; - - list.setAttribute('class', chart.id + '-legend'); - if (datasets.length) { - for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) { - listItem = list.appendChild(document.createElement('li')); - listItemSpan = listItem.appendChild(document.createElement('span')); - listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i]; - if (labels[i]) { - listItem.appendChild(document.createTextNode(labels[i])); - } - } - } - - return list.outerHTML; - }, - legend: { - labels: { - generateLabels: function(chart) { - var data = chart.data; - if (data.labels.length && data.datasets.length) { - return data.labels.map(function(label, i) { - var meta = chart.getDatasetMeta(0); - var style = meta.controller.getStyle(i); - - return { - text: label, - fillStyle: style.backgroundColor, - strokeStyle: style.borderColor, - lineWidth: style.borderWidth, - hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden, - - // Extra data used for toggling the correct item - index: i - }; - }); - } - return []; - } - }, - - onClick: function(e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - meta.data[index].hidden = !meta.data[index].hidden; - } - - chart.update(); - } - }, - - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function() { - return ''; - }, - label: function(item, data) { - return data.labels[item.index] + ': ' + item.yLabel; - } - } - } -}); - -var controller_polarArea = core_datasetController.extend({ - - dataElementType: elements.Arc, - - linkScales: helpers$1.noop, - - /** - * @private - */ - _dataElementOptions: [ - 'backgroundColor', - 'borderColor', - 'borderWidth', - 'borderAlign', - 'hoverBackgroundColor', - 'hoverBorderColor', - 'hoverBorderWidth', - ], - - /** - * @private - */ - _getIndexScaleId: function() { - return this.chart.scale.id; - }, - - /** - * @private - */ - _getValueScaleId: function() { - return this.chart.scale.id; - }, - - update: function(reset) { - var me = this; - var dataset = me.getDataset(); - var meta = me.getMeta(); - var start = me.chart.options.startAngle || 0; - var starts = me._starts = []; - var angles = me._angles = []; - var arcs = meta.data; - var i, ilen, angle; - - me._updateRadius(); - - meta.count = me.countVisibleElements(); - - for (i = 0, ilen = dataset.data.length; i < ilen; i++) { - starts[i] = start; - angle = me._computeAngle(i); - angles[i] = angle; - start += angle; - } - - for (i = 0, ilen = arcs.length; i < ilen; ++i) { - arcs[i]._options = me._resolveDataElementOptions(arcs[i], i); - me.updateElement(arcs[i], i, reset); - } - }, - - /** - * @private - */ - _updateRadius: function() { - var me = this; - var chart = me.chart; - var chartArea = chart.chartArea; - var opts = chart.options; - var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); - - chart.outerRadius = Math.max(minSize / 2, 0); - chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); - chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); - - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); - me.innerRadius = me.outerRadius - chart.radiusLength; - }, - - updateElement: function(arc, index, reset) { - var me = this; - var chart = me.chart; - var dataset = me.getDataset(); - var opts = chart.options; - var animationOpts = opts.animation; - var scale = chart.scale; - var labels = chart.data.labels; - - var centerX = scale.xCenter; - var centerY = scale.yCenter; - - // var negHalfPI = -0.5 * Math.PI; - var datasetStartAngle = opts.startAngle; - var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); - var startAngle = me._starts[index]; - var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]); - - var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); - var options = arc._options || {}; - - helpers$1.extend(arc, { - // Utility - _datasetIndex: me.index, - _index: index, - _scale: scale, - - // Desired view properties - _model: { - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - borderAlign: options.borderAlign, - x: centerX, - y: centerY, - innerRadius: 0, - outerRadius: reset ? resetRadius : distance, - startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, - endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, - label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index]) - } - }); - - arc.pivot(); - }, - - countVisibleElements: function() { - var dataset = this.getDataset(); - var meta = this.getMeta(); - var count = 0; - - helpers$1.each(meta.data, function(element, index) { - if (!isNaN(dataset.data[index]) && !element.hidden) { - count++; - } - }); - - return count; - }, - - /** - * @protected - */ - setHoverStyle: function(arc) { - var model = arc._model; - var options = arc._options; - var getHoverColor = helpers$1.getHoverColor; - var valueOrDefault = helpers$1.valueOrDefault; - - arc.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth, - }; - - model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor)); - model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor)); - model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth); - }, - - /** - * @private - */ - _computeAngle: function(index) { - var me = this; - var count = this.getMeta().count; - var dataset = me.getDataset(); - var meta = me.getMeta(); - - if (isNaN(dataset.data[index]) || meta.data[index].hidden) { - return 0; - } - - // Scriptable options - var context = { - chart: me.chart, - dataIndex: index, - dataset: dataset, - datasetIndex: me.index - }; - - return resolve$3([ - me.chart.options.elements.arc.angle, - (2 * Math.PI) / count - ], context, index); - } -}); - -core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut)); -core_defaults._set('pie', { - cutoutPercentage: 0 -}); - -// Pie charts are Doughnut chart with different defaults -var controller_pie = controller_doughnut; - -var valueOrDefault$7 = helpers$1.valueOrDefault; - -core_defaults._set('radar', { - spanGaps: false, - scale: { - type: 'radialLinear' - }, - elements: { - line: { - fill: 'start', - tension: 0 // no bezier in radar - } - } -}); - -var controller_radar = core_datasetController.extend({ - datasetElementType: elements.Line, - - dataElementType: elements.Point, - - linkScales: helpers$1.noop, - - /** - * @private - */ - _datasetElementOptions: [ - 'backgroundColor', - 'borderWidth', - 'borderColor', - 'borderCapStyle', - 'borderDash', - 'borderDashOffset', - 'borderJoinStyle', - 'fill' - ], - - /** - * @private - */ - _dataElementOptions: { - backgroundColor: 'pointBackgroundColor', - borderColor: 'pointBorderColor', - borderWidth: 'pointBorderWidth', - hitRadius: 'pointHitRadius', - hoverBackgroundColor: 'pointHoverBackgroundColor', - hoverBorderColor: 'pointHoverBorderColor', - hoverBorderWidth: 'pointHoverBorderWidth', - hoverRadius: 'pointHoverRadius', - pointStyle: 'pointStyle', - radius: 'pointRadius', - rotation: 'pointRotation' - }, - - /** - * @private - */ - _getIndexScaleId: function() { - return this.chart.scale.id; - }, - - /** - * @private - */ - _getValueScaleId: function() { - return this.chart.scale.id; - }, - - update: function(reset) { - var me = this; - var meta = me.getMeta(); - var line = meta.dataset; - var points = meta.data || []; - var scale = me.chart.scale; - var config = me._config; - var i, ilen; - - // Compatibility: If the properties are defined with only the old name, use those values - if (config.tension !== undefined && config.lineTension === undefined) { - config.lineTension = config.tension; - } - - // Utility - line._scale = scale; - line._datasetIndex = me.index; - // Data - line._children = points; - line._loop = true; - // Model - line._model = me._resolveDatasetElementOptions(line); - - line.pivot(); - - // Update Points - for (i = 0, ilen = points.length; i < ilen; ++i) { - me.updateElement(points[i], i, reset); - } - - // Update bezier control points - me.updateBezierControlPoints(); - - // Now pivot the point for animation - for (i = 0, ilen = points.length; i < ilen; ++i) { - points[i].pivot(); - } - }, - - updateElement: function(point, index, reset) { - var me = this; - var custom = point.custom || {}; - var dataset = me.getDataset(); - var scale = me.chart.scale; - var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]); - var options = me._resolveDataElementOptions(point, index); - var lineModel = me.getMeta().dataset._model; - var x = reset ? scale.xCenter : pointPosition.x; - var y = reset ? scale.yCenter : pointPosition.y; - - // Utility - point._scale = scale; - point._options = options; - point._datasetIndex = me.index; - point._index = index; - - // Desired view properties - point._model = { - x: x, // value not used in dataset scale, but we want a consistent API between scales - y: y, - skip: custom.skip || isNaN(x) || isNaN(y), - // Appearance - radius: options.radius, - pointStyle: options.pointStyle, - rotation: options.rotation, - backgroundColor: options.backgroundColor, - borderColor: options.borderColor, - borderWidth: options.borderWidth, - tension: valueOrDefault$7(custom.tension, lineModel ? lineModel.tension : 0), - - // Tooltip - hitRadius: options.hitRadius - }; - }, - - /** - * @private - */ - _resolveDatasetElementOptions: function() { - var me = this; - var config = me._config; - var options = me.chart.options; - var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments); - - values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps); - values.tension = valueOrDefault$7(config.lineTension, options.elements.line.tension); - - return values; - }, - - updateBezierControlPoints: function() { - var me = this; - var meta = me.getMeta(); - var area = me.chart.chartArea; - var points = meta.data || []; - var i, ilen, model, controlPoints; - - // Only consider points that are drawn in case the spanGaps option is used - if (meta.dataset._model.spanGaps) { - points = points.filter(function(pt) { - return !pt._model.skip; - }); - } - - function capControlPoint(pt, min, max) { - return Math.max(Math.min(pt, max), min); - } - - for (i = 0, ilen = points.length; i < ilen; ++i) { - model = points[i]._model; - controlPoints = helpers$1.splineCurve( - helpers$1.previousItem(points, i, true)._model, - model, - helpers$1.nextItem(points, i, true)._model, - model.tension - ); - - // Prevent the bezier going outside of the bounds of the graph - model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right); - model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom); - model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right); - model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom); - } - }, - - setHoverStyle: function(point) { - var model = point._model; - var options = point._options; - var getHoverColor = helpers$1.getHoverColor; - - point.$previousStyle = { - backgroundColor: model.backgroundColor, - borderColor: model.borderColor, - borderWidth: model.borderWidth, - radius: model.radius - }; - - model.backgroundColor = valueOrDefault$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor)); - model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor)); - model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth); - model.radius = valueOrDefault$7(options.hoverRadius, options.radius); - } -}); - -core_defaults._set('scatter', { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - id: 'x-axis-1', // need an ID so datasets can reference the scale - type: 'linear', // scatter should not use a category axis - position: 'bottom' - }], - yAxes: [{ - id: 'y-axis-1', - type: 'linear', - position: 'left' - }] - }, - - tooltips: { - callbacks: { - title: function() { - return ''; // doesn't make sense for scatter since data are formatted as a point - }, - label: function(item) { - return '(' + item.xLabel + ', ' + item.yLabel + ')'; - } - } - } -}); - -core_defaults._set('global', { - datasets: { - scatter: { - showLine: false - } - } -}); - -// Scatter charts use line controllers -var controller_scatter = controller_line; - -// NOTE export a map in which the key represents the controller type, not -// the class, and so must be CamelCase in order to be correctly retrieved -// by the controller in core.controller.js (`controllers[meta.type]`). - -var controllers = { - bar: controller_bar, - bubble: controller_bubble, - doughnut: controller_doughnut, - horizontalBar: controller_horizontalBar, - line: controller_line, - polarArea: controller_polarArea, - pie: controller_pie, - radar: controller_radar, - scatter: controller_scatter -}; - -/** - * Helper function to get relative position for an event - * @param {Event|IEvent} event - The event to get the position for - * @param {Chart} chart - The chart - * @returns {object} the event position - */ -function getRelativePosition(e, chart) { - if (e.native) { - return { - x: e.x, - y: e.y - }; - } - - return helpers$1.getRelativePosition(e, chart); -} - -/** - * Helper function to traverse all of the visible elements in the chart - * @param {Chart} chart - the chart - * @param {function} handler - the callback to execute for each visible item - */ -function parseVisibleItems(chart, handler) { - var metasets = chart._getSortedVisibleDatasetMetas(); - var metadata, i, j, ilen, jlen, element; - - for (i = 0, ilen = metasets.length; i < ilen; ++i) { - metadata = metasets[i].data; - for (j = 0, jlen = metadata.length; j < jlen; ++j) { - element = metadata[j]; - if (!element._view.skip) { - handler(element); - } - } - } -} - -/** - * Helper function to get the items that intersect the event position - * @param {ChartElement[]} items - elements to filter - * @param {object} position - the point to be nearest to - * @return {ChartElement[]} the nearest items - */ -function getIntersectItems(chart, position) { - var elements = []; - - parseVisibleItems(chart, function(element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - } - }); - - return elements; -} - -/** - * Helper function to get the items nearest to the event position considering all visible items in teh chart - * @param {Chart} chart - the chart to look at elements from - * @param {object} position - the point to be nearest to - * @param {boolean} intersect - if true, only consider items that intersect the position - * @param {function} distanceMetric - function to provide the distance between points - * @return {ChartElement[]} the nearest items - */ -function getNearestItems(chart, position, intersect, distanceMetric) { - var minDistance = Number.POSITIVE_INFINITY; - var nearestItems = []; - - parseVisibleItems(chart, function(element) { - if (intersect && !element.inRange(position.x, position.y)) { - return; - } - - var center = element.getCenterPoint(); - var distance = distanceMetric(position, center); - if (distance < minDistance) { - nearestItems = [element]; - minDistance = distance; - } else if (distance === minDistance) { - // Can have multiple items at the same distance in which case we sort by size - nearestItems.push(element); - } - }); - - return nearestItems; -} - -/** - * Get a distance metric function for two points based on the - * axis mode setting - * @param {string} axis - the axis mode. x|y|xy - */ -function getDistanceMetricForAxis(axis) { - var useX = axis.indexOf('x') !== -1; - var useY = axis.indexOf('y') !== -1; - - return function(pt1, pt2) { - var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; - var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; - return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); - }; -} - -function indexMode(chart, e, options) { - var position = getRelativePosition(e, chart); - // Default axis for index mode is 'x' to match old behaviour - options.axis = options.axis || 'x'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); - var elements = []; - - if (!items.length) { - return []; - } - - chart._getSortedVisibleDatasetMetas().forEach(function(meta) { - var element = meta.data[items[0]._index]; - - // don't count items that are skipped (null data) - if (element && !element._view.skip) { - elements.push(element); - } - }); - - return elements; -} - -/** - * @interface IInteractionOptions - */ -/** - * If true, only consider items that intersect the point - * @name IInterfaceOptions#boolean - * @type Boolean - */ - -/** - * Contains interaction related functions - * @namespace Chart.Interaction - */ -var core_interaction = { - // Helper function for different modes - modes: { - single: function(chart, e) { - var position = getRelativePosition(e, chart); - var elements = []; - - parseVisibleItems(chart, function(element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - return elements; - } - }); - - return elements.slice(0, 1); - }, - - /** - * @function Chart.Interaction.modes.label - * @deprecated since version 2.4.0 - * @todo remove at version 3 - * @private - */ - label: indexMode, - - /** - * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item - * @function Chart.Interaction.modes.index - * @since v2.4.0 - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @param {IInteractionOptions} options - options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - index: indexMode, - - /** - * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect is false, we find the nearest item and return the items in that dataset - * @function Chart.Interaction.modes.dataset - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @param {IInteractionOptions} options - options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - dataset: function(chart, e, options) { - var position = getRelativePosition(e, chart); - options.axis = options.axis || 'xy'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); - - if (items.length > 0) { - items = chart.getDatasetMeta(items[0]._datasetIndex).data; - } - - return items; - }, - - /** - * @function Chart.Interaction.modes.x-axis - * @deprecated since version 2.4.0. Use index mode and intersect == true - * @todo remove at version 3 - * @private - */ - 'x-axis': function(chart, e) { - return indexMode(chart, e, {intersect: false}); - }, - - /** - * Point mode returns all elements that hit test based on the event position - * of the event - * @function Chart.Interaction.modes.intersect - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - point: function(chart, e) { - var position = getRelativePosition(e, chart); - return getIntersectItems(chart, position); - }, - - /** - * nearest mode returns the element closest to the point - * @function Chart.Interaction.modes.intersect - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @param {IInteractionOptions} options - options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - nearest: function(chart, e, options) { - var position = getRelativePosition(e, chart); - options.axis = options.axis || 'xy'; - var distanceMetric = getDistanceMetricForAxis(options.axis); - return getNearestItems(chart, position, options.intersect, distanceMetric); - }, - - /** - * x mode returns the elements that hit-test at the current x coordinate - * @function Chart.Interaction.modes.x - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @param {IInteractionOptions} options - options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - x: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function(element) { - if (element.inXRange(position.x)) { - items.push(element); - } - - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; - } - return items; - }, - - /** - * y mode returns the elements that hit-test at the current y coordinate - * @function Chart.Interaction.modes.y - * @param {Chart} chart - the chart we are returning items from - * @param {Event} e - the event we are find things at - * @param {IInteractionOptions} options - options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - y: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function(element) { - if (element.inYRange(position.y)) { - items.push(element); - } - - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; - } - return items; - } - } -}; - -var extend = helpers$1.extend; - -function filterByPosition(array, position) { - return helpers$1.where(array, function(v) { - return v.pos === position; - }); -} - -function sortByWeight(array, reverse) { - return array.sort(function(a, b) { - var v0 = reverse ? b : a; - var v1 = reverse ? a : b; - return v0.weight === v1.weight ? - v0.index - v1.index : - v0.weight - v1.weight; - }); -} - -function wrapBoxes(boxes) { - var layoutBoxes = []; - var i, ilen, box; - - for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { - box = boxes[i]; - layoutBoxes.push({ - index: i, - box: box, - pos: box.position, - horizontal: box.isHorizontal(), - weight: box.weight - }); - } - return layoutBoxes; -} - -function setLayoutDims(layouts, params) { - var i, ilen, layout; - for (i = 0, ilen = layouts.length; i < ilen; ++i) { - layout = layouts[i]; - // store width used instead of chartArea.w in fitBoxes - layout.width = layout.horizontal - ? layout.box.fullWidth && params.availableWidth - : params.vBoxMaxWidth; - // store height used instead of chartArea.h in fitBoxes - layout.height = layout.horizontal && params.hBoxMaxHeight; - } -} - -function buildLayoutBoxes(boxes) { - var layoutBoxes = wrapBoxes(boxes); - var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); - var right = sortByWeight(filterByPosition(layoutBoxes, 'right')); - var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); - var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); - - return { - leftAndTop: left.concat(top), - rightAndBottom: right.concat(bottom), - chartArea: filterByPosition(layoutBoxes, 'chartArea'), - vertical: left.concat(right), - horizontal: top.concat(bottom) - }; -} - -function getCombinedMax(maxPadding, chartArea, a, b) { - return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); -} - -function updateDims(chartArea, params, layout) { - var box = layout.box; - var maxPadding = chartArea.maxPadding; - var newWidth, newHeight; - - if (layout.size) { - // this layout was already counted for, lets first reduce old size - chartArea[layout.pos] -= layout.size; - } - layout.size = layout.horizontal ? box.height : box.width; - chartArea[layout.pos] += layout.size; - - if (box.getPadding) { - var boxPadding = box.getPadding(); - maxPadding.top = Math.max(maxPadding.top, boxPadding.top); - maxPadding.left = Math.max(maxPadding.left, boxPadding.left); - maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); - maxPadding.right = Math.max(maxPadding.right, boxPadding.right); - } - - newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'); - newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'); - - if (newWidth !== chartArea.w || newHeight !== chartArea.h) { - chartArea.w = newWidth; - chartArea.h = newHeight; - - // return true if chart area changed in layout's direction - var sizes = layout.horizontal ? [newWidth, chartArea.w] : [newHeight, chartArea.h]; - return sizes[0] !== sizes[1] && (!isNaN(sizes[0]) || !isNaN(sizes[1])); - } -} - -function handleMaxPadding(chartArea) { - var maxPadding = chartArea.maxPadding; - - function updatePos(pos) { - var change = Math.max(maxPadding[pos] - chartArea[pos], 0); - chartArea[pos] += change; - return change; - } - chartArea.y += updatePos('top'); - chartArea.x += updatePos('left'); - updatePos('right'); - updatePos('bottom'); -} - -function getMargins(horizontal, chartArea) { - var maxPadding = chartArea.maxPadding; - - function marginForPositions(positions) { - var margin = {left: 0, top: 0, right: 0, bottom: 0}; - positions.forEach(function(pos) { - margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); - }); - return margin; - } - - return horizontal - ? marginForPositions(['left', 'right']) - : marginForPositions(['top', 'bottom']); -} - -function fitBoxes(boxes, chartArea, params) { - var refitBoxes = []; - var i, ilen, layout, box, refit, changed; - - for (i = 0, ilen = boxes.length; i < ilen; ++i) { - layout = boxes[i]; - box = layout.box; - - box.update( - layout.width || chartArea.w, - layout.height || chartArea.h, - getMargins(layout.horizontal, chartArea) - ); - if (updateDims(chartArea, params, layout)) { - changed = true; - if (refitBoxes.length) { - // Dimensions changed and there were non full width boxes before this - // -> we have to refit those - refit = true; - } - } - if (!box.fullWidth) { // fullWidth boxes don't need to be re-fitted in any case - refitBoxes.push(layout); - } - } - - return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed; -} - -function placeBoxes(boxes, chartArea, params) { - var userPadding = params.padding; - var x = chartArea.x; - var y = chartArea.y; - var i, ilen, layout, box; - - for (i = 0, ilen = boxes.length; i < ilen; ++i) { - layout = boxes[i]; - box = layout.box; - if (layout.horizontal) { - box.left = box.fullWidth ? userPadding.left : chartArea.left; - box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w; - box.top = y; - box.bottom = y + box.height; - box.width = box.right - box.left; - y = box.bottom; - } else { - box.left = x; - box.right = x + box.width; - box.top = chartArea.top; - box.bottom = chartArea.top + chartArea.h; - box.height = box.bottom - box.top; - x = box.right; - } - } - - chartArea.x = x; - chartArea.y = y; -} - -core_defaults._set('global', { - layout: { - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } - } -}); - -/** - * @interface ILayoutItem - * @prop {string} position - The position of the item in the chart layout. Possible values are - * 'left', 'top', 'right', 'bottom', and 'chartArea' - * @prop {number} weight - The weight used to sort the item. Higher weights are further away from the chart area - * @prop {boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down - * @prop {function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom) - * @prop {function} update - Takes two parameters: width and height. Returns size of item - * @prop {function} getPadding - Returns an object with padding on the edges - * @prop {number} width - Width of item. Must be valid after update() - * @prop {number} height - Height of item. Must be valid after update() - * @prop {number} left - Left edge of the item. Set by layout system and cannot be used in update - * @prop {number} top - Top edge of the item. Set by layout system and cannot be used in update - * @prop {number} right - Right edge of the item. Set by layout system and cannot be used in update - * @prop {number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update - */ - -// The layout service is very self explanatory. It's responsible for the layout within a chart. -// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need -// It is this service's responsibility of carrying out that layout. -var core_layouts = { - defaults: {}, - - /** - * Register a box to a chart. - * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title. - * @param {Chart} chart - the chart to use - * @param {ILayoutItem} item - the item to add to be layed out - */ - addBox: function(chart, item) { - if (!chart.boxes) { - chart.boxes = []; - } - - // initialize item with default values - item.fullWidth = item.fullWidth || false; - item.position = item.position || 'top'; - item.weight = item.weight || 0; - item._layers = item._layers || function() { - return [{ - z: 0, - draw: function() { - item.draw.apply(item, arguments); - } - }]; - }; - - chart.boxes.push(item); - }, - - /** - * Remove a layoutItem from a chart - * @param {Chart} chart - the chart to remove the box from - * @param {ILayoutItem} layoutItem - the item to remove from the layout - */ - removeBox: function(chart, layoutItem) { - var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; - if (index !== -1) { - chart.boxes.splice(index, 1); - } - }, - - /** - * Sets (or updates) options on the given `item`. - * @param {Chart} chart - the chart in which the item lives (or will be added to) - * @param {ILayoutItem} item - the item to configure with the given options - * @param {object} options - the new item options. - */ - configure: function(chart, item, options) { - var props = ['fullWidth', 'position', 'weight']; - var ilen = props.length; - var i = 0; - var prop; - - for (; i < ilen; ++i) { - prop = props[i]; - if (options.hasOwnProperty(prop)) { - item[prop] = options[prop]; - } - } - }, - - /** - * Fits boxes of the given chart into the given size by having each box measure itself - * then running a fitting algorithm - * @param {Chart} chart - the chart - * @param {number} width - the width to fit into - * @param {number} height - the height to fit into - */ - update: function(chart, width, height) { - if (!chart) { - return; - } - - var layoutOptions = chart.options.layout || {}; - var padding = helpers$1.options.toPadding(layoutOptions.padding); - - var availableWidth = width - padding.width; - var availableHeight = height - padding.height; - var boxes = buildLayoutBoxes(chart.boxes); - var verticalBoxes = boxes.vertical; - var horizontalBoxes = boxes.horizontal; - - // Essentially we now have any number of boxes on each of the 4 sides. - // Our canvas looks like the following. - // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and - // B1 is the bottom axis - // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays - // These locations are single-box locations only, when trying to register a chartArea location that is already taken, - // an error will be thrown. - // - // |----------------------------------------------------| - // | T1 (Full Width) | - // |----------------------------------------------------| - // | | | T2 | | - // | |----|-------------------------------------|----| - // | | | C1 | | C2 | | - // | | |----| |----| | - // | | | | | - // | L1 | L2 | ChartArea (C0) | R1 | - // | | | | | - // | | |----| |----| | - // | | | C3 | | C4 | | - // | |----|-------------------------------------|----| - // | | | B1 | | - // |----------------------------------------------------| - // | B2 (Full Width) | - // |----------------------------------------------------| - // - - var params = Object.freeze({ - outerWidth: width, - outerHeight: height, - padding: padding, - availableWidth: availableWidth, - vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length, - hBoxMaxHeight: availableHeight / 2 - }); - var chartArea = extend({ - maxPadding: extend({}, padding), - w: availableWidth, - h: availableHeight, - x: padding.left, - y: padding.top - }, padding); - - setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); - - // First fit vertical boxes - fitBoxes(verticalBoxes, chartArea, params); - - // Then fit horizontal boxes - if (fitBoxes(horizontalBoxes, chartArea, params)) { - // if the area changed, re-fit vertical boxes - fitBoxes(verticalBoxes, chartArea, params); - } - - handleMaxPadding(chartArea); - - // Finally place the boxes to correct coordinates - placeBoxes(boxes.leftAndTop, chartArea, params); - - // Move to opposite side of chart - chartArea.x += chartArea.w; - chartArea.y += chartArea.h; - - placeBoxes(boxes.rightAndBottom, chartArea, params); - - chart.chartArea = { - left: chartArea.left, - top: chartArea.top, - right: chartArea.left + chartArea.w, - bottom: chartArea.top + chartArea.h - }; - - // Finally update boxes in chartArea (radial scale for example) - helpers$1.each(boxes.chartArea, function(layout) { - var box = layout.box; - extend(box, chart.chartArea); - box.update(chartArea.w, chartArea.h); - }); - } -}; - -/** - * Platform fallback implementation (minimal). - * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939 - */ - -var platform_basic = { - acquireContext: function(item) { - if (item && item.canvas) { - // Support for any object associated to a canvas (including a context2d) - item = item.canvas; - } - - return item && item.getContext('2d') || null; - } -}; - -var platform_dom = "/*\r\n * DOM element rendering detection\r\n * https://davidwalsh.name/detect-node-insertion\r\n */\r\n@keyframes chartjs-render-animation {\r\n\tfrom { opacity: 0.99; }\r\n\tto { opacity: 1; }\r\n}\r\n\r\n.chartjs-render-monitor {\r\n\tanimation: chartjs-render-animation 0.001s;\r\n}\r\n\r\n/*\r\n * DOM element resizing detection\r\n * https://github.com/marcj/css-element-queries\r\n */\r\n.chartjs-size-monitor,\r\n.chartjs-size-monitor-expand,\r\n.chartjs-size-monitor-shrink {\r\n\tposition: absolute;\r\n\tdirection: ltr;\r\n\tleft: 0;\r\n\ttop: 0;\r\n\tright: 0;\r\n\tbottom: 0;\r\n\toverflow: hidden;\r\n\tpointer-events: none;\r\n\tvisibility: hidden;\r\n\tz-index: -1;\r\n}\r\n\r\n.chartjs-size-monitor-expand > div {\r\n\tposition: absolute;\r\n\twidth: 1000000px;\r\n\theight: 1000000px;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n\r\n.chartjs-size-monitor-shrink > div {\r\n\tposition: absolute;\r\n\twidth: 200%;\r\n\theight: 200%;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n"; - -var platform_dom$1 = /*#__PURE__*/Object.freeze({ -__proto__: null, -'default': platform_dom -}); - -var stylesheet = getCjsExportFromNamespace(platform_dom$1); - -var EXPANDO_KEY = '$chartjs'; -var CSS_PREFIX = 'chartjs-'; -var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor'; -var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor'; -var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation'; -var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart']; - -/** - * DOM event types -> Chart.js event types. - * Note: only events with different types are mapped. - * @see https://developer.mozilla.org/en-US/docs/Web/Events - */ -var EVENT_TYPES = { - touchstart: 'mousedown', - touchmove: 'mousemove', - touchend: 'mouseup', - pointerenter: 'mouseenter', - pointerdown: 'mousedown', - pointermove: 'mousemove', - pointerup: 'mouseup', - pointerleave: 'mouseout', - pointerout: 'mouseout' -}; - -/** - * The "used" size is the final value of a dimension property after all calculations have - * been performed. This method uses the computed style of `element` but returns undefined - * if the computed style is not expressed in pixels. That can happen in some cases where - * `element` has a size relative to its parent and this last one is not yet displayed, - * for example because of `display: none` on a parent node. - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value - * @returns {number} Size in pixels or undefined if unknown. - */ -function readUsedSize(element, property) { - var value = helpers$1.getStyle(element, property); - var matches = value && value.match(/^(\d+)(\.\d+)?px$/); - return matches ? Number(matches[1]) : undefined; -} - -/** - * Initializes the canvas style and render size without modifying the canvas display size, - * since responsiveness is handled by the controller.resize() method. The config is used - * to determine the aspect ratio to apply in case no explicit height has been specified. - */ -function initCanvas(canvas, config) { - var style = canvas.style; - - // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it - // returns null or '' if no explicit value has been set to the canvas attribute. - var renderHeight = canvas.getAttribute('height'); - var renderWidth = canvas.getAttribute('width'); - - // Chart.js modifies some canvas values that we want to restore on destroy - canvas[EXPANDO_KEY] = { - initial: { - height: renderHeight, - width: renderWidth, - style: { - display: style.display, - height: style.height, - width: style.width - } - } - }; - - // Force canvas to display as block to avoid extra space caused by inline - // elements, which would interfere with the responsive resize process. - // https://github.com/chartjs/Chart.js/issues/2538 - style.display = style.display || 'block'; - - if (renderWidth === null || renderWidth === '') { - var displayWidth = readUsedSize(canvas, 'width'); - if (displayWidth !== undefined) { - canvas.width = displayWidth; - } - } - - if (renderHeight === null || renderHeight === '') { - if (canvas.style.height === '') { - // If no explicit render height and style height, let's apply the aspect ratio, - // which one can be specified by the user but also by charts as default option - // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2. - canvas.height = canvas.width / (config.options.aspectRatio || 2); - } else { - var displayHeight = readUsedSize(canvas, 'height'); - if (displayWidth !== undefined) { - canvas.height = displayHeight; - } - } - } - - return canvas; -} - -/** - * Detects support for options object argument in addEventListener. - * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support - * @private - */ -var supportsEventListenerOptions = (function() { - var supports = false; - try { - var options = Object.defineProperty({}, 'passive', { - // eslint-disable-next-line getter-return - get: function() { - supports = true; - } - }); - window.addEventListener('e', null, options); - } catch (e) { - // continue regardless of error - } - return supports; -}()); - -// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events. -// https://github.com/chartjs/Chart.js/issues/4287 -var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; - -function addListener(node, type, listener) { - node.addEventListener(type, listener, eventListenerOptions); -} - -function removeListener(node, type, listener) { - node.removeEventListener(type, listener, eventListenerOptions); -} - -function createEvent(type, chart, x, y, nativeEvent) { - return { - type: type, - chart: chart, - native: nativeEvent || null, - x: x !== undefined ? x : null, - y: y !== undefined ? y : null, - }; -} - -function fromNativeEvent(event, chart) { - var type = EVENT_TYPES[event.type] || event.type; - var pos = helpers$1.getRelativePosition(event, chart); - return createEvent(type, chart, pos.x, pos.y, event); -} - -function throttled(fn, thisArg) { - var ticking = false; - var args = []; - - return function() { - args = Array.prototype.slice.call(arguments); - thisArg = thisArg || this; - - if (!ticking) { - ticking = true; - helpers$1.requestAnimFrame.call(window, function() { - ticking = false; - fn.apply(thisArg, args); - }); - } - }; -} - -function createDiv(cls) { - var el = document.createElement('div'); - el.className = cls || ''; - return el; -} - -// Implementation based on https://github.com/marcj/css-element-queries -function createResizer(handler) { - var maxSize = 1000000; - - // NOTE(SB) Don't use innerHTML because it could be considered unsafe. - // https://github.com/chartjs/Chart.js/issues/5902 - var resizer = createDiv(CSS_SIZE_MONITOR); - var expand = createDiv(CSS_SIZE_MONITOR + '-expand'); - var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink'); - - expand.appendChild(createDiv()); - shrink.appendChild(createDiv()); - - resizer.appendChild(expand); - resizer.appendChild(shrink); - resizer._reset = function() { - expand.scrollLeft = maxSize; - expand.scrollTop = maxSize; - shrink.scrollLeft = maxSize; - shrink.scrollTop = maxSize; - }; - - var onScroll = function() { - resizer._reset(); - handler(); - }; - - addListener(expand, 'scroll', onScroll.bind(expand, 'expand')); - addListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink')); - - return resizer; -} - -// https://davidwalsh.name/detect-node-insertion -function watchForRender(node, handler) { - var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); - var proxy = expando.renderProxy = function(e) { - if (e.animationName === CSS_RENDER_ANIMATION) { - handler(); - } - }; - - helpers$1.each(ANIMATION_START_EVENTS, function(type) { - addListener(node, type, proxy); - }); - - // #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class - // is removed then added back immediately (same animation frame?). Accessing the - // `offsetParent` property will force a reflow and re-evaluate the CSS animation. - // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics - // https://github.com/chartjs/Chart.js/issues/4737 - expando.reflow = !!node.offsetParent; - - node.classList.add(CSS_RENDER_MONITOR); -} - -function unwatchForRender(node) { - var expando = node[EXPANDO_KEY] || {}; - var proxy = expando.renderProxy; - - if (proxy) { - helpers$1.each(ANIMATION_START_EVENTS, function(type) { - removeListener(node, type, proxy); - }); - - delete expando.renderProxy; - } - - node.classList.remove(CSS_RENDER_MONITOR); -} - -function addResizeListener(node, listener, chart) { - var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); - - // Let's keep track of this added resizer and thus avoid DOM query when removing it. - var resizer = expando.resizer = createResizer(throttled(function() { - if (expando.resizer) { - var container = chart.options.maintainAspectRatio && node.parentNode; - var w = container ? container.clientWidth : 0; - listener(createEvent('resize', chart)); - if (container && container.clientWidth < w && chart.canvas) { - // If the container size shrank during chart resize, let's assume - // scrollbar appeared. So we resize again with the scrollbar visible - - // effectively making chart smaller and the scrollbar hidden again. - // Because we are inside `throttled`, and currently `ticking`, scroll - // events are ignored during this whole 2 resize process. - // If we assumed wrong and something else happened, we are resizing - // twice in a frame (potential performance issue) - listener(createEvent('resize', chart)); - } - } - })); - - // The resizer needs to be attached to the node parent, so we first need to be - // sure that `node` is attached to the DOM before injecting the resizer element. - watchForRender(node, function() { - if (expando.resizer) { - var container = node.parentNode; - if (container && container !== resizer.parentNode) { - container.insertBefore(resizer, container.firstChild); - } - - // The container size might have changed, let's reset the resizer state. - resizer._reset(); - } - }); -} - -function removeResizeListener(node) { - var expando = node[EXPANDO_KEY] || {}; - var resizer = expando.resizer; - - delete expando.resizer; - unwatchForRender(node); - - if (resizer && resizer.parentNode) { - resizer.parentNode.removeChild(resizer); - } -} - -/** - * Injects CSS styles inline if the styles are not already present. - * @param {HTMLDocument|ShadowRoot} rootNode - the node to contain the {% block title %}{{ SITE_TITLE }}{% endblock %} @@ -44,12 +56,14 @@ {% block page_container %} - +
- + {% endblock %} @@ -82,9 +98,8 @@ {% for url in INCLUDED_JS %} - {% endfor %} + {% endfor %} {% if user %} - {% if user %} {% endif %} + + {% block scripts %}{% endblock %} diff --git a/lnbits/templates/components.vue b/lnbits/templates/components.vue index 3aa97f337..84e6b562c 100644 --- a/lnbits/templates/components.vue +++ b/lnbits/templates/components.vue @@ -1,4 +1,5 @@ -{% include('components/admin/funding.vue') %} {% +{% include('components/admin/funding_seed_backup.vue') %} {% +include('components/admin/funding.vue') %} {% include('components/admin/funding_sources.vue') %} {% include('components/admin/fiat_providers.vue') %} {% include('components/admin/exchange_providers.vue') %} {% @@ -7,9 +8,12 @@ include('components/admin/users.vue') %} {% include('components/admin/site_customisation.vue') %} {% include('components/admin/audit.vue') %} {% include('components/admin/extensions.vue') %} {% +include('components/admin/wasm-runtime.vue') %} {% +include('components/admin/wasm-limit-config.vue') %} {% include('components/admin/assets-config.vue') %} {% include('components/admin/notifications.vue') %} {% include('components/admin/server.vue') %} {% +include('components/admin/blockexplorer.vue') %} {% include('components/lnbits-qrcode.vue') %} {% include('components/lnbits-qrcode-scanner.vue') %} {% include('components/lnbits-disclaimer.vue') %} {% @@ -19,6 +23,7 @@ include('components/lnbits-header-wallets.vue') %} {% include('components/lnbits-drawer.vue') %} {% include('components/lnbits-home-logos.vue') %} {% include('components/lnbits-manage-extension-list.vue') %} {% +include('components/lnbits-extension-permissions.vue') %} {% include('components/lnbits-manage-wallet-list.vue') %} {% include('components/lnbits-language-dropdown.vue') %} {% include('components/lnbits-payment-list.vue') %} {% @@ -96,6 +101,21 @@ include('components/lnbits-error.vue') %} + + + + + + + + + + +
@@ -774,7 +794,13 @@ include('components/lnbits-error.vue') %} v-model="password" name="password" :label="$t('password') + ' *'" - type="password" + :type="showPwd ? 'text' : 'password'" + >
+ + + + +
+ +
+
diff --git a/lnbits/templates/components/admin/blockexplorer.vue b/lnbits/templates/components/admin/blockexplorer.vue new file mode 100644 index 000000000..a642fc2d9 --- /dev/null +++ b/lnbits/templates/components/admin/blockexplorer.vue @@ -0,0 +1,90 @@ + diff --git a/lnbits/templates/components/admin/exchange_providers.vue b/lnbits/templates/components/admin/exchange_providers.vue index 5a23dd927..eb2a33dc2 100644 --- a/lnbits/templates/components/admin/exchange_providers.vue +++ b/lnbits/templates/components/admin/exchange_providers.vue @@ -1,7 +1,46 @@ - - Coming Soon + + + + + + + + + + +
+
+ +
+
+
+
+ + + + + + +
+
+ +
+
+ + + + + +
+
+ +
+ + +
    +
  • payment.updated
  • +
  • invoice.payment_made
  • +
+
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+
+
+ + +
+
+ +
+
+ +
+
+ +
+
+ + + + +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+
+
+
+ + + + + +
+ + +
+
+
+
+ + + + + + + + + + + + + + +
+
+ +
+
+
+
+ + + + Configure a Revolut Merchant webhook that points to your LNbits + server. LNbits will create it through the Revolut API and + subscribe to ORDER_AUTHORISED, + ORDER_COMPLETED, and + SUBSCRIPTION_INITIATED. + + +
+
+ +
+
+ + + + + +
+
+
+ + + Signing secret saved + +
+
+ + +
    +
  • + ORDER_AUTHORISED +
  • +
  • + ORDER_COMPLETED +
  • +
  • + SUBSCRIPTION_INITIATED +
  • +
+
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+
+
+ + + +
+
+ +
+
+ +
+
+ +
+
+
+
+ + + + + + +
+ + +
+
+
@@ -640,9 +1172,22 @@ >
-
- Square (coming soon) -
+
Square
+ Checkout + Subscriptions coming soon + Tap-to-pay + Regions: Square-supported countries +
+
+
Revolut
Checkout @@ -653,7 +1198,7 @@ >Tap-to-pay Regions: GlobalRegions: Revolut-supported countries
diff --git a/lnbits/templates/components/admin/funding.vue b/lnbits/templates/components/admin/funding.vue index 2a70bd253..79d58bd35 100644 --- a/lnbits/templates/components/admin/funding.vue +++ b/lnbits/templates/components/admin/funding.vue @@ -75,7 +75,35 @@

-
+
+ +
+
+ + + + + + + + + +
+
+
+
@@ -160,33 +188,26 @@ min="0" >
-
-
- -
-
- - - - - - - - - -
+
+

+ + + + + + + +

+
@@ -280,5 +301,11 @@
+ diff --git a/lnbits/templates/components/admin/funding_seed_backup.vue b/lnbits/templates/components/admin/funding_seed_backup.vue new file mode 100644 index 000000000..74d12c9ca --- /dev/null +++ b/lnbits/templates/components/admin/funding_seed_backup.vue @@ -0,0 +1,136 @@ + diff --git a/lnbits/templates/components/admin/funding_sources.vue b/lnbits/templates/components/admin/funding_sources.vue index 7eb1110d4..a6e8a8438 100644 --- a/lnbits/templates/components/admin/funding_sources.vue +++ b/lnbits/templates/components/admin/funding_sources.vue @@ -52,6 +52,7 @@ :label="prop.label" :hint="prop.hint" :value="prop.value" + :readonly="prop.readonly || false" > +

+ + + + +

+ OIDC Auth + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
diff --git a/lnbits/templates/components/admin/server.vue b/lnbits/templates/components/admin/server.vue index 3a885b383..76b75aa2c 100644 --- a/lnbits/templates/components/admin/server.vue +++ b/lnbits/templates/components/admin/server.vue @@ -69,6 +69,127 @@ +
+
+
+ + + + + + + + + +
+
+ + + + + + + + + +
+
+
+ + + + + + + + + + +
+ +
+
+ +
+
+ +
diff --git a/lnbits/templates/components/admin/site_customisation.vue b/lnbits/templates/components/admin/site_customisation.vue index f3e87d445..ad26e0281 100644 --- a/lnbits/templates/components/admin/site_customisation.vue +++ b/lnbits/templates/components/admin/site_customisation.vue @@ -251,10 +251,27 @@ type="text" v-model="formData.lnbits_default_bgimage" label="Background Image" - @update:model-value="applyGlobalBgimage" hint="This must be a trusted source. It can change the content and it can log your IP address." > + +
@@ -303,6 +320,15 @@ >
+
+ + +
diff --git a/lnbits/templates/components/admin/wasm-limit-config.vue b/lnbits/templates/components/admin/wasm-limit-config.vue new file mode 100644 index 000000000..4b67b3ab0 --- /dev/null +++ b/lnbits/templates/components/admin/wasm-limit-config.vue @@ -0,0 +1,242 @@ + diff --git a/lnbits/templates/components/admin/wasm-runtime.vue b/lnbits/templates/components/admin/wasm-runtime.vue new file mode 100644 index 000000000..9d7195fb4 --- /dev/null +++ b/lnbits/templates/components/admin/wasm-runtime.vue @@ -0,0 +1,245 @@ + diff --git a/lnbits/templates/components/lnbits-extension-permissions.vue b/lnbits/templates/components/lnbits-extension-permissions.vue new file mode 100644 index 000000000..6219a9b0b --- /dev/null +++ b/lnbits/templates/components/lnbits-extension-permissions.vue @@ -0,0 +1,202 @@ + diff --git a/lnbits/templates/components/lnbits-manage-extension-list.vue b/lnbits/templates/components/lnbits-manage-extension-list.vue index 6705d6dc3..53298545d 100644 --- a/lnbits/templates/components/lnbits-manage-extension-list.vue +++ b/lnbits/templates/components/lnbits-manage-extension-list.vue @@ -18,13 +18,18 @@ - + + @@ -32,10 +37,7 @@ > - + diff --git a/lnbits/templates/components/lnbits-payment-list.vue b/lnbits/templates/components/lnbits-payment-list.vue index 22a927cb7..64b083b3d 100644 --- a/lnbits/templates/components/lnbits-payment-list.vue +++ b/lnbits/templates/components/lnbits-payment-list.vue @@ -156,7 +156,7 @@ - + diff --git a/lnbits/templates/components/lnbits-qrcode.vue b/lnbits/templates/components/lnbits-qrcode.vue index 6f1ab85f0..b22876a9c 100644 --- a/lnbits/templates/components/lnbits-qrcode.vue +++ b/lnbits/templates/components/lnbits-qrcode.vue @@ -12,7 +12,7 @@ > + @@ -66,7 +72,7 @@ diff --git a/lnbits/templates/components/lnbits-wallet-extra.vue b/lnbits/templates/components/lnbits-wallet-extra.vue index 6b12fe945..d43d3f30a 100644 --- a/lnbits/templates/components/lnbits-wallet-extra.vue +++ b/lnbits/templates/components/lnbits-wallet-extra.vue @@ -157,6 +157,60 @@ + +
+
+ + + + +
+
+ +
+
+ + + +
+
+
diff --git a/lnbits/templates/error.html b/lnbits/templates/error.html index 47f57b274..7bd6374d4 100644 --- a/lnbits/templates/error.html +++ b/lnbits/templates/error.html @@ -1,6 +1,4 @@ -{% extends "public.html" %} {% from "macros.jinja" import window_vars with -context %} {% block scripts %} {{ window_vars() }} {% endblock %} {% block -page_container %} +{% extends "base.html" %} {% block page_container %} - //Needed for Vue to create the app on first load (although called on every page, its only loaded once) - window.app = Vue.createApp({ - el: '#vue', - mixins: [window.windowMixin] - }) + {%- endmacro %} diff --git a/lnbits/templates/pages.vue b/lnbits/templates/pages.vue index 344fccb65..b50d3b6b4 100644 --- a/lnbits/templates/pages.vue +++ b/lnbits/templates/pages.vue @@ -4,4 +4,4 @@ include('pages/users.vue') %} {% include('pages/admin.vue') %} {% include('pages/account.vue') %} {% include('pages/extensions_builder.vue') %} {% include('pages/extensions.vue') %} {% include('pages/first-install.vue') %} {% include('pages/home.vue') %} {% include('pages/wallet.vue') %} {% -include('pages/error.vue') %} +include('pages/error.vue') %} {% include('pages/blockexplorer.vue') %} diff --git a/lnbits/templates/pages/account.vue b/lnbits/templates/pages/account.vue index 94afba0b4..aa5cf9530 100644 --- a/lnbits/templates/pages/account.vue +++ b/lnbits/templates/pages/account.vue @@ -262,7 +262,9 @@
@@ -310,6 +312,58 @@
GitHub
+
+ + + + +
+
+
+
+ + + + +
+
+
@@ -438,10 +492,28 @@ siteCustomisationChanged({bgimageChoice: $event}) " > + +
@@ -529,6 +601,30 @@
+
+
+ +
+
+ + + +
+
+
@@ -793,6 +889,17 @@ >
+
+ + + +
@@ -1054,82 +1161,130 @@ - - - + - - - - - Copy Link - Copy asset link to - clipboard - - - - - - - - - Unpublish - Make this asset private - - - Publish - Make this asset public - - + + + + + Copy Link + Copy asset link to + clipboard + + - - - - - - Delete - Permanently delete this - asset - - - - + + + + + Unpublish + Make this asset + private + + + Publish + Make this asset + public + + + + + + + + + Delete + Permanently delete this + asset + + + + +
+
+ + Full image + +
+
+ + Thumbnail + +
+
diff --git a/lnbits/templates/pages/admin.vue b/lnbits/templates/pages/admin.vue index 919bd7564..20b8ee6df 100644 --- a/lnbits/templates/pages/admin.vue +++ b/lnbits/templates/pages/admin.vue @@ -74,7 +74,13 @@
-
+
+ @@ -199,6 +213,7 @@ > + + + + + + @@ -234,6 +255,9 @@ + + + diff --git a/lnbits/templates/pages/blockexplorer.vue b/lnbits/templates/pages/blockexplorer.vue new file mode 100644 index 000000000..364bb8298 --- /dev/null +++ b/lnbits/templates/pages/blockexplorer.vue @@ -0,0 +1,385 @@ + + + diff --git a/lnbits/templates/pages/extensions.vue b/lnbits/templates/pages/extensions.vue index ae1ecd2e6..4f636bb2d 100644 --- a/lnbits/templates/pages/extensions.vue +++ b/lnbits/templates/pages/extensions.vue @@ -7,7 +7,29 @@ - + + + + + + + + + + - - + + + +
+ + + + +
+ + + +
+ + +
+
+
@@ -468,20 +537,43 @@
- + + + + + - + class="row items-center q-gutter-sm" + > + +
+ + +
+
@@ -752,9 +859,175 @@ >
- +
+ + + + + +
+ + +
+
+
+ + + + + + + +
+
+
+ +
+
+ +
+
+ + + +
+
+ + + +
+
+
+
+ +
+
+
@@ -836,7 +1109,7 @@
-
+
- - - + diff --git a/lnbits/templates/pages/node.vue b/lnbits/templates/pages/node.vue index 56f5acc23..71d1444dd 100644 --- a/lnbits/templates/pages/node.vue +++ b/lnbits/templates/pages/node.vue @@ -589,23 +589,16 @@ v-if="transactionDetailsDialog.data.bolt11" class="text-center q-mb-lg" > - - - - - + :value=" + 'LIGHTNING:' + + transactionDetailsDialog.data.bolt11.toUpperCase() + " + > - - - - - + >
diff --git a/lnbits/templates/pages/users.vue b/lnbits/templates/pages/users.vue index a8df5aed9..a0b44f4dd 100644 --- a/lnbits/templates/pages/users.vue +++ b/lnbits/templates/pages/users.vue @@ -109,6 +109,18 @@ Copy Invoice Key + + + + + + + +
+
+ + · + +
+
+ + + + + + + +
+
diff --git a/lnbits/templates/pages/wallet.vue b/lnbits/templates/pages/wallet.vue index 89b8a9284..c185eb6b0 100644 --- a/lnbits/templates/pages/wallet.vue +++ b/lnbits/templates/pages/wallet.vue @@ -28,7 +28,13 @@
-
+
@@ -228,6 +238,113 @@
+ + + +
+
+
+
+
+
+ + Refresh + +
+ + + +
+ + +
+ + + +
+ + + + + + + + + + + + + + + + + +
+ +
+ + No completed payments. + +
+ +
+ +
+
+
+
+ + + + + + + + + + + + + + + + R + + + + +
@@ -438,9 +593,37 @@ +
+ + + +

@@ -626,7 +809,8 @@ unelevated color="primary" @click="payInvoice" - :label="$t('pay')" + :disable="parse.sending" + :label="parse.sending ? $t('sending') + '...' : $t('pay')" >

- Send + { ) { // Open the cache event.respondWith( - caches.open(CURRENT_CACHE + getApiKey(event.request)).then(cache => { - // Go to the network first - return fetch(event.request) - .then(fetchedResponse => { - cache.put(event.request, fetchedResponse.clone()) + caches + .open(CURRENT_CACHE + getApiKey(event.request)) + .then(cache => { + // Go to the network first + return fetch(event.request) + .then(fetchedResponse => { + cache.put(event.request, fetchedResponse.clone()).catch(() => {}) - return fetchedResponse - }) - .catch(() => { - // If the network is unavailable, get - return cache.match(event.request.url) - }) - }) + return fetchedResponse + }) + .catch(() => { + // If the network is unavailable, get + return cache.match(event.request).then(cachedResponse => { + return cachedResponse || offlineResponse() + }) + }) + }) + .catch(() => fetch(event.request).catch(() => offlineResponse())) ) } }) +const offlineResponse = () => + new Response('', { + status: 503, + statusText: 'Service Unavailable' + }) + // Handle and show incoming push notifications self.addEventListener('push', function (event) { if (!(self.Notification && self.Notification.permission === 'granted')) { diff --git a/lnbits/templates/wasm_extension.html b/lnbits/templates/wasm_extension.html new file mode 100644 index 000000000..94d9808cc --- /dev/null +++ b/lnbits/templates/wasm_extension.html @@ -0,0 +1 @@ +{% extends "base.html" %} diff --git a/lnbits/utils/cache.py b/lnbits/utils/cache.py index 904447e19..9d8c6c3b1 100644 --- a/lnbits/utils/cache.py +++ b/lnbits/utils/cache.py @@ -1,13 +1,8 @@ from __future__ import annotations -import asyncio from time import time from typing import Any, NamedTuple -from loguru import logger - -from lnbits.settings import settings - class Cached(NamedTuple): value: Any @@ -22,8 +17,7 @@ class Cache: Small caching utility providing simple get/set interface (very much like redis) """ - def __init__(self, interval: float = 10) -> None: - self.interval = interval + def __init__(self) -> None: self._values: dict[Any, Cached] = {} def value(self, key: str) -> Cached | None: @@ -59,16 +53,11 @@ class Cache: self.set(key, value, expiry=expiry) return value - async def invalidate_forever(self): - while settings.lnbits_running: - try: - await asyncio.sleep(self.interval) - ts = time() - expired = [k for k, v in self._values.items() if v.expiry < ts] - for k in expired: - self._values.pop(k) - except Exception: - logger.error("Error invalidating cache") + async def invalidate_cache(self): + ts = time() + expired = [k for k, v in self._values.items() if v.expiry < ts] + for k in expired: + self._values.pop(k) cache = Cache() diff --git a/lnbits/utils/electrum.py b/lnbits/utils/electrum.py new file mode 100644 index 000000000..1c103a19d --- /dev/null +++ b/lnbits/utils/electrum.py @@ -0,0 +1,1059 @@ +""" +Electrum protocol client (https://github.com/spesmilo/electrum-protocol). + +JSON-RPC 2.0 over TCP / SSL (newline-delimited), with request/response +correlation, subscription dispatch, and automatic keepalive pings. +server.version is sent automatically on connect as required by the spec. +""" + +import asyncio +import hashlib +import itertools +import json +import ssl +import struct +from collections.abc import Callable, Coroutine +from typing import Any +from urllib.parse import urlparse + +from embit.networks import NETWORKS +from embit.script import Script +from embit.transaction import Transaction as EmbitTransaction +from loguru import logger +from pydantic import BaseModel + +DEFAULT_NETWORK = NETWORKS["main"] + + +def network_from_name(name: str) -> dict: + """Look up an embit network dict (see embit.networks.NETWORKS) by name.""" + try: + return NETWORKS[name] + except KeyError as exc: + raise ValueError( + f"Unknown network {name!r}, expected one of {list(NETWORKS)}" + ) from exc + + +class ElectrumError(Exception): + pass + + +def scripthash_from_scriptpubkey(scriptpubkey: bytes) -> str: + """Electrum script hash: SHA-256 of scriptPubKey, byte-reversed to hex.""" + return hashlib.sha256(scriptpubkey).digest()[::-1].hex() + + +def address_to_scriptpubkey(address: str) -> bytes: + """Convert a Bitcoin address (P2PKH/P2SH/P2WPKH/P2WSH/P2TR) to scriptPubKey.""" + try: + script = Script.from_address(address) + except Exception as exc: + raise ValueError(f"Invalid address: {address!r}") from exc + if script is None: + raise ValueError(f"Invalid address: {address!r}") + return script.data + + +def scripthash_from_address(address: str) -> str: + return scripthash_from_scriptpubkey(address_to_scriptpubkey(address)) + + +_SCRIPT_TYPE_NAMES = { + "p2pkh": "pubkeyhash", + "p2sh": "scripthash", + "p2wpkh": "witness_v0_keyhash", + "p2wsh": "witness_v0_scripthash", + "p2tr": "witness_v1_taproot", +} + + +def _scriptpubkey_info(spk: bytes, network: dict) -> tuple[str, str | None]: + """Return (type, address_or_None) for a scriptPubKey.""" + n = len(spk) + # P2PK (not classified by embit) + if n in (35, 67) and spk[-1] == 0xAC: + return "pubkey", None + # OP_RETURN (not classified by embit) + if n >= 1 and spk[0] == 0x6A: + return "nulldata", None + + script = Script(spk) + script_type = script.script_type() + if script_type is None: + return "nonstandard", None + return _SCRIPT_TYPE_NAMES[script_type], script.address(network) + + +# --------------------------------------------------------------------------- +# Response models +# --------------------------------------------------------------------------- + + +class Balance(BaseModel): + confirmed: int + unconfirmed: int + + +class HistoryEntry(BaseModel): + tx_hash: str + height: int + fee: int | None = None # present for mempool entries + + +class MempoolEntry(BaseModel): + tx_hash: str + height: int + fee: int + + +class UTXO(BaseModel): + tx_hash: str + tx_pos: int + height: int + value: int # satoshis + + +class BlockHeader(BaseModel): + height: int + hex: str + + +class BlockHeaderProof(BaseModel): + """Returned by get_block_header when cp_height > 0.""" + + branch: list[str] + header: str + root: str + + +class BlockHeaders(BaseModel): + count: int + hex: str + max: int + + +class MerkleProof(BaseModel): + block_height: int + merkle: list[str] + pos: int + + +class TxIdWithMerkle(BaseModel): + tx_hash: str + merkle: list[str] + + +class FeeHistogramEntry(BaseModel): + fee_rate: float + vsize: float + + +class ServerFeatures(BaseModel): + class Config: + extra = "allow" + + genesis_hash: str = "" + protocol_max: str = "" + protocol_min: str = "" + server_version: str = "" + pruning: int | None = None + hash_function: str = "sha256d" + hosts: dict[str, Any] = {} + + +class ScriptSig(BaseModel): + hex: str + + +class ScriptPubKey(BaseModel): + hex: str + type: str + address: str | None = None + + +class TxInput(BaseModel): + txid: str | None = None + vout: int | None = None + scriptSig: ScriptSig | None = None # noqa: N815 + sequence: int + coinbase: str | None = None + + +class TxOutput(BaseModel): + value: float + n: int + scriptPubKey: ScriptPubKey # noqa: N815 + + +class Transaction(BaseModel): + txid: str + version: int + locktime: int + vin: list[TxInput] + vout: list[TxOutput] + size: int + vsize: int + weight: int + hex: str + + +class FeeResponse(BaseModel): + estimates: dict[str, float] + histogram: list[FeeHistogramEntry] + + +class AddressResponse(BaseModel): + balance: Balance + history: list[HistoryEntry] + history_error: str | None = None + + +class BlockInfo(BaseModel): + height: int + hash: str + timestamp: int + version: int + bits: str + nonce: int + prev_hash: str + merkle_root: str + + +def parse_block_header(header_hex: str, height: int) -> BlockInfo: + """Parse an 80-byte block header hex string into a BlockInfo model.""" + data = bytes.fromhex(header_hex) + version = struct.unpack_from(" Transaction: + """Parse a raw transaction hex string into a Transaction model.""" + network = network or DEFAULT_NETWORK + data = bytes.fromhex(hex_str) + tx = EmbitTransaction.parse(data) + + vin: list[TxInput] = [] + for inp in tx.vin: + if inp.txid == b"\x00" * 32 and inp.vout == 0xFFFFFFFF: + vin.append( + TxInput(sequence=inp.sequence, coinbase=inp.script_sig.data.hex()) + ) + else: + vin.append( + TxInput( + txid=inp.txid.hex(), + vout=inp.vout, + scriptSig=ScriptSig(hex=inp.script_sig.data.hex()), + sequence=inp.sequence, + ) + ) + + vout: list[TxOutput] = [] + for n_out, out in enumerate(tx.vout): + spk_type, address = _scriptpubkey_info(out.script_pubkey.data, network) + vout.append( + TxOutput( + value=round(out.value / 1e8, 8), + n=n_out, + scriptPubKey=ScriptPubKey( + hex=out.script_pubkey.data.hex(), type=spk_type, address=address + ), + ) + ) + + if tx.is_segwit: + # base (non-witness) size = full size minus the segwit marker/flag + # (2 bytes) and each input's witness stack + witness_bytes = sum(len(inp.witness.serialize()) for inp in tx.vin) + base_size = len(data) - 2 - witness_bytes + weight = base_size * 3 + len(data) + vsize = (weight + 3) // 4 + else: + weight = len(data) * 4 + vsize = len(data) + + return Transaction( + txid=tx.txid().hex(), + version=tx.version, + locktime=tx.locktime, + vin=vin, + vout=vout, + size=len(data), + vsize=vsize, + weight=weight, + hex=hex_str, + ) + + +# --------------------------------------------------------------------------- +# Client +# --------------------------------------------------------------------------- + + +class ElectrumClient: + """ + Async Electrum protocol client over plain TCP or SSL. + + Messages are newline-terminated JSON-RPC 2.0, as required by the spec. + Handles request/response correlation by id, routes push notifications to + registered callbacks, and sends periodic pings to keep the connection alive. + + Usage:: + + # Plain TCP + async with ElectrumClient("tcp://blockstream.info:110") as client: + height = await client.get_height() + + # SSL + async with ElectrumClient("ssl://electrum.blockstream.info:50002") as c: + height = await c.get_height() + """ + + def __init__( + self, + url: str, + client_name: str = "lnbits", + protocol_version: str = "1.4", + ping_interval: float = 60.0, + network: dict | None = None, + ) -> None: + parsed = urlparse(url) + self.host = parsed.hostname or "" + self.port = parsed.port or ( + 50002 if parsed.scheme in ("ssl", "https") else 50001 + ) + self.use_ssl = parsed.scheme in ("ssl", "https") + self.client_name = client_name + self.protocol_version = protocol_version + self.ping_interval = ping_interval + self.network = network or DEFAULT_NETWORK + self._counter = itertools.count(1) + self._pending: dict[int, asyncio.Future[Any]] = {} + self._subscriptions: dict[str, list[Callable[[list[Any]], Any]]] = {} + self._recv_task: asyncio.Task[None] | None = None + self._ping_task: asyncio.Task[None] | None = None + self._reader: asyncio.StreamReader | None = None + self._writer: asyncio.StreamWriter | None = None + self.closed: asyncio.Event = asyncio.Event() + self.server_version: str = "" + self.negotiated_protocol: str = "" + + async def connect(self, timeout: float = 10.0) -> None: + ssl_ctx: ssl.SSLContext | None = None + if self.use_ssl: + ssl_ctx = ssl.create_default_context() + self._reader, self._writer = await asyncio.wait_for( + asyncio.open_connection( + self.host, self.port, ssl=ssl_ctx, limit=4 * 1024 * 1024 + ), + timeout=timeout, + ) + self._recv_task = asyncio.create_task(self._recv_loop()) + result = await self._call( + "server.version", [self.client_name, self.protocol_version], timeout=timeout + ) + self.server_version, self.negotiated_protocol = result[0], result[1] + logger.debug( + f"Electrum connected: server={self.server_version}" + f" protocol={self.negotiated_protocol}" + ) + if self.ping_interval > 0: + self._ping_task = asyncio.create_task(self._ping_loop()) + + async def close(self) -> None: + for task in (self._ping_task, self._recv_task): + if task: + task.cancel() + try: + await task + except asyncio.CancelledError: + pass + except Exception: + logger.debug("Electrum: error while cancelling task") + self._ping_task = None + self._recv_task = None + if self._writer: + self._writer.close() + try: + await asyncio.wait_for(self._writer.wait_closed(), timeout=5.0) + except Exception: + logger.debug("Electrum: error while closing writer") + self._reader = None + self._writer = None + + async def __aenter__(self) -> "ElectrumClient": + try: + await self.connect() + except BaseException: + await self.close() + raise + return self + + async def __aexit__(self, *_: Any) -> None: + await self.close() + + # ---- internal plumbing ---- + + async def _call( + self, + method: str, + params: list[Any] | dict[str, Any] | None = None, + timeout: float = 30.0, + ) -> Any: + if not self._writer: + raise ElectrumError("Not connected") + req_id = next(self._counter) + fut: asyncio.Future[Any] = asyncio.get_running_loop().create_future() + self._pending[req_id] = fut + self._writer.write( + json.dumps( + { + "jsonrpc": "2.0", + "id": req_id, + "method": method, + "params": params if params is not None else [], + } + ).encode() + + b"\n" + ) + await self._writer.drain() + try: + return await asyncio.wait_for(asyncio.shield(fut), timeout=timeout) + except asyncio.TimeoutError as exc: + self._pending.pop(req_id, None) + raise ElectrumError(f"Timeout waiting for response to {method!r}") from exc + + def _dispatch(self, msg: dict[str, Any]) -> None: + msg_id = msg.get("id") + if msg_id is not None: + fut = self._pending.pop(msg_id, None) + if fut and not fut.done(): + err = msg.get("error") + if err: + fut.set_exception(ElectrumError(err)) + else: + fut.set_result(msg.get("result")) + else: + method = msg.get("method", "") + params = msg.get("params", []) + for cb in list(self._subscriptions.get(method, [])): + try: + result = cb(params) + if asyncio.iscoroutine(result): + self._bg_tasks.add(asyncio.create_task(result)) + except Exception: + logger.exception(f"Electrum: callback error for {method!r}") + + async def _recv_loop(self) -> None: + assert self._reader + self._bg_tasks: set[asyncio.Task[Any]] = set() + buf = b"" + try: + while True: + chunk = await self._reader.read(65536) + if not chunk: + break + buf += chunk + while b"\n" in buf: + line, buf = buf.split(b"\n", 1) + if not line.strip(): + continue + try: + msg: dict[str, Any] = json.loads(line) + except json.JSONDecodeError: + logger.warning(f"Electrum: invalid JSON: {line!r}") + continue + self._dispatch(msg) + except asyncio.CancelledError: + pass + except Exception: + logger.exception("Electrum: recv loop error") + finally: + self.closed.set() + for fut in self._pending.values(): + if not fut.done(): + fut.set_exception(ElectrumError("Connection closed")) + self._pending.clear() + + async def _ping_loop(self) -> None: + try: + while True: + await asyncio.sleep(self.ping_interval) + await self._call("server.ping") + except asyncio.CancelledError: + pass + except Exception: + logger.exception("Electrum: ping loop error") + + # ---- subscription management ---- + + def on(self, method: str, callback: Callable[[list[Any]], Any]) -> None: + """Register a notification callback for a subscription method.""" + self._subscriptions.setdefault(method, []).append(callback) + + def off(self, method: str, callback: Callable[[list[Any]], Any]) -> None: + """Remove a previously registered notification callback.""" + cbs = self._subscriptions.get(method) + if cbs and callback in cbs: + cbs.remove(callback) + + # ---- server methods ---- + + async def server_ping(self) -> None: + await self._call("server.ping") + + async def server_banner(self) -> str: + return await self._call("server.banner") + + async def server_features(self) -> ServerFeatures: + data = await self._call("server.features") + return ServerFeatures.parse_obj(data) + + async def server_peers(self) -> list[Any]: + return await self._call("server.peers.subscribe") + + # ---- scripthash methods ---- + + async def get_balance(self, scripthash: str) -> Balance: + data = await self._call("blockchain.scripthash.get_balance", [scripthash]) + return Balance.parse_obj(data) + + async def get_history(self, scripthash: str) -> list[HistoryEntry]: + data = await self._call("blockchain.scripthash.get_history", [scripthash]) + return [HistoryEntry.parse_obj(e) for e in data] + + async def get_mempool(self, scripthash: str) -> list[MempoolEntry]: + data = await self._call("blockchain.scripthash.get_mempool", [scripthash]) + return [MempoolEntry.parse_obj(e) for e in data] + + async def listunspent(self, scripthash: str) -> list[UTXO]: + data = await self._call("blockchain.scripthash.listunspent", [scripthash]) + return [UTXO.parse_obj(e) for e in data] + + async def subscribe_scripthash( + self, + scripthash: str, + callback: Callable[[list[Any]], Any] | None = None, + ) -> str | None: + """Subscribe to status changes; returns current status hash or None.""" + if callback: + self.on("blockchain.scripthash.subscribe", callback) + return await self._call("blockchain.scripthash.subscribe", [scripthash]) + + async def unsubscribe_scripthash( + self, + scripthash: str, + callback: Callable[[list[Any]], Any] | None = None, + ) -> bool: + if callback: + self.off("blockchain.scripthash.subscribe", callback) + return await self._call("blockchain.scripthash.unsubscribe", [scripthash]) + + async def subscribe_headers( + self, + callback: Callable[[list[Any]], Any] | None = None, + ) -> BlockHeader: + """Subscribe to new block headers; returns current tip.""" + if callback: + self.on("blockchain.headers.subscribe", callback) + data = await self._call("blockchain.headers.subscribe") + return BlockHeader.parse_obj(data) + + # ---- transaction methods ---- + + async def broadcast(self, raw_tx: str) -> str: + """Broadcast a raw transaction hex; returns txid on success.""" + return await self._call("blockchain.transaction.broadcast", [raw_tx]) + + async def get_transaction(self, txid: str) -> str: + """Fetch raw transaction hex by txid.""" + return await self._call("blockchain.transaction.get", [txid]) + + async def get_merkle(self, txid: str, height: int) -> MerkleProof: + data = await self._call("blockchain.transaction.get_merkle", [txid, height]) + return MerkleProof.parse_obj(data) + + async def get_tx_id_from_pos( + self, height: int, tx_pos: int, merkle: bool = False + ) -> str | TxIdWithMerkle: + data = await self._call( + "blockchain.transaction.id_from_pos", [height, tx_pos, merkle] + ) + if isinstance(data, dict): + return TxIdWithMerkle.parse_obj(data) + return data + + # ---- block methods ---- + + async def get_tip(self) -> BlockHeader: + """Returns current chain tip.""" + data = await self._call("blockchain.headers.subscribe") + return BlockHeader.parse_obj(data) + + async def get_height(self) -> int: + """Returns the current best block height.""" + return (await self.get_tip()).height + + async def get_block_header( + self, height: int, cp_height: int = 0 + ) -> str | BlockHeaderProof: + data = await self._call("blockchain.block.header", [height, cp_height]) + if isinstance(data, dict): + return BlockHeaderProof.parse_obj(data) + return data + + async def get_block_headers( + self, start_height: int, count: int, cp_height: int = 0 + ) -> BlockHeaders: + data = await self._call( + "blockchain.block.headers", [start_height, count, cp_height] + ) + return BlockHeaders.parse_obj(data) + + # ---- fee methods ---- + + async def estimate_fee(self, num_blocks: int) -> float: + """Returns estimated fee rate in BTC/kB for confirmation within num_blocks.""" + return await self._call("blockchain.estimatefee", [num_blocks]) + + async def fee_histogram(self) -> list[FeeHistogramEntry]: + """Returns mempool fee histogram as FeeHistogramEntry(fee_rate, vsize) list.""" + data = await self._call("mempool.get_fee_histogram") + return [FeeHistogramEntry(fee_rate=r[0], vsize=r[1]) for r in data] + + +# --------------------------------------------------------------------------- +# Address tracking +# --------------------------------------------------------------------------- + + +class OnchainAddressEvent(BaseModel): + address: str + confirmed: int # satoshis + unconfirmed: int # satoshis + history: list[HistoryEntry] = [] + history_error: str | None = None + + @property + def txids(self) -> list[str]: + return [e.tx_hash for e in self.history] + + +class AddressTracker: + """ + Subscribes to a set of Bitcoin addresses over a single shared Electrum + connection and calls a callback on every balance/history change. + Addresses can be added/removed at runtime via :meth:`add`/:meth:`remove`, + and per-connection queues can be attached via :meth:`register_queue` for + consumers (e.g. websockets) that want events for one specific address. + Reconnects automatically on failure. + + Args: + url: Electrum server URL (e.g. ``ssl://electrum.blockstream.info:50002``). + """ + + def __init__(self, url: str) -> None: + self.url = url + self._ref_counts: dict[str, int] = {} + self._queues: dict[str, list[asyncio.Queue[OnchainAddressEvent]]] = {} + self._updated = asyncio.Event() + + def add(self, address: str) -> None: + """Start tracking an address on the shared connection (ref-counted).""" + count = self._ref_counts.get(address, 0) + self._ref_counts[address] = count + 1 + if count == 0: + self._updated.set() + + def remove(self, address: str) -> None: + """Decrement ref count; drop the subscription once the last caller leaves.""" + count = self._ref_counts.get(address, 0) + if count <= 1: + self._ref_counts.pop(address, None) + self._updated.set() + else: + self._ref_counts[address] = count - 1 + + def register_queue( + self, address: str, queue: "asyncio.Queue[OnchainAddressEvent]" + ) -> None: + """Register a per-connection queue to receive events for `address`.""" + self._queues.setdefault(address, []).append(queue) + self.add(address) + + def unregister_queue( + self, address: str, queue: "asyncio.Queue[OnchainAddressEvent]" + ) -> None: + """Deregister a per-connection queue for `address`.""" + queues = self._queues.get(address, []) + if queue in queues: + queues.remove(queue) + if not queues: + self._queues.pop(address, None) + self.remove(address) + + async def run( + self, + callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> None: + while is_active(): + try: + await self._run_once(callback, is_active) + except asyncio.CancelledError: + raise + except Exception as exc: + if not is_active(): + return + logger.warning(f"AddressTracker: {exc!s}, retrying in 5s") + await asyncio.sleep(5) + + async def _run_once( + self, + callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> None: + async with ElectrumClient(self.url) as client: + subscribed: dict[str, str] = {} # scripthash -> address + + async def on_status_change(params: list[Any]) -> None: + if not params: + return + address = subscribed.get(params[0]) + if address: + await self._fetch_and_dispatch(client, address, params[0], callback) + + client.on("blockchain.scripthash.subscribe", on_status_change) + + while is_active(): + self._updated.clear() + await self._sync_subscriptions(client, subscribed, callback) + if await self._wait_for_change_or_close(client): + break # connection closed; reconnect + + async def _sync_subscriptions( + self, + client: ElectrumClient, + subscribed: dict[str, str], + callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]], + ) -> None: + wanted = {a: scripthash_from_address(a) for a in self._ref_counts} + for address, scripthash in wanted.items(): + if scripthash not in subscribed: + subscribed[scripthash] = address + await client.subscribe_scripthash(scripthash) + await self._fetch_and_dispatch(client, address, scripthash, callback) + still_wanted = set(wanted.values()) + for scripthash, address in list(subscribed.items()): + if address not in still_wanted: + del subscribed[scripthash] + try: + await client.unsubscribe_scripthash(scripthash) + except ElectrumError: + # blockchain.scripthash.unsubscribe is part of the spec but + # many ElectrumX deployments don't implement it, returning + # "unknown method". This is expected and harmless: we've + # already dropped the scripthash from `subscribed` above, + # so if the server keeps pushing notifications for it + # anyway, on_status_change() looks it up, finds nothing, + # and drops them. Not logged since it fires on every + # untrack against these servers. + pass + + async def _wait_for_change_or_close(self, client: ElectrumClient) -> bool: + """Waits until addresses change or the connection closes; returns True + if it was the connection that closed.""" + wait_task = asyncio.create_task(self._updated.wait()) + closed_task = asyncio.create_task(client.closed.wait()) + try: + done, _ = await asyncio.wait( + [wait_task, closed_task], + timeout=30, + return_when=asyncio.FIRST_COMPLETED, + ) + finally: + for t in (wait_task, closed_task): + if not t.done(): + t.cancel() + return closed_task in done + + async def _fetch_and_dispatch( + self, + client: ElectrumClient, + address: str, + scripthash: str, + callback: Callable[[OnchainAddressEvent], Coroutine[Any, Any, None]], + ) -> None: + balance_r, history_r, mempool_r = await asyncio.gather( + client.get_balance(scripthash), + client.get_history(scripthash), + client.get_mempool(scripthash), + return_exceptions=True, + ) + if isinstance(balance_r, BaseException): + raise balance_r + history: list[HistoryEntry] = ( + [] if isinstance(history_r, BaseException) else history_r + ) + history_error: str | None = ( + str(history_r) if isinstance(history_r, BaseException) else None + ) + if not isinstance(mempool_r, BaseException): + seen = {e.tx_hash for e in history} + for m in mempool_r: + if m.tx_hash not in seen: + history.append(HistoryEntry(tx_hash=m.tx_hash, height=0, fee=m.fee)) + event = OnchainAddressEvent( + address=address, + confirmed=balance_r.confirmed, + unconfirmed=balance_r.unconfirmed, + history=history, + history_error=history_error, + ) + for q in list(self._queues.get(address, [])): + q.put_nowait(event) + await callback(event) + + +# --------------------------------------------------------------------------- +# Transaction tracking +# --------------------------------------------------------------------------- + + +class OnchainTxEvent(BaseModel): + txid: str + confirmed: bool + height: int | None = None + fee: int | None = None + + +def tx_watch_scripthash(tx: Transaction) -> str | None: + """Return the scripthash of the first spendable output, used to subscribe + for confirmation notifications.""" + for out in tx.vout: + if out.scriptPubKey.type != "nulldata": + return scripthash_from_scriptpubkey(bytes.fromhex(out.scriptPubKey.hex)) + return None + + +class TransactionTracker: + """ + Subscribes to a Bitcoin transaction via Electrum and calls a callback on + each status change (unconfirmed → confirmed). Stops automatically once + the transaction is confirmed or ``is_active()`` returns ``False``. + Per-connection queues can be attached via :meth:`register_queue` for + consumers (e.g. websockets) that want events for this transaction. + + Args: + url: Electrum server URL (e.g. ``ssl://electrum.blockstream.info:50002``). + """ + + def __init__(self, url: str) -> None: + self.url = url + self._queues: list[asyncio.Queue[OnchainTxEvent]] = [] + + def register_queue(self, queue: asyncio.Queue[OnchainTxEvent]) -> None: + """Register a per-connection queue to receive events for this tx.""" + self._queues.append(queue) + + def unregister_queue(self, queue: asyncio.Queue[OnchainTxEvent]) -> None: + """Deregister a per-connection queue.""" + if queue in self._queues: + self._queues.remove(queue) + + def has_queues(self) -> bool: + return bool(self._queues) + + async def track( + self, + txid: str, + callback: Callable[[OnchainTxEvent], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> None: + while is_active(): + try: + confirmed = await self._track_once(txid, callback, is_active) + if confirmed: + return + except asyncio.CancelledError: + raise + except Exception as exc: + if not is_active(): + return + logger.warning( + f"TransactionTracker {txid[:8]}: {exc!s}, retrying in 5s" + ) + await asyncio.sleep(5) + + async def _track_once( + self, + txid: str, + callback: Callable[[OnchainTxEvent], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> bool: + """One connection attempt; returns True if the tx is confirmed.""" + async with ElectrumClient(self.url) as client: + try: + raw = await client.get_transaction(txid) + except ElectrumError as exc: + logger.warning(f"TransactionTracker {txid[:8]}: {exc!s}") + await asyncio.sleep(10) + return False + + scripthash = tx_watch_scripthash(parse_raw_tx(raw)) + confirmed_event = asyncio.Event() + + async def on_change( + params: list[Any], + _sh: str | None = scripthash, + _done: asyncio.Event = confirmed_event, + ) -> None: + if params and params[0] == _sh: + ev = await self._fetch_status(client, txid, _sh) + await self._dispatch(ev, callback) + if ev.confirmed: + _done.set() + + if scripthash: + await client.subscribe_scripthash(scripthash, on_change) + + event = await self._fetch_status(client, txid, scripthash) + await self._dispatch(event, callback) + if event.confirmed: + return True + + while is_active() and not confirmed_event.is_set(): + try: + await asyncio.wait_for(client.closed.wait(), timeout=30) + break # connection closed; reconnect + except asyncio.TimeoutError: + pass + return confirmed_event.is_set() + + async def _dispatch( + self, + event: OnchainTxEvent, + callback: Callable[[OnchainTxEvent], Coroutine[Any, Any, None]], + ) -> None: + for q in list(self._queues): + q.put_nowait(event) + await callback(event) + + @staticmethod + async def _fetch_status( + client: ElectrumClient, txid: str, scripthash: str | None + ) -> OnchainTxEvent: + if scripthash: + try: + for entry in await client.get_history(scripthash): + if entry.tx_hash == txid: + return OnchainTxEvent( + txid=txid, + confirmed=entry.height > 0, + height=entry.height if entry.height > 0 else None, + fee=entry.fee, + ) + except ElectrumError: + try: + for m in await client.get_mempool(scripthash): + if m.tx_hash == txid: + return OnchainTxEvent(txid=txid, confirmed=False, fee=m.fee) + return OnchainTxEvent(txid=txid, confirmed=True) + except ElectrumError: + pass + return OnchainTxEvent(txid=txid, confirmed=False) + + +# --------------------------------------------------------------------------- +# Block tracking +# --------------------------------------------------------------------------- + + +class BlockTracker: + """ + Subscribes to new block headers via Electrum and dispatches them to + registered queues. Per-connection queues can be attached via + :meth:`register_queue`. Reconnects automatically on failure. + + Args: + url: Electrum server URL (e.g. ``ssl://electrum.blockstream.info:50002``). + """ + + def __init__(self, url: str) -> None: + self.url = url + self._queues: list[asyncio.Queue[BlockInfo]] = [] + + def register_queue(self, queue: "asyncio.Queue[BlockInfo]") -> None: + """Register a per-connection queue to receive new block events.""" + self._queues.append(queue) + + def unregister_queue(self, queue: "asyncio.Queue[BlockInfo]") -> None: + """Deregister a per-connection queue.""" + if queue in self._queues: + self._queues.remove(queue) + + def has_queues(self) -> bool: + return bool(self._queues) + + async def run( + self, + callback: Callable[[BlockInfo], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> None: + while is_active(): + try: + await self._run_once(callback, is_active) + except asyncio.CancelledError: + raise + except Exception as exc: + if not is_active(): + return + logger.warning(f"BlockTracker: {exc!s}, retrying in 5s") + await asyncio.sleep(5) + + async def _run_once( + self, + callback: Callable[[BlockInfo], Coroutine[Any, Any, None]], + is_active: Callable[[], bool], + ) -> None: + async with ElectrumClient(self.url) as client: + + async def on_header(params: list[Any]) -> None: + h = params[0] + event = parse_block_header(h["hex"], h["height"]) + await self._dispatch(event, callback) + + tip = await client.subscribe_headers(on_header) + await self._dispatch(parse_block_header(tip.hex, tip.height), callback) + + while is_active(): + try: + await asyncio.wait_for(client.closed.wait(), timeout=30) + break # connection closed; reconnect + except asyncio.TimeoutError: + pass + + async def _dispatch( + self, + event: BlockInfo, + callback: Callable[[BlockInfo], Coroutine[Any, Any, None]], + ) -> None: + for q in list(self._queues): + q.put_nowait(event) + await callback(event) diff --git a/lnbits/utils/exchange_rates.py b/lnbits/utils/exchange_rates.py index 7cbd7f01b..4ecd06ec0 100644 --- a/lnbits/utils/exchange_rates.py +++ b/lnbits/utils/exchange_rates.py @@ -289,7 +289,32 @@ async def btc_rates(currency: str) -> list[tuple[str, float]]: return apply_trimmed_mean_filter(all_rates) +async def btc_price_from_aggregator(currency: str) -> float | None: + url = settings.lnbits_price_aggregator_url.rstrip("/") + try: + headers = {"User-Agent": settings.user_agent} + async with httpx.AsyncClient(headers=headers) as client: + r = await client.get(f"{url}/rate/{currency.upper()}", timeout=3) + r.raise_for_status() + data = r.json() + median = data.get("rates", {}).get("median") + if median: + return float(median) + except Exception as e: + logger.warning(f"Failed to fetch price from aggregator {url}: {e}") + return None + + async def btc_price(currency: str) -> float: + if ( + settings.lnbits_price_aggregator_enabled + and settings.lnbits_price_aggregator_url + ): + price = await btc_price_from_aggregator(currency) + if price: + return price + logger.warning("Price aggregator failed, falling back to exchange providers.") + rates = await btc_rates(currency) if not rates: logger.warning("Could not fetch any Bitcoin price.") diff --git a/lnbits/utils/logger.py b/lnbits/utils/logger.py index 9551af6e2..06c80822d 100644 --- a/lnbits/utils/logger.py +++ b/lnbits/utils/logger.py @@ -15,7 +15,11 @@ from lnbits.settings import settings def log_server_info(): logger.info("LNbits Info") if settings.first_install: - logger.success("This is a fresh install of LNbits.") + if settings.has_first_install_token_changed(): + logger.success("This is a first install token reset.") + else: + logger.success("This is a fresh install of LNbits.") + if settings.first_install_token: logger.success( f"FIRST_INSTALL_TOKEN: `{settings.first_install_token}`. " @@ -37,19 +41,16 @@ def log_server_info(): def initialize_server_websocket_logger() -> Callable: super_user_hash = sha256(settings.super_user.encode("utf-8")).hexdigest() - serverlog_queue: asyncio.Queue = asyncio.Queue() - - async def update_websocket_serverlog(): - while settings.lnbits_running: - msg = await serverlog_queue.get() - await websocket_updater(super_user_hash, msg) - logger.add( lambda msg: serverlog_queue.put_nowait(msg), format=Formatter().format, ) + async def update_websocket_serverlog(): + msg = await serverlog_queue.get() + await websocket_updater(super_user_hash, msg) + return update_websocket_serverlog diff --git a/lnbits/utils/nostr.py b/lnbits/utils/nostr.py index c91111791..2301c8443 100644 --- a/lnbits/utils/nostr.py +++ b/lnbits/utils/nostr.py @@ -69,7 +69,7 @@ def decrypt_content( 1: ] # extract iv and content - (encrypted_content_b64, iv_b64) = content.split("?iv=") + encrypted_content_b64, iv_b64 = content.split("?iv=") encrypted_content = base64.b64decode(encrypted_content_b64.encode("ascii")) iv = base64.b64decode(iv_b64.encode("ascii")) # Decrypt diff --git a/lnbits/wallets/__init__.py b/lnbits/wallets/__init__.py index f6e31dcd0..2f2384c7d 100644 --- a/lnbits/wallets/__init__.py +++ b/lnbits/wallets/__init__.py @@ -6,6 +6,7 @@ from lnbits.settings import settings from lnbits.wallets.base import Feature, Wallet from .alby import AlbyWallet +from .bark import BarkWallet from .blink import BlinkWallet from .boltz import BoltzWallet from .breez import BreezSdkWallet @@ -57,6 +58,7 @@ funding_source: Wallet = fake_wallet __all__ = [ "AlbyWallet", + "BarkWallet", "BlinkWallet", "BoltzWallet", "BreezLiquidSdkWallet", diff --git a/lnbits/wallets/alby.py b/lnbits/wallets/alby.py index bc7822c0b..cfd8d6c03 100644 --- a/lnbits/wallets/alby.py +++ b/lnbits/wallets/alby.py @@ -16,6 +16,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -146,6 +147,21 @@ class AlbyWallet(Wallet): return PaymentResponse( ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage ) + except httpx.HTTPStatusError as exc: + logger.warning(exc) + rejected = payment_request_was_rejected(exc.response.status_code) + try: + response_message = exc.response.json().get("message", exc.response.text) + except Exception: + response_message = exc.response.text + return PaymentResponse( + ok=False if rejected else None, + error_message=( + response_message + if rejected + else f"Unable to connect to {self.endpoint}." + ), + ) except KeyError as exc: logger.warning(exc) return PaymentResponse( @@ -185,7 +201,7 @@ class AlbyWallet(Wallet): # - https://api.getalby.com/invoices/incoming # - https://api.getalby.com/invoices/outgoing return PaymentStatus( - statuses[data.get("state")], fee_msat=None, preimage=None + statuses.get(data.get("state")), fee_msat=None, preimage=None ) except Exception as e: logger.error(f"Error getting invoice status: {e}") diff --git a/lnbits/wallets/bark.py b/lnbits/wallets/bark.py new file mode 100644 index 000000000..1b6291be5 --- /dev/null +++ b/lnbits/wallets/bark.py @@ -0,0 +1,575 @@ +import asyncio +import json +from collections.abc import AsyncGenerator +from typing import Any +from urllib.parse import quote, urlencode, urlsplit, urlunsplit + +import httpx +from bolt11 import decode as bolt11_decode +from loguru import logger +from websockets import connect + +from lnbits.helpers import normalize_endpoint +from lnbits.settings import settings + +from .base import ( + InvoiceResponse, + PaymentFailedStatus, + PaymentPendingStatus, + PaymentResponse, + PaymentStatus, + PaymentSuccessStatus, + StatusResponse, + Wallet, + payment_request_was_rejected, +) + + +class BarkError(Exception): + pass + + +class BarkHTTPError(BarkError): + def __init__(self, message: str, status_code: int): + super().__init__(message) + self.status_code = status_code + + +class BarkWallet(Wallet): + """https://second.tech/docs/barkd""" + + def __init__(self): + if not settings.bark_api_endpoint: + raise ValueError("cannot initialize BarkWallet: missing bark_api_endpoint") + if not settings.bark_api_token: + raise ValueError("cannot initialize BarkWallet: missing bark_api_token") + + super().__init__() + self.endpoint = normalize_endpoint(settings.bark_api_endpoint) + parsed_endpoint = urlsplit(self.endpoint) + ws_scheme = "wss" if parsed_endpoint.scheme == "https" else "ws" + self.ws_endpoint = urlunsplit( + ( + ws_scheme, + parsed_endpoint.netloc, + "/api/v1/notifications/ws", + "", + "", + ) + ) + self.headers = { + "Authorization": f"Bearer {settings.bark_api_token}", + "Accept": "application/json", + "Content-Type": "application/json", + "User-Agent": settings.user_agent, + } + self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers) + self.pending_payments: dict[str, str] = {} + self.outgoing_payment_waiters: dict[str, asyncio.Future[PaymentStatus]] = {} + self.notified_paid_invoice: str | None = None + + async def cleanup(self): + try: + await self.client.aclose() + except RuntimeError as e: + logger.warning(f"Error closing wallet connection: {e}") + + async def status(self) -> StatusResponse: + try: + connected = await self._request_json( + "GET", "/api/v1/wallet/connected", timeout=10 + ) + if not connected.get("connected"): + return StatusResponse("Bark wallet is not connected to Ark server.", 0) + + data = await self._request_json("GET", "/api/v1/wallet/balance", timeout=10) + if "spendable_sat" not in data: + return StatusResponse("Server error: 'missing required fields'", 0) + + return StatusResponse(None, int(data["spendable_sat"]) * 1000) + except BarkError as exc: + return StatusResponse(str(exc), 0) + except Exception as exc: + logger.warning(exc) + return StatusResponse(f"Unable to connect to {self.endpoint}.", 0) + + async def create_invoice( + self, + amount: int, + memo: str | None = None, + description_hash: bytes | None = None, + unhashed_description: bytes | None = None, + **_, + ) -> InvoiceResponse: + if description_hash or unhashed_description: + return InvoiceResponse( + ok=False, + error_message="Bark does not support description-hash invoices.", + ) + + payload: dict[str, Any] = {"amount_sat": int(amount)} + if memo is not None: + payload["description"] = memo + + try: + data = await self._request_json( + "POST", + "/api/v1/lightning/receives/invoice", + json=payload, + timeout=40, + ) + payment_request = data["invoice"] + checking_id = bolt11_decode(payment_request).payment_hash + + return InvoiceResponse( + ok=True, + checking_id=checking_id, + payment_request=payment_request, + ) + except KeyError as exc: + logger.warning(exc) + return InvoiceResponse( + ok=False, error_message="Server error: 'missing required fields'" + ) + except BarkError as exc: + return InvoiceResponse(ok=False, error_message=str(exc)) + except Exception as exc: + logger.warning(exc) + return InvoiceResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + + async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: + decoded = self._decode_invoice_for_payment(bolt11) + if isinstance(decoded, PaymentResponse): + return decoded + + checking_id, amount_sat = decoded + fee_response = await self._check_fee_limit( + checking_id, amount_sat, fee_limit_msat + ) + if fee_response: + return fee_response + + return await self._send_payment(bolt11, checking_id) + + async def get_invoice_status(self, checking_id: str) -> PaymentStatus: + try: + identifier = quote(checking_id, safe="") + data = await self._request_json( + "GET", f"/api/v1/lightning/receives/{identifier}" + ) + except BarkHTTPError as exc: + notification_status = self._consume_paid_invoice_notification(checking_id) + if notification_status: + return notification_status + if exc.status_code == 404: + return PaymentFailedStatus() + logger.warning(exc) + return PaymentPendingStatus() + except Exception as exc: + logger.warning(exc) + notification_status = self._consume_paid_invoice_notification(checking_id) + if notification_status: + return notification_status + return PaymentPendingStatus() + + return self._invoice_status_from_response(checking_id, data) + + async def get_payment_status(self, checking_id: str) -> PaymentStatus: + try: + data = await self._request_json("GET", "/api/v1/history") + if not isinstance(data, list): + return PaymentPendingStatus() + + for movement in data: + if self._movement_matches_payment_hash(movement, checking_id): + return self._movement_to_payment_status(movement) + except Exception as exc: + logger.warning(exc) + + return PaymentPendingStatus() + + async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: + while settings.lnbits_running: + try: + async for checking_id in self._listen_paid_invoices(): + yield checking_id + except asyncio.CancelledError: + raise + except Exception as exc: + logger.warning( + "Bark invoices stream unavailable " + f"({type(exc).__name__}); retrying in 5 seconds." + ) + await asyncio.sleep(5) + + async def _listen_paid_invoices(self) -> AsyncGenerator[str, None]: + ticket = await self._request_json( + "GET", "/api/v1/notifications/ws/ticket", timeout=10 + ) + if not isinstance(ticket, str) or not ticket: + raise BarkError("Server error: 'invalid websocket ticket'") + + ws_url = f"{self.ws_endpoint}?{urlencode({'ticket': ticket})}" + async with connect(ws_url) as ws: + logger.info("Connected to Bark invoices stream.") + + while settings.lnbits_running: + notification = self._parse_notification(await ws.recv()) + if not notification: + continue + if notification.get("type") == "channel-lagging": + logger.warning( + "Bark invoice notifications were lost; pending payments " + "will be reconciled by the scheduled check." + ) + continue + + self._notify_outgoing_payment(notification) + checking_id = self._incoming_payment_hash(notification) + if checking_id: + self.notified_paid_invoice = checking_id + yield checking_id + + def _parse_notification(self, message: str | bytes) -> dict[str, Any] | None: + try: + notification = json.loads(message) + except (json.JSONDecodeError, TypeError): + logger.warning("Invalid message from Bark invoices stream.") + return None + return notification if isinstance(notification, dict) else None + + def _incoming_payment_hash(self, notification: dict[str, Any]) -> str | None: + if notification.get("type") not in { + "movement-created", + "movement-updated", + }: + return None + + movement = notification.get("movement") + if not isinstance(movement, dict) or movement.get("status") != "successful": + return None + + for destination in movement.get("received_on") or []: + if not isinstance(destination, dict): + continue + method = destination.get("destination") + if not isinstance(method, dict) or method.get("type") != "invoice": + continue + invoice = method.get("value") + if not isinstance(invoice, str): + continue + try: + return bolt11_decode(invoice).payment_hash + except Exception as exc: + logger.debug(f"Unable to decode Bark notification invoice: {exc}") + return None + + def _consume_paid_invoice_notification( + self, checking_id: str, preimage: str | None = None + ) -> PaymentStatus | None: + if checking_id != self.notified_paid_invoice: + return None + self.notified_paid_invoice = None + return PaymentSuccessStatus(preimage=preimage) + + def _invoice_status_from_response( + self, checking_id: str, data: Any + ) -> PaymentStatus: + preimage = data.get("payment_preimage") if isinstance(data, dict) else None + notification_status = self._consume_paid_invoice_notification( + checking_id, preimage + ) + if notification_status: + return notification_status + if not isinstance(data, dict): + return PaymentPendingStatus() + if data.get("state") == "settled" or data.get("settled_at"): + return PaymentSuccessStatus(preimage=preimage) + if not data.get("finished_at"): + return PaymentPendingStatus() + if data.get("preimage_revealed_at"): + return PaymentSuccessStatus(preimage=preimage) + return PaymentFailedStatus() + + def _decode_invoice_for_payment( + self, bolt11: str + ) -> tuple[str, int] | PaymentResponse: + try: + invoice = bolt11_decode(bolt11) + checking_id = invoice.payment_hash + except Exception as exc: + logger.warning(exc) + return PaymentResponse(ok=False, error_message=f"Invalid invoice: {exc!s}") + + if not invoice.amount_msat or invoice.amount_msat <= 0: + return PaymentResponse( + ok=False, + checking_id=checking_id, + error_message="Bark 0 amount invoice not supported.", + ) + + amount_sat = (int(invoice.amount_msat) + 999) // 1000 + return checking_id, amount_sat + + async def _check_fee_limit( + self, checking_id: str, amount_sat: int, fee_limit_msat: int + ) -> PaymentResponse | None: + try: + fee_estimate = await self._request_json( + "GET", + "/api/v1/fees/lightning/pay", + params={"amount_sat": amount_sat}, + timeout=30, + ) + fee_msat = int(fee_estimate["fee_sat"]) * 1000 + if fee_msat > fee_limit_msat: + return PaymentResponse( + ok=False, + checking_id=checking_id, + fee_msat=fee_msat, + error_message=( + f"fee of {fee_msat} msat exceeds limit of " + f"{fee_limit_msat} msat" + ), + ) + except KeyError as exc: + logger.warning(exc) + return PaymentResponse( + ok=False, + checking_id=checking_id, + error_message="Server error: 'missing required fields'", + ) + except BarkError as exc: + return PaymentResponse( + ok=False, checking_id=checking_id, error_message=str(exc) + ) + return None + + async def _send_payment(self, bolt11: str, checking_id: str) -> PaymentResponse: + waiter = asyncio.get_running_loop().create_future() + self.outgoing_payment_waiters[checking_id] = waiter + try: + initiation_error = await self._initiate_payment(bolt11, checking_id) + if initiation_error is not None: + return initiation_error + + self.pending_payments[checking_id] = bolt11 + response = await self._payment_response_from_status(checking_id) + if not response.pending: + return response + + wait_seconds = max( + 0, settings.lnbits_funding_source_pay_invoice_wait_seconds - 1 + ) + if not wait_seconds: + return response + try: + status = await asyncio.wait_for(waiter, timeout=wait_seconds) + except TimeoutError: + return response + return self._payment_response(checking_id, status) + finally: + current_waiter = self.outgoing_payment_waiters.pop(checking_id, None) + if current_waiter and not current_waiter.done(): + current_waiter.cancel() + + async def _initiate_payment( + self, bolt11: str, checking_id: str + ) -> PaymentResponse | None: + try: + r = await self.client.post( + "/api/v1/lightning/pay", + json={"destination": bolt11}, + timeout=40, + ) + r.raise_for_status() + data = r.json() + if not isinstance(data, dict) or not isinstance(data.get("message"), str): + return self._pending_payment_response( + bolt11, + checking_id, + "Server error: 'invalid payment response'", + ) + except httpx.TimeoutException: + message = f"Timeout connecting to {self.endpoint}. keep pending..." + logger.warning(message) + return self._pending_payment_response(bolt11, checking_id, message) + except httpx.HTTPStatusError as exc: + if payment_request_was_rejected(exc.response.status_code): + return PaymentResponse( + ok=False, + checking_id=checking_id, + error_message=self._http_error_message(exc.response), + ) + message = self._http_error_message(exc.response) + logger.warning(message) + return self._pending_payment_response(bolt11, checking_id, message) + except httpx.RequestError as exc: + message = f"Unable to connect to {self.endpoint}. keep pending..." + logger.warning(message) + logger.warning(exc) + return self._pending_payment_response(bolt11, checking_id, message) + except json.JSONDecodeError: + return self._pending_payment_response( + bolt11, + checking_id, + "Server error: 'invalid json response'", + ) + except Exception as exc: + message = f"Unable to connect to {self.endpoint}. keep pending..." + logger.warning(exc) + return self._pending_payment_response(bolt11, checking_id, message) + return None + + def _pending_payment_response( + self, bolt11: str, checking_id: str, error_message: str + ) -> PaymentResponse: + self.pending_payments[checking_id] = bolt11 + return PaymentResponse( + ok=None, + checking_id=checking_id, + error_message=error_message, + ) + + async def _payment_response_from_status(self, checking_id: str) -> PaymentResponse: + status = await self.get_payment_status(checking_id) + return self._payment_response(checking_id, status) + + def _payment_response( + self, checking_id: str, status: PaymentStatus + ) -> PaymentResponse: + if status.success: + return PaymentResponse( + ok=True, + checking_id=checking_id, + fee_msat=status.fee_msat, + preimage=status.preimage, + ) + if status.failed: + return PaymentResponse(ok=False, checking_id=checking_id) + return PaymentResponse(ok=None, checking_id=checking_id) + + def _notify_outgoing_payment(self, notification: dict[str, Any]) -> None: + if notification.get("type") not in { + "movement-created", + "movement-updated", + }: + return + + movement = notification.get("movement") + if not isinstance(movement, dict): + return + status = self._movement_to_payment_status(movement) + if status.pending: + return + + for destination in movement.get("sent_to") or []: + if not isinstance(destination, dict): + continue + method = destination.get("destination") + if not isinstance(method, dict) or method.get("type") != "invoice": + continue + invoice = method.get("value") + if not isinstance(invoice, str): + continue + try: + checking_id = bolt11_decode(invoice).payment_hash + except Exception as exc: + logger.debug(f"Unable to decode Bark notification invoice: {exc}") + continue + + waiter = self.outgoing_payment_waiters.get(checking_id) + if waiter and not waiter.done(): + waiter.set_result(status) + return + + async def _request_json(self, method: str, path: str, **kwargs) -> Any: + try: + r = await self.client.request(method, path, **kwargs) + r.raise_for_status() + return r.json() + except httpx.HTTPStatusError as exc: + raise BarkHTTPError( + self._http_error_message(exc.response), exc.response.status_code + ) from exc + except json.JSONDecodeError as exc: + raise BarkError("Server error: 'invalid json response'") from exc + except httpx.RequestError as exc: + raise BarkError(f"Unable to connect to {self.endpoint}.") from exc + + def _http_error_message(self, response: httpx.Response) -> str: + try: + data = response.json() + except json.JSONDecodeError: + return response.text or f"HTTP {response.status_code}" + + if isinstance(data, dict): + for key in ("message", "detail", "error"): + if key in data: + return f"Server error: '{data[key]}'" + return response.text or f"HTTP {response.status_code}" + + def _movement_matches_payment_hash(self, movement: Any, checking_id: str) -> bool: + if not isinstance(movement, dict): + return False + + metadata_hash = self._find_value( + movement.get("metadata"), {"payment_hash", "paymentHash"} + ) + if metadata_hash == checking_id: + return True + + for destination in movement.get("sent_to") or []: + if not isinstance(destination, dict): + continue + method = destination.get("destination") + if not isinstance(method, dict) or method.get("type") != "invoice": + continue + + invoice = method.get("value") + if not isinstance(invoice, str): + continue + + if invoice == self.pending_payments.get(checking_id): + return True + + try: + if bolt11_decode(invoice).payment_hash == checking_id: + return True + except Exception as exc: + logger.debug(f"Unable to decode Bark history invoice: {exc}") + continue + + return False + + def _movement_to_payment_status(self, movement: dict[str, Any]) -> PaymentStatus: + status = movement.get("status") + if status == "successful": + fee_sat = movement.get("offchain_fee_sat") + fee_msat = int(fee_sat) * 1000 if fee_sat is not None else None + preimage = self._find_value( + movement.get("metadata"), + {"preimage", "payment_preimage", "paymentPreimage"}, + ) + return PaymentSuccessStatus(fee_msat=fee_msat, preimage=preimage) + if status in {"failed", "canceled"}: + return PaymentFailedStatus() + return PaymentPendingStatus() + + def _find_value(self, data: Any, keys: set[str]) -> str | None: + if isinstance(data, dict): + for key, value in data.items(): + if key in keys and isinstance(value, str): + return value + for value in data.values(): + found = self._find_value(value, keys) + if found: + return found + if isinstance(data, list): + for value in data: + found = self._find_value(value, keys) + if found: + return found + return None diff --git a/lnbits/wallets/base.py b/lnbits/wallets/base.py index 90517948d..d9f4ef025 100644 --- a/lnbits/wallets/base.py +++ b/lnbits/wallets/base.py @@ -15,9 +15,18 @@ if TYPE_CHECKING: from lnbits.nodes.base import Node +def payment_request_was_rejected(status_code: int) -> bool: + """Return whether HTTP rejected the request before payment dispatch.""" + # Generic 400 and 422 responses are provider-specific. They can report an + # existing payment, so adapters must not treat them as terminal based only + # on the status code. Timeouts, conflicts and rate limits are also ambiguous. + return status_code in {401, 403, 404, 405} + + class Feature(Enum): nodemanager = "nodemanager" holdinvoice = "holdinvoice" + descriptionhash = "descriptionhash" # bolt12 = "bolt12" @@ -94,15 +103,15 @@ class PaymentStatus(NamedTuple): class PaymentSuccessStatus(PaymentStatus): - paid = True + paid = True # type: ignore[reportIncompatibleVariableOverride] class PaymentFailedStatus(PaymentStatus): - paid = False + paid = False # type: ignore[reportIncompatibleVariableOverride] class PaymentPendingStatus(PaymentStatus): - paid = None + paid = None # type: ignore[reportIncompatibleVariableOverride] class Wallet(ABC): diff --git a/lnbits/wallets/blink.py b/lnbits/wallets/blink.py index be736086a..b2f05e06d 100644 --- a/lnbits/wallets/blink.py +++ b/lnbits/wallets/blink.py @@ -8,7 +8,7 @@ from loguru import logger from pydantic import BaseModel from websockets import Subprotocol, connect -from lnbits import bolt11 +from lnbits import bolt11 as bolt11_lib from lnbits.helpers import normalize_endpoint from lnbits.settings import settings @@ -164,15 +164,86 @@ class BlinkWallet(Wallet): ok=False, error_message=f"Unable to connect to {self.endpoint}." ) - async def pay_invoice( - self, bolt11_invoice: str, fee_limit_msat: int - ) -> PaymentResponse: + async def _fee_probe(self, bolt11: str) -> tuple[int | None, str | None]: + """ + Probe the route for the fee of an amount lightning invoice. + + Probing caches the route on the Blink backend so that the subsequent + payment settles with the exact fee instead of Blink's max fee reserve. + Only invoices that carry an amount can be probed here, since the + pay_invoice interface does not provide a separate amount for + zero-amount invoices. + + Returns a tuple of (fee_sat, error_message). On success the fee in + satoshis is returned; on failure an error message is returned. + """ + probe_input = { + "paymentRequest": bolt11, + "walletId": self.wallet_id, + } + data = {"query": q.fee_probe_query, "variables": {"input": probe_input}} + response = await self._graphql_query(data) + + errors = response.get("errors") or [] + if len(errors) > 0: + return None, errors[0].get("message") or "Fee probe failed." + + result = (response.get("data") or {}).get("lnInvoiceFeeProbe") or {} + + errors = result.get("errors") or [] + if len(errors) > 0: + return None, errors[0].get("message") or "Fee probe failed." + + fee_sat = result.get("amount") + if fee_sat is None: + return None, "Server error: 'missing fee probe amount'" + + return fee_sat, None + + async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: # https://dev.blink.sv/api/btc-ln-send - # Future: add check fee estimate is < fee_limit_msat before paying invoice + + invoice = bolt11_lib.decode(bolt11) + + # Only amount invoices can be probed: lnInvoiceFeeProbe takes no amount, + # and zero-amount invoices have no amount to probe with (pay_invoice + # does not receive a separate amount). Zero-amount invoices skip the + # probe and fall back to the send-without-probe behaviour. + try: + if invoice.amount_msat: + fee_sat, probe_error = await self._fee_probe(bolt11) + if probe_error is not None: + if not settings.blink_send_without_probe: + logger.info(f"Fee probe failed for invoice {bolt11}") + return PaymentResponse(ok=False, error_message=probe_error) + logger.warning( + f"Fee probe failed ('{probe_error}'), " + "sending payment without probe." + ) + elif fee_sat is not None and fee_sat * 1000 > fee_limit_msat: + error_message = ( + f"fee of {fee_sat * 1000} msat exceeds " + f"limit of {fee_limit_msat} msat" + ) + return PaymentResponse(ok=False, error_message=error_message) + elif not settings.blink_send_without_probe: + logger.info(f"Cannot probe zero-amount invoice {bolt11}") + return PaymentResponse( + ok=False, + error_message="Cannot probe fee for zero-amount invoice.", + ) + except Exception as exc: + if not settings.blink_send_without_probe: + logger.info(f"Failed to probe fee for invoice {bolt11}") + logger.warning(exc) + return PaymentResponse( + ok=False, error_message=f"Unable to connect to {self.endpoint}." + ) + logger.warning(f"Fee probe errored ('{exc}'), sending without probe.") payment_variables = { "input": { - "paymentRequest": bolt11_invoice, + "paymentRequest": bolt11, "walletId": self.wallet_id, "memo": "Payment memo", } @@ -181,25 +252,29 @@ class BlinkWallet(Wallet): try: response = await self._graphql_query(data) - errors = ( - response.get("data", {}) - .get("lnInvoicePaymentSend", {}) - .get("errors", {}) - ) + payment_result = response.get("data", {}).get("lnInvoicePaymentSend", {}) + errors = payment_result.get("errors", {}) if len(errors) > 0: error_message = errors[0].get("message") - return PaymentResponse(ok=False, error_message=error_message) + status = payment_result.get("status") + return PaymentResponse( + ok=False if status in {"FAILURE", "FAILED"} else None, + error_message=error_message, + ) - checking_id = bolt11.decode(bolt11_invoice).payment_hash + checking_id = invoice.payment_hash payment_status = await self.get_payment_status(checking_id) fee_msat = payment_status.fee_msat preimage = payment_status.preimage return PaymentResponse( - ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage + ok=payment_status.paid, + checking_id=checking_id, + fee_msat=fee_msat, + preimage=preimage, ) except Exception as exc: - logger.info(f"Failed to pay invoice {bolt11_invoice}") + logger.info(f"Failed to pay invoice {bolt11}") logger.warning(exc) return PaymentResponse( error_message=f"Unable to connect to {self.endpoint}." @@ -367,6 +442,7 @@ class BlinkGrafqlQueries(BaseModel): balance_query: str invoice_query: str payment_query: str + fee_probe_query: str status_query: str wallet_query: str tx_query: str @@ -415,6 +491,16 @@ q = BlinkGrafqlQueries( } } """, + fee_probe_query=""" + mutation LnInvoiceFeeProbe($input: LnInvoiceFeeProbeInput!) { + lnInvoiceFeeProbe(input: $input) { + amount + errors { + message + } + } + } + """, status_query=""" query InvoiceByPaymentHash($walletId: WalletId!, $paymentHash: PaymentHash!) { me { diff --git a/lnbits/wallets/boltz.py b/lnbits/wallets/boltz.py index c6473f181..050021a6c 100644 --- a/lnbits/wallets/boltz.py +++ b/lnbits/wallets/boltz.py @@ -2,6 +2,8 @@ import asyncio from collections.abc import AsyncGenerator from bolt11.decode import decode +from bolt11.types import Bolt11 +from grpc import StatusCode from grpc.aio import AioRpcError from loguru import logger @@ -124,26 +126,12 @@ class BoltzWallet(Wallet): ) async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: + prepared = await self._prepare_payment(bolt11, fee_limit_msat) + if isinstance(prepared, PaymentResponse): + return prepared + pair, invoice = prepared - pair = boltzrpc_pb2.Pair(**{"from": boltzrpc_pb2.LBTC}) try: - pair_info: boltzrpc_pb2.PairInfo - pair_request = boltzrpc_pb2.GetPairInfoRequest( - type=boltzrpc_pb2.SUBMARINE, pair=pair - ) - pair_info = await self.rpc.GetPairInfo(pair_request, metadata=self.metadata) - invoice = decode(bolt11) - - if not invoice.amount_msat: - raise ValueError("amountless invoice") - - service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100 - estimate = int(service_fee + pair_info.fees.miner_fees * 1000) - if estimate > fee_limit_msat: - error = f"fee of {estimate} msat exceeds limit of {fee_limit_msat} msat" - - return PaymentResponse(ok=False, error_message=error) - request = boltzrpc_pb2.CreateSwapRequest( invoice=bolt11, pair=pair, @@ -165,8 +153,13 @@ class BoltzWallet(Wallet): ) return PaymentResponse(ok=True, checking_id=invoice.payment_hash) except AioRpcError as exc: + return await self._resolve_create_swap_error(invoice, exc) + except Exception as exc: logger.warning(exc) - return PaymentResponse(ok=False, error_message=exc.details()) + return PaymentResponse( + checking_id=invoice.payment_hash, + error_message=str(exc), + ) try: info_request = boltzrpc_pb2.GetSwapInfoRequest(id=response.id) @@ -186,14 +179,87 @@ class BoltzWallet(Wallet): fee_msat=fee_msat, preimage=info.swap.preimage, ) - elif info.swap.error != "": - return PaymentResponse(ok=False, error_message=info.swap.error) - return PaymentResponse( - ok=False, error_message="stream stopped unexpectedly" - ) + if info.swap.state in { + boltzrpc_pb2.ERROR, + boltzrpc_pb2.SERVER_ERROR, + boltzrpc_pb2.REFUNDED, + boltzrpc_pb2.ABANDONED, + }: + return PaymentResponse( + ok=False, + checking_id=invoice.payment_hash, + error_message=info.swap.error or "swap failed", + ) + return PaymentResponse(error_message="stream stopped unexpectedly") except AioRpcError as exc: logger.warning(exc) - return PaymentResponse(ok=False, error_message=exc.details()) + return PaymentResponse(error_message=exc.details()) + + async def _resolve_create_swap_error( + self, invoice: Bolt11, exc: AioRpcError + ) -> PaymentResponse: + logger.warning(exc) + if _is_pre_dispatch_create_swap_error(exc): + status: PaymentStatus = PaymentFailedStatus() + else: + try: + status = await self.get_payment_status(invoice.payment_hash) + except Exception as status_exc: + logger.warning(status_exc) + status = PaymentPendingStatus() + + return PaymentResponse( + ok=status.paid, + checking_id=invoice.payment_hash, + fee_msat=status.fee_msat, + preimage=status.preimage, + error_message=exc.details(), + ) + + async def _prepare_payment( + self, bolt11: str, fee_limit_msat: int + ) -> tuple[boltzrpc_pb2.Pair, Bolt11] | PaymentResponse: + pair = boltzrpc_pb2.Pair(**{"from": boltzrpc_pb2.LBTC}) + try: + invoice = decode(bolt11) + except Exception as exc: + logger.warning(exc) + return PaymentResponse( + ok=False, + error_message=f"invalid bolt11 invoice: {exc}", + ) + + if not invoice.amount_msat: + return PaymentResponse( + ok=False, + checking_id=invoice.payment_hash, + error_message="amountless invoice", + ) + + try: + pair_info: boltzrpc_pb2.PairInfo + pair_request = boltzrpc_pb2.GetPairInfoRequest( + type=boltzrpc_pb2.SUBMARINE, pair=pair + ) + pair_info = await self.rpc.GetPairInfo(pair_request, metadata=self.metadata) + except Exception as exc: + logger.warning(exc) + return PaymentResponse( + ok=False, + checking_id=invoice.payment_hash, + error_message=f"unable to get swap terms: {exc}", + ) + + service_fee: float = invoice.amount_msat * pair_info.fees.percentage / 100 + estimate = int(service_fee + pair_info.fees.miner_fees * 1000) + if estimate > fee_limit_msat: + error = f"fee of {estimate} msat exceeds limit of {fee_limit_msat} msat" + return PaymentResponse( + ok=False, + checking_id=invoice.payment_hash, + error_message=error, + ) + return pair, invoice async def get_invoice_status(self, checking_id: str) -> PaymentStatus: try: @@ -217,10 +283,14 @@ class BoltzWallet(Wallet): fee_msat=fee_msat, preimage=swap.preimage, ) - elif swap.state == boltzrpc_pb2.SwapState.PENDING: - return PaymentPendingStatus() - - return PaymentFailedStatus() + if swap.state in { + boltzrpc_pb2.SwapState.ERROR, + boltzrpc_pb2.SwapState.SERVER_ERROR, + boltzrpc_pb2.SwapState.REFUNDED, + boltzrpc_pb2.SwapState.ABANDONED, + }: + return PaymentFailedStatus() + return PaymentPendingStatus() async def get_payment_status(self, checking_id: str) -> PaymentStatus: try: @@ -231,7 +301,7 @@ class BoltzWallet(Wallet): metadata=self.metadata, ) swap = response.swap - except AioRpcError as exc: + except (AioRpcError, ValueError) as exc: logger.warning(exc) return PaymentPendingStatus() if swap.state == boltzrpc_pb2.SwapState.SUCCESSFUL: @@ -243,10 +313,14 @@ class BoltzWallet(Wallet): fee_msat=fee_msat, preimage=swap.preimage, ) - elif swap.state == boltzrpc_pb2.SwapState.PENDING: - return PaymentPendingStatus() - - return PaymentFailedStatus() + if swap.state in { + boltzrpc_pb2.SwapState.ERROR, + boltzrpc_pb2.SwapState.SERVER_ERROR, + boltzrpc_pb2.SwapState.REFUNDED, + boltzrpc_pb2.SwapState.ABANDONED, + }: + return PaymentFailedStatus() + return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: while settings.lnbits_running: @@ -352,3 +426,23 @@ class BoltzWallet(Wallet): except Exception as e: logger.error(f"❌ Failed to create Boltz wallet: {e}") + + +_PRE_DISPATCH_CREATE_SWAP_ERROR_CODES = { + StatusCode.INVALID_ARGUMENT, + StatusCode.PERMISSION_DENIED, + StatusCode.UNAUTHENTICATED, +} +_PRE_DISPATCH_CREATE_SWAP_ERROR_MESSAGES = ( + "boltz error: could not find route to pay invoice", +) + + +def _is_pre_dispatch_create_swap_error(exc: AioRpcError) -> bool: + if exc.code() in _PRE_DISPATCH_CREATE_SWAP_ERROR_CODES: + return True + + details = (exc.details() or "").lower() + return any( + message in details for message in _PRE_DISPATCH_CREATE_SWAP_ERROR_MESSAGES + ) diff --git a/lnbits/wallets/breez.py b/lnbits/wallets/breez.py index bf6d59c94..dd47e69f1 100644 --- a/lnbits/wallets/breez.py +++ b/lnbits/wallets/breez.py @@ -19,7 +19,7 @@ else: from bolt11 import Bolt11Exception from bolt11 import decode as bolt11_decode - from breez_sdk import ( + from breez_sdk import ( # type: ignore[reportMissingImports] BreezEvent, ConnectRequest, EnvironmentType, @@ -39,7 +39,9 @@ else: default_config, mnemonic_to_seed, ) - from breez_sdk import PaymentStatus as BreezPaymentStatus + from breez_sdk import ( + PaymentStatus as BreezPaymentStatus, # type: ignore[reportMissingImports] + ) from loguru import logger from lnbits.settings import settings @@ -238,6 +240,12 @@ else: logger.info(ex) return PaymentResponse(error_message=f"exception while payment {exc!s}") + if payment.status == BreezPaymentStatus.FAILED: + return PaymentResponse( + ok=False, + checking_id=invoice.payment_hash, + error_message="payment failed", + ) if payment.status != BreezPaymentStatus.COMPLETE: return PaymentResponse(ok=None, error_message="payment is pending") diff --git a/lnbits/wallets/breez_liquid.py b/lnbits/wallets/breez_liquid.py index 6f1f6fb56..e9c192f0d 100644 --- a/lnbits/wallets/breez_liquid.py +++ b/lnbits/wallets/breez_liquid.py @@ -18,7 +18,7 @@ else: from pathlib import Path from bolt11 import decode as bolt11_decode - from breez_sdk_liquid import ( + from breez_sdk_liquid import ( # type: ignore[reportMissingImports] ConnectRequest, EventListener, GetInfoResponse, @@ -173,29 +173,44 @@ else: async def pay_invoice( self, bolt11: str, fee_limit_msat: int ) -> PaymentResponse: - invoice_data = bolt11_decode(bolt11) + try: + invoice_data = bolt11_decode(bolt11) + except Exception as exc: + logger.warning(exc) + return PaymentResponse( + ok=False, + error_message=f"invalid bolt11 invoice: {exc}", + ) try: prepare_req = PrepareSendRequest(destination=bolt11) req = self.sdk_services.prepare_send_payment(prepare_req) - - fee_limit_sat = settings.breez_liquid_fee_offset_sat + int( - fee_limit_msat / 1000 + except Exception as exc: + logger.warning(exc) + return PaymentResponse( + ok=False, + checking_id=invoice_data.payment_hash, + error_message=f"unable to prepare payment: {exc}", ) - if req.fees_sat and req.fees_sat > fee_limit_sat: - return PaymentResponse( - ok=False, - error_message=( - f"fee of {req.fees_sat} sat exceeds limit of " - f"{fee_limit_sat} sat" - ), - ) + fee_limit_sat = settings.breez_liquid_fee_offset_sat + int( + fee_limit_msat / 1000 + ) + if req.fees_sat and req.fees_sat > fee_limit_sat: + return PaymentResponse( + ok=False, + checking_id=invoice_data.payment_hash, + error_message=( + f"fee of {req.fees_sat} sat exceeds limit of " + f"{fee_limit_sat} sat" + ), + ) + + try: send_response = self.sdk_services.send_payment( SendPaymentRequest(prepare_response=req) ) - except Exception as exc: logger.warning(exc) return PaymentResponse(error_message=f"Exception while payment: {exc}") @@ -206,6 +221,14 @@ else: fees = req.fees_sat * 1000 if req.fees_sat and req.fees_sat > 0 else 0 + if payment.status in {PaymentState.FAILED, PaymentState.TIMED_OUT}: + return PaymentResponse( + ok=False, + checking_id=checking_id, + fee_msat=fees, + error_message=f"payment {payment.status!s}", + ) + if payment.status != PaymentState.COMPLETE: return await self._wait_for_outgoing_payment(checking_id, fees, 10) @@ -262,7 +285,10 @@ else: fee_msat=int(payment.fees_sat * 1000), preimage=payment.details.preimage, ) - if payment.status == PaymentState.FAILED: + if payment.status in { + PaymentState.FAILED, + PaymentState.TIMED_OUT, + }: return PaymentFailedStatus() return PaymentPendingStatus() except Exception as exc: diff --git a/lnbits/wallets/cliche.py b/lnbits/wallets/cliche.py index a0ef0e3ce..ead40e617 100644 --- a/lnbits/wallets/cliche.py +++ b/lnbits/wallets/cliche.py @@ -104,41 +104,42 @@ class ClicheWallet(Wallet): ) async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: - ws = create_connection(self.endpoint) - ws.send(f"pay-invoice --invoice {bolt11}") - checking_id, fee_msat, preimage, payment_ok = ( - None, - None, - None, - None, - ) - for _ in range(2): - r = ws.recv() - data = json.loads(r) + try: + ws = create_connection(self.endpoint) + ws.send(f"pay-invoice --invoice {bolt11}") checking_id, fee_msat, preimage, payment_ok = ( None, None, None, None, ) + for _ in range(2): + r = ws.recv() + data = json.loads(r) - if data.get("error") is not None: - error_message = data["error"].get("message") - return PaymentResponse(ok=False, error_message=error_message) + if data.get("error") is not None: + error_message = data["error"].get("message") + return PaymentResponse(error_message=error_message) - if data.get("method") == "payment_succeeded": - payment_ok = True - checking_id = data["params"]["payment_hash"] - fee_msat = data["params"]["fee_msatoshi"] - preimage = data["params"]["preimage"] - continue + if data.get("method") == "payment_succeeded": + payment_ok = True + checking_id = data["params"]["payment_hash"] + fee_msat = data["params"]["fee_msatoshi"] + preimage = data["params"]["preimage"] + continue - if data.get("result") is None: - return PaymentResponse(error_message="result is None") + if data.get("result") is None: + return PaymentResponse(error_message="result is None") - return PaymentResponse( - ok=payment_ok, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage - ) + return PaymentResponse( + ok=payment_ok, + checking_id=checking_id, + fee_msat=fee_msat, + preimage=preimage, + ) + except Exception as exc: + logger.warning(exc) + return PaymentResponse(error_message=f"Unable to query {self.endpoint}.") async def get_invoice_status(self, checking_id: str) -> PaymentStatus: ws = create_connection(self.endpoint) @@ -154,21 +155,25 @@ class ClicheWallet(Wallet): return PaymentStatus(statuses[data["result"]["status"]]) async def get_payment_status(self, checking_id: str) -> PaymentStatus: - ws = create_connection(self.endpoint) - ws.send(f"check-payment --hash {checking_id}") - r = ws.recv() - data = json.loads(r) + try: + ws = create_connection(self.endpoint) + ws.send(f"check-payment --hash {checking_id}") + r = ws.recv() + data = json.loads(r) - if data.get("error") is not None and data["error"].get("message"): - logger.error(data["error"]["message"]) + if data.get("error") is not None and data["error"].get("message"): + logger.error(data["error"]["message"]) + return PaymentPendingStatus() + payment = data["result"] + statuses = {"pending": None, "complete": True, "failed": False} + return PaymentStatus( + statuses.get(payment.get("status")), + payment.get("fee_msatoshi"), + payment.get("preimage"), + ) + except Exception as exc: + logger.warning(exc) return PaymentPendingStatus() - payment = data["result"] - statuses = {"pending": None, "complete": True, "failed": False} - return PaymentStatus( - statuses[payment["status"]], - payment.get("fee_msatoshi"), - payment.get("preimage"), - ) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: while settings.lnbits_running: diff --git a/lnbits/wallets/clnrest.py b/lnbits/wallets/clnrest.py index 8d34cef34..d9b86c370 100644 --- a/lnbits/wallets/clnrest.py +++ b/lnbits/wallets/clnrest.py @@ -19,6 +19,7 @@ from lnbits.utils.crypto import random_secret_and_hash from .base import ( InvoiceResponse, + PaymentFailedStatus, PaymentPendingStatus, PaymentResponse, PaymentStatus, @@ -379,9 +380,12 @@ class CLNRestWallet(Wallet): pay = pays_list[-1] - if pay["status"] == "complete": + status = pay.get("status") + if status == "complete": fee_msat = pay["amount_sent_msat"] - pay["amount_msat"] return PaymentSuccessStatus(fee_msat=fee_msat, preimage=pay["preimage"]) + if status == "failed": + return PaymentFailedStatus() except Exception as exc: logger.warning(f"Error getting payment status: {exc}") diff --git a/lnbits/wallets/corelightning.py b/lnbits/wallets/corelightning.py index e21cb4f13..41d1b6617 100644 --- a/lnbits/wallets/corelightning.py +++ b/lnbits/wallets/corelightning.py @@ -31,6 +31,21 @@ async def run_sync(func) -> Any: return await loop.run_in_executor(None, func) +def _all_payment_attempts_failed(error: object) -> bool: + if not isinstance(error, dict): + return False + + attempts = error.get("attempts") + return ( + isinstance(attempts, list) + and bool(attempts) + and all( + isinstance(attempt, dict) and attempt.get("status") == "failed" + for attempt in attempts + ) + ) + + class CoreLightningWallet(Wallet): """Core Lightning RPC implementation.""" @@ -184,7 +199,9 @@ class CoreLightningWallet(Wallet): logger.warning(exc) try: error_code = exc.error.get("code") # type: ignore - if error_code in self.pay_failure_error_codes: + if error_code in self.pay_failure_error_codes or ( + _all_payment_attempts_failed(exc.error) + ): error_message = exc.error.get("message", error_code) # type: ignore return PaymentResponse( ok=False, error_message=f"Payment failed: {error_message}" diff --git a/lnbits/wallets/eclair.py b/lnbits/wallets/eclair.py index dc5ed590d..88d12dec6 100644 --- a/lnbits/wallets/eclair.py +++ b/lnbits/wallets/eclair.py @@ -22,6 +22,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -165,6 +166,24 @@ class EclairWallet(Wallet): checking_id = data["paymentHash"] preimage = data["paymentPreimage"] + except httpx.HTTPStatusError as exc: + error_message = f"Unable to connect to {self.url}." + try: + error_data = exc.response.json() + if isinstance(error_data, dict) and error_data.get("error"): + error_message = str(error_data["error"]) + except json.JSONDecodeError: + pass + + # Eclair uses HTTP 400 for invoice and form validation failures, + # which happen before it dispatches the payment. + rejected = exc.response.status_code == 400 or payment_request_was_rejected( + exc.response.status_code + ) + return PaymentResponse( + ok=False if rejected else None, + error_message=error_message, + ) except json.JSONDecodeError: return PaymentResponse( error_message="Server error: 'invalid json response'" diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index be70d5726..438c8401f 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -103,7 +103,7 @@ class FakeWallet(Wallet): preimage=preimage.hex(), ) - async def pay_invoice(self, bolt11: str, _: int) -> PaymentResponse: + async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: try: invoice = decode(bolt11) except Bolt11Exception as exc: @@ -130,7 +130,7 @@ class FakeWallet(Wallet): return PaymentPendingStatus() return PaymentFailedStatus() - async def get_payment_status(self, _: str) -> PaymentStatus: + async def get_payment_status(self, checking_id: str) -> PaymentStatus: return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 878433e94..2641de233 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -118,7 +118,7 @@ class LndWallet(Wallet): cert = open(cert_path, "rb").read() creds = grpc.ssl_channel_credentials(cert) - auth_creds = grpc.metadata_call_credentials(self.metadata_callback) + auth_creds = grpc.metadata_call_credentials(self.metadata_callback) # type: ignore[reportArgumentType] composite_creds = grpc.composite_channel_credentials(creds, auth_creds) channel = grpc.aio.secure_channel( f"{self.endpoint}:{self.port}", composite_creds @@ -192,12 +192,21 @@ class LndWallet(Wallet): fee_limit_msat=fee_limit_msat, timeout_seconds=30, no_inflight_updates=True, + max_parts=16, + time_pref=0.9, + allow_self_payment=settings.lnd_grpc_allow_self_payment, ) try: res: Payment = await self.router_rpc.SendPaymentV2(req).read() + except grpc.aio.AioRpcError as exc: + logger.warning(exc) + return PaymentResponse( + ok=False if _is_pre_dispatch_payment_error(exc) else None, + error_message=exc.details() or str(exc), + ) except Exception as exc: logger.warning(exc) - return PaymentResponse(error_message=str(exc)) + return PaymentResponse(ok=None, error_message=str(exc)) if res.status == Payment.PaymentStatus.SUCCEEDED: return PaymentResponse( @@ -375,3 +384,22 @@ class LndWallet(Wallet): ) # If we reach here, the invoice was successfully canceled and payment failed return InvoiceResponse(True, checking_id=payment_hash) + + +_PRE_DISPATCH_PAYMENT_ERROR_CODES = { + grpc.StatusCode.INVALID_ARGUMENT, + grpc.StatusCode.PERMISSION_DENIED, + grpc.StatusCode.UNAUTHENTICATED, +} +_PRE_DISPATCH_PAYMENT_ERROR_MESSAGES = ( + "invoice not for current active network", + "invoice expired", +) + + +def _is_pre_dispatch_payment_error(exc: grpc.aio.AioRpcError) -> bool: + if exc.code() in _PRE_DISPATCH_PAYMENT_ERROR_CODES: + return True + + details = (exc.details() or "").lower() + return any(message in details for message in _PRE_DISPATCH_PAYMENT_ERROR_MESSAGES) diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index da72a61f1..bec06bf2b 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -3,6 +3,7 @@ import base64 import hashlib import json from collections.abc import AsyncGenerator +from typing import Any import httpx from loguru import logger @@ -25,6 +26,42 @@ from .base import ( ) from .macaroon import load_macaroon +_PRE_DISPATCH_PAYMENT_ERROR_CODES = {3, 7, 16} +_PRE_DISPATCH_PAYMENT_ERROR_MESSAGES = ( + "invoice not for current active network", + "invoice expired", +) + + +def _is_pre_dispatch_payment_error(code: int | None, message: str) -> bool: + # LND's REST gateway uses the numeric gRPC status codes. UNKNOWN (2) + # is ambiguous unless LND returned one of its request-validation errors. + if code in _PRE_DISPATCH_PAYMENT_ERROR_CODES: + return True + + message = message.lower() + return any(error in message for error in _PRE_DISPATCH_PAYMENT_ERROR_MESSAGES) + + +def _payment_response_from_http_error( + exc: httpx.HTTPStatusError, endpoint: str +) -> PaymentResponse: + try: + error = exc.response.json()["error"] + error_code = error.get("code") + error_message = str(error.get("message") or exc) + except (json.JSONDecodeError, KeyError, TypeError, AttributeError): + error_code = None + error_message = f"Unable to connect to {endpoint}." + + logger.warning(f"LndRestWallet pay_invoice POST error: {error_message}.") + return PaymentResponse( + ok=( + False if _is_pre_dispatch_payment_error(error_code, error_message) else None + ), + error_message=error_message, + ) + class LndRestWallet(Wallet): """https://api.lightning.community/#lnd-rest-api-reference""" @@ -123,8 +160,8 @@ class LndRestWallet(Wallet): hashlib.sha256(unhashed_description).digest() ).decode("ascii") - preimage, _payment_hash = random_secret_and_hash() - _data["r_hash"] = base64.b64encode(bytes.fromhex(_payment_hash)).decode() + preimage, payment_hash = random_secret_and_hash() + _data["r_hash"] = base64.b64encode(bytes.fromhex(payment_hash)).decode() _data["r_preimage"] = base64.b64encode(bytes.fromhex(preimage)).decode() try: @@ -132,34 +169,7 @@ class LndRestWallet(Wallet): r.raise_for_status() data = r.json() - if len(data) == 0: - return InvoiceResponse(ok=False, error_message="no data") - - if "error" in data: - return InvoiceResponse( - ok=False, error_message=f"""Server error: '{data["error"]}'""" - ) - - if r.is_error: - return InvoiceResponse( - ok=False, error_message=f"Server error: '{r.text}'" - ) - - if "payment_request" not in data or "r_hash" not in data: - return InvoiceResponse( - ok=False, error_message="Server error: 'missing required fields'" - ) - - payment_request = data["payment_request"] - payment_hash = base64.b64decode(data["r_hash"]).hex() - checking_id = payment_hash - return InvoiceResponse( - ok=True, - checking_id=checking_id, - payment_request=payment_request, - preimage=preimage, - ) - + return self._parse_create_invoice_response(r, data, preimage) except json.JSONDecodeError: return InvoiceResponse( ok=False, error_message="Server error: 'invalid json response'" @@ -188,6 +198,8 @@ class LndRestWallet(Wallet): ) r.raise_for_status() data = r.json() + except httpx.HTTPStatusError as exc: + return _payment_response_from_http_error(exc, self.endpoint) except json.JSONDecodeError: return PaymentResponse( error_message="Server error: 'invalid json response'" @@ -227,7 +239,7 @@ class LndRestWallet(Wallet): elif status == "IN_FLIGHT": return PaymentResponse(ok=None, checking_id=checking_id) return PaymentResponse( - ok=False, + ok=None, checking_id=checking_id, error_message="Server error: 'unknown payment status returned'", ) @@ -242,12 +254,13 @@ class LndRestWallet(Wallet): logger.warning(f"Error getting invoice status: {e}") return PaymentPendingStatus() - if r.is_error or data.get("settled") is None: + if r.is_error or data.get("state") is None: # this must also work when checking_id is not a hex recognizable by lnd - # it will return an error and no "settled" attribute on the object + # it will return an error and no "state" attribute on the object + logger.warning(f"Error checking invoice from LND REST API: {r.text}") return PaymentPendingStatus() - if data.get("settled") is True: + if data.get("state") == "SETTLED": return PaymentSuccessStatus() if data.get("state") == "CANCELED": @@ -264,10 +277,11 @@ class LndRestWallet(Wallet): "ascii" ) except ValueError: + logger.warning("Invalid checking_id format, must be hex: {checking_id}") return PaymentPendingStatus() url = f"/v2/router/track/{checking_id}" - async with self.client.stream("GET", url, timeout=None) as r: + async with self.client.stream("GET", url, timeout=30) as r: async for json_line in r.aiter_lines(): try: line = json.loads(json_line) @@ -298,7 +312,7 @@ class LndRestWallet(Wallet): return PaymentFailedStatus() elif status == "IN_FLIGHT": logger.info(f"LNDRest Payment in flight: {checking_id}") - return PaymentPendingStatus() + continue logger.info(f"LNDRest Payment non-existent: {checking_id}") return PaymentPendingStatus() @@ -311,13 +325,12 @@ class LndRestWallet(Wallet): async for line in r.aiter_lines(): try: inv = json.loads(line)["result"] - if not inv["settled"]: + if not inv.get("state") == "SETTLED": continue + payment_hash = base64.b64decode(inv.get("r_hash")).hex() except Exception as exc: logger.debug(exc) continue - - payment_hash = base64.b64decode(inv["r_hash"]).hex() yield payment_hash except Exception as exc: logger.warning( @@ -363,8 +376,6 @@ class LndRestWallet(Wallet): return InvoiceResponse(ok=False, error_message=str(exc)) payment_request = data["payment_request"] - payment_hash = base64.b64encode(bytes.fromhex(payment_hash)).decode("ascii") - return InvoiceResponse( ok=True, checking_id=payment_hash, payment_request=payment_request ) @@ -399,3 +410,31 @@ class LndRestWallet(Wallet): except Exception as exc: logger.warning(exc) return InvoiceResponse(ok=False, error_message=str(exc)) + + def _parse_create_invoice_response( + self, r: Any, data: dict, preimage: str + ) -> InvoiceResponse: + if not data: + return InvoiceResponse(ok=False, error_message="no data") + if "error" in data: + return InvoiceResponse( + ok=False, error_message=f"Server error: '{data['error']}'" + ) + if r.is_error: + return InvoiceResponse(ok=False, error_message=f"Server error: '{r.text}'") + if "payment_request" not in data or "r_hash" not in data: + return InvoiceResponse( + ok=False, error_message="Server error: 'missing required fields'" + ) + try: + payment_hash = base64.b64decode(data["r_hash"]).hex() + except Exception: + return InvoiceResponse( + ok=False, error_message=f"Unable to b64decode to {data['r_hash']}." + ) + return InvoiceResponse( + ok=True, + checking_id=payment_hash, + payment_request=data["payment_request"], + preimage=preimage, + ) diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index 738faf9ea..0212f9be8 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -15,6 +15,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -105,44 +106,58 @@ class LNPayWallet(Wallet): ) async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: - r = await self.client.post( - f"/wallet/{self.wallet_key}/withdraw", - json={"payment_request": bolt11}, - timeout=None, - ) + try: + r = await self.client.post( + f"/wallet/{self.wallet_key}/withdraw", + json={"payment_request": bolt11}, + timeout=None, + ) + except Exception as exc: + logger.warning(exc) + return PaymentResponse(error_message="Unable to connect to LNPay.") try: data = r.json() except Exception: - return PaymentResponse(ok=False, error_message="Got invalid JSON.") + return PaymentResponse(error_message="Got invalid JSON.") if r.is_error: - return PaymentResponse(ok=False, error_message=data["message"]) + return PaymentResponse( + ok=False if payment_request_was_rejected(r.status_code) else None, + error_message=data.get("message", r.text), + ) - checking_id = data["lnTx"]["id"] - fee_msat = 0 - preimage = data["lnTx"]["payment_preimage"] + try: + checking_id = data["lnTx"]["id"] + preimage = data["lnTx"]["payment_preimage"] + except (KeyError, TypeError): + return PaymentResponse( + error_message="LNPay response is missing required payment fields." + ) return PaymentResponse( - ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage + ok=True, checking_id=checking_id, fee_msat=0, preimage=preimage ) async def get_invoice_status(self, checking_id: str) -> PaymentStatus: return await self.get_payment_status(checking_id) async def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = await self.client.get( - url=f"/lntx/{checking_id}", - ) + try: + r = await self.client.get( + url=f"/lntx/{checking_id}", + ) + if r.is_error: + return PaymentPendingStatus() - if r.is_error: + data = r.json() + paid = {0: None, 1: True, -1: False}.get(data.get("settled")) + return PaymentStatus( + paid, data.get("fee_msat"), data.get("payment_preimage") + ) + except Exception as exc: + logger.warning(exc) return PaymentPendingStatus() - data = r.json() - preimage = data["payment_preimage"] - fee_msat = data["fee_msat"] - statuses = {0: None, 1: True, -1: False} - return PaymentStatus(statuses[data["settled"]], fee_msat, preimage) - async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) while settings.lnbits_running: diff --git a/lnbits/wallets/lntips.py b/lnbits/wallets/lntips.py index 5a15be1a0..1179f2673 100644 --- a/lnbits/wallets/lntips.py +++ b/lnbits/wallets/lntips.py @@ -17,6 +17,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -103,26 +104,43 @@ class LnTipsWallet(Wallet): ) async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: - r = await self.client.post( - "/api/v1/payinvoice", - json={"pay_req": bolt11}, - timeout=None, - ) + try: + r = await self.client.post( + "/api/v1/payinvoice", + json={"pay_req": bolt11}, + timeout=None, + ) + except Exception as exc: + logger.warning(exc) + return PaymentResponse( + error_message=f"Unable to connect to {self.endpoint}." + ) if r.is_error: - return PaymentResponse(ok=False, error_message=r.text) + return PaymentResponse( + ok=False if payment_request_was_rejected(r.status_code) else None, + error_message=r.text, + ) - if "error" in r.json(): - try: - data = r.json() - error_message = data["error"] - except Exception: - error_message = r.text - return PaymentResponse(ok=False, error_message=error_message) + try: + response = r.json() + except json.JSONDecodeError: + return PaymentResponse( + error_message="Server error: 'invalid json response'" + ) - data = r.json()["details"] - checking_id = data["payment_hash"] - fee_msat = -data["fee"] - preimage = data["preimage"] + if "error" in response: + error_message = response.get("error") or r.text + return PaymentResponse(error_message=error_message) + + try: + data = response["details"] + checking_id = data["payment_hash"] + fee_msat = -data["fee"] + preimage = data["preimage"] + except (KeyError, TypeError): + return PaymentResponse( + error_message="Server error: 'missing required fields'" + ) return PaymentResponse( ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage ) diff --git a/lnbits/wallets/nwc.py b/lnbits/wallets/nwc.py index c73ba6683..928ea6518 100644 --- a/lnbits/wallets/nwc.py +++ b/lnbits/wallets/nwc.py @@ -1,14 +1,19 @@ import asyncio +import base64 import hashlib +import hmac import json import random +import secrets import time -from collections.abc import AsyncGenerator -from typing import cast +from collections.abc import AsyncGenerator, Awaitable, Callable +from typing import Any, cast from urllib.parse import parse_qs, unquote, urlparse from bolt11 import decode as bolt11_decode from coincurve import PrivateKey, PublicKey +from Cryptodome.Cipher import ChaCha20 +from Cryptodome.Hash import HMAC, SHA256 from loguru import logger from websockets import connect as ws_connect @@ -44,6 +49,26 @@ class NWCError(Exception): return f"{self.code} {self.message}" +NWC_ENCRYPTION_NIP04 = "nip04" +NWC_ENCRYPTION_NIP44_V2 = "nip44_v2" +NWC_SUPPORTED_ENCRYPTIONS = [NWC_ENCRYPTION_NIP44_V2, NWC_ENCRYPTION_NIP04] +NWC_NOTIFICATION_KIND_NIP04 = 23196 +NWC_NOTIFICATION_KIND_NIP44 = 23197 + + +def _normalize_supported_encryptions(encryptions: list[str]) -> list[str]: + normalized = [enc for enc in encryptions if enc in NWC_SUPPORTED_ENCRYPTIONS] + return normalized or [NWC_ENCRYPTION_NIP04] + + +def _choose_preferred_encryption(encryptions: list[str]) -> str: + supported = set(_normalize_supported_encryptions(encryptions)) + for encryption in NWC_SUPPORTED_ENCRYPTIONS: + if encryption in supported: + return encryption + return NWC_ENCRYPTION_NIP04 + + class NWCWallet(Wallet): """ A funding source that connects to a Nostr Wallet Connect (NWC) service provider. @@ -51,22 +76,32 @@ class NWCWallet(Wallet): """ def __init__(self): + super().__init__() self.shutdown = False nwc_data = parse_nwc(settings.nwc_pairing_url) self.conn = NWCConnection( - nwc_data["pubkey"], nwc_data["secret"], nwc_data["relay"] + nwc_data["pubkey"], + nwc_data["secret"], + nwc_data["relay"], + notification_handler=self._handle_notification, ) - # pending payments for paid_invoices_stream. - # They are tracked until they expire or are settled - self.pending_payments = [] - # interval in seconds between checks for pending payments - self.pending_payments_lookup_interval = 10 - # track paid invoices for paid_invoices_stream + self.pending_invoice_details: dict[str, dict[str, Any]] = {} + self.payment_status_cache: dict[str, dict[str, Any]] = {} + self.payment_status_cache_pending_ttl = 30 + self.payment_status_cache_terminal_ttl = 60 * 60 * 24 + self.transactions_refresh_interval = 30 + self.transactions_refresh_max_age = 60 * 60 * 24 * 15 + self.transactions_refresh_max_pages = 20 + self.transactions_refresh_lock = asyncio.Lock() + self.last_transactions_refresh_at: dict[bool, float] = {} + self.pending_invoices_maintenance_interval = 5 + self.notification_lookup_schedule = [60, 120, 300, 600, 1200, 1800] + self.lookup_only_schedule = [15, 30, 60, 120, 300, 600, 1200, 1800] + self.pending_invoices_lookup_cooldown = 1.0 + self.pending_invoices_reconcile_interval = 180 + self.next_reconcile_at = 0.0 + self.last_connection_generation = -1 self.paid_invoices_queue = asyncio.Queue(0) - # This task periodically checks if pending payments have been settled - self.pending_payments_lookup_task = asyncio.create_task( - self._handle_pending_payments() - ) def _is_shutting_down(self) -> bool: """ @@ -74,57 +109,412 @@ class NWCWallet(Wallet): """ return self.shutdown or not settings.lnbits_running - async def _handle_pending_payments(self): - """ - Periodically checks if any pending payments have been settled. - """ - while not self._is_shutting_down(): - await asyncio.sleep(self.pending_payments_lookup_interval) - # Check if any pending payments have been settled or timed out - now = time.time() - for payment in self.pending_payments: - try: - if not payment["settled"]: - payment_data = await self.conn.call( - "lookup_invoice", {"payment_hash": payment["checking_id"]} - ) - settled = ( - "settled_at" in payment_data - and payment_data["settled_at"] - and int(payment_data["settled_at"]) > 0 - and "preimage" in payment_data - and payment_data["preimage"] - ) - if settled: - logger.debug( - "Pending payment " + payment["checking_id"] + " settled" - ) - payment["settled"] = True - self.paid_invoices_queue.put_nowait(payment["checking_id"]) - except Exception as e: - logger.error("Error handling pending payment: " + str(e)) - try: - if now > payment["expires_at"]: - logger.warning( - "Pending payment " + payment["checking_id"] + " timed out" - ) - payment["expired"] = True - except Exception as e: - logger.error("Error handling pending payment: " + str(e)) + async def _handle_notification(self, notification: dict[str, Any]): + notification_type = notification.get("notification_type") + notification_payload = notification.get("notification") or {} + if not isinstance(notification_payload, dict): + logger.warning( + "Ignoring malformed NWC notification payload: " + + str(notification_payload) + ) + return - # Remove all settled or expired payments - self.pending_payments = [ - payment - for payment in self.pending_payments - if not payment["settled"] and not payment["expired"] + if notification_type == "payment_received": + checking_id = str(notification_payload.get("payment_hash") or "") + if checking_id: + logger.debug( + "Received NWC payment_received notification for " + checking_id + ) + self._cache_payment_data(checking_id, notification_payload) + self._mark_invoice_settled(checking_id, source="notification") + elif notification_type == "payment_sent": + checking_id = str(notification_payload.get("payment_hash") or "") + if checking_id: + logger.debug( + "Received NWC payment_sent notification for " + checking_id + ) + payment_data = dict(notification_payload) + payment_data.setdefault("state", "settled") + payment_data.setdefault("settled_at", int(time.time())) + self._cache_payment_data(checking_id, payment_data) + elif notification_type == "hold_invoice_accepted": + logger.debug( + "Received NWC hold_invoice_accepted notification for " + + str(notification_payload.get("payment_hash") or "") + ) + elif notification_type: + logger.debug( + "Ignoring unsupported NWC notification type " + notification_type + ) + + def _get_lookup_schedule(self) -> list[int]: + if self.conn.supports_notification_type("payment_received"): + return self.notification_lookup_schedule + return self.lookup_only_schedule + + def _schedule_next_lookup(self, invoice: dict[str, Any], now: float | None = None): + now = now or time.time() + schedule = self._get_lookup_schedule() + attempt = int(invoice.get("lookup_attempts", 0)) + delay = schedule[min(attempt, len(schedule) - 1)] + jitter = random.uniform(0, min(15, max(1, delay * 0.1))) # noqa: S311 + invoice["next_lookup_at"] = now + delay + jitter + + def _track_pending_invoice( + self, checking_id: str, created_at: int, expires_at: int + ) -> None: + invoice = self.pending_invoice_details.get(checking_id, {}) + invoice["checking_id"] = checking_id + invoice["created_at"] = created_at + invoice["expires_at"] = expires_at + invoice.setdefault("lookup_attempts", 0) + invoice.setdefault("last_lookup_at", 0.0) + self.pending_invoice_details[checking_id] = invoice + if checking_id not in self.pending_invoices: + self.pending_invoices.append(checking_id) + if "next_lookup_at" not in invoice: + self._schedule_next_lookup(invoice, created_at) + self.next_reconcile_at = 0.0 + + def _remove_pending_invoice(self, checking_id: str) -> bool: + self.pending_invoice_details.pop(checking_id, None) + if checking_id in self.pending_invoices: + self.pending_invoices.remove(checking_id) + return True + return False + + def _mark_invoice_settled(self, checking_id: str, source: str): + was_pending = self._remove_pending_invoice(checking_id) + if was_pending: + logger.debug("Pending invoice " + checking_id + " settled via " + source) + self.paid_invoices_queue.put_nowait(checking_id) + + def _expire_pending_invoices(self, now: float): + expired_ids: list[str] = [] + for checking_id in list(self.pending_invoices): + invoice = self.pending_invoice_details.get(checking_id, {}) + expires_at = int(invoice.get("expires_at", 0) or 0) + if expires_at and now > expires_at: + logger.warning("Pending invoice " + checking_id + " timed out") + expired_ids.append(checking_id) + for checking_id in expired_ids: + self._remove_pending_invoice(checking_id) + + async def _should_run_reconciliation(self, now: float) -> bool: + if now < self.next_reconcile_at: + return False + await self.conn.get_info() + if not self.conn.supports_method("list_transactions"): + self.next_reconcile_at = now + self.pending_invoices_reconcile_interval + return False + return True + + def _cache_ids(self, *extra_ids: str) -> set[str]: + ids = {checking_id for checking_id in self.pending_invoices if checking_id} + ids.update(checking_id for checking_id in extra_ids if checking_id) + return ids + + async def _fetch_incoming_transactions( + self, + *, + from_ts: int, + now: float | None = None, + cache_ids: set[str] | None = None, + stop_when_found_ids: set[str] | None = None, + unpaid: bool = False, + ) -> list[dict[str, Any]]: + now = now or time.time() + await self.conn.get_info() + if not self.conn.supports_method("list_transactions"): + return [] + + offset = 0 + limit = 20 + transactions: list[dict[str, Any]] = [] + remaining_ids = { + checking_id for checking_id in (stop_when_found_ids or set()) if checking_id + } + + while offset < limit * self.transactions_refresh_max_pages: + result = await self.conn.call( + "list_transactions", + { + "from": from_ts, + "until": int(now), + "limit": limit, + "offset": offset, + "type": "incoming", + "unpaid": unpaid, + }, + ) + page = result.get("transactions", []) + tx_summary = [ + { + "payment_hash": tx.get("payment_hash"), + "state": tx.get("state"), + "settled_at": tx.get("settled_at"), + "expires_at": tx.get("expires_at"), + } + for tx in page + if isinstance(tx, dict) ] + logger.debug( + "NWC list_transactions response. " + f"from={from_ts} until={int(now)} offset={offset} " + f"limit={limit} unpaid={unpaid} " + f"count={len(page) if isinstance(page, list) else 'malformed'} " + f"transactions={tx_summary} raw={result}" + ) + if not isinstance(page, list) or not page: + break + + for tx in page: + if not isinstance(tx, dict): + continue + checking_id = str(tx.get("payment_hash") or "") + if checking_id and (cache_ids is None or checking_id in cache_ids): + self._cache_payment_data(checking_id, tx, cached_at=now) + if checking_id: + remaining_ids.discard(checking_id) + transactions.append(tx) + + if len(page) < limit: + break + if not remaining_ids and stop_when_found_ids: + break + offset += limit + + return transactions + + async def _reconcile_pending_invoices(self, now: float): + try: + await self.conn.get_info() + if not self.conn.supports_method("list_transactions"): + self.next_reconcile_at = now + self.pending_invoices_reconcile_interval + return + + created_from = min( + int( + self.pending_invoice_details.get(checking_id, {}).get( + "created_at", now + ) + ) + for checking_id in self.pending_invoices + ) + from_ts = max(0, created_from - 60) + matched = 0 + pending_ids = self._cache_ids() + + logger.debug( + "Reconciling pending NWC invoices with list_transactions. " + f"pending_count={len(self.pending_invoices)} from={from_ts}" + ) + + transactions = await self._fetch_incoming_transactions( + from_ts=from_ts, + now=now, + cache_ids=pending_ids, + stop_when_found_ids=pending_ids, + ) + for tx in transactions: + checking_id = str(tx.get("payment_hash") or "") + if checking_id not in self.pending_invoices: + continue + if self._payment_data_is_settled(tx): + self._mark_invoice_settled(checking_id, source="reconciliation") + matched += 1 + + logger.debug( + "NWC reconciliation complete. " + f"matched={matched} remaining_pending={len(self.pending_invoices)}" + ) + except Exception as e: + logger.error("Error reconciling pending NWC invoices: " + str(e)) + finally: + self.next_reconcile_at = now + self.pending_invoices_reconcile_interval + + async def _run_fallback_lookups(self, now: float): + await self.conn.get_info() + if not self.conn.supports_method("lookup_invoice"): + return + + due_invoices = [ + self.pending_invoice_details[checking_id] + for checking_id in self.pending_invoices + if checking_id in self.pending_invoice_details + and float( + self.pending_invoice_details[checking_id].get("next_lookup_at", 0.0) + or 0.0 + ) + <= now + ] + due_invoices.sort(key=lambda invoice: float(invoice.get("next_lookup_at", 0.0))) + + for index, invoice in enumerate(due_invoices): + checking_id = str(invoice["checking_id"]) + if checking_id not in self.pending_invoices: + continue + try: + payment_data = await self.conn.call( + "lookup_invoice", {"payment_hash": checking_id} + ) + self._cache_payment_data(checking_id, payment_data, cached_at=now) + invoice["last_lookup_at"] = now + invoice["lookup_attempts"] = int(invoice.get("lookup_attempts", 0)) + 1 + if self._payment_data_is_settled(payment_data): + self._mark_invoice_settled(checking_id, source="lookup") + continue + self._schedule_next_lookup(invoice, now) + except NWCError as e: + logger.warning( + "Error handling pending invoice via lookup. " + f"checking_id={checking_id} code={e.code} message={e.message}" + ) + invoice["lookup_attempts"] = int(invoice.get("lookup_attempts", 0)) + 1 + if e.code == "RATE_LIMITED": + self.next_reconcile_at = max( + self.next_reconcile_at, + now + self.pending_invoices_reconcile_interval, + ) + self._schedule_next_lookup(invoice, now) + except Exception as e: + logger.error("Error handling pending invoice: " + str(e)) + invoice["lookup_attempts"] = int(invoice.get("lookup_attempts", 0)) + 1 + self._schedule_next_lookup(invoice, now) + if ( + index < len(due_invoices) - 1 + and self.pending_invoices_lookup_cooldown > 0 + and not self._is_shutting_down() + ): + await asyncio.sleep(self.pending_invoices_lookup_cooldown) + + async def _maintain_pending_invoices(self): + if not self.pending_invoices: + return + + now = time.time() + if self.conn.connection_generation != self.last_connection_generation: + self.last_connection_generation = self.conn.connection_generation + self.next_reconcile_at = 0.0 + + self._expire_pending_invoices(now) + if not self.pending_invoices: + return + + if await self._should_run_reconciliation(now): + await self._reconcile_pending_invoices(now) + + await self._run_fallback_lookups(now) + self._prune_payment_status_cache(self._cache_ids()) + + def _payment_data_is_settled(self, payment_data: dict[str, Any]) -> bool: + state = payment_data.get("state") + settled_at = payment_data.get("settled_at") + preimage = payment_data.get("preimage") + if state == "settled": + return True + return bool(settled_at and int(settled_at) > 0 and preimage) + + def _payment_data_is_failed(self, payment_data: dict[str, Any]) -> bool: + state = payment_data.get("state") + if state in {"expired", "failed"}: + return True + created_at = int(payment_data.get("created_at", time.time())) + expires_at = int(payment_data.get("expires_at", created_at + 3600)) + return bool( + expires_at + and time.time() > expires_at + and not self._payment_data_is_settled(payment_data) + ) + + def _payment_data_to_status(self, payment_data: dict[str, Any]) -> PaymentStatus: + fee_msat = payment_data.get("fees_paid", None) + preimage = payment_data.get("preimage", None) + if self._payment_data_is_settled(payment_data): + return PaymentStatus(True, fee_msat=fee_msat, preimage=preimage) + if self._payment_data_is_failed(payment_data): + return PaymentStatus(False, fee_msat=fee_msat, preimage=preimage) + return PaymentStatus(None, fee_msat=fee_msat, preimage=preimage) + + def _cache_payment_data( + self, + checking_id: str, + payment_data: dict[str, Any], + cached_at: float | None = None, + ) -> None: + cached_at = cached_at or time.time() + ttl = ( + self.payment_status_cache_terminal_ttl + if self._payment_data_is_settled(payment_data) + or self._payment_data_is_failed(payment_data) + else self.payment_status_cache_pending_ttl + ) + self.payment_status_cache[checking_id] = { + "payment_data": dict(payment_data), + "expires_at": cached_at + ttl, + } + + def _prune_payment_status_cache(self, keep_ids: set[str] | None = None) -> None: + now = time.time() + for checking_id in list(self.payment_status_cache.keys()): + cached = self.payment_status_cache.get(checking_id) or {} + expires_at = float(cached.get("expires_at", 0.0) or 0.0) + if expires_at <= now or ( + keep_ids is not None and checking_id not in keep_ids + ): + self.payment_status_cache.pop(checking_id, None) + + def _get_cached_payment_data(self, checking_id: str) -> dict[str, Any] | None: + cached = self.payment_status_cache.get(checking_id) + if not cached: + return None + if float(cached.get("expires_at", 0.0) or 0.0) <= time.time(): + self.payment_status_cache.pop(checking_id, None) + return None + payment_data = cached.get("payment_data") + if isinstance(payment_data, dict): + return payment_data + return None + + async def _refresh_recent_incoming_transactions( + self, + *, + now: float | None = None, + from_ts: int | None = None, + cache_ids: set[str] | None = None, + stop_when_found_ids: set[str] | None = None, + unpaid: bool = True, + force: bool = False, + ) -> None: + now = now or time.time() + last_refresh_at = self.last_transactions_refresh_at.get(unpaid, 0.0) + if not force and now - last_refresh_at < self.transactions_refresh_interval: + return + + async with self.transactions_refresh_lock: + now = time.time() + last_refresh_at = self.last_transactions_refresh_at.get(unpaid, 0.0) + if not force and now - last_refresh_at < self.transactions_refresh_interval: + return + + from_ts = from_ts or max(0, int(now - self.transactions_refresh_max_age)) + + logger.debug( + "Refreshing recent NWC incoming transactions cache. " + f"from={from_ts} max_pages={self.transactions_refresh_max_pages}" + ) + + await self._fetch_incoming_transactions( + from_ts=from_ts, + now=now, + cache_ids=cache_ids, + stop_when_found_ids=stop_when_found_ids, + unpaid=unpaid, + ) + self.last_transactions_refresh_at[unpaid] = now async def cleanup(self): self.shutdown = True - try: - self.pending_payments_lookup_task.cancel() - except Exception as e: - logger.warning("Error cancelling pending payments lookup task: " + str(e)) await self.conn.close() async def create_invoice( @@ -146,8 +536,8 @@ class NWCWallet(Wallet): else: desc = memo or "" try: - info = await self.conn.get_info() - if "make_invoice" not in info["supported_methods"]: + await self.conn.get_info() + if not self.conn.supports_method("make_invoice"): return InvoiceResponse( ok=False, error_message="make_invoice is not supported by this NWC service.", @@ -162,18 +552,14 @@ class NWCWallet(Wallet): ) checking_id = str(resp["payment_hash"]) payment_request = resp.get("invoice", None) - # if lookup_invoice is not supported, we can't track the payment - if "lookup_invoice" in info["supported_methods"]: - created_at = int(resp.get("created_at", time.time())) - expires_at = int(resp.get("expires_at", created_at + 3600)) - self.pending_payments.append( - { # Start tracking - "checking_id": checking_id, - "expires_at": expires_at, - "settled": False, - "expired": False, - } - ) + created_at = int(resp.get("created_at", time.time())) + expires_at = int(resp.get("expires_at", created_at + 3600)) + if ( + self.conn.supports_method("lookup_invoice") + or self.conn.supports_method("list_transactions") + or self.conn.supports_notification_type("payment_received") + ): + self._track_pending_invoice(checking_id, created_at, expires_at) return InvoiceResponse( ok=True, checking_id=checking_id, payment_request=payment_request ) @@ -182,8 +568,8 @@ class NWCWallet(Wallet): async def status(self) -> StatusResponse: try: - info = await self.conn.get_info() - if "get_balance" not in info["supported_methods"]: + await self.conn.get_info() + if not self.conn.supports_method("get_balance"): logger.debug("get_balance is not supported by this NWC service.") return StatusResponse(None, 0) resp = await self.conn.call("get_balance", {}) @@ -200,9 +586,9 @@ class NWCWallet(Wallet): payment_hash = invoice_data.payment_hash # pay_invoice doesn't return payment data, so we need # to call lookup_invoice too (if supported) - info = await self.conn.get_info() + await self.conn.get_info() - if "lookup_invoice" not in info["supported_methods"]: + if not self.conn.supports_method("lookup_invoice"): # if not supported, we assume it succeeded return PaymentResponse( ok=True, checking_id=payment_hash, preimage=preimage, fee_msat=0 @@ -239,8 +625,6 @@ class NWCWallet(Wallet): "QUOTA_EXCEEDED", "RESTRICTED", "UNAUTHORIZED", - "INTERNAL", - "OTHER", "PAYMENT_FAILED", ] failed = e.code in failure_codes @@ -254,32 +638,64 @@ class NWCWallet(Wallet): # assume pending return PaymentResponse(error_message=msg) + async def _get_status_via_transactions( + self, checking_id: str, unpaid_filters: list[bool] + ) -> PaymentStatus | None: + keep_ids = self._cache_ids(checking_id) + self._prune_payment_status_cache() + payment_data = self._get_cached_payment_data(checking_id) + if payment_data: + return self._payment_data_to_status(payment_data) + + if self.conn.supports_method("list_transactions"): + invoice_details = self.pending_invoice_details.get(checking_id, {}) + created_at_hint = int( + invoice_details.get( + "created_at", time.time() - self.transactions_refresh_max_age + ) + ) + from_ts = max(0, created_at_hint - 60) + + for unpaid in unpaid_filters: + await self._refresh_recent_incoming_transactions( + from_ts=from_ts, + cache_ids=None, + stop_when_found_ids=keep_ids, + unpaid=unpaid, + ) + payment_data = self._get_cached_payment_data(checking_id) + if payment_data: + return self._payment_data_to_status(payment_data) + + if self.conn.supports_method("lookup_invoice"): + payment_data = await self.conn.call( + "lookup_invoice", {"payment_hash": checking_id} + ) + self._cache_payment_data(checking_id, payment_data) + return self._payment_data_to_status(payment_data) + + return None + async def get_invoice_status(self, checking_id: str) -> PaymentStatus: - return await self.get_payment_status(checking_id) + try: + await self.conn.get_info() + status = await self._get_status_via_transactions(checking_id, [True, False]) + return status or PaymentStatus(None, fee_msat=None, preimage=None) + except NWCError as e: + logger.error("Error getting invoice status: " + str(e)) + failed = e.code == "NOT_FOUND" + return PaymentStatus( + None if not failed else False, fee_msat=None, preimage=None + ) + except Exception as e: + logger.error("Error getting invoice status: " + str(e)) + return PaymentStatus(None, fee_msat=None, preimage=None) async def get_payment_status(self, checking_id: str) -> PaymentStatus: try: - info = await self.conn.get_info() - if "lookup_invoice" in info["supported_methods"]: - payment_data = await self.conn.call( - "lookup_invoice", {"payment_hash": checking_id} - ) - settled = payment_data.get("settled_at", None) and payment_data.get( - "preimage", None - ) - fee_msat = payment_data.get("fees_paid", None) - preimage = payment_data.get("preimage", None) - created_at = int(payment_data.get("created_at", time.time())) - expires_at = int(payment_data.get("expires_at", created_at + 3600)) - expired = expires_at and time.time() > expires_at - if expired and not settled: - return PaymentStatus(False, fee_msat=fee_msat, preimage=preimage) - else: - return PaymentStatus( - True if settled else None, fee_msat=fee_msat, preimage=preimage - ) - else: - return PaymentStatus(None, fee_msat=None, preimage=None) + await self.conn.get_info() + status = await self._get_status_via_transactions(checking_id, [False]) + return status or PaymentStatus(None, fee_msat=None, preimage=None) except NWCError as e: logger.error("Error getting payment status: " + str(e)) failed = e.code == "NOT_FOUND" @@ -293,8 +709,14 @@ class NWCWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: while not self._is_shutting_down(): - value = await self.paid_invoices_queue.get() - yield value + try: + value = await asyncio.wait_for( + self.paid_invoices_queue.get(), + timeout=self.pending_invoices_maintenance_interval, + ) + yield value + except asyncio.TimeoutError: + await self._maintain_pending_invoices() class NWCConnection: @@ -302,7 +724,13 @@ class NWCConnection: A connection to a Nostr Wallet Connect (NWC) service provider. """ - def __init__(self, pubkey, secret, relay): + def __init__( + self, + pubkey, + secret, + relay, + notification_handler: Callable[[dict[str, Any]], Awaitable[None]] | None = None, + ): # Parse pairing url (if invalid an exception is raised) # Extract keys (used to sign nwc events+identify NWC user) @@ -321,7 +749,7 @@ class NWCConnection: self.relay = relay # Create temporary subscriptions, stored until the response is received/expires - self.subscriptions = {} + self.subscriptions: dict[str, dict[str, Any]] = {} # Timeout in seconds after which a subscription is closed # if no response is received self.subscription_timeout = 10 @@ -336,7 +764,15 @@ class NWCConnection: self.shutdown = False # cached info about the service provider - self.info = None + self.info: dict[str, Any] | None = None + self.supported_methods: set[str] = set() + self.notification_types: set[str] = set() + self.supported_encryptions = [NWC_ENCRYPTION_NIP04] + self.selected_encryption = NWC_ENCRYPTION_NIP04 + self.advertises_encryption_tag = False + self.notification_handler = notification_handler + self.notification_subscription_ids: set[str] = set() + self.connection_generation = 0 # This task handles connection and reconnection to the relay self.connection_task = asyncio.create_task(self._connect_to_relay()) @@ -375,6 +811,7 @@ class NWCConnection: return await self._wait_for_connection() # ensure the connection is established tx = json_dumps(data) + logger.debug("Sending raw NWC relay message: " + tx) await self.ws.send(tx) def _get_new_subid(self) -> str: @@ -384,7 +821,7 @@ class NWCConnection: Returns: str: The generated 64 characters long subscription id (eg. lnbits0abc...) """ - subid = "lnbits" + str(self.subscriptions_count) + subid = str(self.subscriptions_count) self.subscriptions_count += 1 max_length = 64 chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" @@ -416,6 +853,7 @@ class NWCConnection: # remove the subscription from the list if sub_to_close: self.subscriptions.pop(sub_to_close["event_id"], None) + self.notification_subscription_ids.discard(sub_id) if not sub_to_close["closed"]: sub_to_close["closed"] = True if send_event: @@ -444,6 +882,7 @@ class NWCConnection: if subscription: if not subscription["closed"]: subscription["closed"] = True + self.notification_subscription_ids.discard(subscription["sub_id"]) if send_event: try: await self._send(["CLOSE", subscription["sub_id"]]) @@ -480,6 +919,8 @@ class NWCConnection: now = time.time() subscriptions_to_close = [] for subscription in self.subscriptions.values(): + if subscription["method"] == "notification_sub": + continue t = now - subscription["timestamp"] if t > self.subscription_timeout: logger.warning( @@ -520,7 +961,9 @@ class NWCConnection: """ sub_id = cast(str, msg[1]) event = cast(dict, msg[2]) - if not verify_event(event): # Ensure the event is valid (do not trust relays) + # Ensure the event is valid and comes from the configured service + # provider (do not trust relays). + if not verify_event(event) or event.get("pubkey") != self.service_pubkey_hex: raise Exception("Invalid event signature") tags = event["tags"] if event["kind"] == 13194: # An info event @@ -539,8 +982,20 @@ class NWCConnection: # methods that is passed to the future content = event["content"] subscription["future"].set_result( - {"supported_methods": content.split(" ")} + self._normalize_info( + { + "supported_methods": content.split(" "), + "notification_types": self._get_tag_values( + tags, "notifications" + ), + "supported_encryptions": self._get_tag_values( + tags, "encryption" + ), + } + ) ) + elif event["kind"] in (23196, 23197): + await self._on_notification_event(event) else: # A response event subscription = None # find the first "e" tag that is handled by @@ -554,10 +1009,17 @@ class NWCConnection: break # if a subscription was found, pass the result to the future if subscription: - content = decrypt_content( - event["content"], self.service_pubkey, self.account_private_key_hex - ) - content = json.loads(content) + try: + content = self._decrypt_event_content(event) + content = json.loads(content) + except Exception as e: + logger.error( + "Failed to decode NWC response event. " + f"kind={event.get('kind')} id={event.get('id')} " + f"tags={event.get('tags', [])} " + f"ciphertext={event.get('content')} error={e}" + ) + raise result_type = content.get("result_type", "") error = content.get("error", None) result = content.get("result", None) @@ -573,6 +1035,30 @@ class NWCConnection: else: subscription["future"].set_result(result) + async def _on_notification_event(self, event: dict[str, Any]): + if event.get("pubkey") != self.service_pubkey_hex: + logger.warning( + "Ignoring NWC notification from unexpected pubkey " + + str(event.get("pubkey")) + ) + return + + if not self.notification_handler: + return + + try: + content = self._decrypt_event_content(event) + notification = json.loads(content) + except Exception as e: + logger.error( + "Failed to decode NWC notification event. " + f"kind={event.get('kind')} id={event.get('id')} " + f"tags={event.get('tags', [])} " + f"ciphertext={event.get('content')} error={e}" + ) + raise + await self.notification_handler(notification) + async def _on_closed_message(self, msg: list[str]): """ Handles CLOSED messages from the relay. @@ -590,6 +1076,7 @@ class NWCConnection: Handle incoming messages from the relay. """ try: + logger.debug("Received raw NWC relay message: " + message) msg = json.loads(message) if msg[0] == "OK": # Event status message await self._on_ok_message(msg) @@ -622,6 +1109,9 @@ class NWCConnection: async with ws_connect(self.relay) as ws: self.ws = ws self.connected = True + self.connection_generation += 1 + self.notification_subscription_ids = set() + await self._subscribe_to_notifications() while ( not self._is_shutting_down() ): # receive messages until the connection is shutting down @@ -648,6 +1138,133 @@ class NWCConnection: logger.debug("Reconnecting to NWC relay in 5 seconds...") await asyncio.sleep(5) + async def _subscribe_to_notifications(self): + for kind in (23197, 23196): + sub_id = self._get_new_subid() + sub_filter = { + "kinds": [kind], + "authors": [self.service_pubkey_hex], + "#p": [self.account_public_key_hex], + "since": int(time.time()), + } + future = asyncio.get_event_loop().create_future() + self.subscriptions[sub_id] = { + "method": "notification_sub", + "future": future, + "sub_id": sub_id, + "event_id": sub_id, + "timestamp": time.time(), + "closed": False, + } + self.notification_subscription_ids.add(sub_id) + await self._send(["REQ", sub_id, sub_filter]) + + def _get_tag_values(self, tags: list[list[str]], tag_name: str) -> list[str]: + for tag in tags: + if tag and tag[0] == tag_name and len(tag) > 1: + return [value for value in tag[1].split(" ") if value] + return [] + + def supports_notification_type(self, notification_type: str) -> bool: + return notification_type in self.notification_types + + def supports_method(self, method: str) -> bool: + return method in self.supported_methods + + def _normalize_info(self, info: dict[str, Any]) -> dict[str, Any]: + methods = info.get("supported_methods", []) or [] + notifications = info.get("notification_types", []) or [] + encryptions = _normalize_supported_encryptions( + info.get("supported_encryptions", []) or [] + ) + normalized = { + "supported_methods": [method for method in methods if method], + "notification_types": [ + notification for notification in notifications if notification + ], + "supported_encryptions": encryptions, + } + return normalized + + def _apply_capabilities(self, info: dict[str, Any]) -> dict[str, Any]: + normalized = self._normalize_info(info) + self.supported_methods = set(normalized["supported_methods"]) + self.notification_types = set(normalized["notification_types"]) + self.supported_encryptions = normalized["supported_encryptions"] + self.advertises_encryption_tag = bool(info.get("supported_encryptions")) + self.selected_encryption = _choose_preferred_encryption( + normalized["supported_encryptions"] + ) + logger.debug( + "Negotiated NWC provider capabilities. " + f"supported_encryptions={self.supported_encryptions} " + f"selected_encryption={self.selected_encryption} " + f"advertises_encryption_tag={self.advertises_encryption_tag} " + f"supported_methods={sorted(self.supported_methods)} " + f"notification_types={sorted(self.notification_types)}" + ) + return normalized + + def _get_event_encryption(self, event: dict[str, Any]) -> str: + encryption_tag = self._get_tag_values(event.get("tags", []), "encryption") + if encryption_tag: + return _choose_preferred_encryption(encryption_tag) + if event.get("kind") == NWC_NOTIFICATION_KIND_NIP44: + return NWC_ENCRYPTION_NIP44_V2 + if event.get("kind") == NWC_NOTIFICATION_KIND_NIP04: + return NWC_ENCRYPTION_NIP04 + return ( + self.selected_encryption + if self.selected_encryption + else NWC_ENCRYPTION_NIP04 + ) + + def _encrypt_payload(self, content: str) -> tuple[str, str]: + encryption = self.selected_encryption or NWC_ENCRYPTION_NIP04 + logger.debug( + "Encrypting NWC payload. " f"encryption={encryption} plaintext={content}" + ) + if encryption == NWC_ENCRYPTION_NIP44_V2: + encrypted = NIP44Encryption.encrypt( + content, self.service_pubkey, self.account_private_key_hex + ) + else: + encrypted = encrypt_content( + content, + self.service_pubkey, + self.account_private_key_hex, + ) + encryption = NWC_ENCRYPTION_NIP04 + logger.debug( + "Encrypted NWC payload. " f"encryption={encryption} ciphertext={encrypted}" + ) + return encrypted, encryption + + def _decrypt_event_content(self, event: dict[str, Any]) -> str: + encryption = self._get_event_encryption(event) + logger.debug( + "Decrypting NWC event. " + f"kind={event.get('kind')} id={event.get('id')} " + f"encryption={encryption} tags={event.get('tags', [])} " + f"ciphertext={event.get('content')}" + ) + if encryption == NWC_ENCRYPTION_NIP44_V2: + plaintext = NIP44Encryption.decrypt( + event["content"], self.service_pubkey, self.account_private_key_hex + ) + else: + plaintext = decrypt_content( + event["content"], + self.service_pubkey, + self.account_private_key_hex, + ) + logger.debug( + "Decrypted NWC event. " + f"kind={event.get('kind')} id={event.get('id')} " + f"encryption={encryption} plaintext={plaintext}" + ) + return plaintext + async def call(self, method: str, params: dict) -> dict: """ Call a NWC method. @@ -668,22 +1285,27 @@ class NWCConnection: "params": params, } ) - # Encrypt - content = encrypt_content( - content, self.service_pubkey, self.account_private_key_hex - ) + content, encryption = self._encrypt_payload(content) # Prepare the NWC event + tags = [["p", self.service_pubkey_hex]] + if encryption != NWC_ENCRYPTION_NIP04 or self.advertises_encryption_tag: + tags.append(["encryption", encryption]) + logger.debug( + "Using NWC provider encryption for request. " + f"method={method} encryption={encryption} tags={tags}" + ) event = { "kind": 23194, "content": content, "created_at": int(time.time()), - "tags": [["p", self.service_pubkey_hex]], + "tags": tags, } # Sign sign_event(event, self.account_public_key_hex, self.account_private_key) # Subscribe for a response to this event sub_filter = { "kinds": [23195], + "authors": [self.service_pubkey_hex], "#p": [self.account_public_key_hex], "#e": [event["id"]], "since": event["created_at"], @@ -691,16 +1313,17 @@ class NWCConnection: sub_id = self._get_new_subid() # register a future to receive the response asynchronously future = asyncio.get_event_loop().create_future() + event_id = cast(str, event["id"]) # Check if the subscription already exists # (this means there is a bug somewhere, should not happen) - if event["id"] in self.subscriptions: + if event_id in self.subscriptions: raise Exception("Subscription for this event id already exists?") # Store the subscription in the list - self.subscriptions[event["id"]] = { + self.subscriptions[event_id] = { "method": method, "future": future, "sub_id": sub_id, - "event_id": event["id"], + "event_id": event_id, "timestamp": time.time(), "closed": False, } @@ -737,22 +1360,32 @@ class NWCConnection: await self._send(["REQ", sub_id, sub_filter]) # Wait for the response service_info = await future + service_info = self._apply_capabilities(service_info) # Get account info when possible - if "get_info" in service_info["supported_methods"]: + if self.supports_method("get_info"): try: account_info = await self.call("get_info", {}) # cache - self.info = service_info - self.info["alias"] = account_info.get("alias", "") - self.info["color"] = account_info.get("color", "") - self.info["pubkey"] = account_info.get("pubkey", "") - self.info["network"] = account_info.get("network", "") - self.info["block_height"] = account_info.get("block_height", 0) - self.info["block_hash"] = account_info.get("block_hash", "") - self.info["supported_methods"] = account_info.get( + info: dict[str, Any] = dict(service_info) + info["alias"] = account_info.get("alias", "") + info["color"] = account_info.get("color", "") + info["pubkey"] = account_info.get("pubkey", "") + info["network"] = account_info.get("network", "") + info["block_height"] = account_info.get("block_height", 0) + info["block_hash"] = account_info.get("block_hash", "") + info["supported_methods"] = account_info.get( "methods", service_info.get("supported_methods", ["pay_invoice"]), ) + info["notification_types"] = account_info.get( + "notifications", + service_info.get("notification_types", []), + ) + info["supported_encryptions"] = service_info.get( + "supported_encryptions", + [NWC_ENCRYPTION_NIP04], + ) + self.info = self._apply_capabilities(info) except Exception as e: # If there is an error, fallback to using service info logger.error( @@ -770,10 +1403,14 @@ class NWCConnection: # The error could mean that the service provider does # not provide an info note # So we just assume it supports the bare minimum to be Nip47 compliant - self.info = { - "supported_methods": ["pay_invoice"], - } - return self.info + self.info = self._apply_capabilities( + { + "supported_methods": ["pay_invoice"], + "notification_types": [], + "supported_encryptions": [NWC_ENCRYPTION_NIP04], + } + ) + return self.info or {} async def close(self): logger.debug("Closing NWCConnection") @@ -787,6 +1424,11 @@ class NWCConnection: self.connection_task.cancel() except Exception as e: logger.warning("Error cancelling connection task: " + str(e)) + for sub_id in list(self.notification_subscription_ids): + try: + await self._send(["CLOSE", sub_id]) + except Exception as e: + logger.warning("Error closing notification subscription: " + str(e)) # close the websocket try: if self.ws: @@ -825,3 +1467,148 @@ def parse_nwc(nwc) -> dict: else: raise ValueError("Invalid NWC pairing url") return data + + +class NIP44Encryption: + @staticmethod + def encrypt( + content: str, + service_pubkey: PublicKey, + account_private_key_hex: str, + ) -> str: + conversation_key = NIP44Encryption._get_conversation_key( + service_pubkey, + account_private_key_hex, + ) + nonce = secrets.token_bytes(32) + chacha_key, chacha_nonce, hmac_key = NIP44Encryption._get_message_keys( + conversation_key, + nonce, + ) + padded = NIP44Encryption._pad(content) + ciphertext = ChaCha20.new(key=chacha_key, nonce=chacha_nonce).encrypt(padded) + mac = HMAC.new(hmac_key, digestmod=SHA256) + mac.update(nonce + ciphertext) + payload = bytes([2]) + nonce + ciphertext + mac.digest() + return base64.b64encode(payload).decode("ascii") + + @staticmethod + def decrypt( + content: str, + service_pubkey: PublicKey, + account_private_key_hex: str, + ) -> str: + if not content or content[0] == "#": + raise ValueError("unknown encryption version") + raw = base64.b64decode(content.encode("ascii")) + if len(raw) < 99 or len(raw) > 65603: + raise ValueError("invalid data size") + version = raw[0] + if version != 2: + raise ValueError(f"unknown version {version}") + nonce = raw[1:33] + ciphertext = raw[33:-32] + mac = raw[-32:] + conversation_key = NIP44Encryption._get_conversation_key( + service_pubkey, + account_private_key_hex, + ) + chacha_key, chacha_nonce, hmac_key = NIP44Encryption._get_message_keys( + conversation_key, + nonce, + ) + expected_mac = HMAC.new(hmac_key, digestmod=SHA256) + expected_mac.update(nonce + ciphertext) + if not hmac.compare_digest(expected_mac.digest(), mac): + raise ValueError("invalid MAC") + padded = ChaCha20.new(key=chacha_key, nonce=chacha_nonce).decrypt(ciphertext) + return NIP44Encryption._unpad(padded) + + @staticmethod + def _get_shared_x( + service_pubkey: PublicKey, + account_private_key_hex: str, + ) -> bytes: + return service_pubkey.multiply(bytes.fromhex(account_private_key_hex)).format()[ + 1: + ] + + @staticmethod + def _hkdf_extract(*, ikm: bytes, salt: bytes) -> bytes: + return hmac.new(salt, ikm, hashlib.sha256).digest() + + @staticmethod + def _hkdf_expand(*, prk: bytes, info: bytes, length: int) -> bytes: + output = bytearray() + previous = b"" + counter = 1 + while len(output) < length: + previous = hmac.new( + prk, + previous + info + bytes([counter]), + hashlib.sha256, + ).digest() + output.extend(previous) + counter += 1 + return bytes(output[:length]) + + @staticmethod + def _get_conversation_key( + service_pubkey: PublicKey, + account_private_key_hex: str, + ) -> bytes: + return NIP44Encryption._hkdf_extract( + ikm=NIP44Encryption._get_shared_x(service_pubkey, account_private_key_hex), + salt=b"nip44-v2", + ) + + @staticmethod + def _calc_padded_len(unpadded_len: int) -> int: + if unpadded_len <= 32: + return 32 + next_power = 1 << ((unpadded_len - 1).bit_length()) + chunk = 32 if next_power <= 256 else next_power // 8 + return chunk * (((unpadded_len - 1) // chunk) + 1) + + @staticmethod + def _pad(content: str) -> bytes: + plaintext = content.encode("utf-8") + plaintext_len = len(plaintext) + if plaintext_len < 1 or plaintext_len > 65535: + raise ValueError("invalid plaintext length") + padded_len = NIP44Encryption._calc_padded_len(plaintext_len) + return ( + plaintext_len.to_bytes(2, "big") + + plaintext + + bytes(padded_len - plaintext_len) + ) + + @staticmethod + def _unpad(padded: bytes) -> str: + if len(padded) < 34: + raise ValueError("invalid padded payload size") + plaintext_len = int.from_bytes(padded[:2], "big") + plaintext = padded[2 : 2 + plaintext_len] + expected_len = 2 + NIP44Encryption._calc_padded_len(plaintext_len) + if ( + plaintext_len < 1 + or len(plaintext) != plaintext_len + or len(padded) != expected_len + ): + raise ValueError("invalid padding") + return plaintext.decode("utf-8") + + @staticmethod + def _get_message_keys( + conversation_key: bytes, nonce: bytes + ) -> tuple[bytes, bytes, bytes]: + if len(conversation_key) != 32: + raise ValueError("invalid conversation_key length") + if len(nonce) != 32: + raise ValueError("invalid nonce length") + keys = NIP44Encryption._hkdf_expand( + prk=conversation_key, + info=nonce, + length=76, + ) + return keys[:32], keys[32:44], keys[44:76] diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index f05349746..95506c3c6 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -15,6 +15,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -100,24 +101,38 @@ class OpenNodeWallet(Wallet): ) async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: - r = await self.client.post( - "/v2/withdrawals", - json={"type": "ln", "address": bolt11}, - timeout=None, - ) + try: + r = await self.client.post( + "/v2/withdrawals", + json={"type": "ln", "address": bolt11}, + timeout=None, + ) - if r.is_error: - error_message = r.json()["message"] - logger.warning(error_message) - return PaymentResponse(ok=None, error_message=error_message) + if r.is_error: + error_message = r.json().get("message", r.text) + logger.warning(error_message) + return PaymentResponse( + ok=(False if payment_request_was_rejected(r.status_code) else None), + error_message=error_message, + ) - data = r.json()["data"] - checking_id = data["id"] - fee_msat = -data["fee"] * 1000 - # pending - if data["status"] != "paid": + data = r.json()["data"] + checking_id = data.get("id") + fee = data.get("fee") + fee_msat = -fee * 1000 if fee is not None else None + status = str(data.get("status", "")).lower() + if status in {"paid", "confirmed"}: + return PaymentResponse( + ok=True, checking_id=checking_id, fee_msat=fee_msat + ) + if status in {"error", "failed"}: + return PaymentResponse( + ok=False, checking_id=checking_id, fee_msat=fee_msat + ) return PaymentResponse(ok=None, checking_id=checking_id, fee_msat=fee_msat) - return PaymentResponse(ok=True, checking_id=checking_id, fee_msat=fee_msat) + except Exception as exc: + logger.warning(exc) + return PaymentResponse(error_message="Invalid OpenNode payment response.") async def get_invoice_status(self, checking_id: str) -> PaymentStatus: r = await self.client.get(f"/v1/charge/{checking_id}") @@ -128,22 +143,26 @@ class OpenNodeWallet(Wallet): return PaymentStatus(statuses[data.get("status")]) async def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = await self.client.get(f"/v1/withdrawal/{checking_id}") + try: + r = await self.client.get(f"/v1/withdrawal/{checking_id}") + if r.is_error: + return PaymentPendingStatus() - if r.is_error: + data = r.json()["data"] + statuses = { + "initial": None, + "pending": None, + "confirmed": True, + "error": False, + "failed": False, + } + fee = data.get("fee") + fee_msat = -fee * 1000 if fee is not None else None + return PaymentStatus(statuses.get(data.get("status")), fee_msat) + except Exception as exc: + logger.warning(exc) return PaymentPendingStatus() - data = r.json()["data"] - statuses = { - "initial": None, - "pending": None, - "confirmed": True, - "error": None, - "failed": False, - } - fee_msat = -data.get("fee") * 1000 - return PaymentStatus(statuses[data.get("status")], fee_msat) - async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) while settings.lnbits_running: diff --git a/lnbits/wallets/phoenixd.py b/lnbits/wallets/phoenixd.py index 8de95e277..e386855a0 100644 --- a/lnbits/wallets/phoenixd.py +++ b/lnbits/wallets/phoenixd.py @@ -4,9 +4,11 @@ import hashlib import json import urllib.parse from collections.abc import AsyncGenerator +from pathlib import Path from typing import Any import httpx +from embit.bip39 import mnemonic_is_valid from httpx import RequestError, TimeoutException from loguru import logger from websockets import connect @@ -61,6 +63,8 @@ class PhoenixdWallet(Wallet): } self.client = httpx.AsyncClient(base_url=self.endpoint, headers=self.headers) + self._seed_mnemonic_to_persist: str | None = None + self._load_mnemonic_from_seed_file() async def cleanup(self): try: @@ -69,6 +73,7 @@ class PhoenixdWallet(Wallet): logger.warning(f"Error closing wallet connection: {e}") async def status(self) -> StatusResponse: + await self._persist_loaded_mnemonic() try: r = await self.client.get("/getinfo", timeout=10) r.raise_for_status() @@ -93,6 +98,24 @@ class PhoenixdWallet(Wallet): logger.warning(exc) return StatusResponse(f"Unable to connect to {self.endpoint}.", 0) + async def _incoming_preimage(self, payment_hash: str) -> str | None: + """Fetch preimage from Phoenixd incoming payment (createinvoice omits it).""" + try: + r = await self.client.get( + f"/payments/incoming/{payment_hash}", + timeout=40, + ) + if r.is_error: + return None + return r.json().get("preimage") or None + except Exception as exc: + logger.warning( + "Phoenixd: could not fetch preimage for %s: %s", + payment_hash, + exc, + ) + return None + async def create_invoice( self, amount: int, @@ -101,7 +124,6 @@ class PhoenixdWallet(Wallet): unhashed_description: bytes | None = None, **kwargs, ) -> InvoiceResponse: - try: msats_amount = amount data: dict[str, Any] = { @@ -113,11 +135,12 @@ class PhoenixdWallet(Wallet): # PhoenixD description limited to 128 characters if description_hash: data["descriptionHash"] = description_hash.hex() + elif unhashed_description: + data["descriptionHash"] = hashlib.sha256( + unhashed_description + ).hexdigest() else: - desc = memo - if desc is None and unhashed_description: - desc = unhashed_description.decode() - desc = desc or "" + desc = memo or "" if len(desc) > 128: data["descriptionHash"] = hashlib.sha256(desc.encode()).hexdigest() else: @@ -142,7 +165,10 @@ class PhoenixdWallet(Wallet): checking_id = data["paymentHash"] payment_request = data["serialized"] - preimage = data.get("paymentPreimage", None) # if available + # Phoenixd createinvoice often omits paymentPreimage. + preimage = data.get("paymentPreimage") or await self._incoming_preimage( + checking_id + ) return InvoiceResponse( ok=True, checking_id=checking_id, @@ -182,11 +208,11 @@ class PhoenixdWallet(Wallet): logger.warning(msg) return PaymentResponse(ok=None, error_message=msg) except RequestError as exc: - # RequestError is raised when the request never hit the destination server + # RequestError can also be raised after the server received the request. msg = f"Unable to connect to {self.endpoint}." logger.warning(msg) logger.warning(exc) - return PaymentResponse(ok=False, error_message=msg) + return PaymentResponse(ok=None, error_message=msg) except Exception as exc: logger.warning(exc) return PaymentResponse( @@ -309,7 +335,7 @@ class PhoenixdWallet(Wallet): and message_json.get("type") == "payment_received" ): logger.info( - f'payment-received: {message_json["paymentHash"]}' + f"payment-received: {message_json['paymentHash']}" ) yield message_json["paymentHash"] @@ -319,3 +345,49 @@ class PhoenixdWallet(Wallet): "retrying in 5 seconds" ) await asyncio.sleep(5) + + def _load_mnemonic_from_seed_file(self): + data_dir = settings.phoenixd_data_dir + if not data_dir: + return + + seed_path = Path(data_dir).expanduser() / "seed.dat" + if not seed_path.is_file(): + return + + try: + mnemonic = seed_path.read_text(encoding="utf-8").strip() + if mnemonic == settings.phoenixd_mnemonic: + return + except OSError as exc: + logger.warning(f"Failed to read Phoenixd seed file '{seed_path}': {exc}") + return + + if not mnemonic: + logger.warning(f"Phoenixd seed file '{seed_path}' is empty.") + return + + if not mnemonic_is_valid(mnemonic): + logger.warning( + f"Phoenixd seed file '{seed_path}' does not contain a valid " + "BIP39 mnemonic." + ) + return + + settings.phoenixd_mnemonic = mnemonic + self._seed_mnemonic_to_persist = mnemonic + + async def _persist_loaded_mnemonic(self): + if not self._seed_mnemonic_to_persist: + return + + logger.info("Updating 'PHOENIXD_MNEMONIC' mnemonic settings.") + try: + from lnbits.core.crud.settings import set_settings_field + + await set_settings_field( + "phoenixd_mnemonic", self._seed_mnemonic_to_persist + ) + self._seed_mnemonic_to_persist = None + except Exception as exc: + logger.warning(f"Failed to persist Phoenixd mnemonic: {exc}") diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index 90dcc05e0..34b68b077 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -162,11 +162,16 @@ class SparkWallet(Wallet): ) except (SparkError, UnknownError) as exc: - listpays = await self.listpays(bolt11) + try: + listpays = await self.listpays(bolt11) + except (SparkError, UnknownError): + return PaymentResponse(error_message=str(exc)) if not listpays: - return PaymentResponse(ok=False, error_message=str(exc)) + return PaymentResponse(error_message=str(exc)) - pays = listpays["pays"] + pays = listpays.get("pays") + if not isinstance(pays, list): + return PaymentResponse(error_message=str(exc)) if len(pays) == 0: return PaymentResponse(ok=False, error_message=str(exc)) @@ -175,10 +180,12 @@ class SparkWallet(Wallet): payment_hash = pay["payment_hash"] if len(pays) > 1: - raise SparkError( - f"listpays({payment_hash}) returned an unexpected response:" - f" {listpays}" - ) from exc + return PaymentResponse( + error_message=( + f"listpays({payment_hash}) returned an unexpected response:" + f" {listpays}" + ) + ) if pay["status"] == "failed": return PaymentResponse(ok=False, error_message=str(exc)) @@ -203,7 +210,7 @@ class SparkWallet(Wallet): preimage=preimage, ) else: - return PaymentResponse(ok=False, error_message=str(exc)) + return PaymentResponse(error_message=str(exc)) async def get_invoice_status(self, checking_id: str) -> PaymentStatus: try: @@ -214,10 +221,12 @@ class SparkWallet(Wallet): if not r or not r.get("invoices"): return PaymentPendingStatus() - if r["invoices"][0]["status"] == "paid": + status = r["invoices"][0]["status"] + if status == "paid": return PaymentSuccessStatus() - else: + if status == "expired": return PaymentFailedStatus() + return PaymentPendingStatus() async def get_payment_status(self, checking_id: str) -> PaymentStatus: # check if it's 32 bytes hex @@ -249,7 +258,8 @@ class SparkWallet(Wallet): if status == "failed": return PaymentFailedStatus() return PaymentPendingStatus() - raise KeyError("supplied an invalid checking_id") + logger.warning(f"supplied an invalid checking_id: {checking_id}") + return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: url = f"/stream?access-key={self.token}" diff --git a/lnbits/wallets/sparkl2.py b/lnbits/wallets/sparkl2.py index e565fa884..ea1370beb 100644 --- a/lnbits/wallets/sparkl2.py +++ b/lnbits/wallets/sparkl2.py @@ -1,6 +1,7 @@ import asyncio import hashlib import json +import secrets import uuid from collections.abc import AsyncGenerator from pathlib import Path @@ -8,7 +9,6 @@ from typing import Any, cast import httpx from bolt11 import decode as bolt11_decode -from coincurve.keys import PrivateKey from embit.bip39 import mnemonic_from_bytes, mnemonic_is_valid from loguru import logger @@ -159,10 +159,9 @@ class SparkL2Wallet(Wallet): "payment_hash": payment_hash, } res = await self._request("POST", "/v1/payments", payload) - checking_id = payment_hash or res.get("checking_id") + checking_id = res.get("checking_id") if not checking_id: return PaymentResponse( - ok=False, error_message="Spark sidecar payment response missing checking_id.", ) status = res.get("status") @@ -178,7 +177,7 @@ class SparkL2Wallet(Wallet): ) except Exception as e: - return PaymentResponse(ok=False, error_message=str(e)) + return PaymentResponse(error_message=str(e)) async def get_invoice_status(self, checking_id: str) -> PaymentStatus: try: @@ -340,7 +339,7 @@ class SparkL2Wallet(Wallet): return logger.info("SPARK_L2_MNEMONIC is not set, one will be generated for you.") - mnemonic = mnemonic_from_bytes(PrivateKey().secret) + mnemonic = mnemonic_from_bytes(secrets.token_bytes(16)) await self._set_sidecar_mnemonic(mnemonic) async def _set_sidecar_mnemonic(self, mnemonic: str): diff --git a/lnbits/wallets/strike.py b/lnbits/wallets/strike.py index 8fbbb7e1c..aa2b0170d 100644 --- a/lnbits/wallets/strike.py +++ b/lnbits/wallets/strike.py @@ -237,50 +237,59 @@ class StrikeWallet(Wallet): ok=False, error_message=f"Invalid invoice: {decode_exc!s}" ) + # Creating a quote cannot make the payment. Any failure before the execute + # request is therefore a definite failure of this payment attempt. try: - # 1) Create a payment quote quote_id, error = await self._create_payment_quote(bolt11) if error or not quote_id: return PaymentResponse(ok=False, error_message=error or "Unknown error") + except Exception as exc: + logger.warning(f"Strike quote creation exception: {exc}", exc_info=True) + return PaymentResponse( + ok=False, + error_message=f"Failed to create payment quote: {exc!s}", + ) + + try: + # Keep the quote id while this process is running. Strike only documents + # payment status lookup by payment id, which an ambiguous execute request + # may not return. + self.pending_payments[payment_hash] = quote_id - # 2) Execute the payment quote data, error = await self._execute_payment_quote(quote_id) if error or not data: - return PaymentResponse(ok=False, error_message=error or "Unknown error") + return PaymentResponse(error_message=error or "Unknown error") state = data.get("state", "").upper() payment_id = data.get("paymentId") + checking_id = payment_id or payment_hash # Parse fee - fee_msat = self._parse_payment_fee(data, payment_id or "") + fee_msat = self._parse_payment_fee(data, checking_id) # Handle successful payment if state in {"SUCCEEDED", "COMPLETED"}: preimage = self._extract_preimage(data) return PaymentResponse( ok=True, - checking_id=payment_hash, + checking_id=checking_id, fee_msat=fee_msat, preimage=preimage, ) # Handle failed payment - failed_states = {"CANCELED", "FAILED", "TIMED_OUT"} - if state in failed_states: + if state == "FAILED": logger.warning( f"Strike payment {payment_id} failed with state: {state}" ) return PaymentResponse( ok=False, - checking_id=payment_hash, + checking_id=checking_id, error_message=f"Payment {state.lower()}", ) - # Store mapping for later polling - self.pending_payments[payment_hash] = quote_id - # Treat all other states as pending - return PaymentResponse(ok=None, checking_id=payment_hash) + return PaymentResponse(ok=None, checking_id=payment_id) except httpx.HTTPStatusError as http_exc: logger.warning(f"Strike HTTP error during payment: {http_exc}") @@ -289,7 +298,6 @@ class StrikeWallet(Wallet): f"body: {http_exc.response.text}" ) return PaymentResponse( - ok=False, error_message=f"Strike API error: {http_exc.response.status_code}", ) except Exception as e: @@ -343,7 +351,8 @@ class StrikeWallet(Wallet): quote_id = self.pending_payments.get(checking_id) try: - # Attempt 1: Use quote_id if available (from in-memory store) + # A quote id can only be associated with an invoice hash while this + # process is running. Persisted payment ids are checked below. if quote_id: status = await self._get_payment_status_by_quote_id( checking_id, quote_id @@ -527,10 +536,8 @@ class StrikeWallet(Wallet): return None, error_msg data = e.json() if e.content else {} - payment_id = data.get("paymentId") - if not payment_id: + if not data.get("paymentId"): logger.warning(f"Strike: missing paymentId in response: {data}") - return None, "Strike: missing paymentId in response" return data, None @@ -629,7 +636,7 @@ class StrikeWallet(Wallet): self.pending_payments.pop(checking_id, None) return PaymentFailedStatus() - return None + return PaymentPendingStatus() async def _get_payment_status_by_checking_id( # noqa: C901 self, checking_id: str @@ -693,16 +700,28 @@ class StrikeWallet(Wallet): continue logger.warning( f"Payment '{checking_id}' not a valid Strike payment. " - f"Marked as failed. Response: {r_payment.text}" + "Keeping pending because it may be the invoice payment " + f"hash fallback. Response: {r_payment.text}" ) - self.pending_payments.pop(checking_id, None) - return PaymentFailedStatus() + return PaymentPendingStatus() except Exception as e: logger.warning(e) return PaymentPendingStatus() if r_payment.status_code == 404: + if len(checking_id) == 64: + try: + bytes.fromhex(checking_id) + logger.warning( + f"Payment '{checking_id}' not found, but the identifier may " + "be a legacy invoice payment hash. Keeping pending." + ) + return PaymentPendingStatus() + except ValueError as exc: + logger.warning( + f"Payment identifier '{checking_id}' is not valid hex: {exc}" + ) logger.warning(f"Payment {checking_id} not found. Marking as failed.") self.pending_payments.pop(checking_id, None) return PaymentFailedStatus() diff --git a/lnbits/wallets/void.py b/lnbits/wallets/void.py index 6d2ac9f4e..ca38dc215 100644 --- a/lnbits/wallets/void.py +++ b/lnbits/wallets/void.py @@ -1,5 +1,3 @@ -from collections.abc import AsyncGenerator - from loguru import logger from .base import ( @@ -40,6 +38,3 @@ class VoidWallet(Wallet): async def get_payment_status(self, *_, **__) -> PaymentStatus: return PaymentPendingStatus() - - async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - yield "" diff --git a/lnbits/wallets/zbd.py b/lnbits/wallets/zbd.py index 1377e0db8..f6747abb3 100644 --- a/lnbits/wallets/zbd.py +++ b/lnbits/wallets/zbd.py @@ -3,7 +3,6 @@ import hashlib from collections.abc import AsyncGenerator import httpx -from bolt11 import decode as bolt11_decode from loguru import logger from lnbits.helpers import normalize_endpoint @@ -16,6 +15,7 @@ from .base import ( PaymentStatus, StatusResponse, Wallet, + payment_request_was_rejected, ) @@ -105,30 +105,62 @@ class ZBDWallet(Wallet): async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: # https://api.zebedee.io/v0/payments - r = await self.client.post( - "payments", - json={ - "invoice": bolt11, - "description": "", - "amount": "", - "internalId": "", - "callbackUrl": "", - }, - timeout=40, - ) + try: + r = await self.client.post( + "payments", + json={ + "invoice": bolt11, + "description": "", + "amount": "", + "internalId": "", + "callbackUrl": "", + }, + timeout=40, + ) + except Exception as exc: + logger.warning(exc) + return PaymentResponse(error_message="Unable to query ZBD.") if r.is_error: - error_message = r.json()["message"] - return PaymentResponse(ok=False, error_message=error_message) + try: + error_message = r.json().get("message", r.text) + except Exception: + error_message = r.text + return PaymentResponse( + ok=False if payment_request_was_rejected(r.status_code) else None, + error_message=error_message, + ) - data = r.json() - - checking_id = bolt11_decode(bolt11).payment_hash - fee_msat = -int(data["data"]["fee"]) - preimage = data["data"]["preimage"] + try: + data = r.json()["data"] + checking_id = data.get("id") + fee = data.get("fee") + fee_msat = -int(fee) if fee is not None else None + preimage = data.get("preimage") + status = str(data.get("status", "")).lower() + except Exception as exc: + logger.warning(exc) + return PaymentResponse(error_message="Invalid ZBD payment response.") + if status == "completed": + return PaymentResponse( + ok=True, + checking_id=checking_id, + fee_msat=fee_msat, + preimage=preimage, + ) + if status in {"failed", "expired"}: + return PaymentResponse( + ok=False, + checking_id=checking_id, + fee_msat=fee_msat, + error_message=data.get("errorMessage"), + ) return PaymentResponse( - ok=True, checking_id=checking_id, fee_msat=fee_msat, preimage=preimage + ok=None, + checking_id=checking_id, + fee_msat=fee_msat, + error_message=data.get("errorMessage"), ) async def get_invoice_status(self, checking_id: str) -> PaymentStatus: @@ -147,11 +179,20 @@ class ZBDWallet(Wallet): return PaymentStatus(paid=statuses[data.get("status")]) async def get_payment_status(self, checking_id: str) -> PaymentStatus: - r = await self.client.get(f"payments/{checking_id}") + try: + r = await self.client.get(f"payments/{checking_id}") + except Exception as exc: + logger.warning(exc) + return PaymentPendingStatus() + if r.is_error: return PaymentPendingStatus() - data = r.json()["data"] + try: + data = r.json()["data"] + except Exception as exc: + logger.warning(exc) + return PaymentPendingStatus() statuses = { "initial": None, @@ -161,8 +202,7 @@ class ZBDWallet(Wallet): "expired": False, "failed": False, } - - return PaymentStatus(paid=statuses[data.get("status")]) + return PaymentStatus(paid=statuses.get(data.get("status"))) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) diff --git a/package-lock.json b/package-lock.json index 2b3aeb959..c7b03269c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,27 +6,44 @@ "": { "name": "lnbits", "dependencies": { - "axios": "^1.13.5", + "axios": "^1.18.0", "chart.js": "^4.5.1", "moment": "^2.30.1", - "nostr-tools": "^2.18.2", - "qrcode.vue": "^3.6.0", - "quasar": "2.18.6", + "nostr-tools": "^2.23.3", + "qrcode.vue": "^3.9.0", + "quasar": "2.22.0", "showdown": "^2.1.0", "underscore": "^1.13.8", - "vue": "3.5.25", - "vue-i18n": "^11.2.2", + "vue": "3.5.34", + "vue-i18n": "^11.4.2", "vue-qrcode-reader": "^5.7.3", - "vue-router": "4.6.3", + "vue-router": "5.0.6", "vuex": "4.1.0" }, "devDependencies": { + "@playwright/test": "^1.61.0", "clean-css-cli": "^5.6.3", "concat": "^1.0.3", - "prettier": "^3.7.4", - "pyright": "1.1.289", - "sass": "^1.94.2", - "terser": "^5.44.1" + "prettier": "^3.8.3", + "pyright": "1.1.409", + "sass": "^1.99.0", + "terser": "^5.47.1" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { @@ -48,12 +65,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -63,9 +80,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -76,13 +93,30 @@ } }, "node_modules/@intlify/core-base": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.2.2.tgz", - "integrity": "sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==", + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.2.tgz", + "integrity": "sha512-7fpuCcVmeLv2T9qHsARqGvh8xt+sV2fH+Q+gMHFwB/rPXzo85DpbJFKn7dBH1L5p0c2cSh2DW+2h/64EKrISmA==", "license": "MIT", "dependencies": { - "@intlify/message-compiler": "11.2.2", - "@intlify/shared": "11.2.2" + "@intlify/devtools-types": "11.4.2", + "@intlify/message-compiler": "11.4.2", + "@intlify/shared": "11.4.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/kazupon" + } + }, + "node_modules/@intlify/devtools-types": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.2.tgz", + "integrity": "sha512-3u8EN1kB6EMSi96KXs5k7a8y2X2g4+h3X6iwVZU47cP4n+mTuq//WMjG588BzSp/2XQ/dTXo2BLUXX+XS+PNfA==", + "license": "MIT", + "dependencies": { + "@intlify/core-base": "11.4.2", + "@intlify/shared": "11.4.2" }, "engines": { "node": ">= 16" @@ -92,12 +126,12 @@ } }, "node_modules/@intlify/message-compiler": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.2.2.tgz", - "integrity": "sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==", + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.2.tgz", + "integrity": "sha512-a6CDSGSMTGrg0BjD97x8TBYPf7qQMDlZipJ6UDfv/pd4OIym8TMlHu3MsH0bTNnRdAG2D6EFEykIgiQPqvtTkA==", "license": "MIT", "dependencies": { - "@intlify/shared": "11.2.2", + "@intlify/shared": "11.4.2", "source-map-js": "^1.0.2" }, "engines": { @@ -108,9 +142,9 @@ } }, "node_modules/@intlify/shared": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.2.2.tgz", - "integrity": "sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==", + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.2.tgz", + "integrity": "sha512-NzpHbguRCsOHDwxmlBa9qu/imc+/QWgsYUaK6FZeNC0wK8QfAbhqrktEp/haVzxU1aikH8IX4ytD+mfFEMi/9A==", "license": "MIT", "engines": { "node": ">= 16" @@ -123,18 +157,26 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -161,7 +203,6 @@ "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -174,41 +215,39 @@ "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" }, "node_modules/@noble/ciphers": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.5.3.tgz", - "integrity": "sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dependencies": { - "@noble/hashes": "1.3.2" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.1.1.tgz", + "integrity": "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, - "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "node_modules/@noble/curves": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.0.1.tgz", + "integrity": "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.0.1" + }, "engines": { - "node": ">= 16" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz", + "integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==", + "license": "MIT", "engines": { - "node": ">= 16" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -538,48 +577,53 @@ "node": ">=0.10" } }, - "node_modules/@scure/base": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", - "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@scure/bip32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", - "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "node_modules/@playwright/test": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz", + "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" + "playwright": "1.61.1" }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@scure/base": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.0.0.tgz", + "integrity": "sha512-3E1kpuZginKkek01ovG8krQ0Z44E3DHPjc5S2rjJw9lZn3KSQOs8S7wqikF/AH7iRanHypj85uGyxk0XAyC37w==", + "license": "MIT", "funding": { "url": "https://paulmillr.com/funding/" } }, - "node_modules/@scure/bip32/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "node_modules/@scure/bip32": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.0.1.tgz", + "integrity": "sha512-4Md1NI5BzoVP+bhyJaY3K6yMesEFzNS1sE/cP+9nuvE7p/b0kx9XbpDHHFl8dHtufcbdHRUUQdRqLIPHN/s7yA==", + "license": "MIT", "dependencies": { - "@noble/hashes": "1.3.1" + "@noble/curves": "2.0.1", + "@noble/hashes": "2.0.1", + "@scure/base": "2.0.0" }, "funding": { "url": "https://paulmillr.com/funding/" } }, "node_modules/@scure/bip39": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.0.1.tgz", + "integrity": "sha512-PsxdFj/d2AcJcZDX1FXN3dDgitDDTmwf78rKZq1a6c1P1Nan1X/Sxc7667zU3U+AN60g7SxxP0YCVw2H/hBycg==", + "license": "MIT", "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" + "@noble/hashes": "2.0.1", + "@scure/base": "2.0.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -595,54 +639,81 @@ "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.13.tgz", "integrity": "sha512-cFq+fO/isvhvmuP/+Sl4K4jtU6E23DoivtbO4r50e3odaxAiVdbfSYRDdJ4gCdxx+3aRjhphS5ZMwIH4hFy/Cw==" }, - "node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", + "node_modules/@vue-macros/common": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", + "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", + "@vue/compiler-sfc": "^3.5.22", + "ast-kit": "^2.1.2", + "local-pkg": "^1.1.2", + "magic-string-ast": "^1.0.2", + "unplugin-utils": "^0.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.34.tgz", + "integrity": "sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.34", + "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", - "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.34.tgz", + "integrity": "sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.25", - "@vue/shared": "3.5.25" + "@vue/compiler-core": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", - "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.34.tgz", + "integrity": "sha512-D/ihr6uZeIt6r+pVZf46RWT1fAsLFMbUP7k8G1VkiiWexriED9GrX3echHd4Abbt17zjlfiFJ8z7a3BxZOPNjg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.25", - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25", + "@babel/parser": "^7.29.3", + "@vue/compiler-core": "3.5.34", + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.6", + "postcss": "^8.5.14", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.34.tgz", + "integrity": "sha512-cDtTHKibkThKGHH1SP+WdccquNRYQDFH6rRjQCqT9G2ltFAfoR5pUftpab/z+aM5mW9HLLVQW7hfKKQe/1GBeQ==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" + "@vue/compiler-dom": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/devtools-api": { @@ -650,61 +721,78 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" }, - "node_modules/@vue/reactivity": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.25.tgz", - "integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==", + "node_modules/@vue/devtools-kit": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz", + "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.25" + "@vue/devtools-shared": "^8.1.2", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz", + "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.34.tgz", + "integrity": "sha512-y9XDjCEuBp+98k+UL5dbYkh57AHU4o6cxZedOPXw3bmrZZYLQsVHguGurq7hVrPCSrQtrnz1f9dssyFr+dMXfQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.34" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.25.tgz", - "integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.34.tgz", + "integrity": "sha512-mKeBYvu8tcMSLhypAHBmriUFfWXKTCF/23Z4jiCoYK3UtWepkliViNLuR90V9XOyD62mUxs9p1jsrpK3CCGIzw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/shared": "3.5.25" + "@vue/reactivity": "3.5.34", + "@vue/shared": "3.5.34" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.25.tgz", - "integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.34.tgz", + "integrity": "sha512-e8kZzERmCwUnBRVsgSQlAfrfU2rGoy0FFKPBXSlfEjc/O3KfA7QP0t1/2ZylrbchjmIKB4dPTd07A6WPr0eOrg==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.25", - "@vue/runtime-core": "3.5.25", - "@vue/shared": "3.5.25", - "csstype": "^3.1.3" + "@vue/reactivity": "3.5.34", + "@vue/runtime-core": "3.5.34", + "@vue/shared": "3.5.34", + "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.25.tgz", - "integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.34.tgz", + "integrity": "sha512-nHxmJoTrKsmrkbILRhkC9gY1G3moZbJTqCzDd7DOOzG5KH9oeJ0Unqrff5f9v0pW//jES05ZkJcNtfE8JjOIew==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25" + "@vue/compiler-ssr": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { - "vue": "3.5.25" + "vue": "3.5.34" } }, "node_modules/@vue/shared": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz", - "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.34.tgz", + "integrity": "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==", "license": "MIT" }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -713,6 +801,18 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -727,6 +827,38 @@ "node": ">= 8" } }, + "node_modules/ast-kit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", + "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", + "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.4", + "ast-kit": "^2.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -734,14 +866,15 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" } }, "node_modules/balanced-match": { @@ -773,6 +906,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -965,12 +1107,35 @@ "dev": true, "license": "MIT" }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -995,9 +1160,9 @@ } }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -1057,6 +1222,12 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1071,9 +1242,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", @@ -1091,16 +1262,16 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -1248,9 +1419,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -1259,10 +1430,29 @@ "node": ">= 0.4" } }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/immutable": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", - "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", "dev": true, "license": "MIT" }, @@ -1331,6 +1521,47 @@ "node": ">=0.12.0" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -1340,6 +1571,21 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magic-string-ast": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", + "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.19" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1398,6 +1644,35 @@ "node": "*" } }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -1407,10 +1682,22 @@ "node": "*" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" + }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -1444,17 +1731,17 @@ } }, "node_modules/nostr-tools": { - "version": "2.18.2", - "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.18.2.tgz", - "integrity": "sha512-lUCJQd9YZG3kEvxV5Zgm7qUkBpaeuvFrtqBz4TJLAxHzUn2pE7nmZZRDQmNzp5neEw20tQS3jR16o7XzzF8ncg==", + "version": "2.23.3", + "resolved": "https://registry.npmjs.org/nostr-tools/-/nostr-tools-2.23.3.tgz", + "integrity": "sha512-AALyt9k8xPdF4UV2mlLJ2mgCn4kpTB0DZ8t2r6wjdUh6anfx2cTVBsHUlo9U0EY/cKC5wcNyiMAmRJV5OVEalA==", "license": "Unlicense", "dependencies": { - "@noble/ciphers": "^0.5.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.1", - "@scure/base": "1.1.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1", + "@noble/ciphers": "2.1.1", + "@noble/curves": "2.0.1", + "@noble/hashes": "2.0.1", + "@scure/base": "2.0.0", + "@scure/bip32": "2.0.1", + "@scure/bip39": "2.0.1", "nostr-wasm": "0.1.0" }, "peerDependencies": { @@ -1491,6 +1778,18 @@ "node": ">=0.10.0" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1498,9 +1797,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -1510,10 +1809,68 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/playwright": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz", + "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.61.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.61.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz", + "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "funding": [ { "type": "opencollective", @@ -1530,7 +1887,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -1539,9 +1896,9 @@ } }, "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { @@ -1555,14 +1912,18 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/pyright": { - "version": "1.1.289", - "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.289.tgz", - "integrity": "sha512-fG3STxnwAt3i7bxbXUPJdYNFrcOWHLwCSEOySH2foUqtYdzWLcxDez0Kgl1X8LMQx0arMJ6HRkKghxfRD1/z6g==", + "version": "1.1.409", + "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.409.tgz", + "integrity": "sha512-13VFQyw4mJzshZxcxiYbNjo1hG/WHSRDj70Y3lbJEHqCkI2dvBAUTti8VV6Ezsr5gT93pFvC0e/jAQS4JdHarA==", "dev": true, "license": "MIT", "bin": { @@ -1570,22 +1931,41 @@ "pyright-langserver": "langserver.index.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, "node_modules/qrcode.vue": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-3.6.0.tgz", - "integrity": "sha512-vQcl2fyHYHMjDO1GguCldJxepq2izQjBkDEEu9NENgfVKP6mv/e2SU62WbqYHGwTgWXLhxZ1NCD1dAZKHQq1fg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-3.9.0.tgz", + "integrity": "sha512-AxkgdNXd6R6N1rJcSKna3GfMz3cMpLZo95CLuF/3227nNY32iACBtyqRr6mJc3SW7w628Iy0vgnLWYqxHqgRLw==", "license": "MIT", "peerDependencies": { "vue": "^3.0.0" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/quasar": { - "version": "2.18.6", - "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.18.6.tgz", - "integrity": "sha512-ZlK+vJXOBPSFDCNQDBDNwSI+AHoqaFPxK8ve6mhsYLhMKWI5b8zsGY9VU1xYjngO2aBvU4fvGWXy4tTbzrBk8Q==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/quasar/-/quasar-2.22.0.tgz", + "integrity": "sha512-0WAJ0ZnNMWK7QNFnpOVLyUDeEZ6cexkO+f7GjOEEIITIynH2xkfuryWO97Pa/G/+eQJc0ZwX9GohEXXwYTIBew==", "license": "MIT", "engines": { "node": ">= 10.18.1", @@ -1612,14 +1992,14 @@ } }, "node_modules/sass": { - "version": "1.94.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.2.tgz", - "integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==", + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz", + "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -1632,6 +2012,12 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, "node_modules/sdp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", @@ -1690,9 +2076,9 @@ } }, "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "version": "5.47.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.47.1.tgz", + "integrity": "sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -1708,6 +2094,51 @@ "node": ">=10" } }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1721,23 +2152,83 @@ "node": ">=8.0" } }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "license": "MIT" + }, "node_modules/underscore": { "version": "1.13.8", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", "license": "MIT" }, - "node_modules/vue": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", - "integrity": "sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==", + "node_modules/unplugin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", + "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-sfc": "3.5.25", - "@vue/runtime-dom": "3.5.25", - "@vue/server-renderer": "3.5.25", - "@vue/shared": "3.5.25" + "@jridgewell/remapping": "^2.3.5", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-utils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vue": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz", + "integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.34", + "@vue/compiler-sfc": "3.5.34", + "@vue/runtime-dom": "3.5.34", + "@vue/server-renderer": "3.5.34", + "@vue/shared": "3.5.34" }, "peerDependencies": { "typescript": "*" @@ -1749,13 +2240,14 @@ } }, "node_modules/vue-i18n": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.2.2.tgz", - "integrity": "sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==", + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.2.tgz", + "integrity": "sha512-sADDeKXqAGsPX6tK3t3y2ZiMpbVWN12tG+MhTiJ06rVoh58eGtM4wFyw3uWGbVkXByVp9Ne/AP+nSSzI+J9OAQ==", "license": "MIT", "dependencies": { - "@intlify/core-base": "11.2.2", - "@intlify/shared": "11.2.2", + "@intlify/core-base": "11.4.2", + "@intlify/devtools-types": "11.4.2", + "@intlify/shared": "11.4.2", "@vue/devtools-api": "^6.5.0" }, "engines": { @@ -1782,18 +2274,97 @@ } }, "node_modules/vue-router": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.3.tgz", - "integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.6.tgz", + "integrity": "sha512-9+kmUTGbKMyW9Asoy98IXXYIzrTMT7JDAdpDDeEkorHvybpUvBI2wsrSM5jFOXrFydpzRFJ9vAh+80DN2PGu9w==", "license": "MIT", "dependencies": { - "@vue/devtools-api": "^6.6.4" + "@babel/generator": "^7.28.6", + "@vue-macros/common": "^3.1.1", + "@vue/devtools-api": "^8.0.6", + "ast-walker-scope": "^0.8.3", + "chokidar": "^5.0.0", + "json5": "^2.2.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.15", + "unplugin": "^3.0.0", + "unplugin-utils": "^0.3.1", + "yaml": "^2.8.2" }, "funding": { "url": "https://github.com/sponsors/posva" }, "peerDependencies": { + "@pinia/colada": ">=0.21.2", + "@vue/compiler-sfc": "^3.5.17", + "pinia": "^3.0.4", "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@pinia/colada": { + "optional": true + }, + "@vue/compiler-sfc": { + "optional": true + }, + "pinia": { + "optional": true + } + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz", + "integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.1.2" + } + }, + "node_modules/vue-router/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/vue-router/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vue-router/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/vuex": { @@ -1807,6 +2378,12 @@ "vue": "^3.2.0" } }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, "node_modules/webrtc-adapter": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-8.2.3.tgz", @@ -1826,6 +2403,21 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/zxing-wasm": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-1.1.3.tgz", diff --git a/package.json b/package.json index f2a7778c3..19a314a46 100644 --- a/package.json +++ b/package.json @@ -10,29 +10,31 @@ "vendor_minify_css": "./node_modules/.bin/cleancss -o ./lnbits/static/bundle.min.css ./lnbits/static/bundle.css", "vendor_minify_js": "./node_modules/.bin/terser ./lnbits/static/bundle.js -o ./lnbits/static/bundle.min.js --compress --mangle", "vendor_minify_components": "./node_modules/.bin/terser ./lnbits/static/bundle-components.js -o ./lnbits/static/bundle-components.min.js --compress --mangle", - "bundle": "npm run sass && npm run vendor_copy && npm run vendor_json && npm run vendor_bundle_css && npm run vendor_bundle_js && npm run vendor_bundle_components && npm run vendor_minify_css && npm run vendor_minify_js && npm run vendor_minify_components" + "bundle": "npm run sass && npm run vendor_copy && npm run vendor_json && npm run vendor_bundle_css && npm run vendor_bundle_js && npm run vendor_bundle_components && npm run vendor_minify_css && npm run vendor_minify_js && npm run vendor_minify_components", + "test:e2e": "playwright test --config tests/e2e/playwright.config.ts" }, "devDependencies": { + "@playwright/test": "^1.61.0", "clean-css-cli": "^5.6.3", "concat": "^1.0.3", - "prettier": "^3.7.4", - "pyright": "1.1.289", - "sass": "^1.94.2", - "terser": "^5.44.1" + "prettier": "^3.8.3", + "pyright": "1.1.409", + "sass": "^1.99.0", + "terser": "^5.47.1" }, "dependencies": { - "axios": "^1.13.5", + "axios": "^1.18.0", "chart.js": "^4.5.1", "moment": "^2.30.1", - "nostr-tools": "^2.18.2", - "qrcode.vue": "^3.6.0", - "quasar": "2.18.6", + "nostr-tools": "^2.23.3", + "qrcode.vue": "^3.9.0", + "quasar": "2.22.0", "showdown": "^2.1.0", "underscore": "^1.13.8", - "vue": "3.5.25", - "vue-i18n": "^11.2.2", + "vue": "3.5.34", + "vue-i18n": "^11.4.2", "vue-qrcode-reader": "^5.7.3", - "vue-router": "4.6.3", + "vue-router": "5.0.6", "vuex": "4.1.0" }, "vendor": [ @@ -86,6 +88,7 @@ "i18n/sk.js", "i18n/kr.js", "i18n/fi.js", + "i18n/fo.js", "js/utils.js", "js/api.js", "js/globals.js", @@ -111,6 +114,7 @@ "js/pages/users.js", "js/pages/account.js", "js/pages/admin.js", + "js/components/admin/lnbits-admin-funding-seed-backup.js", "js/components/admin/lnbits-admin-funding.js", "js/components/admin/lnbits-admin-funding-sources.js", "js/components/admin/lnbits-admin-fiat-providers.js", @@ -119,10 +123,14 @@ "js/components/admin/lnbits-admin-users.js", "js/components/admin/lnbits-admin-server.js", "js/components/admin/lnbits-admin-extensions.js", + "js/components/admin/lnbits-admin-wasm-runtime.js", + "js/components/admin/lnbits-admin-wasm-limit-config.js", "js/components/admin/lnbits-admin-notifications.js", "js/components/admin/lnbits-admin-site-customisation.js", "js/components/admin/lnbits-admin-assets-config.js", "js/components/admin/lnbits-admin-audit.js", + "js/components/admin/lnbits-admin-blockexplorer.js", + "js/pages/blockexplorer.js", "js/components/lnbits-wallet-charts.js", "js/components/lnbits-wallet-api-docs.js", "js/components/lnbits-wallet-icon.js", @@ -142,6 +150,7 @@ "js/components/lnbits-theme.js", "js/components/lnbits-qrcode-scanner.js", "js/components/lnbits-manage-extension-list.js", + "js/components/lnbits-extension-permissions.js", "js/components/lnbits-manage-wallet-list.js", "js/components/lnbits-language-dropdown.js", "js/components/lnbits-payment-list.js", @@ -149,6 +158,7 @@ "js/components/extension-settings.js", "js/components/data-fields.js", "js/components.js", + "js/wasm-extension-component.js", "js/init-app.js" ], "css": [ diff --git a/poetry.lock b/poetry.lock index 99a70a423..2a9a66ebb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.4.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" @@ -187,6 +187,18 @@ files = [ dev = ["attribution (==1.8.0)", "black (==25.11.0)", "build (>=1.2)", "coverage[toml] (==7.10.7)", "flake8 (==7.3.0)", "flake8-bugbear (==24.12.12)", "flit (==3.12.0)", "mypy (==1.19.0)", "ufmt (==2.8.0)", "usort (==1.0.8.post1)"] docs = ["sphinx (==8.1.3)", "sphinx-mdinclude (==0.6.2)"] +[[package]] +name = "annotated-doc" +version = "0.0.4" +description = "Document parameters, class attributes, return types, and variables inline, with Annotated." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320"}, + {file = "annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4"}, +] + [[package]] name = "anyio" version = "4.12.1" @@ -322,24 +334,16 @@ gssauth = ["gssapi ; platform_system != \"Windows\"", "sspilib ; platform_system [[package]] name = "attrs" -version = "25.3.0" +version = "26.1.0" description = "Classes Without Boilerplate" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, - {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, + {file = "attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"}, + {file = "attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32"}, ] -[package.extras] -benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] -tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] -tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] - [[package]] name = "base58" version = "2.1.1" @@ -446,14 +450,14 @@ files = [ [[package]] name = "bip32" -version = "4.0" -description = "Minimalistic implementation of the BIP32 key derivation scheme" +version = "5.0.0" +description = "Minimalistic implementation of BIP32 (Bitcoin HD wallets)" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "bip32-4.0-py3-none-any.whl", hash = "sha256:9728b38336129c00e1f870bbb3e328c9632d51c1bddeef4011fd3115cb3aeff9"}, - {file = "bip32-4.0.tar.gz", hash = "sha256:8035588f252f569bb414bc60df151ae431fc1c6789a19488a32890532ef3a2fc"}, + {file = "bip32-5.0.0-py3-none-any.whl", hash = "sha256:b20872795ae2bb4e5fac351f53ccdf2b998f82e927413922a2c5473a004bd6d0"}, + {file = "bip32-5.0.0.tar.gz", hash = "sha256:4caa1f74eed9f2cd4624b55f34a4094f52542552fe3d0cc52e1179b8d6e9f21e"}, ] [package.dependencies] @@ -461,207 +465,178 @@ coincurve = ">=15.0,<21" [[package]] name = "bitarray" -version = "3.6.1" +version = "3.8.0" description = "efficient arrays of booleans -- C extension" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "bitarray-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716ec396af5292275f7f572850596990ff84bf1a8552428ee982fe54f773aeb9"}, - {file = "bitarray-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c1d916d36c03c2100af0accc3698091c0bc2e94470cac88462d9f6b56758f37"}, - {file = "bitarray-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:028e95a4792ddef067a5c6151d223089665d5c566cb88f3fe68155e251d8f522"}, - {file = "bitarray-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66db701a1c3ea69919a2eb415fb0fce83d55179fd65390399eb40579b102f0a4"}, - {file = "bitarray-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cff53ab9cf8d088e88402174ed53529c6ec3897a5146c2a18625253b3b2f6d21"}, - {file = "bitarray-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bb5c678d3957104a33e093427bd514d3b08673e47b358242be6a53d33613ce"}, - {file = "bitarray-3.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3916c63580d9ca9c3264744ce1162e500a6b99c841f25b9657bca2595d2d438"}, - {file = "bitarray-3.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7134fa2d0d253ce1fcd6a5d646f4024ede4a3bf845420bc799dccb430c254ecc"}, - {file = "bitarray-3.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed3009c2ecb7c01b4da8fd0a5e47e0e86a45af746700a6386f247fd922cd3cc2"}, - {file = "bitarray-3.6.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:73cee88d7af7a881447ea593cbaae207be4a472a8c0a9f2da54bcb17512fd75f"}, - {file = "bitarray-3.6.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:3abea085790b12c12b3f8ceefae4a7953e14518d88c4b0547187805b999e4158"}, - {file = "bitarray-3.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8aa92c400c813961ff868801ef71a6fa161c6f546433bfb396ee3f596d807a20"}, - {file = "bitarray-3.6.1-cp310-cp310-win32.whl", hash = "sha256:32dc6efc7c87badd7c7941df5ca40346a29532d37bd97a52b67ed563d324b6c7"}, - {file = "bitarray-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ad4e07524372225302e17cb92e7f682baa38fe323e2647dc4f6202304dd8d1a"}, - {file = "bitarray-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:52320d72dca8022b4c61bfb5d059743f44421488c0502df623ff87b6d6f48166"}, - {file = "bitarray-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bc717849ea0693b6b93480e499f0da3ea7501f52aaea2b144aa28ac5eecbe62"}, - {file = "bitarray-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00a129b2d790e772fbfb26e31c65f54d5451636654e7f0600af03086aba6461a"}, - {file = "bitarray-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9016c534c64342cf3d8c6fda8df681b9771e9fa15a1697423a3766e986d2f958"}, - {file = "bitarray-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8404a2c126abdc6cb236347565d4ea622712734fa0987f13c6505b550963b651"}, - {file = "bitarray-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:966478685f59bd429e2425f6a8172a6d8f54fd7d6df48fcae98fd24ff03163d1"}, - {file = "bitarray-3.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41248ab4781a68d5f7ad492d1546b98c2f190c99941de6c92445b693d79123b4"}, - {file = "bitarray-3.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:285a4a39b8d4715bc5165ee3e0bc81bc7f27ef92483bae478dc3d430c0734e82"}, - {file = "bitarray-3.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c9d578179a618b8176fd625dcc3f756f9dc46647c35250798c318e5d4689d096"}, - {file = "bitarray-3.6.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a2581ad5f45eba60bb8d5be324d26052620bb72fd3f76cb6d54d3d0f74859b2"}, - {file = "bitarray-3.6.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:be8f2fd4798539f9b49db517ec9a2e9d1e9132ec92562220f67f80f176900c21"}, - {file = "bitarray-3.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4af03ea3ed535f0c50ed1b871b1c7985188310b26fc5455241a66efb7ac0139f"}, - {file = "bitarray-3.6.1-cp311-cp311-win32.whl", hash = "sha256:1e04d1176f0657fc250ad022c3adc86b52ac7c5352d3d00262b0fc53c376005a"}, - {file = "bitarray-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:eb6ba70e7cf5128ec43787dbc0b5cd661118bf32b756078ff5cb143c9c825d11"}, - {file = "bitarray-3.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a236fc1e87a70adb588b37b09b18add71224279d28140d9ee847778e1f3f5a1a"}, - {file = "bitarray-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d5cf59d8f1ee8332f60e7352464209db1de909ae960d3b1f9d76897e484aa4ed"}, - {file = "bitarray-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38ce28427eea22bafcef073768d7e14d14233ced3eea8505ee13b92fb3723bce"}, - {file = "bitarray-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e92011003d87e224e101533a98ede388bb40de0ec65978c6d0bb0d98f949f1b8"}, - {file = "bitarray-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f378316f45ffcec4ed429cf2ef446c8a3d7afe29e5020eb51ed789e443f4359f"}, - {file = "bitarray-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b12c11894d991dfaa415229329452e8be2b230e06fba2aff27110158e2f0dafd"}, - {file = "bitarray-3.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f53d6a0ac86d67b6760530196963ea0598588c1a9b155f7e137d9b6a1befd27"}, - {file = "bitarray-3.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b17029647fd990ce6fd3f1fb253ff47bfc27df8255bea99b5e381b2030b6d54"}, - {file = "bitarray-3.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:36cd656877eb3d215ecbb575743d05c521911514985b2a0999a23bb504a8ae64"}, - {file = "bitarray-3.6.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ac29a0cda5ea50c78ff20d06d8c5b8402147448a9dde2b118ecea2b4cec490ec"}, - {file = "bitarray-3.6.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8dceb8d43fe51b8643766152736ec0f32f0a6a5b6e2e6742f1165cbe5799102e"}, - {file = "bitarray-3.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:137bfb9c00c172c16ddabe8615a4746e745789cfedb0e7c5b25236a20ccf051c"}, - {file = "bitarray-3.6.1-cp312-cp312-win32.whl", hash = "sha256:aba6043eb44b68055145c5ae2062f976c02ec0b04ff688ee5b43deda8185b708"}, - {file = "bitarray-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:64a3a8c79468bd5283907f2e60651c857f0dab3dc671943bcf5ec2d15e2f8177"}, - {file = "bitarray-3.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:639fc29267348a78b259fb24c471b7e3322c85f1eb95712bac852ab2a56e742a"}, - {file = "bitarray-3.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357f6c07cb3116a2d4a917fd4f54727f1b71102f5e316c2d4c9fe26ec3dfd8e9"}, - {file = "bitarray-3.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:384eee34bdb4ea52517421cac778d4a881652cd7a5a052bd0939adbca9a6b7d6"}, - {file = "bitarray-3.6.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25cc576ac013b33e69b8123dd7eca78af80100f1a10174e5a30e174ad31f715a"}, - {file = "bitarray-3.6.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84951ce773cbe69e4e15ae27bf6617f08ef2415ad37e1114a2d7979e210bf9e5"}, - {file = "bitarray-3.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c277f6a1cbfdedcec704add6ff2ace89b56a29c1955f2441a7fd2fbde410f791"}, - {file = "bitarray-3.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8d8f78bf8bebac391867a7637008ffa68f4870d9ee8154c836745ff237cfa98"}, - {file = "bitarray-3.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9b263a460b4ea6a7ebbe450593928651fa81fa3a1426732ff6ea52bb4b210d6c"}, - {file = "bitarray-3.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2a2f08fa831bafb42903231c23df5c597d2cc47fabb2532659180a54386dc49a"}, - {file = "bitarray-3.6.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:43d2244aa721dc92713a72695d43dd2a75b920338c9f34da50133d05e23c9ff3"}, - {file = "bitarray-3.6.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:298a0f4442edb98695040009e9d411f221b33cc8d3b749a00d9813a69c047fc1"}, - {file = "bitarray-3.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7f16d704c40bd3db661005819daa818c4f5f82823d29491d6744dfc7ff3d6b4a"}, - {file = "bitarray-3.6.1-cp313-cp313-win32.whl", hash = "sha256:a2120ce67c0d0047564c5af1afdd7d03688c2d7109e21ce699742366934c658f"}, - {file = "bitarray-3.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:e3361f1c9e537925284d1f37447a3aad5f5dc1c741cec2ebc078250232d939af"}, - {file = "bitarray-3.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:88c54caba69b9b70ffe123a98d97574e77d74f74676f5a5cfeb97fa7ad5d2e64"}, - {file = "bitarray-3.6.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:992b7ecdfa792fe15670d8f3b74373467341e24669fd40aa05b2c884b84d1475"}, - {file = "bitarray-3.6.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57d15b0903ab8f0eee14fea52c44267fe8b498562a293a3c7ca7063a16c70d51"}, - {file = "bitarray-3.6.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5455059a12eeb1690f943f478de9fc20064a7afd2b78559e98b325bffda55d00"}, - {file = "bitarray-3.6.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecc825ecd7f9a51c65a7b22c0015f39de9c3c0ab5a349ed9de6dd56e9f222de3"}, - {file = "bitarray-3.6.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91f9ef64a2b973b5ae8a43db43d6ff5d274b02e8d169a641ac2b24f7a3aec5bf"}, - {file = "bitarray-3.6.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:5ee5b9ba3eadd40717c9ec79a831e765a49dde0e0bc1c6e3238b34fc4ea45059"}, - {file = "bitarray-3.6.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:cba075e4b15a5824f23fd876087d4a0b9e0e72d31ee48ac43829d18f0dd46a5f"}, - {file = "bitarray-3.6.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:861bda407bf9b774b2a662acf96993869f8c687aa207b52c8e8e18afef0da9c0"}, - {file = "bitarray-3.6.1-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:2858a633151134f0734fd78e8b36ac7401277dffd6ee70ada773b2edce596f36"}, - {file = "bitarray-3.6.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:b2c36ebfba3fb9436c78ef043f75078cd0e61581aaff742194b554e772cb992b"}, - {file = "bitarray-3.6.1-cp36-cp36m-win32.whl", hash = "sha256:18fc5ce54aa8ba7bd717a64c518bc4d67f4f51b4ebf30e5c5ecf63ee86399562"}, - {file = "bitarray-3.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:4e9d19a85d9d027ad4e99e579d04bda3ed5ab06aab37e5bffc6410772cc3b6f0"}, - {file = "bitarray-3.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb4c0635001566a68bde26bc1f47553ceeb83474069a68d7b1f29ac2cb473da1"}, - {file = "bitarray-3.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d511549d169a62533a99e235c06355a43e70fb0dbe6ff05df2c700704f1adc6"}, - {file = "bitarray-3.6.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b18b80658df576d088b1e338212c0a674ca3efb067eb73d7403b4cadd75ab32e"}, - {file = "bitarray-3.6.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ec62778cea9a23baf8112bbdd070fa174646dc9d36b8e1b34dad041cf21b495"}, - {file = "bitarray-3.6.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2d9c5527be2996555e5b71bb30d4b98bb155916fa118372d314b316f7b5af7"}, - {file = "bitarray-3.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc3b4b5b57a0718abb957971af21b044ee7d568b67d6979081ac443c1418c79"}, - {file = "bitarray-3.6.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:e870d8f161a93a325d43bd04e61990d0e4123d800442f38f4ba819802452bc70"}, - {file = "bitarray-3.6.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f922b8fb406c241ccece1b358019e992167dc4ec31d4a77e4066886c5dacbff6"}, - {file = "bitarray-3.6.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5560a87c77c48f1e30d422e1f771307870e0f98315695745b0f9a3148aec05fc"}, - {file = "bitarray-3.6.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:eb590c1d8b956cfcb16c055de87dc992e3136df9d31cf07bda69febe6b39a7c0"}, - {file = "bitarray-3.6.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:88563f3b8e23aa3f342cf5d65f4551f8aa9d1733ba12bcf7bc58cbb126e40770"}, - {file = "bitarray-3.6.1-cp37-cp37m-win32.whl", hash = "sha256:cb277d69541c5763c27bba6c74a603e6d177b4614e3d3af68a37414a8e06415b"}, - {file = "bitarray-3.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0b17de6920a45e70de8a58a69b1b309da9f5203efd27ac4712bb46cac882b823"}, - {file = "bitarray-3.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3ef907cf76d12506ec05278b65147e64babd7ccf5ecc549669300fe4729eef00"}, - {file = "bitarray-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f84fdb0c901db810548b8e01e1204462a806066299befbe1a6141a098ca2c5c9"}, - {file = "bitarray-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65db64692b1ae518d3339c4f7fc5bbda17e8e0274784bd0167360d329d2b4974"}, - {file = "bitarray-3.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee5ee008313e9b53accf719be44905e41c968da94cbe1b7812498e87d07987f7"}, - {file = "bitarray-3.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bb69c4ccc5433ecf5462a867a3b4ff3dce9080ce665f7dcf6189f6786e440ef9"}, - {file = "bitarray-3.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd211eba612ca9fff50b1b55bd654e1cd406f78cb9c4456d2a12b9df68d53b16"}, - {file = "bitarray-3.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c8e23f03dca065698c6fe931bc78aea5ca6db3e1be2e7204c584029a9444d33"}, - {file = "bitarray-3.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:27666556eccbfb3c6524a175fc557534f1fda1d7ca09a6f77673fa63278308a0"}, - {file = "bitarray-3.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:6dd497b807e87c3ba27d85027a57414292a119ef5c329b19dd719ac402a99dcc"}, - {file = "bitarray-3.6.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:507cc28c1ff26646b0868e6a854ee0fad1f1e36fefc1286f3f9db4533dae581c"}, - {file = "bitarray-3.6.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f7e853cdb173ca644a58cba6d5438af0f8df3ea17165d85dd20bc8ba8ec1e6c1"}, - {file = "bitarray-3.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6b6e05e0ecc32b1099b3d53b765676a2bfffc708d02ef7dcb60b5a6c2d15b0c8"}, - {file = "bitarray-3.6.1-cp38-cp38-win32.whl", hash = "sha256:8db11d96c1fcce48dced1e06084cc5dfd76db7bc41ec78c85f972ed6922cc328"}, - {file = "bitarray-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:0e0dbd5301e803c93b9e948b2bba9c12f5d76a16c94039888580b42f8419c8ba"}, - {file = "bitarray-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:02e9ed2a586a63dea57e3692727b4c56ae71347e058b5465188b592767bd1c84"}, - {file = "bitarray-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34a8c0f9d3e27a486d620db769f8f9d800830a7805d5e7a336018c991371bc60"}, - {file = "bitarray-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2574fba97ae17cd58b1b0d59fa9a69e0cff0a83e1fa9eb4adeee1b7bca1df41b"}, - {file = "bitarray-3.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55bbc633a2aab0c3d31514d3efb045b7dc5b46c97d9a1fbc225660f8de98c6e9"}, - {file = "bitarray-3.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0b2ece38b225891dde8a17b1ed432f116b8e18a0a1a913c757d4d9e888540283"}, - {file = "bitarray-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:547b075e81f907b7e50ca76103eb7ab81fbac763aebb73daf542c59f5b9528b2"}, - {file = "bitarray-3.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bab001c6bd051efa9e4fbe725b0250c55cd21e56c38c651d90692963e97e46f4"}, - {file = "bitarray-3.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:40035ca664c0479af8439a84ae218da631a6ef5d3f6d89ec43566f7a54f1f23d"}, - {file = "bitarray-3.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ae700d6a55a912c853c6ebd1effe3da1303da4d66d8d21cfcb0f426b41568400"}, - {file = "bitarray-3.6.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:53824a01475f53a314b734711673110bfcaeedaa4235b7398a7687ecb9847d70"}, - {file = "bitarray-3.6.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d17db3e301f7aaa9ba9e30599de1362b06b6871fd5cb3abf7c73a7dc08c38a06"}, - {file = "bitarray-3.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:09c807c7cd43001c7a2d1746ba2352c97dd8a1c0c232f8b61976aa27ee7d9202"}, - {file = "bitarray-3.6.1-cp39-cp39-win32.whl", hash = "sha256:b0059a2bd2263f7bee6b8b0cf9914eb3ac7c0d8e2f7d8f84b4c12875e8194fd5"}, - {file = "bitarray-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a0b200c3382fb585ac9d9018fea2a5fe2ce5ff655098e1f1e804bdb8419ae56d"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a15055d392a921093d3c583e7978acc63fd3f76068a10f8e2deaa078b58a0ac9"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b6b68a6f7b7b872ea4838d438547ee69a1b020078893f087b35152dd6c3550e"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26180314ad363dcefa03fff9b7008d8cc2dcc7b080bb38e5bfde545d08e0a7cb"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cae78167bceb3991652dab9d5e66c94e09860005753b51ba608a803a8c2504fb"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b04a4884e52958d2a5c5e17389fdcc99cb01acbf311a7aa81871a28a2756f89"}, - {file = "bitarray-3.6.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:78a3c6fe40206a3d550a1d10249732152a849d1817fced3e7af5b19f5e832615"}, - {file = "bitarray-3.6.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:445fdb24af5fb4d8d3d6e1ff34ca25f94793ea1ef23b5c33e1787db9138e3dac"}, - {file = "bitarray-3.6.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc5ba1cb99cd3391c09b61fffa95d22287b49d7304fba15bd3d3886a16b78a5"}, - {file = "bitarray-3.6.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1825fccae78906d7a642fcde100f7efe0dfd7497ee14376259bda08a1bee93b9"}, - {file = "bitarray-3.6.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:883f3bdd214a66a531d2074cd3c8955e72af4bb9acacccb77894eb5a23dd9ef7"}, - {file = "bitarray-3.6.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f29dccd681ffe55b14f7561030f07f8eb6a5c8c7b1974be459c4bee28d7da85e"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:085b83604bf4ab3e193bbd2f8a913ae3ec6965b2e334f0fdd50b078af807d208"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:9f7a85d16fef11dbeaa85b6a8df5ac98917b933e10d6e94a29eded45f6fc41a1"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24c898583ac116ce9608b8573f7b596ba0087301f29e9c4c6bcbe504a59d6313"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c058f45cd7edec858a83af8bf40ec03d357e0d870ef3d1fe422dff68980bca"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78afb2f8212e931150072fb4ec30281aa968c2e5643af3d01469d8f83da7a151"}, - {file = "bitarray-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f2b724859e46d3fa93bb1816bfd71faeeaa7b71473484a998beb7cca551a5b1c"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d23b40c9e97a57e2b2dc75b78282ce62b9fea76013a171421ab18f1056d7a7a1"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7de7f6cd5df096dae16ae8a31d5237b191b98b40e2bb03ef71d9b5479922584c"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbbcbfede6e78bd2fdfa5b625859a7ddaeedb0d4130fdb31cdd10a6a3533d19"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3776c1155fd690c18bf7ae0f15c6b10d4e0cf0fec696ec31cd53d8ff4109e59"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5cec7314701c2e8f63a5ad0b86911099b61bd2bd9c2c50c73094a751d86cfa1"}, - {file = "bitarray-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:55575dd221eec2176531fe29a99eb2682d6107b34ba036b77d48549a1f3aa9dc"}, - {file = "bitarray-3.6.1.tar.gz", hash = "sha256:4255bff37b01562b8e6adcf9db256029765985b0790c5ff76bbe1837edcd53ea"}, + {file = "bitarray-3.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f08342dc8d19214faa7ef99574dea6c37a2790d6d04a9793ef8fa76c188dc08d"}, + {file = "bitarray-3.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:792462abfeeca6cc8c6c1e6d27e14319682f0182f6b0ba37befe911af794db70"}, + {file = "bitarray-3.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0df69d26f21a9d2f1b20266f6737fa43f08aa5015c99900fb69f255fbe4dabb4"}, + {file = "bitarray-3.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b4f10d3f304be7183fac79bf2cd997f82e16aa9a9f37343d76c026c6e435a8a8"}, + {file = "bitarray-3.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fc98ff43abad61f00515ad9a06213b7716699146e46eabd256cdfe7cb522bd97"}, + {file = "bitarray-3.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81c6b4a6c1af800d52a6fa32389ef8f4281583f4f99dc1a40f2bb47667281541"}, + {file = "bitarray-3.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f3fd8df63c41ff6a676d031956aebf68ebbc687b47c507da25501eb22eec341f"}, + {file = "bitarray-3.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0ce9d9e07c75da8027c62b4c9f45771d1d8aae7dc9ad7fb606c6a5aedbe9741"}, + {file = "bitarray-3.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8a9c962c64a4c08def58b9799333e33af94ec53038cf151d36edacdb41f81646"}, + {file = "bitarray-3.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1a54d7e7999735faacdcbe8128e30207abc2caf9f9fd7102d180b32f1b78bfce"}, + {file = "bitarray-3.8.0-cp310-cp310-win32.whl", hash = "sha256:3ea52df96566457735314794422274bd1962066bfb609e7eea9113d70cf04ffe"}, + {file = "bitarray-3.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:82a07de83dce09b4fa1bccbdc8bde8f188b131666af0dc9048ba0a0e448d8a3b"}, + {file = "bitarray-3.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:c5ba07e58fd98c9782201e79eb8dd4225733d212a5a3700f9a84d329bd0463a6"}, + {file = "bitarray-3.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25b9cff6c9856bc396232e2f609ea0c5ec1a8a24c500cee4cca96ba8a3cd50b6"}, + {file = "bitarray-3.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d9984017314da772f5f7460add7a0301a4ffc06c72c2998bb16c300a6253607"}, + {file = "bitarray-3.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbbbfbb7d039b20d289ce56b1beb46138d65769d04af50c199c6ac4cb6054d52"}, + {file = "bitarray-3.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1f723e260c35e1c7c57a09d3a6ebe681bd56c83e1208ae3ce1869b7c0d10d4f"}, + {file = "bitarray-3.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cbd1660fb48827381ce3a621a4fdc237959e1cd4e98b098952a8f624a0726425"}, + {file = "bitarray-3.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df6d7bf3e15b7e6e202a16ff4948a51759354016026deb04ab9b5acbbe35e096"}, + {file = "bitarray-3.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d5c931ec1c03111718cabf85f6012bb2815fa0ce578175567fa8d6f2cc15d3b4"}, + {file = "bitarray-3.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:41b53711f89008ba2de62e4c2d2260a8b357072fd4f18e1351b28955db2719dc"}, + {file = "bitarray-3.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4f298daaaea58d45e245a132d6d2bdfb6f856da50dc03d75ebb761439fb626cf"}, + {file = "bitarray-3.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:30989a2451b693c3f9359d91098a744992b5431a0be4858f1fdf0ec76b457125"}, + {file = "bitarray-3.8.0-cp311-cp311-win32.whl", hash = "sha256:e5aed4754895942ae15ffa48c52d181e1c1463236fda68d2dba29c03aa61786b"}, + {file = "bitarray-3.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:22c540ed20167d3dbb1e2d868ca935180247d620c40eace90efa774504a40e3b"}, + {file = "bitarray-3.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:84b52b2cf77bb7f703d16c4007b021078dbbe6cf8ffb57abe81a7bacfc175ef2"}, + {file = "bitarray-3.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2fcbe9b3a5996b417e030aa33a562e7e20dfc86271e53d7e841fc5df16268b8"}, + {file = "bitarray-3.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cd761d158f67e288fd0ebe00c3b158095ce80a4bc7c32b60c7121224003ba70d"}, + {file = "bitarray-3.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c394a3f055b49f92626f83c1a0b6d6cd2c628f1ccd72481c3e3c6aa4695f3b20"}, + {file = "bitarray-3.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:969fd67de8c42affdb47b38b80f1eaa79ac0ef17d65407cdd931db1675315af1"}, + {file = "bitarray-3.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:99d25aff3745c54e61ab340b98400c52ebec04290a62078155e0d7eb30380220"}, + {file = "bitarray-3.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e645b4c365d6f1f9e0799380ad6395268f3c3b898244a650aaeb8d9d27b74c35"}, + {file = "bitarray-3.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2fa23fdb3beab313950bbb49674e8a161e61449332d3997089fe3944953f1b77"}, + {file = "bitarray-3.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:165052a0e61c880f7093808a0c524ce1b3555bfa114c0dfb5c809cd07918a60d"}, + {file = "bitarray-3.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:337c8cd46a4c6568d367ed676cbf2d7de16f890bb31dbb54c44c1d6bb6d4a1de"}, + {file = "bitarray-3.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21ca6a47bf20db9e7ad74ca04b3d479e4d76109b68333eb23535553d2705339e"}, + {file = "bitarray-3.8.0-cp312-cp312-win32.whl", hash = "sha256:178c5a4c7fdfb5cd79e372ae7f675390e670f3732e5bc68d327e01a5b3ff8d55"}, + {file = "bitarray-3.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:75a3b6e9c695a6570ea488db75b84bb592ff70a944957efa1c655867c575018b"}, + {file = "bitarray-3.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:5591daf81313096909d973fb2612fccd87528fdfdd39f6478bdce54543178954"}, + {file = "bitarray-3.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18214bac86341f1cc413772e66447d6cca10981e2880b70ecaf4e826c04f95e9"}, + {file = "bitarray-3.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:01c5f0dc080b0ebb432f7a68ee1e88a76bd34f6d89c9568fcec65fb16ed71f0e"}, + {file = "bitarray-3.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86685fa04067f7175f9718489ae755f6acde03593a1a9ca89305554af40e14fd"}, + {file = "bitarray-3.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56896ceeffe25946c4010320629e2d858ca763cd8ded273c81672a5edbcb1e0a"}, + {file = "bitarray-3.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9858dcbc23ba7eaadcd319786b982278a1a2b2020720b19db43e309579ff76fb"}, + {file = "bitarray-3.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa7dec53c25f1949513457ef8b0ea1fb40e76c672cc4d2daa8ad3c8d6b73491a"}, + {file = "bitarray-3.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15a2eff91f54d2b1f573cca8ca6fb58763ce8fea80e7899ab028f3987ef71cd5"}, + {file = "bitarray-3.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b1572ee0eb1967e71787af636bb7d1eb9c6735d5337762c450650e7f51844594"}, + {file = "bitarray-3.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5bfac7f236ba1a4d402644bdce47fb9db02a7cf3214a1f637d3a88390f9e5428"}, + {file = "bitarray-3.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0a55cf02d2cdd739b40ce10c09bbdd520e141217696add7a48b56e67bdfdfe6"}, + {file = "bitarray-3.8.0-cp313-cp313-win32.whl", hash = "sha256:a2ba92f59e30ce915e9e79af37649432e3a212ddddf416d4d686b1b4825bcdb2"}, + {file = "bitarray-3.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f2a5d8006db5a555e06f9437e76bf52537d3dfd130cb8ae2b30866aca32c9"}, + {file = "bitarray-3.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:50ddbe3a7b4b6ab96812f5a4d570f401a2cdb95642fd04c062f98939610bbeee"}, + {file = "bitarray-3.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8cbd4bfc933b33b85c43ef4c1f4d5e3e9d91975ea6368acf5fbac02bac06ea89"}, + {file = "bitarray-3.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9d35d8f8a1c9ed4e2b08187b513f8a3c71958600129db3aa26d85ea3abfd1310"}, + {file = "bitarray-3.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99f55e14e7c56f4fafe1343480c32b110ef03836c21ff7c48bae7add6818f77c"}, + {file = "bitarray-3.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dfbe2aa45b273f49e715c5345d94874cb65a28482bf231af408891c260601b8d"}, + {file = "bitarray-3.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:64af877116edf051375b45f0bda648143176a017b13803ec7b3a3111dc05f4c5"}, + {file = "bitarray-3.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cdfbb27f2c46bb5bbdcee147530cbc5ca8ab858d7693924e88e30ada21b2c5e2"}, + {file = "bitarray-3.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4d73d4948dcc5591d880db8933004e01f1dd2296df9de815354d53469beb26fe"}, + {file = "bitarray-3.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:28a85b056c0eb7f5d864c0ceef07034117e8ebfca756f50648c71950a568ba11"}, + {file = "bitarray-3.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:79ec4498a545733ecace48d780d22407411b07403a2e08b9a4d7596c0b97ebd7"}, + {file = "bitarray-3.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:33af25c4ff7723363cb8404dfc2eefeab4110b654f6c98d26aba8a08c745d860"}, + {file = "bitarray-3.8.0-cp314-cp314-win32.whl", hash = "sha256:2c3bb96b6026643ce24677650889b09073f60b9860a71765f843c99f9ab38b25"}, + {file = "bitarray-3.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:847c7f61964225fc489fe1d49eda7e0e0d253e98862c012cecf845f9ad45cdf4"}, + {file = "bitarray-3.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:a2cb35a6efaa0e3623d8272471371a12c7e07b51a33e5efce9b58f655d864b4e"}, + {file = "bitarray-3.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:15e8d0597cc6e8496de6f4dea2a6880c57e1251502a7072f5631108a1aa28521"}, + {file = "bitarray-3.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8ffe660e963ae711cb9e2b8d8461c9b1ad6167823837fc17d59d5e539fb898fa"}, + {file = "bitarray-3.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4779f356083c62e29b4198d290b7b17a39a69702d150678b7efff0fdddf494a8"}, + {file = "bitarray-3.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:025d133bf4ca8cf75f904eeb8ea946228d7c043231866143f31946a6f4dd0bf3"}, + {file = "bitarray-3.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:451f9958850ea98440d542278368c8d1e1ea821e2494b204570ba34a340759df"}, + {file = "bitarray-3.8.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6d79f659965290af60d6acc8e2716341865fe74609a7ede2a33c2f86ad893b8f"}, + {file = "bitarray-3.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fbf05678c2ae0064fb1b8de7e9e8f0fc30621b73c8477786dd0fb3868044a8c8"}, + {file = "bitarray-3.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:c396358023b876cff547ce87f4e8ff8a2280598873a137e8cc69e115262260b8"}, + {file = "bitarray-3.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed3493a369fe849cce98542d7405c88030b355e4d2e113887cb7ecc86c205773"}, + {file = "bitarray-3.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c764fb167411d5afaef88138542a4bfa28bd5e5ded5e8e42df87cef965efd6e9"}, + {file = "bitarray-3.8.0-cp314-cp314t-win32.whl", hash = "sha256:e12769d3adcc419e65860de946df8d2ed274932177ac1cdb05186e498aaa9149"}, + {file = "bitarray-3.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0ca70ccf789446a6dfde40b482ec21d28067172cd1f8efd50d5548159fccad9e"}, + {file = "bitarray-3.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2a3d1b05ffdd3e95687942ae7b13c63689f85d3f15c39b33329e3cb9ce6c015f"}, + {file = "bitarray-3.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f8d3417db5e14a6789073b21ae44439a755289477901901bae378a57b905e148"}, + {file = "bitarray-3.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f65bd5d4cdb396295b6aa07f84ca659ac65c5c68b53956a6d95219e304b0ada"}, + {file = "bitarray-3.8.0-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f14d6b303e55bd7d19b28309ef8014370e84a3806c5e452e078e7df7344d97a"}, + {file = "bitarray-3.8.0-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c5a8a83df95e51f7a7c2b083eaea134cbed39fc42c6aeb2e764ddb7ccccd43e"}, + {file = "bitarray-3.8.0-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6d70fa9c6d2e955bde8cd327ffc11f2cc34bc21944e5571a46ca501e7eadef24"}, + {file = "bitarray-3.8.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f8069a807a3e6e3c361ce302ece4bf1c3b49962c1726d1d56587e8f48682861"}, + {file = "bitarray-3.8.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a358277122456666a8b2a0b9aa04f1b89d34e8aa41d08a6557d693e6abb6667c"}, + {file = "bitarray-3.8.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:014df8a9430276862392ac5d471697de042367996c49f32d0008585d2c60755a"}, + {file = "bitarray-3.8.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:720963fee259291a88348ae9735d9deb5d334e84a016244f61c89f5a49aa400a"}, + {file = "bitarray-3.8.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:239578587b9c29469ab61149dda40a2fe714a6a4eca0f8ff9ea9439ec4b7bc30"}, + {file = "bitarray-3.8.0-cp38-cp38-win32.whl", hash = "sha256:004d518fa410e6da43386d20e07b576a41eb417ac67abf9f30fa75e125697199"}, + {file = "bitarray-3.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:5338a313f998e1be7267191b7caaae82563b4a2b42b393561055412a34042caa"}, + {file = "bitarray-3.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d2dbe8a3baf2d842e342e8acb06ae3844765d38df67687c144cdeb71f1bcb5d7"}, + {file = "bitarray-3.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff1863f037dad765ef5963efc2e37d399ac023e192a6f2bb394e2377d023cefe"}, + {file = "bitarray-3.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26714898eb0d847aac8af94c4441c9cb50387847d0fe6b9fc4217c086cd68b80"}, + {file = "bitarray-3.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5f2fb10518f6b365f5b720e43a529c3b2324ca02932f609631a44edb347d8d54"}, + {file = "bitarray-3.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1a926fa554870642607fd10e66ee25b75fdd9a7ca4bbffa93d424e4ae2bf734a"}, + {file = "bitarray-3.8.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4902f4ecd5fcb6a5f482d7b0ae1c16c21f26fc5279b3b6127363d13ad8e7a9d9"}, + {file = "bitarray-3.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94652da1a4ca7cfb69c15dd6986b205e0bd9c63a05029c3b48b4201085f527bd"}, + {file = "bitarray-3.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:31a4ad2b730128e273f1c22300da3e3631f125703e4fee0ac44d385abfb15671"}, + {file = "bitarray-3.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:cbba763d99de0255a3e4938f25a8579930ac8aa089233cb2fb2ed7d04d4aff02"}, + {file = "bitarray-3.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46cf239856b87fe1c86dfbb3d459d840a8b1649e7922b1e0bfb6b6464692644a"}, + {file = "bitarray-3.8.0-cp39-cp39-win32.whl", hash = "sha256:2fe8c54b15a9cd4f93bc2aaceab354ec65af93370aa1496ba2f9c537a4855ee0"}, + {file = "bitarray-3.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:58a01ea34057463f7a98a4d6ff40160f65f945e924fec08a5b39e327e372875d"}, + {file = "bitarray-3.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:a60da2f9efbed355edb35a1fb6829148676786c829fad708bb6bb47211b3593a"}, + {file = "bitarray-3.8.0.tar.gz", hash = "sha256:3eae38daffd77c9621ae80c16932eea3fb3a4af141fb7cc724d4ad93eff9210d"}, ] [[package]] name = "bitstring" -version = "4.3.1" +version = "4.4.0" description = "Simple construction, analysis and modification of binary data." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "bitstring-4.3.1-py3-none-any.whl", hash = "sha256:69d1587f0ac18dc7d93fc7e80d5f447161a33e57027e726dc18a0a8bacf1711a"}, - {file = "bitstring-4.3.1.tar.gz", hash = "sha256:a08bc09d3857216d4c0f412a1611056f1cc2b64fd254fb1e8a0afba7cfa1a95a"}, + {file = "bitstring-4.4.0-py3-none-any.whl", hash = "sha256:feac49524fcf3ef27e6081e86f02b10d2adf6c3773bf22fbe0e7eea9534bc737"}, + {file = "bitstring-4.4.0.tar.gz", hash = "sha256:e682ac522bb63e041d16cbc9d0ca86a4f00194db16d0847c7efe066f836b2e37"}, ] [package.dependencies] bitarray = ">=3.0.0,<4.0" +tibs = ">=0.5.6,<0.6" [[package]] name = "black" -version = "25.12.0" +version = "26.3.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "black-25.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f85ba1ad15d446756b4ab5f3044731bf68b777f8f9ac9cdabd2425b97cd9c4e8"}, - {file = "black-25.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546eecfe9a3a6b46f9d69d8a642585a6eaf348bcbbc4d87a19635570e02d9f4a"}, - {file = "black-25.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17dcc893da8d73d8f74a596f64b7c98ef5239c2cd2b053c0f25912c4494bf9ea"}, - {file = "black-25.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:09524b0e6af8ba7a3ffabdfc7a9922fb9adef60fed008c7cd2fc01f3048e6e6f"}, - {file = "black-25.12.0-cp310-cp310-win_arm64.whl", hash = "sha256:b162653ed89eb942758efeb29d5e333ca5bb90e5130216f8369857db5955a7da"}, - {file = "black-25.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0cfa263e85caea2cff57d8f917f9f51adae8e20b610e2b23de35b5b11ce691a"}, - {file = "black-25.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a2f578ae20c19c50a382286ba78bfbeafdf788579b053d8e4980afb079ab9be"}, - {file = "black-25.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e1b65634b0e471d07ff86ec338819e2ef860689859ef4501ab7ac290431f9b"}, - {file = "black-25.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3fa71e3b8dd9f7c6ac4d818345237dfb4175ed3bf37cd5a581dbc4c034f1ec5"}, - {file = "black-25.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:51e267458f7e650afed8445dc7edb3187143003d52a1b710c7321aef22aa9655"}, - {file = "black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a"}, - {file = "black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783"}, - {file = "black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59"}, - {file = "black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892"}, - {file = "black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43"}, - {file = "black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5"}, - {file = "black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f"}, - {file = "black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf"}, - {file = "black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d"}, - {file = "black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce"}, - {file = "black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5"}, - {file = "black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f"}, - {file = "black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f"}, - {file = "black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83"}, - {file = "black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b"}, - {file = "black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828"}, - {file = "black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7"}, + {file = "black-26.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:86a8b5035fce64f5dcd1b794cf8ec4d31fe458cf6ce3986a30deb434df82a1d2"}, + {file = "black-26.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5602bdb96d52d2d0672f24f6ffe5218795736dd34807fd0fd55ccd6bf206168b"}, + {file = "black-26.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c54a4a82e291a1fee5137371ab488866b7c86a3305af4026bdd4dc78642e1ac"}, + {file = "black-26.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:6e131579c243c98f35bce64a7e08e87fb2d610544754675d4a0e73a070a5aa3a"}, + {file = "black-26.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:5ed0ca58586c8d9a487352a96b15272b7fa55d139fc8496b519e78023a8dab0a"}, + {file = "black-26.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28ef38aee69e4b12fda8dba75e21f9b4f979b490c8ac0baa7cb505369ac9e1ff"}, + {file = "black-26.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bf162ed91a26f1adba8efda0b573bc6924ec1408a52cc6f82cb73ec2b142c"}, + {file = "black-26.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:474c27574d6d7037c1bc875a81d9be0a9a4f9ee95e62800dab3cfaadbf75acd5"}, + {file = "black-26.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e9d0d86df21f2e1677cc4bd090cd0e446278bcbbe49bf3659c308c3e402843e"}, + {file = "black-26.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9a5e9f45e5d5e1c5b5c29b3bd4265dcc90e8b92cf4534520896ed77f791f4da5"}, + {file = "black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1"}, + {file = "black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f"}, + {file = "black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7"}, + {file = "black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983"}, + {file = "black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb"}, + {file = "black-26.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:855822d90f884905362f602880ed8b5df1b7e3ee7d0db2502d4388a954cc8c54"}, + {file = "black-26.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8a33d657f3276328ce00e4d37fe70361e1ec7614da5d7b6e78de5426cb56332f"}, + {file = "black-26.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1cd08e99d2f9317292a311dfe578fd2a24b15dbce97792f9c4d752275c1fa56"}, + {file = "black-26.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:c7e72339f841b5a237ff14f7d3880ddd0fc7f98a1199e8c4327f9a4f478c1839"}, + {file = "black-26.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:afc622538b430aa4c8c853f7f63bc582b3b8030fd8c80b70fb5fa5b834e575c2"}, + {file = "black-26.3.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2d6bfaf7fd0993b420bed691f20f9492d53ce9a2bcccea4b797d34e947318a78"}, + {file = "black-26.3.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f89f2ab047c76a9c03f78d0d66ca519e389519902fa27e7a91117ef7611c0568"}, + {file = "black-26.3.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b07fc0dab849d24a80a29cfab8d8a19187d1c4685d8a5e6385a5ce323c1f015f"}, + {file = "black-26.3.1-cp314-cp314-win_amd64.whl", hash = "sha256:0126ae5b7c09957da2bdbd91a9ba1207453feada9e9fe51992848658c6c8e01c"}, + {file = "black-26.3.1-cp314-cp314-win_arm64.whl", hash = "sha256:92c0ec1f2cc149551a2b7b47efc32c866406b6891b0ee4625e95967c8f4acfb1"}, + {file = "black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b"}, + {file = "black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" packaging = ">=22.0" -pathspec = ">=0.9.0" +pathspec = ">=1.0.0" platformdirs = ">=2" -pytokens = ">=0.3.0" +pytokens = ">=0.4.0,<0.5.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} @@ -669,7 +644,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] +uvloop = ["uvloop (>=0.15.2) ; sys_platform != \"win32\"", "winloop (>=0.5.0) ; sys_platform == \"win32\""] [[package]] name = "bolt11" @@ -690,6 +665,19 @@ bitstring = "*" click = "*" coincurve = "*" +[[package]] +name = "boltz-client" +version = "0.4.0" +description = "Boltz Swap library" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"liquid\"" +files = [ + {file = "boltz_client-0.4.0-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:ed0b520209cf1b05a8523002f5d8f26fa29c04d2faecc9cbde3621b4ddc417e6"}, + {file = "boltz_client-0.4.0.tar.gz", hash = "sha256:a3f5a6b637350267856e3ab680cd92158de720fa2d5805fc075e4583d020cb2a"}, +] + [[package]] name = "breez-sdk" version = "0.8.0" @@ -733,249 +721,303 @@ files = [ [[package]] name = "breez-sdk-liquid" -version = "0.11.11" +version = "0.11.13" description = "Python language bindings for the Breez Liquid SDK" optional = true python-versions = "*" groups = ["main"] markers = "extra == \"breez\"" files = [ - {file = "breez_sdk_liquid-0.11.11-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0c1da93d69112cee65c07f1bf3efbcfbb9182c5e3d8933ca27adc659eae064e0"}, - {file = "breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:c2b2d9a04022e05eb56699b6e8a628e7b53676d6f90b1c461c0b1b38b781d952"}, - {file = "breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:6fb44fb16bd55a53fcbd22c7a1982bc8b83de655d0b3e677fe6debd366b41890"}, - {file = "breez_sdk_liquid-0.11.11-cp310-cp310-win32.whl", hash = "sha256:04719223f8b5a44401c02aef6202076e0e557f28476b7cbe787ed9e7947e641a"}, - {file = "breez_sdk_liquid-0.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0d36272277e8d5b0287b45cacce5444934579ae9f6726de377c9de7d4535dc6f"}, - {file = "breez_sdk_liquid-0.11.11-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:4ab4029773e5d2f946872ced5b3c76c5686e00cf6786b9515b707e16691e40dd"}, - {file = "breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:b3ab95f85f7454710c312443d4c0bc96fd1f06a4d3453305eb2fc9c510e9441e"}, - {file = "breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:bf85cecaad3d433ee9af75814a921d5ae582a74c9f4009c8bc865c820b9f8cd9"}, - {file = "breez_sdk_liquid-0.11.11-cp311-cp311-win32.whl", hash = "sha256:f9b0c5393111f7de3511c061f680f94cfd867f6f2e114904c3f5e31fe1fa2824"}, - {file = "breez_sdk_liquid-0.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:7d2862108da64e2b73de46f61ff7d2df5607cbb6bb78a1bc437d19d06caa9f93"}, - {file = "breez_sdk_liquid-0.11.11-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:93faa55da3b4c850b1655b66b8822bd36b40a0491990d31d5d6f9000e0e61521"}, - {file = "breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:337be3e6c59bba6890629fc82e7b8f342bbf19fdb0f9c4a2f0d2aa5e93dfa690"}, - {file = "breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:129baf243381bf5ce4d2927f52dabc68f61f9e173d498ee53d9aef55f4e44fb2"}, - {file = "breez_sdk_liquid-0.11.11-cp312-cp312-win32.whl", hash = "sha256:9acd3eea87c861ed5cde91e188d38e893090d5de925c9ed3c9b21f9be15abe0d"}, - {file = "breez_sdk_liquid-0.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:466824ad3124ef22262ccc5ce76f5cedefd4a2540bb0cd0408e9b2f4e67ac58a"}, - {file = "breez_sdk_liquid-0.11.11-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:3708379531b0273da5da7797d857caf2ee8b3837e003e70d36d2592a98f62ee0"}, - {file = "breez_sdk_liquid-0.11.11-cp313-cp313-manylinux_2_31_aarch64.whl", hash = "sha256:026d33a1fda6d2fc80bc3c6eae7df2924d7bf101050fb71dddfe79a24c6e641a"}, - {file = "breez_sdk_liquid-0.11.11-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:adea3697e464257bc306de8680f82436ae46a6dd3af9390b6a3c55202bba37df"}, - {file = "breez_sdk_liquid-0.11.11-cp313-cp313-win32.whl", hash = "sha256:653b8b06a4f891c4a08901dff49a08c8f9f3624089441c6d3f1e558ee7e137fa"}, - {file = "breez_sdk_liquid-0.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:6becd498285eb7c9a17c3ccf2a2ae02780919f89e968eadab46003ed39c54099"}, - {file = "breez_sdk_liquid-0.11.11-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:978faa63b72f272672dfb77f19617dd80a98f739a40af8748bfa3739e6ff783f"}, - {file = "breez_sdk_liquid-0.11.11-cp38-cp38-manylinux_2_31_aarch64.whl", hash = "sha256:78cd9f069e277274cf708f4bbc1d84b6cc152222b2b56ce0019e3daf4750bc51"}, - {file = "breez_sdk_liquid-0.11.11-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:315074affc1ffe86440fa380367719d623e469205d14b28e42c4f9bc0277836a"}, - {file = "breez_sdk_liquid-0.11.11-cp38-cp38-win32.whl", hash = "sha256:01600323bf8e273a50baac42d431bbb4779ae5108e225c6e4dbee7c535b6d8d1"}, - {file = "breez_sdk_liquid-0.11.11-cp38-cp38-win_amd64.whl", hash = "sha256:ba21c8bb1f674baad81c077abb046c77ec6994bcb3e4c67f48581173c49f8dc2"}, - {file = "breez_sdk_liquid-0.11.11-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:ffa2303c39fb5aa872e88e8d42d1e9e0aeafd97dd3c132d3149d97496cc9e037"}, - {file = "breez_sdk_liquid-0.11.11-cp39-cp39-manylinux_2_31_aarch64.whl", hash = "sha256:0fd15395866c70cffcfbc1faaf2ca0d1e9f602542aefa02dd9f90478dc43ed8d"}, - {file = "breez_sdk_liquid-0.11.11-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:9ee716853388d23466e28b81b79835a9713faba7a7f7648575aa194c9577e080"}, - {file = "breez_sdk_liquid-0.11.11-cp39-cp39-win32.whl", hash = "sha256:f768e0e8326e26bdb92efd2dfb9850d9f6b51868d0a123986b7d70790c9446db"}, - {file = "breez_sdk_liquid-0.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:f8272efaae258167befe98a6551755beda397ed2a7e10b45a795419380e2c345"}, + {file = "breez_sdk_liquid-0.11.13-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:b690f2a1aa7ac4ab2cfd043888f1c31c5c3002e868416b5b589f9206175f7944"}, + {file = "breez_sdk_liquid-0.11.13-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:147c4d3c78417dc73afca419e2edc2a32cd8d849de1861932c391591485a349d"}, + {file = "breez_sdk_liquid-0.11.13-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:3b2cebfeb31ffa32772d43976dfb613167cfcf989efb0af9f62ddec6a6766ea5"}, + {file = "breez_sdk_liquid-0.11.13-cp310-cp310-win32.whl", hash = "sha256:fb6dca31b259b13bcfd03c22600bc2d9496e40d55711a0261c67550f6931ade5"}, + {file = "breez_sdk_liquid-0.11.13-cp310-cp310-win_amd64.whl", hash = "sha256:155f24800e9b393b77f9db74d9ba4772e318765d82c844ce99267b31ec2752b6"}, + {file = "breez_sdk_liquid-0.11.13-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:bf6cb7121218fdd04d7ff5e6038b4b3a3dcd444ee5bfe089c05b7211fd3d8fb1"}, + {file = "breez_sdk_liquid-0.11.13-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:892e07b6c1bfcc4e4e64e13d71699d5bd22ea2214502eef35c5ec4efa8cc67d2"}, + {file = "breez_sdk_liquid-0.11.13-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:727b7f00b5626d2373e81463b51accce5b81e64d6a6fff4fc2ce98a18ba80d0d"}, + {file = "breez_sdk_liquid-0.11.13-cp311-cp311-win32.whl", hash = "sha256:7f3956e2e54514c52ec43d60c9212a0045805c172d1fc2898e9cc7529aa8b391"}, + {file = "breez_sdk_liquid-0.11.13-cp311-cp311-win_amd64.whl", hash = "sha256:c8cc01ccb67e6946033c1fcb59d4eeef7fe5255471abae42923dc13a8cc2b64a"}, + {file = "breez_sdk_liquid-0.11.13-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:71d7ef6a1f968afe11097f4ac3cf6e36f0aa5f808305141140b2aa6ab9002eb3"}, + {file = "breez_sdk_liquid-0.11.13-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:dee2f7ef481ee4989676e4833886f4d893bc5095f96bca0ef58d9954d5a28ce5"}, + {file = "breez_sdk_liquid-0.11.13-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:633c34e2dd4135a9ca029486da3670796c7011818bde8e0c996fcfb37ab42512"}, + {file = "breez_sdk_liquid-0.11.13-cp312-cp312-win32.whl", hash = "sha256:d48e0597b8e20f0c2d33715929ee782a8de7b0ffbccb7820137d7d0d30159be0"}, + {file = "breez_sdk_liquid-0.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:452e0dbc495797d9bbbd4b002816c4ad55eb22d6b6a5a296fdf371238aeb3157"}, + {file = "breez_sdk_liquid-0.11.13-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:4558c89b7f198fcd6c39aac5e4c79ece370d93a21ab47707aab5eb3d0bbec1b4"}, + {file = "breez_sdk_liquid-0.11.13-cp313-cp313-manylinux_2_31_aarch64.whl", hash = "sha256:50a4c41e4189cec5a0d3033bfe44a8668739b4b305f3baa2529f7f3140bb1454"}, + {file = "breez_sdk_liquid-0.11.13-cp313-cp313-manylinux_2_31_x86_64.whl", hash = "sha256:2bd6c193bac99798a3768f85d7b388c51131703fb982036711fe774afe87bb6d"}, + {file = "breez_sdk_liquid-0.11.13-cp313-cp313-win32.whl", hash = "sha256:8c8d05ac039e4314fd3b594f438390d98a9fb1986125c565e5dc828fbea5a54a"}, + {file = "breez_sdk_liquid-0.11.13-cp313-cp313-win_amd64.whl", hash = "sha256:3824b24f35d5a23f7e888ee9e0b7088077228d5c3140638dd8cd528a11e5bbd4"}, + {file = "breez_sdk_liquid-0.11.13-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:6927c26951cc7fabd8df14880bf220ba592603474202e1533020fc86420f9690"}, + {file = "breez_sdk_liquid-0.11.13-cp38-cp38-manylinux_2_31_aarch64.whl", hash = "sha256:00046b4af0163e3699ae6e08063e2f253d4b8977ca0ed1a878b9b8d775490949"}, + {file = "breez_sdk_liquid-0.11.13-cp38-cp38-manylinux_2_31_x86_64.whl", hash = "sha256:ff5b0cfeba853ab4a4354e563bca7d3eff46aca034b54bc59fa9df4531e2c78d"}, + {file = "breez_sdk_liquid-0.11.13-cp38-cp38-win32.whl", hash = "sha256:6f562f56e4b3be21014d57f4feb787a48ba5fb437302f3b6c7d23a19f9b7cb57"}, + {file = "breez_sdk_liquid-0.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:695cc4039c01b36fac7972879971ae071d9103bf68d27759d51b1417a492cabe"}, + {file = "breez_sdk_liquid-0.11.13-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:d5f8ccdcb13f809b83491b87c3d68992c6e109cdc94d6f0966abc04f436f616b"}, + {file = "breez_sdk_liquid-0.11.13-cp39-cp39-manylinux_2_31_aarch64.whl", hash = "sha256:0dc2b4c5eeb02445c34802249237dc488a08b19f6775c2b7894ca95031cf12b5"}, + {file = "breez_sdk_liquid-0.11.13-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:f85527900b335e8388210f525420bfbbb6226656e1670656d3b6c1faa88ba7e0"}, + {file = "breez_sdk_liquid-0.11.13-cp39-cp39-win32.whl", hash = "sha256:59328ef18c42bc708d61377afab0a7119cb83726417b44daaa4409b17f02dbc4"}, + {file = "breez_sdk_liquid-0.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:324a520733e9000c24a517980c753ef0d4045db4f686ba17a62ec83686e07969"}, ] [[package]] name = "certifi" -version = "2025.6.15" +version = "2026.2.25" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"}, - {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"}, + {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, + {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, ] [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, ] [package.dependencies] -pycparser = "*" +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] name = "charset-normalizer" -version = "3.4.2" +version = "3.4.6" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, - {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, - {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, - {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, - {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, - {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, - {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, - {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, - {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, - {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2e1d8ca8611099001949d1cdfaefc510cf0f212484fe7c565f735b68c78c3c95"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e25369dc110d58ddf29b949377a93e0716d72a24f62bad72b2b39f155949c1fd"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:259695e2ccc253feb2a016303543d691825e920917e31f894ca1a687982b1de4"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dda86aba335c902b6149a02a55b38e96287157e609200811837678214ba2b1db"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51fb3c322c81d20567019778cb5a4a6f2dc1c200b886bc0d636238e364848c89"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:4482481cb0572180b6fd976a4d5c72a30263e98564da68b86ec91f0fe35e8565"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39f5068d35621da2881271e5c3205125cc456f54e9030d3f723288c873a71bf9"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8bea55c4eef25b0b19a0337dc4e3f9a15b00d569c77211fa8cde38684f234fb7"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f0cdaecd4c953bfae0b6bb64910aaaca5a424ad9c72d85cb88417bb9814f7550"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:150b8ce8e830eb7ccb029ec9ca36022f756986aaaa7956aad6d9ec90089338c0"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e68c14b04827dd76dcbd1aeea9e604e3e4b78322d8faf2f8132c7138efa340a8"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:3778fd7d7cd04ae8f54651f4a7a0bd6e39a0cf20f801720a4c21d80e9b7ad6b0"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dad6e0f2e481fffdcf776d10ebee25e0ef89f16d691f1e5dee4b586375fdc64b"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-win32.whl", hash = "sha256:74a2e659c7ecbc73562e2a15e05039f1e22c75b7c7618b4b574a3ea9118d1557"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-win_amd64.whl", hash = "sha256:aa9cccf4a44b9b62d8ba8b4dd06c649ba683e4bf04eea606d2e94cfc2d6ff4d6"}, + {file = "charset_normalizer-3.4.6-cp310-cp310-win_arm64.whl", hash = "sha256:e985a16ff513596f217cee86c21371b8cd011c0f6f056d0920aa2d926c544058"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82060f995ab5003a2d6e0f4ad29065b7672b6593c8c63559beefe5b443242c3e"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60c74963d8350241a79cb8feea80e54d518f72c26db618862a8f53e5023deaf9"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e4333fb15c83f7d1482a76d45a0818897b3d33f00efd215528ff7c51b8e35d"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc72863f4d9aba2e8fd9085e63548a324ba706d2ea2c83b260da08a59b9482de"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cc4fc6c196d6a8b76629a70ddfcd4635a6898756e2d9cac5565cf0654605d73"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:0c173ce3a681f309f31b87125fecec7a5d1347261ea11ebbb856fa6006b23c8c"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c907cdc8109f6c619e6254212e794d6548373cc40e1ec75e6e3823d9135d29cc"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:404a1e552cf5b675a87f0651f8b79f5f1e6fd100ee88dc612f89aa16abd4486f"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e3c701e954abf6fc03a49f7c579cc80c2c6cc52525340ca3186c41d3f33482ef"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a6967aaf043bceabab5412ed6bd6bd26603dae84d5cb75bf8d9a74a4959d398"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5feb91325bbceade6afab43eb3b508c63ee53579fe896c77137ded51c6b6958e"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f820f24b09e3e779fe84c3c456cb4108a7aa639b0d1f02c28046e11bfcd088ed"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b35b200d6a71b9839a46b9b7fff66b6638bb52fc9658aa58796b0326595d3021"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-win32.whl", hash = "sha256:9ca4c0b502ab399ef89248a2c84c54954f77a070f28e546a85e91da627d1301e"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:a9e68c9d88823b274cf1e72f28cb5dc89c990edf430b0bfd3e2fb0785bfeabf4"}, + {file = "charset_normalizer-3.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:97d0235baafca5f2b09cf332cc275f021e694e8362c6bb9c96fc9a0eb74fc316"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-win32.whl", hash = "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb"}, + {file = "charset_normalizer-3.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:11afb56037cbc4b1555a34dd69151e8e069bee82e613a73bef6e714ce733585f"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423fb7e748a08f854a08a222b983f4df1912b1daedce51a72bd24fe8f26a1843"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d73beaac5e90173ac3deb9928a74763a6d230f494e4bfb422c217a0ad8e629bf"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d60377dce4511655582e300dc1e5a5f24ba0cb229005a1d5c8d0cb72bb758ab8"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:530e8cebeea0d76bdcf93357aa5e41336f48c3dc709ac52da2bb167c5b8271d9"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:a26611d9987b230566f24a0a125f17fe0de6a6aff9f25c9f564aaa2721a5fb88"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:34315ff4fc374b285ad7f4a0bf7dcbfe769e1b104230d40f49f700d4ab6bbd84"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ddd609f9e1af8c7bd6e2aca279c931aefecd148a14402d4e368f3171769fd"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:80d0a5615143c0b3225e5e3ef22c8d5d51f3f72ce0ea6fb84c943546c7b25b6c"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:92734d4d8d187a354a556626c221cd1a892a4e0802ccb2af432a1d85ec012194"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:613f19aa6e082cf96e17e3ffd89383343d0d589abda756b7764cf78361fd41dc"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2b1a63e8224e401cafe7739f77efd3f9e7f5f2026bda4aead8e59afab537784f"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6cceb5473417d28edd20c6c984ab6fee6c6267d38d906823ebfe20b03d607dc2"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-win32.whl", hash = "sha256:d7de2637729c67d67cf87614b566626057e95c303bc0a55ffe391f5205e7003d"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:572d7c822caf521f0525ba1bce1a622a0b85cf47ffbdae6c9c19e3b5ac3c4389"}, + {file = "charset_normalizer-3.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a4474d924a47185a06411e0064b803c68be044be2d60e50e8bddcc2649957c1f"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:9cc6e6d9e571d2f863fa77700701dae73ed5f78881efc8b3f9a4398772ff53e8"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef5960d965e67165d75b7c7ffc60a83ec5abfc5c11b764ec13ea54fbef8b4421"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b3694e3f87f8ac7ce279d4355645b3c878d24d1424581b46282f24b92f5a4ae2"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5d11595abf8dd942a77883a39d81433739b287b6aa71620f15164f8096221b30"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7bda6eebafd42133efdca535b04ccb338ab29467b3f7bf79569883676fc628db"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:bbc8c8650c6e51041ad1be191742b8b421d05bbd3410f43fa2a00c8db87678e8"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22c6f0c2fbc31e76c3b8a86fba1a56eda6166e238c29cdd3d14befdb4a4e4815"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7edbed096e4a4798710ed6bc75dcaa2a21b68b6c356553ac4823c3658d53743a"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7f9019c9cb613f084481bd6a100b12e1547cf2efe362d873c2e31e4035a6fa43"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:58c948d0d086229efc484fe2f30c2d382c86720f55cd9bc33591774348ad44e0"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:419a9d91bd238052642a51938af8ac05da5b3343becde08d5cdeab9046df9ee1"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5273b9f0b5835ff0350c0828faea623c68bfa65b792720c453e22b25cc72930f"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0e901eb1049fdb80f5bd11ed5ea1e498ec423102f7a9b9e4645d5b8204ff2815"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-win32.whl", hash = "sha256:b4ff1d35e8c5bd078be89349b6f3a845128e685e751b6ea1169cf2160b344c4d"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:74119174722c4349af9708993118581686f343adc1c8c9c007d59be90d077f3f"}, + {file = "charset_normalizer-3.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:e5bcc1a1ae744e0bb59641171ae53743760130600da8db48cbb6e4918e186e4e"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:ad8faf8df23f0378c6d527d8b0b15ea4a2e23c89376877c598c4870d1b2c7866"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5ea69428fa1b49573eef0cc44a1d43bebd45ad0c611eb7d7eac760c7ae771bc"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:06a7e86163334edfc5d20fe104db92fcd666e5a5df0977cb5680a506fe26cc8e"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e1f6e2f00a6b8edb562826e4632e26d063ac10307e80f7461f7de3ad8ef3f077"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:95b52c68d64c1878818687a473a10547b3292e82b6f6fe483808fb1468e2f52f"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:7504e9b7dc05f99a9bbb4525c67a2c155073b44d720470a148b34166a69c054e"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:172985e4ff804a7ad08eebec0a1640ece87ba5041d565fff23c8f99c1f389484"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4be9f4830ba8741527693848403e2c457c16e499100963ec711b1c6f2049b7c7"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:79090741d842f564b1b2827c0b82d846405b744d31e84f18d7a7b41c20e473ff"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:87725cfb1a4f1f8c2fc9890ae2f42094120f4b44db9360be5d99a4c6b0e03a9e"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:fcce033e4021347d80ed9c66dcf1e7b1546319834b74445f561d2e2221de5659"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ca0276464d148c72defa8bb4390cce01b4a0e425f3b50d1435aa6d7a18107602"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:197c1a244a274bb016dd8b79204850144ef77fe81c5b797dc389327adb552407"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-win32.whl", hash = "sha256:2a24157fa36980478dd1770b585c0f30d19e18f4fb0c47c13aa568f871718579"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:cd5e2801c89992ed8c0a3f0293ae83c159a60d9a5d685005383ef4caca77f2c4"}, + {file = "charset_normalizer-3.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:47955475ac79cc504ef2704b192364e51d0d473ad452caedd0002605f780101c"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:659a1e1b500fac8f2779dd9e1570464e012f43e580371470b45277a27baa7532"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f61aa92e4aad0be58eb6eb4e0c21acf32cf8065f4b2cae5665da756c4ceef982"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f50498891691e0864dc3da965f340fada0771f6142a378083dc4608f4ea513e2"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf625105bb9eef28a56a943fec8c8a98aeb80e7d7db99bd3c388137e6eb2d237"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2bd9d128ef93637a5d7a6af25363cf5dec3fa21cf80e68055aad627f280e8afa"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:d08ec48f0a1c48d75d0356cea971921848fb620fdeba805b28f937e90691209f"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ed80ff870ca6de33f4d953fda4d55654b9a2b340ff39ab32fa3adbcd718f264"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f98059e4fcd3e3e4e2d632b7cf81c2faae96c43c60b569e9c621468082f1d104"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:ab30e5e3e706e3063bc6de96b118688cb10396b70bb9864a430f67df98c61ecc"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:d5f5d1e9def3405f60e3ca8232d56f35c98fb7bf581efcc60051ebf53cb8b611"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:461598cd852bfa5a61b09cae2b1c02e2efcd166ee5516e243d540ac24bfa68a7"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:71be7e0e01753a89cf024abf7ecb6bca2c81738ead80d43004d9b5e3f1244e64"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:df01808ee470038c3f8dc4f48620df7225c49c2d6639e38f96e6d6ac6e6f7b0e"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-win32.whl", hash = "sha256:69dd852c2f0ad631b8b60cfbe25a28c0058a894de5abb566619c205ce0550eae"}, + {file = "charset_normalizer-3.4.6-cp38-cp38-win_amd64.whl", hash = "sha256:517ad0e93394ac532745129ceabdf2696b609ec9f87863d337140317ebce1c14"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31215157227939b4fb3d740cd23fe27be0439afef67b785a1eb78a3ae69cba9e"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecbbd45615a6885fe3240eb9db73b9e62518b611850fdf8ab08bd56de7ad2b17"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c45a03a4c69820a399f1dda9e1d8fbf3562eda46e7720458180302021b08f778"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e8aeb10fcbe92767f0fa69ad5a72deca50d0dca07fbde97848997d778a50c9fe"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54fae94be3d75f3e573c9a1b5402dc593de19377013c9a0e4285e3d402dd3a2a"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:2f7fdd9b6e6c529d6a2501a2d36b240109e78a8ceaef5687cfcfa2bbe671d297"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1d02209e06550bdaef34af58e041ad71b88e624f5d825519da3a3308e22687"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8bc5f0687d796c05b1e28ab0d38a50e6309906ee09375dd3aff6a9c09dd6e8f4"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ee4ec14bc1680d6b0afab9aea2ef27e26d2024f18b24a2d7155a52b60da7e833"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d1a2ee9c1499fc8f86f4521f27a973c914b211ffa87322f4ee33bb35392da2c5"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:48696db7f18afb80a068821504296eb0787d9ce239b91ca15059d1d3eaacf13b"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4f41da960b196ea355357285ad1316a00099f22d0929fe168343b99b254729c9"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:802168e03fba8bbc5ce0d866d589e4b1ca751d06edee69f7f3a19c5a9fe6b597"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-win32.whl", hash = "sha256:8761ac29b6c81574724322a554605608a9960769ea83d2c73e396f3df896ad54"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-win_amd64.whl", hash = "sha256:1cf0a70018692f85172348fe06d3a4b63f94ecb055e13a00c644d368eb82e5b8"}, + {file = "charset_normalizer-3.4.6-cp39-cp39-win_arm64.whl", hash = "sha256:3516bbb8d42169de9e61b8520cbeeeb716f12f4ecfe3fd30a9919aa16c806ca8"}, + {file = "charset_normalizer-3.4.6-py3-none-any.whl", hash = "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69"}, + {file = "charset_normalizer-3.4.6.tar.gz", hash = "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6"}, ] [[package]] @@ -1075,104 +1117,118 @@ files = [ [[package]] name = "coverage" -version = "7.13.1" +version = "7.13.5" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "coverage-7.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1fa280b3ad78eea5be86f94f461c04943d942697e0dac889fa18fff8f5f9147"}, - {file = "coverage-7.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c3d8c679607220979434f494b139dfb00131ebf70bb406553d69c1ff01a5c33d"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:339dc63b3eba969067b00f41f15ad161bf2946613156fb131266d8debc8e44d0"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db622b999ffe49cb891f2fff3b340cdc2f9797d01a0a202a0973ba2562501d90"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1443ba9acbb593fa7c1c29e011d7c9761545fe35e7652e85ce7f51a16f7e08d"}, - {file = "coverage-7.13.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c832ec92c4499ac463186af72f9ed4d8daec15499b16f0a879b0d1c8e5cf4a3b"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:562ec27dfa3f311e0db1ba243ec6e5f6ab96b1edfcfc6cf86f28038bc4961ce6"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4de84e71173d4dada2897e5a0e1b7877e5eefbfe0d6a44edee6ce31d9b8ec09e"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a5a68357f686f8c4d527a2dc04f52e669c2fc1cbde38f6f7eb6a0e58cbd17cae"}, - {file = "coverage-7.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:77cc258aeb29a3417062758975521eae60af6f79e930d6993555eeac6a8eac29"}, - {file = "coverage-7.13.1-cp310-cp310-win32.whl", hash = "sha256:bb4f8c3c9a9f34423dba193f241f617b08ffc63e27f67159f60ae6baf2dcfe0f"}, - {file = "coverage-7.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:c8e2706ceb622bc63bac98ebb10ef5da80ed70fbd8a7999a5076de3afaef0fb1"}, - {file = "coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88"}, - {file = "coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf"}, - {file = "coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb"}, - {file = "coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba"}, - {file = "coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19"}, - {file = "coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a"}, - {file = "coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c"}, - {file = "coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3"}, - {file = "coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968"}, - {file = "coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf"}, - {file = "coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c"}, - {file = "coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7"}, - {file = "coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6"}, - {file = "coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c"}, - {file = "coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78"}, - {file = "coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4"}, - {file = "coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398"}, - {file = "coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784"}, - {file = "coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461"}, - {file = "coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500"}, - {file = "coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9"}, - {file = "coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc"}, - {file = "coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1"}, - {file = "coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e"}, - {file = "coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53"}, - {file = "coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842"}, - {file = "coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2"}, - {file = "coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09"}, - {file = "coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894"}, - {file = "coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4"}, - {file = "coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864"}, - {file = "coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9"}, - {file = "coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5"}, - {file = "coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a"}, - {file = "coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0"}, - {file = "coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a"}, - {file = "coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d"}, - {file = "coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7"}, - {file = "coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416"}, - {file = "coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f"}, - {file = "coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79"}, - {file = "coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4"}, - {file = "coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573"}, - {file = "coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd"}, + {file = "coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5"}, + {file = "coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930"}, + {file = "coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0"}, + {file = "coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0"}, + {file = "coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58"}, + {file = "coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d"}, + {file = "coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743"}, + {file = "coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd"}, + {file = "coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8"}, + {file = "coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf"}, + {file = "coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9"}, + {file = "coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01"}, + {file = "coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256"}, + {file = "coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf"}, + {file = "coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c"}, + {file = "coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf"}, + {file = "coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810"}, + {file = "coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ec4af212df513e399cf11610cc27063f1586419e814755ab362e50a85ea69c1"}, + {file = "coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:941617e518602e2d64942c88ec8499f7fbd49d3f6c4327d3a71d43a1973032f3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:da305e9937617ee95c2e39d8ff9f040e0487cbf1ac174f777ed5eddd7a7c1f26"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:78e696e1cc714e57e8b25760b33a8b1026b7048d270140d25dafe1b0a1ee05a3"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02ca0eed225b2ff301c474aeeeae27d26e2537942aa0f87491d3e147e784a82b"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04690832cbea4e4663d9149e05dba142546ca05cb1848816760e7f58285c970a"}, + {file = "coverage-7.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0590e44dd2745c696a778f7bab6aa95256de2cbc8b8cff4f7db8ff09813d6969"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d7cfad2d6d81dd298ab6b89fe72c3b7b05ec7544bdda3b707ddaecff8d25c161"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e092b9499de38ae0fbfbc603a74660eb6ff3e869e507b50d85a13b6db9863e15"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:48c39bc4a04d983a54a705a6389512883d4a3b9862991b3617d547940e9f52b1"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2d3807015f138ffea1ed9afeeb8624fd781703f2858b62a8dd8da5a0994c57b6"}, + {file = "coverage-7.13.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee2aa19e03161671ec964004fb74b2257805d9710bf14a5c704558b9d8dbaf17"}, + {file = "coverage-7.13.5-cp313-cp313-win32.whl", hash = "sha256:ce1998c0483007608c8382f4ff50164bfc5bd07a2246dd272aa4043b75e61e85"}, + {file = "coverage-7.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:631efb83f01569670a5e866ceb80fe483e7c159fac6f167e6571522636104a0b"}, + {file = "coverage-7.13.5-cp313-cp313-win_arm64.whl", hash = "sha256:f4cd16206ad171cbc2470dbea9103cf9a7607d5fe8c242fdf1edf36174020664"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0428cbef5783ad91fe240f673cc1f76b25e74bbfe1a13115e4aa30d3f538162d"}, + {file = "coverage-7.13.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e0b216a19534b2427cc201a26c25da4a48633f29a487c61258643e89d28200c0"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:972a9cd27894afe4bc2b1480107054e062df08e671df7c2f18c205e805ccd806"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4b59148601efcd2bac8c4dbf1f0ad6391693ccf7a74b8205781751637076aee3"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:505d7083c8b0c87a8fa8c07370c285847c1f77739b22e299ad75a6af6c32c5c9"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:60365289c3741e4db327e7baff2a4aaacf22f788e80fa4683393891b70a89fbd"}, + {file = "coverage-7.13.5-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b88c69c8ef5d4b6fe7dea66d6636056a0f6a7527c440e890cf9259011f5e606"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5b13955d31d1633cf9376908089b7cebe7d15ddad7aeaabcbe969a595a97e95e"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f70c9ab2595c56f81a89620e22899eea8b212a4041bd728ac6f4a28bf5d3ddd0"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:084b84a8c63e8d6fc7e3931b316a9bcafca1458d753c539db82d31ed20091a87"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ad14385487393e386e2ea988b09d62dd42c397662ac2dabc3832d71253eee479"}, + {file = "coverage-7.13.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7f2c47b36fe7709a6e83bfadf4eefb90bd25fbe4014d715224c4316f808e59a2"}, + {file = "coverage-7.13.5-cp313-cp313t-win32.whl", hash = "sha256:67e9bc5449801fad0e5dff329499fb090ba4c5800b86805c80617b4e29809b2a"}, + {file = "coverage-7.13.5-cp313-cp313t-win_amd64.whl", hash = "sha256:da86cdcf10d2519e10cabb8ac2de03da1bcb6e4853790b7fbd48523332e3a819"}, + {file = "coverage-7.13.5-cp313-cp313t-win_arm64.whl", hash = "sha256:0ecf12ecb326fe2c339d93fc131816f3a7367d223db37817208905c89bded911"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f"}, + {file = "coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6"}, + {file = "coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0"}, + {file = "coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0"}, + {file = "coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc"}, + {file = "coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633"}, + {file = "coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b"}, + {file = "coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90"}, + {file = "coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea"}, + {file = "coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a"}, + {file = "coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215"}, + {file = "coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43"}, + {file = "coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45"}, + {file = "coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61"}, + {file = "coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179"}, ] [package.dependencies] @@ -1183,87 +1239,105 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "42.0.8" +version = "46.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false -python-versions = ">=3.7" +python-versions = "!=3.9.0,!=3.9.1,>=3.8" groups = ["main"] files = [ - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, - {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, - {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, - {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, - {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, - {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, - {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, - {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, - {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, - {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, - {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, - {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, - {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, - {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, + {file = "cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731"}, + {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82"}, + {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1"}, + {file = "cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48"}, + {file = "cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4"}, + {file = "cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663"}, + {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826"}, + {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d"}, + {file = "cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a"}, + {file = "cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4"}, + {file = "cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c"}, + {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4"}, + {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9"}, + {file = "cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72"}, + {file = "cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7"}, + {file = "cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d"}, ] [package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} [package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] name = "deprecated" -version = "1.2.18" +version = "1.3.1" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" groups = ["main"] files = [ - {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, - {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, + {file = "deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f"}, + {file = "deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223"}, ] [package.dependencies] -wrapt = ">=1.10,<2" +wrapt = ">=1.10,<3" [package.extras] dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, ] [[package]] @@ -1280,54 +1354,35 @@ files = [ [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" description = "DNS toolkit" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, - {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, + {file = "dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af"}, + {file = "dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=43)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=1.0.0)"] -idna = ["idna (>=3.7)"] -trio = ["trio (>=0.23)"] -wmi = ["wmi (>=1.5.1)"] - -[[package]] -name = "ecdsa" -version = "0.19.1" -description = "ECDSA cryptographic signature library (pure python)" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.6" -groups = ["main"] -files = [ - {file = "ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3"}, - {file = "ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61"}, -] - -[package.dependencies] -six = ">=1.9.0" - -[package.extras] -gmpy = ["gmpy"] -gmpy2 = ["gmpy2"] +dev = ["black (>=25.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.17.0)", "mypy (>=1.17)", "pylint (>=3)", "pytest (>=8.4)", "pytest-cov (>=6.2.0)", "quart-trio (>=0.12.0)", "sphinx (>=8.2.0)", "sphinx-rtd-theme (>=3.0.0)", "twine (>=6.1.0)", "wheel (>=0.45.0)"] +dnssec = ["cryptography (>=45)"] +doh = ["h2 (>=4.2.0)", "httpcore (>=1.0.0)", "httpx (>=0.28.0)"] +doq = ["aioquic (>=1.2.0)"] +idna = ["idna (>=3.10)"] +trio = ["trio (>=0.30)"] +wmi = ["wmi (>=1.5.1) ; platform_system == \"Windows\""] [[package]] name = "email-validator" -version = "2.2.0" +version = "2.3.0" description = "A robust email address syntax and deliverability validation library." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, - {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, + {file = "email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4"}, + {file = "email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426"}, ] [package.dependencies] @@ -1350,15 +1405,15 @@ dev = ["black", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mypy", "pr [[package]] name = "exceptiongroup" -version = "1.3.0" +version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main", "dev"] markers = "python_version == \"3.10\"" files = [ - {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, - {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, ] [package.dependencies] @@ -1369,19 +1424,19 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.116.1" +version = "0.116.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565"}, - {file = "fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143"}, + {file = "fastapi-0.116.2-py3-none-any.whl", hash = "sha256:c3a7a8fb830b05f7e087d920e0d786ca1fc9892eb4e9a84b227be4c1bc7569db"}, + {file = "fastapi-0.116.2.tar.gz", hash = "sha256:231a6af2fe21cfa2c32730170ad8514985fc250bec16c9b242d3b94c835ef529"}, ] [package.dependencies] pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.40.0,<0.48.0" +starlette = ">=0.40.0,<0.49.0" typing-extensions = ">=4.8.0" [package.extras] @@ -1410,14 +1465,14 @@ pyjwt = ">=2.10.1,<3.0.0" [[package]] name = "filelock" -version = "3.20.3" +version = "3.25.2" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1"}, - {file = "filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1"}, + {file = "filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70"}, + {file = "filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694"}, ] [[package]] @@ -1434,174 +1489,205 @@ files = [ [[package]] name = "frozenlist" -version = "1.7.0" +version = "1.8.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a"}, - {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61"}, - {file = "frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615"}, - {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd"}, - {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718"}, - {file = "frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e"}, - {file = "frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464"}, - {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a"}, - {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750"}, - {file = "frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86"}, - {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898"}, - {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56"}, - {file = "frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7"}, - {file = "frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d"}, - {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2"}, - {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb"}, - {file = "frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e"}, - {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08"}, - {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43"}, - {file = "frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3"}, - {file = "frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a"}, - {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee"}, - {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d"}, - {file = "frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60"}, - {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b"}, - {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e"}, - {file = "frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1"}, - {file = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"}, - {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d"}, - {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d"}, - {file = "frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384"}, - {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104"}, - {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf"}, - {file = "frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81"}, - {file = "frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e"}, - {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cea3dbd15aea1341ea2de490574a4a37ca080b2ae24e4b4f4b51b9057b4c3630"}, - {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d536ee086b23fecc36c2073c371572374ff50ef4db515e4e503925361c24f71"}, - {file = "frozenlist-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dfcebf56f703cb2e346315431699f00db126d158455e513bd14089d992101e44"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974c5336e61d6e7eb1ea5b929cb645e882aadab0095c5a6974a111e6479f8878"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c70db4a0ab5ab20878432c40563573229a7ed9241506181bba12f6b7d0dc41cb"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1137b78384eebaf70560a36b7b229f752fb64d463d38d1304939984d5cb887b6"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e793a9f01b3e8b5c0bc646fb59140ce0efcc580d22a3468d70766091beb81b35"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74739ba8e4e38221d2c5c03d90a7e542cb8ad681915f4ca8f68d04f810ee0a87"}, - {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e63344c4e929b1a01e29bc184bbb5fd82954869033765bfe8d65d09e336a677"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ea2a7369eb76de2217a842f22087913cdf75f63cf1307b9024ab82dfb525938"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:836b42f472a0e006e02499cef9352ce8097f33df43baaba3e0a28a964c26c7d2"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e22b9a99741294b2571667c07d9f8cceec07cb92aae5ccda39ea1b6052ed4319"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:9a19e85cc503d958abe5218953df722748d87172f71b73cf3c9257a91b999890"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f22dac33bb3ee8fe3e013aa7b91dc12f60d61d05b7fe32191ffa84c3aafe77bd"}, - {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ccec739a99e4ccf664ea0775149f2749b8a6418eb5b8384b4dc0a7d15d304cb"}, - {file = "frozenlist-1.7.0-cp39-cp39-win32.whl", hash = "sha256:b3950f11058310008a87757f3eee16a8e1ca97979833239439586857bc25482e"}, - {file = "frozenlist-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:43a82fce6769c70f2f5a06248b614a7d268080a9d20f7457ef10ecee5af82b63"}, - {file = "frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e"}, - {file = "frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, + {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, + {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, + {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, + {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, + {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, + {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, + {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, + {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, + {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, + {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, + {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, + {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, + {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, + {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, + {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, + {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, + {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, + {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, + {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, + {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, + {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, + {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, + {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, + {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, + {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, + {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, + {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, + {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, + {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, + {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, + {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, + {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, + {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, + {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, + {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, + {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, + {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, + {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, + {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, ] [[package]] name = "greenlet" -version = "3.3.0" +version = "3.3.2" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.10" -groups = ["main"] +groups = ["main", "dev"] files = [ - {file = "greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d"}, - {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb"}, - {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd"}, - {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b"}, - {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5"}, - {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9"}, - {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d"}, - {file = "greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082"}, - {file = "greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e"}, - {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62"}, - {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32"}, - {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45"}, - {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948"}, - {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794"}, - {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5"}, - {file = "greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71"}, - {file = "greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb"}, - {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3"}, - {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655"}, - {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7"}, - {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b"}, - {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53"}, - {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614"}, - {file = "greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39"}, - {file = "greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739"}, - {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808"}, - {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54"}, - {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492"}, - {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527"}, - {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39"}, - {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8"}, - {file = "greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38"}, - {file = "greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f"}, - {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365"}, - {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3"}, - {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45"}, - {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955"}, - {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55"}, - {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc"}, - {file = "greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170"}, - {file = "greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931"}, - {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388"}, - {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3"}, - {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221"}, - {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b"}, - {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd"}, - {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9"}, - {file = "greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb"}, + {file = "greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7"}, + {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f"}, + {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef"}, + {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca"}, + {file = "greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f"}, + {file = "greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2"}, + {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358"}, + {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99"}, + {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be"}, + {file = "greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5"}, + {file = "greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd"}, + {file = "greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb"}, + {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070"}, + {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79"}, + {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395"}, + {file = "greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f"}, + {file = "greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643"}, + {file = "greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd"}, + {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab"}, + {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a"}, + {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b"}, + {file = "greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124"}, + {file = "greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327"}, + {file = "greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9"}, + {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506"}, + {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce"}, + {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5"}, + {file = "greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492"}, + {file = "greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71"}, + {file = "greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf"}, + {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4"}, + {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727"}, + {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e"}, + {file = "greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a"}, + {file = "greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2"}, ] [package.extras] @@ -1837,14 +1923,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "identify" -version = "2.6.12" +version = "2.6.18" description = "File identification library for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2"}, - {file = "identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6"}, + {file = "identify-2.6.18-py2.py3-none-any.whl", hash = "sha256:8db9d3c8ea9079db92cafb0ebf97abdc09d52e97f4dcf773a2e694048b7cd737"}, + {file = "identify-2.6.18.tar.gz", hash = "sha256:873ac56a5e3fd63e7438a7ecbc4d91aca692eb3fefa4534db2b7913f3fc352fd"}, ] [package.extras] @@ -1852,14 +1938,14 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.10" +version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" groups = ["main", "dev"] files = [ - {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, - {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, + {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, + {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, ] [package.extras] @@ -1867,14 +1953,14 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "iniconfig" -version = "2.1.0" +version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, - {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, + {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, + {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] [[package]] @@ -1909,89 +1995,114 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.10.0" +version = "0.13.0" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303"}, - {file = "jiter-0.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32bb468e3af278f095d3fa5b90314728a6916d89ba3d0ffb726dd9bf7367285e"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8b3e0068c26ddedc7abc6fac37da2d0af16b921e288a5a613f4b86f050354f"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:286299b74cc49e25cd42eea19b72aa82c515d2f2ee12d11392c56d8701f52224"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ed5649ceeaeffc28d87fb012d25a4cd356dcd53eff5acff1f0466b831dda2a7"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2ab0051160cb758a70716448908ef14ad476c3774bd03ddce075f3c1f90a3d6"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03997d2f37f6b67d2f5c475da4412be584e1cec273c1cfc03d642c46db43f8cf"}, - {file = "jiter-0.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c404a99352d839fed80d6afd6c1d66071f3bacaaa5c4268983fc10f769112e90"}, - {file = "jiter-0.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66e989410b6666d3ddb27a74c7e50d0829704ede652fd4c858e91f8d64b403d0"}, - {file = "jiter-0.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b532d3af9ef4f6374609a3bcb5e05a1951d3bf6190dc6b176fdb277c9bbf15ee"}, - {file = "jiter-0.10.0-cp310-cp310-win32.whl", hash = "sha256:da9be20b333970e28b72edc4dff63d4fec3398e05770fb3205f7fb460eb48dd4"}, - {file = "jiter-0.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:f59e533afed0c5b0ac3eba20d2548c4a550336d8282ee69eb07b37ea526ee4e5"}, - {file = "jiter-0.10.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3bebe0c558e19902c96e99217e0b8e8b17d570906e72ed8a87170bc290b1e978"}, - {file = "jiter-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:558cc7e44fd8e507a236bee6a02fa17199ba752874400a0ca6cd6e2196cdb7dc"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d613e4b379a07d7c8453c5712ce7014e86c6ac93d990a0b8e7377e18505e98d"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f62cf8ba0618eda841b9bf61797f21c5ebd15a7a1e19daab76e4e4b498d515b2"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:919d139cdfa8ae8945112398511cb7fca58a77382617d279556b344867a37e61"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13ddbc6ae311175a3b03bd8994881bc4635c923754932918e18da841632349db"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c440ea003ad10927a30521a9062ce10b5479592e8a70da27f21eeb457b4a9c5"}, - {file = "jiter-0.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc347c87944983481e138dea467c0551080c86b9d21de6ea9306efb12ca8f606"}, - {file = "jiter-0.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:13252b58c1f4d8c5b63ab103c03d909e8e1e7842d302473f482915d95fefd605"}, - {file = "jiter-0.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7d1bbf3c465de4a24ab12fb7766a0003f6f9bce48b8b6a886158c4d569452dc5"}, - {file = "jiter-0.10.0-cp311-cp311-win32.whl", hash = "sha256:db16e4848b7e826edca4ccdd5b145939758dadf0dc06e7007ad0e9cfb5928ae7"}, - {file = "jiter-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c9c1d5f10e18909e993f9641f12fe1c77b3e9b533ee94ffa970acc14ded3812"}, - {file = "jiter-0.10.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1e274728e4a5345a6dde2d343c8da018b9d4bd4350f5a472fa91f66fda44911b"}, - {file = "jiter-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7202ae396446c988cb2a5feb33a543ab2165b786ac97f53b59aafb803fef0744"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ba7722d6748b6920ed02a8f1726fb4b33e0fd2f3f621816a8b486c66410ab2"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:371eab43c0a288537d30e1f0b193bc4eca90439fc08a022dd83e5e07500ed026"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c675736059020365cebc845a820214765162728b51ab1e03a1b7b3abb70f74c"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c5867d40ab716e4684858e4887489685968a47e3ba222e44cde6e4a2154f959"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395bb9a26111b60141757d874d27fdea01b17e8fac958b91c20128ba8f4acc8a"}, - {file = "jiter-0.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6842184aed5cdb07e0c7e20e5bdcfafe33515ee1741a6835353bb45fe5d1bd95"}, - {file = "jiter-0.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62755d1bcea9876770d4df713d82606c8c1a3dca88ff39046b85a048566d56ea"}, - {file = "jiter-0.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533efbce2cacec78d5ba73a41756beff8431dfa1694b6346ce7af3a12c42202b"}, - {file = "jiter-0.10.0-cp312-cp312-win32.whl", hash = "sha256:8be921f0cadd245e981b964dfbcd6fd4bc4e254cdc069490416dd7a2632ecc01"}, - {file = "jiter-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7c7d785ae9dda68c2678532a5a1581347e9c15362ae9f6e68f3fdbfb64f2e49"}, - {file = "jiter-0.10.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e0588107ec8e11b6f5ef0e0d656fb2803ac6cf94a96b2b9fc675c0e3ab5e8644"}, - {file = "jiter-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cafc4628b616dc32530c20ee53d71589816cf385dd9449633e910d596b1f5c8a"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:520ef6d981172693786a49ff5b09eda72a42e539f14788124a07530f785c3ad6"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dedfd05937f8fc45d17ebdf298fe7e0c77458232bcb73d9fbbf4c6455f5b3"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc299da7789deacf95f64052d97f75c16d4fc8c4c214a22bf8d859a4288a1c2"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5161e201172de298a8a1baad95eb85db4fb90e902353b1f6a41d64ea64644e25"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e2227db6ba93cb3e2bf67c87e594adde0609f146344e8207e8730364db27041"}, - {file = "jiter-0.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15acb267ea5e2c64515574b06a8bf393fbfee6a50eb1673614aa45f4613c0cca"}, - {file = "jiter-0.10.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:901b92f2e2947dc6dfcb52fd624453862e16665ea909a08398dde19c0731b7f4"}, - {file = "jiter-0.10.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d0cb9a125d5a3ec971a094a845eadde2db0de85b33c9f13eb94a0c63d463879e"}, - {file = "jiter-0.10.0-cp313-cp313-win32.whl", hash = "sha256:48a403277ad1ee208fb930bdf91745e4d2d6e47253eedc96e2559d1e6527006d"}, - {file = "jiter-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4"}, - {file = "jiter-0.10.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:28ed2a4c05a1f32ef0e1d24c2611330219fed727dae01789f4a335617634b1ca"}, - {file = "jiter-0.10.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a4c418b1ec86a195f1ca69da8b23e8926c752b685af665ce30777233dfe070"}, - {file = "jiter-0.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d7bfed2fe1fe0e4dda6ef682cee888ba444b21e7a6553e03252e4feb6cf0adca"}, - {file = "jiter-0.10.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:5e9251a5e83fab8d87799d3e1a46cb4b7f2919b895c6f4483629ed2446f66522"}, - {file = "jiter-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:023aa0204126fe5b87ccbcd75c8a0d0261b9abdbbf46d55e7ae9f8e22424eeb8"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c189c4f1779c05f75fc17c0c1267594ed918996a231593a21a5ca5438445216"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15720084d90d1098ca0229352607cd68256c76991f6b374af96f36920eae13c4"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4f2fb68e5f1cfee30e2b2a09549a00683e0fde4c6a2ab88c94072fc33cb7426"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce541693355fc6da424c08b7edf39a2895f58d6ea17d92cc2b168d20907dee12"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31c50c40272e189d50006ad5c73883caabb73d4e9748a688b216e85a9a9ca3b9"}, - {file = "jiter-0.10.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa3402a2ff9815960e0372a47b75c76979d74402448509ccd49a275fa983ef8a"}, - {file = "jiter-0.10.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:1956f934dca32d7bb647ea21d06d93ca40868b505c228556d3373cbd255ce853"}, - {file = "jiter-0.10.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:fcedb049bdfc555e261d6f65a6abe1d5ad68825b7202ccb9692636c70fcced86"}, - {file = "jiter-0.10.0-cp314-cp314-win32.whl", hash = "sha256:ac509f7eccca54b2a29daeb516fb95b6f0bd0d0d8084efaf8ed5dfc7b9f0b357"}, - {file = "jiter-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5ed975b83a2b8639356151cef5c0d597c68376fc4922b45d0eb384ac058cfa00"}, - {file = "jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5"}, - {file = "jiter-0.10.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bd6292a43c0fc09ce7c154ec0fa646a536b877d1e8f2f96c19707f65355b5a4d"}, - {file = "jiter-0.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39de429dcaeb6808d75ffe9effefe96a4903c6a4b376b2f6d08d77c1aaee2f18"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52ce124f13a7a616fad3bb723f2bfb537d78239d1f7f219566dc52b6f2a9e48d"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:166f3606f11920f9a1746b2eea84fa2c0a5d50fd313c38bdea4edc072000b0af"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28dcecbb4ba402916034fc14eba7709f250c4d24b0c43fc94d187ee0580af181"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86c5aa6910f9bebcc7bc4f8bc461aff68504388b43bfe5e5c0bd21efa33b52f4"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceeb52d242b315d7f1f74b441b6a167f78cea801ad7c11c36da77ff2d42e8a28"}, - {file = "jiter-0.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ff76d8887c8c8ee1e772274fcf8cc1071c2c58590d13e33bd12d02dc9a560397"}, - {file = "jiter-0.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a9be4d0fa2b79f7222a88aa488bd89e2ae0a0a5b189462a12def6ece2faa45f1"}, - {file = "jiter-0.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ab7fd8738094139b6c1ab1822d6f2000ebe41515c537235fd45dabe13ec9324"}, - {file = "jiter-0.10.0-cp39-cp39-win32.whl", hash = "sha256:5f51e048540dd27f204ff4a87f5d79294ea0aa3aa552aca34934588cf27023cf"}, - {file = "jiter-0.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b28302349dc65703a9e4ead16f163b1c339efffbe1049c30a44b001a2a4fff9"}, - {file = "jiter-0.10.0.tar.gz", hash = "sha256:07a7142c38aacc85194391108dc91b5b57093c978a9932bd86a36862759d9500"}, + {file = "jiter-0.13.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2ffc63785fd6c7977defe49b9824ae6ce2b2e2b77ce539bdaf006c26da06342e"}, + {file = "jiter-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4a638816427006c1e3f0013eb66d391d7a3acda99a7b0cf091eff4497ccea33a"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19928b5d1ce0ff8c1ee1b9bdef3b5bfc19e8304f1b904e436caf30bc15dc6cf5"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:309549b778b949d731a2f0e1594a3f805716be704a73bf3ad9a807eed5eb5721"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcdabaea26cb04e25df3103ce47f97466627999260290349a88c8136ecae0060"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a3a377af27b236abbf665a69b2bdd680e3b5a0bd2af825cd3b81245279a7606c"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe49d3ff6db74321f144dff9addd4a5874d3105ac5ba7c5b77fac099cfae31ae"}, + {file = "jiter-0.13.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2113c17c9a67071b0f820733c0893ed1d467b5fcf4414068169e5c2cabddb1e2"}, + {file = "jiter-0.13.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ab1185ca5c8b9491b55ebf6c1e8866b8f68258612899693e24a92c5fdb9455d5"}, + {file = "jiter-0.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9621ca242547edc16400981ca3231e0c91c0c4c1ab8573a596cd9bb3575d5c2b"}, + {file = "jiter-0.13.0-cp310-cp310-win32.whl", hash = "sha256:a7637d92b1c9d7a771e8c56f445c7f84396d48f2e756e5978840ecba2fac0894"}, + {file = "jiter-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c1b609e5cbd2f52bb74fb721515745b407df26d7b800458bd97cb3b972c29e7d"}, + {file = "jiter-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ea026e70a9a28ebbdddcbcf0f1323128a8db66898a06eaad3a4e62d2f554d096"}, + {file = "jiter-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66aa3e663840152d18cc8ff1e4faad3dd181373491b9cfdc6004b92198d67911"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3524798e70655ff19aec58c7d05adb1f074fecff62da857ea9be2b908b6d701"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec7e287d7fbd02cb6e22f9a00dd9c9cd504c40a61f2c61e7e1f9690a82726b4c"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47455245307e4debf2ce6c6e65a717550a0244231240dcf3b8f7d64e4c2f22f4"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ee9da221dca6e0429c2704c1b3655fe7b025204a71d4d9b73390c759d776d165"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24ab43126d5e05f3d53a36a8e11eb2f23304c6c1117844aaaf9a0aa5e40b5018"}, + {file = "jiter-0.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9da38b4fedde4fb528c740c2564628fbab737166a0e73d6d46cb4bb5463ff411"}, + {file = "jiter-0.13.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0b34c519e17658ed88d5047999a93547f8889f3c1824120c26ad6be5f27b6cf5"}, + {file = "jiter-0.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2a6394e6af690d462310a86b53c47ad75ac8c21dc79f120714ea449979cb1d3"}, + {file = "jiter-0.13.0-cp311-cp311-win32.whl", hash = "sha256:0f0c065695f616a27c920a56ad0d4fc46415ef8b806bf8fc1cacf25002bd24e1"}, + {file = "jiter-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:0733312953b909688ae3c2d58d043aa040f9f1a6a75693defed7bc2cc4bf2654"}, + {file = "jiter-0.13.0-cp311-cp311-win_arm64.whl", hash = "sha256:5d9b34ad56761b3bf0fbe8f7e55468704107608512350962d3317ffd7a4382d5"}, + {file = "jiter-0.13.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0a2bd69fc1d902e89925fc34d1da51b2128019423d7b339a45d9e99c894e0663"}, + {file = "jiter-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f917a04240ef31898182f76a332f508f2cc4b57d2b4d7ad2dbfebbfe167eb505"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1e2b199f446d3e82246b4fd9236d7cb502dc2222b18698ba0d986d2fecc6152"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04670992b576fa65bd056dbac0c39fe8bd67681c380cb2b48efa885711d9d726"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a1aff1fbdb803a376d4d22a8f63f8e7ccbce0b4890c26cc7af9e501ab339ef0"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b3fb8c2053acaef8580809ac1d1f7481a0a0bdc012fd7f5d8b18fb696a5a089"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdaba7d87e66f26a2c45d8cbadcbfc4bf7884182317907baf39cfe9775bb4d93"}, + {file = "jiter-0.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b88d649135aca526da172e48083da915ec086b54e8e73a425ba50999468cc08"}, + {file = "jiter-0.13.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e404ea551d35438013c64b4f357b0474c7abf9f781c06d44fcaf7a14c69ff9e2"}, + {file = "jiter-0.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1f4748aad1b4a93c8bdd70f604d0f748cdc0e8744c5547798acfa52f10e79228"}, + {file = "jiter-0.13.0-cp312-cp312-win32.whl", hash = "sha256:0bf670e3b1445fc4d31612199f1744f67f889ee1bbae703c4b54dc097e5dd394"}, + {file = "jiter-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:15db60e121e11fe186c0b15236bd5d18381b9ddacdcf4e659feb96fc6c969c92"}, + {file = "jiter-0.13.0-cp312-cp312-win_arm64.whl", hash = "sha256:41f92313d17989102f3cb5dd533a02787cdb99454d494344b0361355da52fcb9"}, + {file = "jiter-0.13.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1f8a55b848cbabf97d861495cd65f1e5c590246fabca8b48e1747c4dfc8f85bf"}, + {file = "jiter-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f556aa591c00f2c45eb1b89f68f52441a016034d18b65da60e2d2875bbbf344a"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7e1d61da332ec412350463891923f960c3073cf1aae93b538f0bb4c8cd46efb"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3097d665a27bc96fd9bbf7f86178037db139f319f785e4757ce7ccbf390db6c2"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d01ecc3a8cbdb6f25a37bd500510550b64ddf9f7d64a107d92f3ccb25035d0f"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed9bbc30f5d60a3bdf63ae76beb3f9db280d7f195dfcfa61af792d6ce912d159"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fbafb6e88256f4454de33c1f40203d09fc33ed19162a68b3b257b29ca7f663"}, + {file = "jiter-0.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5467696f6b827f1116556cb0db620440380434591e93ecee7fd14d1a491b6daa"}, + {file = "jiter-0.13.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:2d08c9475d48b92892583df9da592a0e2ac49bcd41fae1fec4f39ba6cf107820"}, + {file = "jiter-0.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:aed40e099404721d7fcaf5b89bd3b4568a4666358bcac7b6b15c09fb6252ab68"}, + {file = "jiter-0.13.0-cp313-cp313-win32.whl", hash = "sha256:36ebfbcffafb146d0e6ffb3e74d51e03d9c35ce7c625c8066cdbfc7b953bdc72"}, + {file = "jiter-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:8d76029f077379374cf0dbc78dbe45b38dec4a2eb78b08b5194ce836b2517afc"}, + {file = "jiter-0.13.0-cp313-cp313-win_arm64.whl", hash = "sha256:bb7613e1a427cfcb6ea4544f9ac566b93d5bf67e0d48c787eca673ff9c9dff2b"}, + {file = "jiter-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fa476ab5dd49f3bf3a168e05f89358c75a17608dbabb080ef65f96b27c19ab10"}, + {file = "jiter-0.13.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade8cb6ff5632a62b7dbd4757d8c5573f7a2e9ae285d6b5b841707d8363205ef"}, + {file = "jiter-0.13.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9950290340acc1adaded363edd94baebcee7dabdfa8bee4790794cd5cfad2af6"}, + {file = "jiter-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2b4972c6df33731aac0742b64fd0d18e0a69bc7d6e03108ce7d40c85fd9e3e6d"}, + {file = "jiter-0.13.0-cp313-cp313t-win_arm64.whl", hash = "sha256:701a1e77d1e593c1b435315ff625fd071f0998c5f02792038a5ca98899261b7d"}, + {file = "jiter-0.13.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:cc5223ab19fe25e2f0bf2643204ad7318896fe3729bf12fde41b77bfc4fafff0"}, + {file = "jiter-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9776ebe51713acf438fd9b4405fcd86893ae5d03487546dae7f34993217f8a91"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:879e768938e7b49b5e90b7e3fecc0dbec01b8cb89595861fb39a8967c5220d09"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:682161a67adea11e3aae9038c06c8b4a9a71023228767477d683f69903ebc607"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a13b68cd1cd8cc9de8f244ebae18ccb3e4067ad205220ef324c39181e23bbf66"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87ce0f14c6c08892b610686ae8be350bf368467b6acd5085a5b65441e2bf36d2"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c365005b05505a90d1c47856420980d0237adf82f70c4aff7aebd3c1cc143ad"}, + {file = "jiter-0.13.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1317fdffd16f5873e46ce27d0e0f7f4f90f0cdf1d86bf6abeaea9f63ca2c401d"}, + {file = "jiter-0.13.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c05b450d37ba0c9e21c77fef1f205f56bcee2330bddca68d344baebfc55ae0df"}, + {file = "jiter-0.13.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:775e10de3849d0631a97c603f996f518159272db00fdda0a780f81752255ee9d"}, + {file = "jiter-0.13.0-cp314-cp314-win32.whl", hash = "sha256:632bf7c1d28421c00dd8bbb8a3bac5663e1f57d5cd5ed962bce3c73bf62608e6"}, + {file = "jiter-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:f22ef501c3f87ede88f23f9b11e608581c14f04db59b6a801f354397ae13739f"}, + {file = "jiter-0.13.0-cp314-cp314-win_arm64.whl", hash = "sha256:07b75fe09a4ee8e0c606200622e571e44943f47254f95e2436c8bdcaceb36d7d"}, + {file = "jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:964538479359059a35fb400e769295d4b315ae61e4105396d355a12f7fef09f0"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e104da1db1c0991b3eaed391ccd650ae8d947eab1480c733e5a3fb28d4313e40"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e3a5f0cde8ff433b8e88e41aa40131455420fb3649a3c7abdda6145f8cb7202"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57aab48f40be1db920a582b30b116fe2435d184f77f0e4226f546794cedd9cf0"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7772115877c53f62beeb8fd853cab692dbc04374ef623b30f997959a4c0e7e95"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1211427574b17b633cfceba5040de8081e5abf114f7a7602f73d2e16f9fdaa59"}, + {file = "jiter-0.13.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7beae3a3d3b5212d3a55d2961db3c292e02e302feb43fce6a3f7a31b90ea6dfe"}, + {file = "jiter-0.13.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e5562a0f0e90a6223b704163ea28e831bd3a9faa3512a711f031611e6b06c939"}, + {file = "jiter-0.13.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:6c26a424569a59140fb51160a56df13f438a2b0967365e987889186d5fc2f6f9"}, + {file = "jiter-0.13.0-cp314-cp314t-win32.whl", hash = "sha256:24dc96eca9f84da4131cdf87a95e6ce36765c3b156fc9ae33280873b1c32d5f6"}, + {file = "jiter-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0a8d76c7524087272c8ae913f5d9d608bd839154b62c4322ef65723d2e5bb0b8"}, + {file = "jiter-0.13.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2c26cf47e2cad140fa23b6d58d435a7c0161f5c514284802f25e87fddfe11024"}, + {file = "jiter-0.13.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:4397ee562b9f69d283e5674445551b47a5e8076fdde75e71bfac5891113dc543"}, + {file = "jiter-0.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f90023f8f672e13ea1819507d2d21b9d2d1c18920a3b3a5f1541955a85b5504"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed0240dd1536a98c3ab55e929c60dfff7c899fecafcb7d01161b21a99fc8c363"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6207fc61c395b26fffdcf637a0b06b4326f35bfa93c6e92fe1a166a21aeb6731"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00203f47c214156df427b5989de74cb340c65c8180d09be1bf9de81d0abad599"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c26ad6967c9dcedf10c995a21539c3aa57d4abad7001b7a84f621a263a6b605"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a576f5dce9ac7de5d350b8e2f552cf364f32975ed84717c35379a51c7cb198bd"}, + {file = "jiter-0.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b22945be8425d161f2e536cdae66da300b6b000f1c0ba3ddf237d1bfd45d21b8"}, + {file = "jiter-0.13.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6eeb7db8bc77dc20476bc2f7407a23dbe3d46d9cc664b166e3d474e1c1de4baa"}, + {file = "jiter-0.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:19cd6f85e1dc090277c3ce90a5b7d96f32127681d825e71c9dce28788e39fc0c"}, + {file = "jiter-0.13.0-cp39-cp39-win32.whl", hash = "sha256:dc3ce84cfd4fa9628fe62c4f85d0d597a4627d4242cfafac32a12cc1455d00f7"}, + {file = "jiter-0.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:9ffda299e417dc83362963966c50cb76d42da673ee140de8a8ac762d4bb2378b"}, + {file = "jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b1cbfa133241d0e6bdab48dcdc2604e8ba81512f6bbd68ec3e8e1357dd3c316c"}, + {file = "jiter-0.13.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:db367d8be9fad6e8ebbac4a7578b7af562e506211036cba2c06c3b998603c3d2"}, + {file = "jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45f6f8efb2f3b0603092401dc2df79fa89ccbc027aaba4174d2d4133ed661434"}, + {file = "jiter-0.13.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:597245258e6ad085d064780abfb23a284d418d3e61c57362d9449c6c7317ee2d"}, + {file = "jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:3d744a6061afba08dd7ae375dcde870cffb14429b7477e10f67e9e6d68772a0a"}, + {file = "jiter-0.13.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:ff732bd0a0e778f43d5009840f20b935e79087b4dc65bd36f1cd0f9b04b8ff7f"}, + {file = "jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab44b178f7981fcaea7e0a5df20e773c663d06ffda0198f1a524e91b2fde7e59"}, + {file = "jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19"}, + {file = "jiter-0.13.0.tar.gz", hash = "sha256:f2839f9c2c7e2dffc1bc5929a510e14ce0a946be9365fd1219e7ef342dae14f4"}, ] [[package]] @@ -2024,25 +2135,25 @@ ply = "*" [[package]] name = "jsonschema" -version = "4.24.0" +version = "4.26.0" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"}, - {file = "jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196"}, + {file = "jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"}, + {file = "jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326"}, ] [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" -rpds-py = ">=0.7.1" +rpds-py = ">=0.25.0" [package.extras] format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "rfc3987-syntax (>=1.1.0)", "uri-template", "webcolors (>=24.6.0)"] [[package]] name = "jsonschema-path" @@ -2064,14 +2175,14 @@ requests = ">=2.31.0,<3.0.0" [[package]] name = "jsonschema-specifications" -version = "2025.4.1" +version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"}, - {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"}, + {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, + {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, ] [package.dependencies] @@ -2079,77 +2190,106 @@ referencing = ">=0.31.0" [[package]] name = "lazy-object-proxy" -version = "1.11.0" +version = "1.12.0" description = "A fast and thorough lazy object proxy." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "lazy_object_proxy-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:132bc8a34f2f2d662a851acfd1b93df769992ed1b81e2b1fda7db3e73b0d5a18"}, - {file = "lazy_object_proxy-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:01261a3afd8621a1accb5682df2593dc7ec7d21d38f411011a5712dcd418fbed"}, - {file = "lazy_object_proxy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:090935756cc041e191f22f4f9c7fd4fe9a454717067adf5b1bbd2ce3046b556e"}, - {file = "lazy_object_proxy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:76ec715017f06410f57df442c1a8d66e6b5f7035077785b129817f5ae58810a4"}, - {file = "lazy_object_proxy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9a9f39098e93a63618a79eef2889ae3cf0605f676cd4797fdfd49fcd7ddc318b"}, - {file = "lazy_object_proxy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ee13f67f4fcd044ef27bfccb1c93d39c100046fec1fad6e9a1fcdfd17492aeb3"}, - {file = "lazy_object_proxy-1.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4c84eafd8dd15ea16f7d580758bc5c2ce1f752faec877bb2b1f9f827c329cd"}, - {file = "lazy_object_proxy-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:d2503427bda552d3aefcac92f81d9e7ca631e680a2268cbe62cd6a58de6409b7"}, - {file = "lazy_object_proxy-1.11.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0613116156801ab3fccb9e2b05ed83b08ea08c2517fdc6c6bc0d4697a1a376e3"}, - {file = "lazy_object_proxy-1.11.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bb03c507d96b65f617a6337dedd604399d35face2cdf01526b913fb50c4cb6e8"}, - {file = "lazy_object_proxy-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28c174db37946f94b97a97b579932ff88f07b8d73a46b6b93322b9ac06794a3b"}, - {file = "lazy_object_proxy-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:d662f0669e27704495ff1f647070eb8816931231c44e583f4d0701b7adf6272f"}, - {file = "lazy_object_proxy-1.11.0-py3-none-any.whl", hash = "sha256:a56a5093d433341ff7da0e89f9b486031ccd222ec8e52ec84d0ec1cdc819674b"}, - {file = "lazy_object_proxy-1.11.0.tar.gz", hash = "sha256:18874411864c9fbbbaa47f9fc1dd7aea754c86cfde21278ef427639d1dd78e9c"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61d5e3310a4aa5792c2b599a7a78ccf8687292c8eb09cf187cca8f09cf6a7519"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ca33565f698ac1aece152a10f432415d1a2aa9a42dfe23e5ba2bc255ab91f6"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01c7819a410f7c255b20799b65d36b414379a30c6f1684c7bd7eb6777338c1b"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:029d2b355076710505c9545aef5ab3f750d89779310e26ddf2b7b23f6ea03cd8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc6e3614eca88b1c8a625fc0a47d0d745e7c3255b21dac0e30b3037c5e3deeb8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:be5fe974e39ceb0d6c9db0663c0464669cf866b2851c73971409b9566e880eab"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1cf69cd1a6c7fe2dbcc3edaa017cf010f4192e53796538cc7d5e1fedbfa4bcff"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efff4375a8c52f55a145dc8487a2108c2140f0bec4151ab4e1843e52eb9987ad"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1192e8c2f1031a6ff453ee40213afa01ba765b3dc861302cd91dbdb2e2660b00"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3605b632e82a1cbc32a1e5034278a64db555b3496e0795723ee697006b980508"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a61095f5d9d1a743e1e20ec6d6db6c2ca511961777257ebd9b288951b23b44fa"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:997b1d6e10ecc6fb6fe0f2c959791ae59599f41da61d652f6c903d1ee58b7370"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ee0d6027b760a11cc18281e702c0309dd92da458a74b4c15025d7fc490deede"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ab2c584e3cc8be0dfca422e05ad30a9abe3555ce63e9ab7a559f62f8dbc6ff9"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14e348185adbd03ec17d051e169ec45686dcd840a3779c9d4c10aabe2ca6e1c0"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4fcbe74fb85df8ba7825fa05eddca764138da752904b378f0ae5ab33a36c308"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:563d2ec8e4d4b68ee7848c5ab4d6057a6d703cb7963b342968bb8758dda33a23"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:53c7fd99eb156bbb82cbc5d5188891d8fdd805ba6c1e3b92b90092da2a837073"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86fd61cb2ba249b9f436d789d1356deae69ad3231dc3c0f17293ac535162672e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81d1852fb30fab81696f93db1b1e55a5d1ff7940838191062f5f56987d5fcc3e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9045646d83f6c2664c1330904b245ae2371b5c57a3195e4028aedc9f999655"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67f07ab742f1adfb3966c40f630baaa7902be4222a17941f3d85fd1dae5565ff"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ba769017b944fcacbf6a80c18b2761a1795b03f8899acdad1f1c39db4409be"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b22c2bbfb155706b928ac4d74c1a63ac8552a55ba7fff4445155523ea4067e1"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4a79b909aa16bde8ae606f06e6bbc9d3219d2e57fb3e0076e17879072b742c65"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:338ab2f132276203e404951205fe80c3fd59429b3a724e7b662b2eb539bb1be9"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c40b3c9faee2e32bfce0df4ae63f4e73529766893258eca78548bac801c8f66"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:717484c309df78cedf48396e420fa57fc8a2b1f06ea889df7248fdd156e58847"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b7ea5ea1ffe15059eb44bcbcb258f97bcb40e139b88152c40d07b1a1dfc9ac"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:08c465fb5cd23527512f9bd7b4c7ba6cec33e28aad36fbbe46bf7b858f9f3f7f"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c9defba70ab943f1df98a656247966d7729da2fe9c2d5d85346464bf320820a3"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6763941dbf97eea6b90f5b06eb4da9418cc088fce0e3883f5816090f9afcde4a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdc70d81235fc586b9e3d1aeef7d1553259b62ecaae9db2167a5d2550dcc391a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0a83c6f7a6b2bfc11ef3ed67f8cbe99f8ff500b05655d8e7df9aab993a6abc95"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:256262384ebd2a77b023ad02fbcc9326282bcfd16484d5531154b02bc304f4c5"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7601ec171c7e8584f8ff3f4e440aa2eebf93e854f04639263875b8c2971f819f"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae575ad9b674d0029fc077c5231b3bc6b433a3d1a62a8c363df96974b5534728"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31020c84005d3daa4cc0fa5a310af2066efe6b0d82aeebf9ab199292652ff036"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800f32b00a47c27446a2b767df7538e6c66a3488632c402b4fb2224f9794f3c0"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:15400b18893f345857b9e18b9bd87bd06aba84af6ed086187add70aeaa3f93f1"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3d3964fbd326578bcdfffd017ef101b6fb0484f34e731fe060ba9b8816498c36"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:424a8ab6695400845c39f13c685050eab69fa0bbac5790b201cd27375e5e41d7"}, + {file = "lazy_object_proxy-1.12.0-pp39.pp310.pp311.graalpy311-none-any.whl", hash = "sha256:c3b2e0af1f7f77c4263759c4824316ce458fabe0fceadcd24ef8ca08b2d1e402"}, + {file = "lazy_object_proxy-1.12.0.tar.gz", hash = "sha256:1f5a462d92fd0cfb82f1fab28b51bfb209fabbe6aabf7f0d51472c0c124c0c61"}, ] [[package]] name = "limits" -version = "5.5.0" +version = "5.8.0" description = "Rate limiting utilities" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "limits-5.5.0-py3-none-any.whl", hash = "sha256:57217d01ffa5114f7e233d1f5e5bdc6fe60c9b24ade387bf4d5e83c5cf929bae"}, - {file = "limits-5.5.0.tar.gz", hash = "sha256:ee269fedb078a904608b264424d9ef4ab10555acc8d090b6fc1db70e913327ea"}, + {file = "limits-5.8.0-py3-none-any.whl", hash = "sha256:ae1b008a43eb43073c3c579398bd4eb4c795de60952532dc24720ab45e1ac6b8"}, + {file = "limits-5.8.0.tar.gz", hash = "sha256:c9e0d74aed837e8f6f50d1fcebcf5fd8130957287206bc3799adaee5092655da"}, ] [package.dependencies] deprecated = ">=1.2" packaging = ">=21" -typing_extensions = "*" +typing-extensions = "*" [package.extras] -all = ["coredis (>=3.4.0,<6)", "memcachio (>=0.3)", "motor (>=3,<4)", "pymemcache (>3,<5.0.0)", "pymongo (>4.1,<5)", "redis (>3,!=4.5.2,!=4.5.3,<7.0.0)", "redis (>=4.2.0,!=4.5.2,!=4.5.3)", "valkey (>=6)", "valkey (>=6)"] async-memcached = ["memcachio (>=0.3)"] async-mongodb = ["motor (>=3,<4)"] async-redis = ["coredis (>=3.4.0,<6)"] async-valkey = ["valkey (>=6)"] memcached = ["pymemcache (>3,<5.0.0)"] mongodb = ["pymongo (>4.1,<5)"] -redis = ["redis (>3,!=4.5.2,!=4.5.3,<7.0.0)"] +redis = ["redis (>3,!=4.5.2,!=4.5.3,<8.0.0)"] rediscluster = ["redis (>=4.2.0,!=4.5.2,!=4.5.3)"] valkey = ["valkey (>=6)"] [[package]] name = "lnurl" -version = "0.8.3" +version = "0.10.0" description = "LNURL implementation for Python." optional = false -python-versions = ">=3.10" +python-versions = "<3.13,>=3.10" groups = ["main"] files = [ - {file = "lnurl-0.8.3-py3-none-any.whl", hash = "sha256:670cdeaef2c55de986dad89126ab58275d5199ba6554a93d9965d1e162080c2a"}, - {file = "lnurl-0.8.3.tar.gz", hash = "sha256:8ca73af84fb9ee36a184d731d165f289ba7bc6260d4dadb2b6cf24f381c3afba"}, + {file = "lnurl-0.10.0-py3-none-any.whl", hash = "sha256:0d43561b4370cecec19c8f1044fc840f0199fc2698bc83cd8782e8264bfde8f4"}, + {file = "lnurl-0.10.0.tar.gz", hash = "sha256:55ba0a7e810bcdfc7410c682f91c76df4446ff24e83d6bf931a7c759e2e0d5cc"}, ] [package.dependencies] bech32 = "*" -bip32 = ">=4.0,<5.0" +bip32 = ">=5.0.0" bolt11 = "*" -ecdsa = "*" +coincurve = ">=20.0.0" httpx = "*" -pycryptodomex = ">=3.21.0,<4.0.0" -pydantic = ">=1,<2" +pycryptodomex = ">=3.21.0" +pydantic = ">=1.10.0,<2.0.0" [[package]] name = "loguru" @@ -2168,7 +2308,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==v0.910) ; python_version < \"3.6\"", "mypy (==v0.971) ; python_version == \"3.6\"", "mypy (==v1.13.0) ; python_version >= \"3.8\"", "mypy (==v1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""] +dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==0.910) ; python_version < \"3.6\"", "mypy (==0.971) ; python_version == \"3.6\"", "mypy (==1.13.0) ; python_version >= \"3.8\"", "mypy (==1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""] [[package]] name = "markdown-it-py" @@ -2196,73 +2336,101 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] [[package]] name = "markupsafe" -version = "3.0.2" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, - {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, ] [[package]] @@ -2296,122 +2464,158 @@ test = ["pytest", "pytest-cov"] [[package]] name = "multidict" -version = "6.6.4" +version = "6.7.1" description = "multidict implementation" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f"}, - {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb"}, - {file = "multidict-6.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0af5f9dee472371e36d6ae38bde009bd8ce65ac7335f55dcc240379d7bed1495"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:d24f351e4d759f5054b641c81e8291e5d122af0fca5c72454ff77f7cbe492de8"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db6a3810eec08280a172a6cd541ff4a5f6a97b161d93ec94e6c4018917deb6b7"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b20a9d56b2d81e2ff52ecc0670d583eaabaa55f402e8d16dd062373dbbe796"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c9854df0eaa610a23494c32a6f44a3a550fb398b6b51a56e8c6b9b3689578db"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb7627fd7a968f41905a4d6343b0d63244a0623f006e9ed989fa2b78f4438a0"}, - {file = "multidict-6.6.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caebafea30ed049c57c673d0b36238b1748683be2593965614d7b0e99125c877"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ad887a8250eb47d3ab083d2f98db7f48098d13d42eb7a3b67d8a5c795f224ace"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ed8358ae7d94ffb7c397cecb62cbac9578a83ecefc1eba27b9090ee910e2efb6"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecab51ad2462197a4c000b6d5701fc8585b80eecb90583635d7e327b7b6923eb"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c5c97aa666cf70e667dfa5af945424ba1329af5dd988a437efeb3a09430389fb"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9a950b7cf54099c1209f455ac5970b1ea81410f2af60ed9eb3c3f14f0bfcf987"}, - {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:163c7ea522ea9365a8a57832dea7618e6cbdc3cd75f8c627663587459a4e328f"}, - {file = "multidict-6.6.4-cp310-cp310-win32.whl", hash = "sha256:17d2cbbfa6ff20821396b25890f155f40c986f9cfbce5667759696d83504954f"}, - {file = "multidict-6.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce9a40fbe52e57e7edf20113a4eaddfacac0561a0879734e636aa6d4bb5e3fb0"}, - {file = "multidict-6.6.4-cp310-cp310-win_arm64.whl", hash = "sha256:01d0959807a451fe9fdd4da3e139cb5b77f7328baf2140feeaf233e1d777b729"}, - {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c"}, - {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb"}, - {file = "multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50"}, - {file = "multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b"}, - {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f"}, - {file = "multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2"}, - {file = "multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e"}, - {file = "multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf"}, - {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8"}, - {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3"}, - {file = "multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c"}, - {file = "multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802"}, - {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24"}, - {file = "multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793"}, - {file = "multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e"}, - {file = "multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364"}, - {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e"}, - {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657"}, - {file = "multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a"}, - {file = "multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812"}, - {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a"}, - {file = "multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69"}, - {file = "multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf"}, - {file = "multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605"}, - {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb"}, - {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e"}, - {file = "multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45"}, - {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0"}, - {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92"}, - {file = "multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e"}, - {file = "multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4"}, - {file = "multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad"}, - {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:af7618b591bae552b40dbb6f93f5518328a949dac626ee75927bba1ecdeea9f4"}, - {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b6819f83aef06f560cb15482d619d0e623ce9bf155115150a85ab11b8342a665"}, - {file = "multidict-6.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4d09384e75788861e046330308e7af54dd306aaf20eb760eb1d0de26b2bea2cb"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:a59c63061f1a07b861c004e53869eb1211ffd1a4acbca330e3322efa6dd02978"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350f6b0fe1ced61e778037fdc7613f4051c8baf64b1ee19371b42a3acdb016a0"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c5cbac6b55ad69cb6aa17ee9343dfbba903118fd530348c330211dc7aa756d1"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:630f70c32b8066ddfd920350bc236225814ad94dfa493fe1910ee17fe4365cbb"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8d4916a81697faec6cb724a273bd5457e4c6c43d82b29f9dc02c5542fd21fc9"}, - {file = "multidict-6.6.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e42332cf8276bb7645d310cdecca93a16920256a5b01bebf747365f86a1675b"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f3be27440f7644ab9a13a6fc86f09cdd90b347c3c5e30c6d6d860de822d7cb53"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:21f216669109e02ef3e2415ede07f4f8987f00de8cdfa0cc0b3440d42534f9f0"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d9890d68c45d1aeac5178ded1d1cccf3bc8d7accf1f976f79bf63099fb16e4bd"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:edfdcae97cdc5d1a89477c436b61f472c4d40971774ac4729c613b4b133163cb"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0b2e886624be5773e69cf32bcb8534aecdeb38943520b240fed3d5596a430f2f"}, - {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:be5bf4b3224948032a845d12ab0f69f208293742df96dc14c4ff9b09e508fc17"}, - {file = "multidict-6.6.4-cp39-cp39-win32.whl", hash = "sha256:10a68a9191f284fe9d501fef4efe93226e74df92ce7a24e301371293bd4918ae"}, - {file = "multidict-6.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee25f82f53262f9ac93bd7e58e47ea1bdcc3393cef815847e397cba17e284210"}, - {file = "multidict-6.6.4-cp39-cp39-win_arm64.whl", hash = "sha256:f9867e55590e0855bcec60d4f9a092b69476db64573c9fe17e92b0c50614c16a"}, - {file = "multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c"}, - {file = "multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, + {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, + {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, + {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, + {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, + {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, + {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, + {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, + {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, + {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, + {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, + {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, + {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, + {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, + {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, + {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, + {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, + {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, + {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, + {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, + {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, + {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, + {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, + {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, + {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, + {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, + {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, + {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, + {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, + {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, + {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, + {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, + {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, + {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, + {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, + {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, + {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, + {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, + {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, + {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, + {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, + {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, + {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, + {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, + {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, + {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, + {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, + {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, + {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, + {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, + {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, ] [package.dependencies] @@ -2492,37 +2696,37 @@ files = [ [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, + {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, + {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] [[package]] name = "nostr-sdk" -version = "0.44.0" +version = "0.44.2" description = "Nostr protocol implementation, Relay, RelayPool, high-level client library, NWC client and more." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "nostr_sdk-0.44.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:788bd39dc82733f10ddc2b88112efad18551919b19eda0228588d7a22e799344"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-macosx_11_0_x86_64.whl", hash = "sha256:3c22de46697bfafafde78165cf5ecbe36c708b46d672d05ea4447ee15cc88b61"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:c4f82ee06c5e2c49e1f6074b2a94a8985130b766cef182114bd9ec89913cbd89"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:b82fc26d68eb0d9f2effbea453e745cecbf958179620fad2a182902a57cf7e6e"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_i686.whl", hash = "sha256:f2f52e886d2acf6914f02791ba8d0f694dee5a657ea0c09e6b4316b87a09294a"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:650b8e8438da7807d2b1337fa7989b848794cf92e9796d529144a34a9cf0ec77"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53785102f4d4e8db8c5f32a26b8f6d87632f156de33163cb371f36c79aeb077c"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:23e6ace94b35e80a36d49afe22d101d38f57c036f094dc57f73c417708e89096"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3f68f278449ff9271b62c193fc842d836d9ca1dcbf3db6c38e5ce3a8198be9e0"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c1632a8db0a1727481a309c4ebb47a7e5206a485bddca92a966822266b7be5d5"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-win32.whl", hash = "sha256:197d50b7253a1af4db2ce7511542a3d5827208b991fb164794f1c1a750c2ad07"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-win_amd64.whl", hash = "sha256:b07cf13ef05fee7dc05d04d84bbcb21e5004e52b315de3212ed8def3dbb2dad5"}, - {file = "nostr_sdk-0.44.0-cp39-abi3-win_arm64.whl", hash = "sha256:e2765ba0987717a950e20eb87f976f28e0128d28a9cfad3dc7ff9d3754190a47"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:184075689531e34085bc1e71b62f3a964df2d4aeb15a25f94557e15a4294c584"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-macosx_11_0_x86_64.whl", hash = "sha256:65e85c79295f4e258e5276a82b52e36ffb3f5cf59c2c7c4a959970ed9303cf6f"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:d1d557aeb8a423dcd054f699bbf7371eb268a6cec5916bf147957cb3f9f7da02"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:41b1bb050f890f81b4c4edaf4d6cc3054ae9e783911eb4ce7dce6b8e97dfa60e"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_i686.whl", hash = "sha256:db584ba95de5abbb74da77036c3316e9a166bc22d9d2ea3ca38fc09325d9c6a9"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:4e1dccf29b7ad6eeb44945175a45334d4e45d82881ae5f3a28433899f155831c"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:aa347c6437dc33ae45cc2ed56177f5aeded0fda42285b1b325a840de44e1f708"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:a7a03b35ddbc69f31d79bea17ac60b8d250ef62bcf1d52fc33b9e36e0ecf772b"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:e53682dbf192acd137a92ae5d91903fbb22728d55452a8fa2315581f1d8413f2"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b3e6dd4191997546f157aba4532a995d06ad8b0cf9c17e77c0015553f06a9cf2"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-win32.whl", hash = "sha256:aa94a18eb8f4d77559c0290c0f17d6816c00f4fdddba5f1fcf96ff01b4690b42"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-win_amd64.whl", hash = "sha256:31e609a864c3857cddde70d8a91181e2b2cadf923e562b6a9d82e655edded117"}, + {file = "nostr_sdk-0.44.2-cp39-abi3-win_arm64.whl", hash = "sha256:3a9d3284af0547e224bf705d90cd6d9ca5a1b48f5becea1021da915de4408310"}, ] [[package]] @@ -2631,115 +2835,117 @@ files = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.0.4" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, + {file = "pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723"}, + {file = "pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645"}, ] +[package.extras] +hyperscan = ["hyperscan (>=0.7)"] +optional = ["typing-extensions (>=4)"] +re2 = ["google-re2 (>=1.1)"] +tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] + [[package]] name = "pillow" -version = "12.1.0" +version = "12.3.0" description = "Python Imaging Library (fork)" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd"}, - {file = "pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda"}, - {file = "pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7"}, - {file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a"}, - {file = "pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef"}, - {file = "pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09"}, - {file = "pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91"}, - {file = "pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea"}, - {file = "pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3"}, - {file = "pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84"}, - {file = "pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0"}, - {file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b"}, - {file = "pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18"}, - {file = "pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64"}, - {file = "pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75"}, - {file = "pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304"}, - {file = "pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b"}, - {file = "pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661"}, - {file = "pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17"}, - {file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670"}, - {file = "pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616"}, - {file = "pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7"}, - {file = "pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d"}, - {file = "pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179"}, - {file = "pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0"}, - {file = "pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587"}, - {file = "pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c"}, - {file = "pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc"}, - {file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644"}, - {file = "pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c"}, - {file = "pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171"}, - {file = "pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a"}, - {file = "pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45"}, - {file = "pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d"}, - {file = "pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82"}, - {file = "pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4"}, - {file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0"}, - {file = "pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b"}, - {file = "pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65"}, - {file = "pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0"}, - {file = "pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796"}, - {file = "pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd"}, - {file = "pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13"}, - {file = "pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de"}, - {file = "pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9"}, - {file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a"}, - {file = "pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a"}, - {file = "pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030"}, - {file = "pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94"}, - {file = "pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4"}, - {file = "pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2"}, - {file = "pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14"}, - {file = "pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8"}, - {file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924"}, - {file = "pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef"}, - {file = "pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988"}, - {file = "pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6"}, - {file = "pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a"}, - {file = "pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19"}, - {file = "pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed"}, + {file = "pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1"}, + {file = "pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb"}, + {file = "pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5"}, + {file = "pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b"}, + {file = "pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a"}, + {file = "pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df"}, + {file = "pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f"}, + {file = "pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09"}, + {file = "pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e"}, + {file = "pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f"}, + {file = "pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8"}, + {file = "pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130"}, + {file = "pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a"}, + {file = "pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d"}, + {file = "pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931"}, + {file = "pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7"}, + {file = "pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c"}, + {file = "pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71"}, + {file = "pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827"}, + {file = "pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5"}, + {file = "pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9"}, + {file = "pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8"}, + {file = "pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418"}, + {file = "pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a"}, + {file = "pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce"}, ] [package.extras] @@ -2747,25 +2953,42 @@ docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybut fpx = ["olefile"] mic = ["olefile"] test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] +tests = ["coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "setuptools", "trove-classifiers (>=2024.10.12)"] xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.9.4" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, - {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, + {file = "platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868"}, + {file = "platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934"}, ] -[package.extras] -docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] -type = ["mypy (>=1.14.1)"] +[[package]] +name = "playwright" +version = "1.61.0" +description = "A high-level API to automate web browsers" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "playwright-1.61.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:ff138c3a604f69911e9d42fd036e55c2a171e5616edf04c1e7f60a2a285540b0"}, + {file = "playwright-1.61.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:009588c2a7e499bc5a8b425b61fa65490968bbda9cd69e0cf2cff10f8304659a"}, + {file = "playwright-1.61.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9f7de4536088d12037c13a52b7ea34b59270b78926bb56935070597ffac6b1af"}, + {file = "playwright-1.61.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:54f3b39f6eab832e33458c1dd7da0b5682aedab3b09ae731b5c59fa12fd2024e"}, + {file = "playwright-1.61.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93454322ade8c11d5d6c211bfd91bdfb9ffb4810e3e026371bcbc4bec1b7ee4c"}, + {file = "playwright-1.61.0-py3-none-win32.whl", hash = "sha256:372d55a6f1248fa1dd47599686980cb8fb5bbe6fcda59eab793eb657c11d8a9b"}, + {file = "playwright-1.61.0-py3-none-win_amd64.whl", hash = "sha256:35c6cc4589a5d00964a59d7b3e59641e0aac0c02f15479a7af77d20f6bc79597"}, + {file = "playwright-1.61.0-py3-none-win_arm64.whl", hash = "sha256:e9fcbffcf557a8620fdedd92491eb59a32d18e23d6f3b4f6214b952be324fe51"}, +] + +[package.dependencies] +greenlet = ">=3.1.1,<4.0.0" +pyee = ">=13,<14" [[package]] name = "pluggy" @@ -2816,130 +3039,154 @@ virtualenv = ">=20.10.0" [[package]] name = "propcache" -version = "0.3.2" +version = "0.4.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"}, - {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"}, - {file = "propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3"}, - {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e"}, - {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220"}, - {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb"}, - {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614"}, - {file = "propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b"}, - {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c"}, - {file = "propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70"}, - {file = "propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9"}, - {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be"}, - {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f"}, - {file = "propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9"}, - {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf"}, - {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9"}, - {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66"}, - {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df"}, - {file = "propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf"}, - {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e"}, - {file = "propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897"}, - {file = "propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39"}, - {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10"}, - {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154"}, - {file = "propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615"}, - {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db"}, - {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1"}, - {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c"}, - {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67"}, - {file = "propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06"}, - {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1"}, - {file = "propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1"}, - {file = "propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c"}, - {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945"}, - {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252"}, - {file = "propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f"}, - {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33"}, - {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e"}, - {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1"}, - {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3"}, - {file = "propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206"}, - {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43"}, - {file = "propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02"}, - {file = "propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05"}, - {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b"}, - {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0"}, - {file = "propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e"}, - {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28"}, - {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a"}, - {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c"}, - {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725"}, - {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770"}, - {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330"}, - {file = "propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394"}, - {file = "propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198"}, - {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5"}, - {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4"}, - {file = "propcache-0.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2"}, - {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d"}, - {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec"}, - {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701"}, - {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef"}, - {file = "propcache-0.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb"}, - {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe"}, - {file = "propcache-0.3.2-cp39-cp39-win32.whl", hash = "sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1"}, - {file = "propcache-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9"}, - {file = "propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f"}, - {file = "propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"}, + {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"}, + {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"}, + {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"}, + {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"}, + {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"}, + {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"}, + {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"}, + {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"}, + {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"}, + {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"}, + {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"}, + {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"}, + {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"}, + {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"}, + {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"}, + {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"}, + {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"}, + {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"}, + {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"}, + {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"}, + {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"}, + {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"}, + {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"}, + {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"}, + {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"}, + {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"}, + {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"}, + {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"}, + {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"}, + {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"}, + {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"}, + {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"}, + {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"}, + {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"}, + {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"}, + {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"}, + {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"}, + {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"}, + {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"}, + {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"}, + {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"}, + {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"}, + {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"}, + {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"}, + {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"}, + {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"}, + {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"}, + {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"}, + {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"}, + {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"}, ] [[package]] name = "protobuf" -version = "6.33.2" +version = "6.33.6" description = "" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d"}, - {file = "protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4"}, - {file = "protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43"}, - {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e"}, - {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872"}, - {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f"}, - {file = "protobuf-6.33.2-cp39-cp39-win32.whl", hash = "sha256:7109dcc38a680d033ffb8bf896727423528db9163be1b6a02d6a49606dcadbfe"}, - {file = "protobuf-6.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:2981c58f582f44b6b13173e12bb8656711189c2a70250845f264b877f00b1913"}, - {file = "protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c"}, - {file = "protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4"}, + {file = "protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3"}, + {file = "protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326"}, + {file = "protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a"}, + {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2"}, + {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3"}, + {file = "protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593"}, + {file = "protobuf-6.33.6-cp39-cp39-win32.whl", hash = "sha256:bd56799fb262994b2c2faa1799693c95cc2e22c62f56fb43af311cae45d26f0e"}, + {file = "protobuf-6.33.6-cp39-cp39-win_amd64.whl", hash = "sha256:f443a394af5ed23672bc6c486be138628fbe5c651ccbc536873d7da23d1868cf"}, + {file = "protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901"}, + {file = "protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135"}, ] [[package]] @@ -3022,29 +3269,33 @@ files = [ [[package]] name = "py-vapid" -version = "1.9.2" +version = "1.9.4" description = "Simple VAPID header generation library" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "py_vapid-1.9.2-py3-none-any.whl", hash = "sha256:4ccf8a00fc54f1f99f66fb543c96f2c82622508ad814b6e9225f2c26948934d7"}, - {file = "py_vapid-1.9.2.tar.gz", hash = "sha256:3c8973b6cf8384ad0c9ae64d6270ccc480e0b92c702d8f5ea2cc03e6b51247f9"}, + {file = "py_vapid-1.9.4-py2.py3-none-any.whl", hash = "sha256:f165a5bf90dcf966b226114f01f178f137579a09784c7f0628fa2f0a299741b6"}, + {file = "py_vapid-1.9.4.tar.gz", hash = "sha256:a004023560cbc54e34fc06380a0580f04ffcc788e84fb6d19e9339eeb6551a28"}, ] [package.dependencies] -cryptography = ">=2.5" +cryptography = ">=46" + +[package.extras] +test = ["coverage", "flake8", "mock (>=1.0)", "pytest"] [[package]] name = "pycparser" -version = "2.22" +version = "3.0" description = "C parser in Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.10" groups = ["main"] +markers = "implementation_name != \"PyPy\"" files = [ - {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, - {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, + {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, + {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] [[package]] @@ -3153,6 +3404,24 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pyee" +version = "13.0.1" +description = "A rough port of Node.js's EventEmitter to Python with a few tricks of its own" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pyee-13.0.1-py3-none-any.whl", hash = "sha256:af2f8fede4171ef667dfded53f96e2ed0d6e6bd7ee3bb46437f77e3b57689228"}, + {file = "pyee-13.0.1.tar.gz", hash = "sha256:0b931f7c14535667ed4c7e0d531716368715e860b988770fc7eb8578d1f67fc8"}, +] + +[package.dependencies] +typing-extensions = "*" + +[package.extras] +dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "mypy", "pytest", "pytest-asyncio ; python_version >= \"3.4\"", "pytest-trio ; python_version >= \"3.7\"", "sphinx", "toml", "tox", "trio", "trio ; python_version > \"3.6\"", "trio-typing ; python_version > \"3.6\"", "twine", "twisted", "validate-pyproject[all]"] + [[package]] name = "pygments" version = "2.19.2" @@ -3168,23 +3437,108 @@ files = [ [package.extras] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pyinstrument" +version = "5.1.2" +description = "Call stack profiler for Python. Shows you why your code is slow!" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "pyinstrument-5.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f224fe80ba288a00980af298d3808219f9d246fd95b4f91729c9c33a0dc54fe6"}, + {file = "pyinstrument-5.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7df09fc0d5b72daf48b73cdf07738761bff7f656c81aff686b3ccdd7d2abe236"}, + {file = "pyinstrument-5.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75a7e17377d4405666bbaf126b1fd7bbb7e206d7246e6db3d62864d3d4790ae3"}, + {file = "pyinstrument-5.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5381cc6583d26e04d9298acded4242f4fe71986f1472c8aee6992c6816f0cac5"}, + {file = "pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ec08a530bef8d3492d31d8b0b12d0cfde09539f2a1c4b9678662ebc3c843e478"}, + {file = "pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d671168508129b472be570bc9aee361190ba917b997c703bd134bb4de445ce7"}, + {file = "pyinstrument-5.1.2-cp310-cp310-win32.whl", hash = "sha256:5957a94f84564b374a7f856d1b322345d600964280b0d687b8ddcc483f21e576"}, + {file = "pyinstrument-5.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:38a2180a7801c51610b50e5d423674b21872efd019ccf05a11b7f9016cb1dcfc"}, + {file = "pyinstrument-5.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3739a05583ea6312c385eb59fe985cd20d9048e95f9eeeb6a2f6c35202e2d36e"}, + {file = "pyinstrument-5.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c9ee05dc75ac5fb18498c311e624f77f7f321f7ff325b251aa09e52e46f1d6a"}, + {file = "pyinstrument-5.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a49a55ca5b75218767e29cacbe515d0b66fc18cb48a937bca0f77b8dafc7202"}, + {file = "pyinstrument-5.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c45c14974ff04b1bfdc6c2a448627c6da7409c7800d0eb7bd03fb435dcb41d7"}, + {file = "pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22b9c04b3982c41c04b1c5ed05d1bc3a2ba26533450084058119f6dc160e70a3"}, + {file = "pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5c4995ee0774801790c138f0dfec17d4e7a7ef09a6d56d53cbcbf0578a711021"}, + {file = "pyinstrument-5.1.2-cp311-cp311-win32.whl", hash = "sha256:fe449e4a8ee60a2a27cf509350a584670f4c3704649601be7937598f09dbe7ca"}, + {file = "pyinstrument-5.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:3fb839429671a42bf349335af4c1ce5cf83386ac11f04df0bc40720d4cb7d77d"}, + {file = "pyinstrument-5.1.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2519865d4bf58936f2506c1c46a82d29a20f3239aa50c941df1ca9618c7da5f0"}, + {file = "pyinstrument-5.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:059442106b8b5de29ae5ac1bdc20d044fed4da534b8caba434b6ffb119037bf5"}, + {file = "pyinstrument-5.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd51f2d54fc39a4cfd73ba6be27cd0187123132ce3f445b639bff5e1b23d7e26"}, + {file = "pyinstrument-5.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12af1e83795b6c640d657d339014dd1ff718b182dec736d7d1f1d8a97534eb53"}, + {file = "pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2565513658e742c5eb691a779cb29d19d01bc9ee951d0eb76482e9f343c38c2e"}, + {file = "pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5afd0ba788a1d112da49fb77966918e01df1f9e7d62e72894d82f7acb0996c2d"}, + {file = "pyinstrument-5.1.2-cp312-cp312-win32.whl", hash = "sha256:554077b031b278593cb2301f0057be771ea62a729878c69aaf29fcdfb7b71281"}, + {file = "pyinstrument-5.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:55a905384ba43efc924b8863aa6cfd276f029e4aa70c4a0e3b7389e27b191e45"}, + {file = "pyinstrument-5.1.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7b8bab2334bf1d4c9e92d61db574300b914b594588a6b6dd67c45450152dfc29"}, + {file = "pyinstrument-5.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:13dcc138a61298ef4994b7aebff509d2c06db89dfd6e2021f0b9cd96aaa44ec3"}, + {file = "pyinstrument-5.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8abd4a7ffa2e7f9e00039a5e549e8eebc80d7ca8d43f0fb51a50ff2b117ce4a"}, + {file = "pyinstrument-5.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb3a05108edebc30f31e2c69c904576042f1158b2513ab80adc08f7848a7a8f0"}, + {file = "pyinstrument-5.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f70d588b53f3f35829d1d1ddfa05e07fcebf1434b3b1509d542ca317d8e9a2a5"}, + {file = "pyinstrument-5.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b007327e0d6a6a01d5064883dd27c19996f044ce7488d507826fee7884e6a32e"}, + {file = "pyinstrument-5.1.2-cp313-cp313-win32.whl", hash = "sha256:9ba0e6b17a7e86c3dc02d208e4c25506e8f914d9964ae89449f1f37f0b70abc0"}, + {file = "pyinstrument-5.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:660d7fc486a839814db0b2f716bc13d8b99b9c780aaeb47f74a70a34adc02a7b"}, + {file = "pyinstrument-5.1.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:0baed297beee2bb9897e737bbd89e3b9d45a2fbbea9f1ad4e809007d780a9b1e"}, + {file = "pyinstrument-5.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ebb910a32a45bde6c3fc30c578efc28a54517990e11e94b5e48a0d5479728568"}, + {file = "pyinstrument-5.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bad403c157f9c6dba7f731a6fca5bfcd8ca2701a39bcc717dcc6e0b10055ffc4"}, + {file = "pyinstrument-5.1.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f456cabdb95fd343c798a7f2a56688b028f981522e283c5f59bd59195b66df5"}, + {file = "pyinstrument-5.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4e9c4dcc1f2c4a0cd6b576e3604abc37496a7868243c9a1443ad3b9db69d590f"}, + {file = "pyinstrument-5.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:acf93b128328c6d80fdb85431068ac17508f0f7845e89505b0ea6130dead5ca6"}, + {file = "pyinstrument-5.1.2-cp314-cp314-win32.whl", hash = "sha256:9c7f0167903ecff8b1d744f7e37b2bd4918e05a69cca724cb112f5ed59d1e41b"}, + {file = "pyinstrument-5.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:ce3f6b1f9a2b5d74819ecc07d631eadececf915f551474a75ad65ac580ec5a0e"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:af8651b239049accbeecd389d35823233f649446f76f47fd005316b05d08cef2"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c6082f1c3e43e1d22834e91ba8975f0080186df4018a04b4dd29f9623c59df1d"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c031eb066ddc16425e1e2f56aad5c1ce1e27b2432a70329e5385b85e812decee"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f447ec391cad30667ba412dce41607aaa20d4a2496a7ab867e0c199f0fe3ae3d"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:50299bddfc1fe0039898f895b10ef12f9db08acffb4d85326fad589cda24d2ee"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a193ff08825ece115ececa136832acb14c491c77ab1e6b6a361905df8753d5c6"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-win32.whl", hash = "sha256:de887ba19e1057bd2d86e6584f17788516a890ae6fe1b7eed9927873f416b4d8"}, + {file = "pyinstrument-5.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:b6a71f5e7f53c86c9b476b30cf19509463a63581ef17ddbd8680fee37ae509db"}, + {file = "pyinstrument-5.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:47f14f248108f1202d48f34903bddc053a47c62ce46908aee848c1f667a1925b"}, + {file = "pyinstrument-5.1.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc3f2688981af764fa2c5f5a00d7040c0c12771ca5a026730f2d826f7a28d277"}, + {file = "pyinstrument-5.1.2-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7afb24d11d24fb1762059240ed97a1a4607779d5f221f91d62b67ae089bd506d"}, + {file = "pyinstrument-5.1.2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d21221a29718d5dcdc1453dbbbdd100734525672ef1e34ff03d49bc5d688ca4"}, + {file = "pyinstrument-5.1.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3b68aa9f0d5217c67370762c99a80750ce56f66e5e9281c31b5baa3e4b88894d"}, + {file = "pyinstrument-5.1.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:755702f01800934c3bec3c0d30483f97b6ff1fc1d2afcf6d816584703c9f1235"}, + {file = "pyinstrument-5.1.2-cp38-cp38-win32.whl", hash = "sha256:2bacb980c95d4c9ea6a253e5ccf3e99993082de29ff7e7fc397e9484355577b1"}, + {file = "pyinstrument-5.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:2588bc34c25d50f29d3a117c7dfac06513ee59c507b65081e66ca9569bcf45e0"}, + {file = "pyinstrument-5.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bea0687665c181c6e62677fb560739a473c4286816582a43f8eb0aa6094ed529"}, + {file = "pyinstrument-5.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64246d2bd475870b62ed5df4808bfb33328135e8dfbdff823f9cb7d1358eb40b"}, + {file = "pyinstrument-5.1.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff6fd3c7907e57f082cdd405bec1b34768c1810a165538299d259ee1bff5d7b6"}, + {file = "pyinstrument-5.1.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af09af38ee8407ca273407e24a8e6470d2444561d01005ee6a8db5f2fd908c08"}, + {file = "pyinstrument-5.1.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1249d2799cdd57151b4444167e5c7736e2c9b5e79bd781b0779d631338509553"}, + {file = "pyinstrument-5.1.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d653206f50260f20bc78339c3d7aa0f19f8cf9c9f71939fbf02e2ea30353487"}, + {file = "pyinstrument-5.1.2-cp39-cp39-win32.whl", hash = "sha256:d0b0c6e289725f14d0ff73f8190c953bdcb98f21c5c29c3eafb0dca8025583cb"}, + {file = "pyinstrument-5.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:db8243e602aca43dc7ce8e40ed7d0ca4820d024c3c03824870c5a9e98f84e953"}, + {file = "pyinstrument-5.1.2.tar.gz", hash = "sha256:af149d672da9493fa37334a1cc68f7b80c3e6cb9fd99b9e426c447db5c650bf0"}, +] + +[package.extras] +bin = ["click", "nox"] +docs = ["furo (==2024.7.18)", "myst-parser (==3.0.1)", "sphinx (==7.4.7)", "sphinx-autobuild (==2024.4.16)", "sphinxcontrib-programoutput (==0.17)"] +examples = ["django", "litestar", "numpy"] +test = ["cffi (>=1.17.0)", "flaky", "greenlet (>=3)", "ipython", "pytest", "pytest-asyncio (==0.23.8)", "trio"] +types = ["typing_extensions"] + [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.12.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, - {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, + {file = "pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c"}, + {file = "pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"}, ] +[package.dependencies] +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] +tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] [[package]] name = "pyln-bolt7" @@ -3200,14 +3554,14 @@ files = [ [[package]] name = "pyln-client" -version = "25.12" +version = "25.12.1" description = "Client library and plugin library for Core Lightning" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "pyln_client-25.12-py3-none-any.whl", hash = "sha256:9e4ff323acb71cbc4522d160dd931599f59a4c167076db016ec5d63e6a002f86"}, - {file = "pyln_client-25.12.tar.gz", hash = "sha256:9a0435436dea7ce471e096aac9c4e3ede704c305b862b0a3b5e410279b54d8d6"}, + {file = "pyln_client-25.12.1-py3-none-any.whl", hash = "sha256:cb8c42bf4b432a3a2ec0b1ee94b96f5ad91fee1ddd0289930d55c988ab801293"}, + {file = "pyln_client-25.12.1.tar.gz", hash = "sha256:4e92d18ce79879b891355d4a9bb79117466e98e12b83c1b5f321fc3e77039d5b"}, ] [package.dependencies] @@ -3216,22 +3570,22 @@ pyln-proto = ">=23" [[package]] name = "pyln-proto" -version = "25.5" +version = "25.12.1" description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." optional = false -python-versions = "<4.0,>=3.9" +python-versions = "<4.0,>=3.9.2" groups = ["main"] files = [ - {file = "pyln_proto-25.5-py3-none-any.whl", hash = "sha256:31abcf193744d6253b7f06b7712983c6a4d4c28815d46e1f3803eac17bfe1cf9"}, - {file = "pyln_proto-25.5.tar.gz", hash = "sha256:c5e38b726123af723f8c6a4f38ab310cbec46579f52c8e6f666e6beef320b96c"}, + {file = "pyln_proto-25.12.1-py3-none-any.whl", hash = "sha256:84990233ae7ba6a39e4ec9c44fc978efbf74dcfb82953f32921c242807c85764"}, + {file = "pyln_proto-25.12.1.tar.gz", hash = "sha256:7167f361a6bdc9c225749c572fcc23f28f9734dee367252f7fbad13df200984b"}, ] [package.dependencies] -base58 = ">=2.1.1,<3.0.0" -bitstring = ">=4.1.0,<5.0.0" -coincurve = ">=20,<21" -cryptography = ">=42,<43" -PySocks = ">=1,<2" +base58 = ">=2.1.1" +bitstring = ">=4.3.0" +coincurve = "20.0.0" +cryptography = ">=46" +pysocks = ">=1" [[package]] name = "pynostr" @@ -3331,14 +3685,14 @@ testing = ["process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-httpserver" -version = "1.1.3" +version = "1.1.5" description = "pytest-httpserver is a httpserver for pytest" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9"}, - {file = "pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec"}, + {file = "pytest_httpserver-1.1.5-py3-none-any.whl", hash = "sha256:ee83feb587ab652c0c6729598db2820e9048233bac8df756818b7845a1621d0a"}, + {file = "pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1"}, ] [package.dependencies] @@ -3393,16 +3747,36 @@ files = [ cron-description = ["cron-descriptor"] cron-schedule = ["croniter"] +[[package]] +name = "python-discovery" +version = "1.2.0" +description = "Python interpreter discovery" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "python_discovery-1.2.0-py3-none-any.whl", hash = "sha256:1e108f1bbe2ed0ef089823d28805d5ad32be8e734b86a5f212bf89b71c266e4a"}, + {file = "python_discovery-1.2.0.tar.gz", hash = "sha256:7d33e350704818b09e3da2bd419d37e21e7c30db6e0977bb438916e06b41b5b1"}, +] + +[package.dependencies] +filelock = ">=3.15.4" +platformdirs = ">=4.3.6,<5" + +[package.extras] +docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] + [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, - {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, + {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, + {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, ] [package.extras] @@ -3410,26 +3784,66 @@ cli = ["click (>=5.0)"] [[package]] name = "python-multipart" -version = "0.0.21" +version = "0.0.22" description = "A streaming multipart parser for Python" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090"}, - {file = "python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92"}, + {file = "python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155"}, + {file = "python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58"}, ] [[package]] name = "pytokens" -version = "0.3.0" +version = "0.4.1" description = "A Fast, spec compliant Python 3.14+ tokenizer that runs on older Pythons." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3"}, - {file = "pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a"}, + {file = "pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5"}, + {file = "pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe"}, + {file = "pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c"}, + {file = "pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7"}, + {file = "pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2"}, + {file = "pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440"}, + {file = "pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc"}, + {file = "pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d"}, + {file = "pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16"}, + {file = "pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6"}, + {file = "pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083"}, + {file = "pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1"}, + {file = "pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1"}, + {file = "pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9"}, + {file = "pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68"}, + {file = "pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b"}, + {file = "pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f"}, + {file = "pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1"}, + {file = "pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4"}, + {file = "pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78"}, + {file = "pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321"}, + {file = "pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa"}, + {file = "pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d"}, + {file = "pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324"}, + {file = "pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9"}, + {file = "pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb"}, + {file = "pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3"}, + {file = "pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975"}, + {file = "pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a"}, + {file = "pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918"}, + {file = "pytokens-0.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:da5baeaf7116dced9c6bb76dc31ba04a2dc3695f3d9f74741d7910122b456edc"}, + {file = "pytokens-0.4.1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11edda0942da80ff58c4408407616a310adecae1ddd22eef8c692fe266fa5009"}, + {file = "pytokens-0.4.1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0fc71786e629cef478cbf29d7ea1923299181d0699dbe7c3c0f4a583811d9fc1"}, + {file = "pytokens-0.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dcafc12c30dbaf1e2af0490978352e0c4041a7cde31f4f81435c2a5e8b9cabb6"}, + {file = "pytokens-0.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:42f144f3aafa5d92bad964d471a581651e28b24434d184871bd02e3a0d956037"}, + {file = "pytokens-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:34bcc734bd2f2d5fe3b34e7b3c0116bfb2397f2d9666139988e7a3eb5f7400e3"}, + {file = "pytokens-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941d4343bf27b605e9213b26bfa1c4bf197c9c599a9627eb7305b0defcfe40c1"}, + {file = "pytokens-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ad72b851e781478366288743198101e5eb34a414f1d5627cdd585ca3b25f1db"}, + {file = "pytokens-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:682fa37ff4d8e95f7df6fe6fe6a431e8ed8e788023c6bcc0f0880a12eab80ad1"}, + {file = "pytokens-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:30f51edd9bb7f85c748979384165601d028b84f7bd13fe14d3e065304093916a"}, + {file = "pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de"}, + {file = "pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a"}, ] [package.extras] @@ -3437,14 +3851,14 @@ dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "t [[package]] name = "pywebpush" -version = "2.2.0" +version = "2.2.1" description = "WebPush publication library" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pywebpush-2.2.0-py3-none-any.whl", hash = "sha256:f5a03eeeec422f62519d5a94f590937f143b2e9d05ee0da843d0dddd3c335835"}, - {file = "pywebpush-2.2.0.tar.gz", hash = "sha256:d4c0ee4981e7ac08cf14729fec8b6c3aeec58d54e6da388635c5706fcc2db3f6"}, + {file = "pywebpush-2.2.1-py3-none-any.whl", hash = "sha256:50cd824a0af949c7ca2d5c757f10e6b931626740e0aa39fb5f62a4b4662a303d"}, + {file = "pywebpush-2.2.1.tar.gz", hash = "sha256:d881a427a291b4d44e5e6bf920bcb0b4b382bbeb4a63dda63cae5124e65042d8"}, ] [package.dependencies] @@ -3453,72 +3867,103 @@ cryptography = ">=2.6.1" http-ece = ">=1.1.0" py-vapid = ">=1.7.0" requests = ">=2.21.0" -six = ">=1.15.0" [package.extras] dev = ["black", "mock", "pytest"] [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] + +[[package]] +name = "random-username" +version = "1.0.2" +description = "Randomly generate compelling usernames." +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "random-username-1.0.2.tar.gz", hash = "sha256:5fdc0604b5d1bdfe4acf4cd7491a9de1caf41bbdd890f646b434e09ae2a1b7ce"}, + {file = "random_username-1.0.2-py3-none-any.whl", hash = "sha256:2536feb63fecde7e01ede4a541aadb6f0b58794a7ab327ca5369d2a4b7664c06"}, ] [[package]] @@ -3540,14 +3985,14 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, - {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, ] [package.dependencies] @@ -3577,14 +4022,14 @@ six = "*" [[package]] name = "rich" -version = "14.1.0" +version = "14.3.3" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" groups = ["main"] files = [ - {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, - {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, + {file = "rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d"}, + {file = "rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b"}, ] [package.dependencies] @@ -3596,180 +4041,178 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.25.1" +version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "rpds_py-0.25.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f4ad628b5174d5315761b67f212774a32f5bad5e61396d38108bd801c0a8f5d9"}, - {file = "rpds_py-0.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c742af695f7525e559c16f1562cf2323db0e3f0fbdcabdf6865b095256b2d40"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:605ffe7769e24b1800b4d024d24034405d9404f0bc2f55b6db3362cd34145a6f"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc6f3ddef93243538be76f8e47045b4aad7a66a212cd3a0f23e34469473d36b"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f70316f760174ca04492b5ab01be631a8ae30cadab1d1081035136ba12738cfa"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1dafef8df605fdb46edcc0bf1573dea0d6d7b01ba87f85cd04dc855b2b4479e"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0701942049095741a8aeb298a31b203e735d1c61f4423511d2b1a41dcd8a16da"}, - {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e87798852ae0b37c88babb7f7bbbb3e3fecc562a1c340195b44c7e24d403e380"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3bcce0edc1488906c2d4c75c94c70a0417e83920dd4c88fec1078c94843a6ce9"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e2f6a2347d3440ae789505693a02836383426249d5293541cd712e07e7aecf54"}, - {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4fd52d3455a0aa997734f3835cbc4c9f32571345143960e7d7ebfe7b5fbfa3b2"}, - {file = "rpds_py-0.25.1-cp310-cp310-win32.whl", hash = "sha256:3f0b1798cae2bbbc9b9db44ee068c556d4737911ad53a4e5093d09d04b3bbc24"}, - {file = "rpds_py-0.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3ebd879ab996537fc510a2be58c59915b5dd63bccb06d1ef514fee787e05984a"}, - {file = "rpds_py-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f048bbf18b1f9120685c6d6bb70cc1a52c8cc11bdd04e643d28d3be0baf666d"}, - {file = "rpds_py-0.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fbb0dbba559959fcb5d0735a0f87cdbca9e95dac87982e9b95c0f8f7ad10255"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ca54b9cf9d80b4016a67a0193ebe0bcf29f6b0a96f09db942087e294d3d4c2"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ee3e26eb83d39b886d2cb6e06ea701bba82ef30a0de044d34626ede51ec98b0"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89706d0683c73a26f76a5315d893c051324d771196ae8b13e6ffa1ffaf5e574f"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2013ee878c76269c7b557a9a9c042335d732e89d482606990b70a839635feb7"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45e484db65e5380804afbec784522de84fa95e6bb92ef1bd3325d33d13efaebd"}, - {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48d64155d02127c249695abb87d39f0faf410733428d499867606be138161d65"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:048893e902132fd6548a2e661fb38bf4896a89eea95ac5816cf443524a85556f"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0317177b1e8691ab5879f4f33f4b6dc55ad3b344399e23df2e499de7b10a548d"}, - {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffcf57826d77a4151962bf1701374e0fc87f536e56ec46f1abdd6a903354042"}, - {file = "rpds_py-0.25.1-cp311-cp311-win32.whl", hash = "sha256:cda776f1967cb304816173b30994faaf2fd5bcb37e73118a47964a02c348e1bc"}, - {file = "rpds_py-0.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc3c1ff0abc91444cd20ec643d0f805df9a3661fcacf9c95000329f3ddf268a4"}, - {file = "rpds_py-0.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:5a3ddb74b0985c4387719fc536faced33cadf2172769540c62e2a94b7b9be1c4"}, - {file = "rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c"}, - {file = "rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea"}, - {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd"}, - {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb"}, - {file = "rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe"}, - {file = "rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192"}, - {file = "rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728"}, - {file = "rpds_py-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:659d87430a8c8c704d52d094f5ba6fa72ef13b4d385b7e542a08fc240cb4a559"}, - {file = "rpds_py-0.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68f6f060f0bbdfb0245267da014d3a6da9be127fe3e8cc4a68c6f833f8a23bb1"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083a9513a33e0b92cf6e7a6366036c6bb43ea595332c1ab5c8ae329e4bcc0a9c"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:816568614ecb22b18a010c7a12559c19f6fe993526af88e95a76d5a60b8b75fb"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c6564c0947a7f52e4792983f8e6cf9bac140438ebf81f527a21d944f2fd0a40"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c4a128527fe415d73cf1f70a9a688d06130d5810be69f3b553bf7b45e8acf79"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e1d7a4978ed554f095430b89ecc23f42014a50ac385eb0c4d163ce213c325"}, - {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d74ec9bc0e2feb81d3f16946b005748119c0f52a153f6db6a29e8cd68636f295"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3af5b4cc10fa41e5bc64e5c198a1b2d2864337f8fcbb9a67e747e34002ce812b"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79dc317a5f1c51fd9c6a0c4f48209c6b8526d0524a6904fc1076476e79b00f98"}, - {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1521031351865e0181bc585147624d66b3b00a84109b57fcb7a779c3ec3772cd"}, - {file = "rpds_py-0.25.1-cp313-cp313-win32.whl", hash = "sha256:5d473be2b13600b93a5675d78f59e63b51b1ba2d0476893415dfbb5477e65b31"}, - {file = "rpds_py-0.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7b74e92a3b212390bdce1d93da9f6488c3878c1d434c5e751cbc202c5e09500"}, - {file = "rpds_py-0.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:dd326a81afe332ede08eb39ab75b301d5676802cdffd3a8f287a5f0b694dc3f5"}, - {file = "rpds_py-0.25.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a58d1ed49a94d4183483a3ce0af22f20318d4a1434acee255d683ad90bf78129"}, - {file = "rpds_py-0.25.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f251bf23deb8332823aef1da169d5d89fa84c89f67bdfb566c49dea1fccfd50d"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd586bfa270c1103ece2109314dd423df1fa3d9719928b5d09e4840cec0d72"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d273f136e912aa101a9274c3145dcbddbe4bac560e77e6d5b3c9f6e0ed06d34"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:666fa7b1bd0a3810a7f18f6d3a25ccd8866291fbbc3c9b912b917a6715874bb9"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:921954d7fbf3fccc7de8f717799304b14b6d9a45bbeec5a8d7408ccbf531faf5"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d86373ff19ca0441ebeb696ef64cb58b8b5cbacffcda5a0ec2f3911732a194"}, - {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8980cde3bb8575e7c956a530f2c217c1d6aac453474bf3ea0f9c89868b531b6"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8eb8c84ecea987a2523e057c0d950bcb3f789696c0499290b8d7b3107a719d78"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e43a005671a9ed5a650f3bc39e4dbccd6d4326b24fb5ea8be5f3a43a6f576c72"}, - {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58f77c60956501a4a627749a6dcb78dac522f249dd96b5c9f1c6af29bfacfb66"}, - {file = "rpds_py-0.25.1-cp313-cp313t-win32.whl", hash = "sha256:2cb9e5b5e26fc02c8a4345048cd9998c2aca7c2712bd1b36da0c72ee969a3523"}, - {file = "rpds_py-0.25.1-cp313-cp313t-win_amd64.whl", hash = "sha256:401ca1c4a20cc0510d3435d89c069fe0a9ae2ee6495135ac46bdd49ec0495763"}, - {file = "rpds_py-0.25.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ce4c8e485a3c59593f1a6f683cf0ea5ab1c1dc94d11eea5619e4fb5228b40fbd"}, - {file = "rpds_py-0.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8222acdb51a22929c3b2ddb236b69c59c72af4019d2cba961e2f9add9b6e634"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4593c4eae9b27d22df41cde518b4b9e4464d139e4322e2127daa9b5b981b76be"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd035756830c712b64725a76327ce80e82ed12ebab361d3a1cdc0f51ea21acb0"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:114a07e85f32b125404f28f2ed0ba431685151c037a26032b213c882f26eb908"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dec21e02e6cc932538b5203d3a8bd6aa1480c98c4914cb88eea064ecdbc6396a"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09eab132f41bf792c7a0ea1578e55df3f3e7f61888e340779b06050a9a3f16e9"}, - {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c98f126c4fc697b84c423e387337d5b07e4a61e9feac494362a59fd7a2d9ed80"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0e6a327af8ebf6baba1c10fadd04964c1965d375d318f4435d5f3f9651550f4a"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc120d1132cff853ff617754196d0ac0ae63befe7c8498bd67731ba368abe451"}, - {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:140f61d9bed7839446bdd44852e30195c8e520f81329b4201ceead4d64eb3a9f"}, - {file = "rpds_py-0.25.1-cp39-cp39-win32.whl", hash = "sha256:9c006f3aadeda131b438c3092124bd196b66312f0caa5823ef09585a669cf449"}, - {file = "rpds_py-0.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:a61d0b2c7c9a0ae45732a77844917b427ff16ad5464b4d4f5e4adb955f582890"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b24bf3cd93d5b6ecfbedec73b15f143596c88ee249fa98cefa9a9dc9d92c6f28"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:0eb90e94f43e5085623932b68840b6f379f26db7b5c2e6bcef3179bd83c9330f"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d50e4864498a9ab639d6d8854b25e80642bd362ff104312d9770b05d66e5fb13"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c9409b47ba0650544b0bb3c188243b83654dfe55dcc173a86832314e1a6a35d"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:796ad874c89127c91970652a4ee8b00d56368b7e00d3477f4415fe78164c8000"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85608eb70a659bf4c1142b2781083d4b7c0c4e2c90eff11856a9754e965b2540"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4feb9211d15d9160bc85fa72fed46432cdc143eb9cf6d5ca377335a921ac37b"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ccfa689b9246c48947d31dd9d8b16d89a0ecc8e0e26ea5253068efb6c542b76e"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c5b317ecbd8226887994852e85de562f7177add602514d4ac40f87de3ae45a8"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:454601988aab2c6e8fd49e7634c65476b2b919647626208e376afcd22019eeb8"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1c0c434a53714358532d13539272db75a5ed9df75a4a090a753ac7173ec14e11"}, - {file = "rpds_py-0.25.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f73ce1512e04fbe2bc97836e89830d6b4314c171587a99688082d090f934d20a"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee86d81551ec68a5c25373c5643d343150cc54672b5e9a0cafc93c1870a53954"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89c24300cd4a8e4a51e55c31a8ff3918e6651b241ee8876a42cc2b2a078533ba"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:771c16060ff4e79584dc48902a91ba79fd93eade3aa3a12d6d2a4aadaf7d542b"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:785ffacd0ee61c3e60bdfde93baa6d7c10d86f15655bd706c89da08068dc5038"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a40046a529cc15cef88ac5ab589f83f739e2d332cb4d7399072242400ed68c9"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85fc223d9c76cabe5d0bff82214459189720dc135db45f9f66aa7cffbf9ff6c1"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0be9965f93c222fb9b4cc254235b3b2b215796c03ef5ee64f995b1b69af0762"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8378fa4a940f3fb509c081e06cb7f7f2adae8cf46ef258b0e0ed7519facd573e"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:33358883a4490287e67a2c391dfaea4d9359860281db3292b6886bf0be3d8692"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1d1fadd539298e70cac2f2cb36f5b8a65f742b9b9f1014dd4ea1f7785e2470bf"}, - {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a46c2fb2545e21181445515960006e85d22025bd2fe6db23e76daec6eb689fe"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:50f2c501a89c9a5f4e454b126193c5495b9fb441a75b298c60591d8a2eb92e1b"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d779b325cc8238227c47fbc53964c8cc9a941d5dbae87aa007a1f08f2f77b23"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:036ded36bedb727beeabc16dc1dad7cb154b3fa444e936a03b67a86dc6a5066e"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:245550f5a1ac98504147cba96ffec8fabc22b610742e9150138e5d60774686d7"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff7c23ba0a88cb7b104281a99476cccadf29de2a0ef5ce864959a52675b1ca83"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e37caa8cdb3b7cf24786451a0bdb853f6347b8b92005eeb64225ae1db54d1c2b"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2f48ab00181600ee266a095fe815134eb456163f7d6699f525dee471f312cf"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e5fc7484fa7dce57e25063b0ec9638ff02a908304f861d81ea49273e43838c1"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d3c10228d6cf6fe2b63d2e7985e94f6916fa46940df46b70449e9ff9297bd3d1"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:5d9e40f32745db28c1ef7aad23f6fc458dc1e29945bd6781060f0d15628b8ddf"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:35a8d1a24b5936b35c5003313bc177403d8bdef0f8b24f28b1c4a255f94ea992"}, - {file = "rpds_py-0.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6099263f526efff9cf3883dfef505518730f7a7a93049b1d90d42e50a22b4793"}, - {file = "rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, + {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, + {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, + {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, + {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, + {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, + {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, + {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, ] [[package]] name = "ruff" -version = "0.14.10" +version = "0.14.14" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49"}, - {file = "ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f"}, - {file = "ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f"}, - {file = "ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f"}, - {file = "ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d"}, - {file = "ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405"}, - {file = "ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60"}, - {file = "ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830"}, - {file = "ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6"}, - {file = "ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154"}, - {file = "ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6"}, - {file = "ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4"}, + {file = "ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed"}, + {file = "ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c"}, + {file = "ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974"}, + {file = "ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66"}, + {file = "ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13"}, + {file = "ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412"}, + {file = "ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3"}, + {file = "ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b"}, + {file = "ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167"}, + {file = "ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd"}, + {file = "ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c"}, + {file = "ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b"}, ] [[package]] name = "setuptools" -version = "80.9.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" +version = "82.0.1" +description = "Most extensible Python build backend with support for C/C++ extension modules" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, - {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, + {file = "setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb"}, + {file = "setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] -core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.13.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.18.*)", "pytest-mypy"] [[package]] name = "shellingham" @@ -3801,7 +4244,7 @@ version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -3938,14 +4381,14 @@ uvicorn = ["uvicorn (>=0.34.0)"] [[package]] name = "starlette" -version = "0.47.1" +version = "0.48.0" description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527"}, - {file = "starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b"}, + {file = "starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659"}, + {file = "starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46"}, ] [package.dependencies] @@ -3955,6 +4398,50 @@ typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\"" [package.extras] full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] +[[package]] +name = "tibs" +version = "0.5.7" +description = "A sleek Python library for binary data." +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "tibs-0.5.7-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:01ea5258bdf942d21560dc07d532082cd04f07cfef65fedd58ae84f7d0d2562a"}, + {file = "tibs-0.5.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f5eea45851c960628a2bd29847765d55e19a687c5374456ad2c8cf6410eb1efa"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a9feed5931b881809a950eca0e01e757113e2383a2af06a3e6982f110c869e2"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:501728d096e10d9a165aa526743d47418a6bbfd7b084fa47ecb22be7641d3edb"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77103a9f1af72ac4cf5006828d0fb21578d19ce55fd990e9a1c8e46fd549561f"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f95d5db62960205a1e9eba73ce67dc14e7366ae080cd4e5b6f005ebd90faf02"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace018a057459e3dccd06a4aae1c5c8cd57e352b263dcef534ae39bf3e03b5cf"}, + {file = "tibs-0.5.7-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a618de62004d9217d2d2ab0f7f9bbdd098c12642dc01f07b3fb00f0b5f3131a"}, + {file = "tibs-0.5.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42725200f1b02687ed6e6a1c01e0ec150dc829d21d901ffc74cc0ac4d821f57f"}, + {file = "tibs-0.5.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:63255749f937c5e6fedcc7d54e7bd359aef711017e6855f373b0510a14ee2215"}, + {file = "tibs-0.5.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:4b7510235379368b7523f624d46e0680f3706e3a3965877a6583cdcb598b8bac"}, + {file = "tibs-0.5.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29480bf03e3372a5f9cc59ea0541f76f8efd696d4f0d214715e94247c342a037"}, + {file = "tibs-0.5.7-cp314-cp314t-win32.whl", hash = "sha256:b9535dc7b7484904a58b51bd8e64da7efbf1d8466ff7e84ed1d78f4ddc561c99"}, + {file = "tibs-0.5.7-cp314-cp314t-win_amd64.whl", hash = "sha256:1906729038b85c3b4c040aa28a456d85bc976d0c5007177350eb73374ffa0fd0"}, + {file = "tibs-0.5.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7d6592ed93c6748acd39df484c1ee24d40ee247c2a20ca38ba03363506fd24f3"}, + {file = "tibs-0.5.7-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:859f05315ffb307d3474c505d694f3a547f00730a024c982f5f60316a5505b3c"}, + {file = "tibs-0.5.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:a883ca13a922a66b2c1326a9c188123a574741a72510a4bf52fd6f97db191e44"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f70bd250769381c73110d6f24feaf8b6fcd44f680b3cb28a20ea06db3d04fb6f"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76746f01b3db9dbd802f5e615f11f68df7a29ecef521b082dca53f3fa7d0084f"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847709c108800ad6a45efaf9a040628278956938a4897f7427a2587013dc3b98"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad61df93b50f875b277ab736c5d37b6bce56f9abce489a22f4e02d9daa2966e3"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e13b9c7ff2604b0146772025e1ac6f85c8c625bf6ac73736ff671eaf357dda41"}, + {file = "tibs-0.5.7-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a7ce857ef05c59dc61abadc31c4b9b1e3c62f9e5fb29217988c308936aea71e"}, + {file = "tibs-0.5.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1d5521cc6768bfa6282a0c591ba06b079ab91b5c7d5696925ad2abac59779a54"}, + {file = "tibs-0.5.7-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:477608f9b87e24a22ab6d50b81da04a5cb59bfa49598ff7ec5165035a18fb392"}, + {file = "tibs-0.5.7-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:ac0aa2aae38f7325c91c261ce1d18f769c4c7033c98d6ea3ea5534585cf16452"}, + {file = "tibs-0.5.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b56583db148e5094d781c3d746815dbcbb6378c6f813c8ce291efd4ab21da8b"}, + {file = "tibs-0.5.7-cp38-abi3-win32.whl", hash = "sha256:d4f3ff613d486650816bc5516760c0382a2cc0ca8aeddd8914d011bc3b81d9a2"}, + {file = "tibs-0.5.7-cp38-abi3-win_amd64.whl", hash = "sha256:a61d36155f8ab8642e1b6744e13822f72050fc7ec4f86ec6965295afa04949e2"}, + {file = "tibs-0.5.7-cp38-abi3-win_arm64.whl", hash = "sha256:130bc68ff500fc8185677df7a97350b5d5339e6ba7e325bc3031337f6424ede7"}, + {file = "tibs-0.5.7.tar.gz", hash = "sha256:173dfbecb2309edd9771f453580c88cf251e775613461566b23dbd756b3d54cb"}, +] + +[package.extras] +dev = ["build", "hypothesis (>=6.151.0)", "pyright (>=1.1.389)", "pytest (>=9.0.0)", "pytest-benchmark (>=5.2.0)"] + [[package]] name = "tlv8" version = "0.10.0" @@ -3968,79 +4455,92 @@ files = [ [[package]] name = "tomli" -version = "2.2.1" +version = "2.4.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["dev"] markers = "python_full_version <= \"3.11.0a6\"" files = [ - {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, - {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, - {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, - {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, - {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, - {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, - {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, - {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, - {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, - {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, - {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, - {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, - {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, - {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, - {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, - {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, - {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, - {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, ] [[package]] name = "tornado" -version = "6.5.2" +version = "6.5.5" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6"}, - {file = "tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882"}, - {file = "tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4"}, - {file = "tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04"}, - {file = "tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0"}, - {file = "tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f"}, - {file = "tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af"}, - {file = "tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0"}, + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa"}, + {file = "tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5"}, + {file = "tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e"}, + {file = "tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca"}, + {file = "tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7"}, + {file = "tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b"}, + {file = "tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6"}, + {file = "tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9"}, ] [[package]] name = "tqdm" -version = "4.67.1" +version = "4.67.3" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, - {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, + {file = "tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf"}, + {file = "tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb"}, ] [package.dependencies] @@ -4055,21 +4555,21 @@ telegram = ["requests"] [[package]] name = "typer" -version = "0.16.1" +version = "0.24.1" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9"}, - {file = "typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614"}, + {file = "typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e"}, + {file = "typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45"}, ] [package.dependencies] -click = ">=8.0.0" -rich = ">=10.11.0" +annotated-doc = ">=0.0.2" +click = ">=8.2.1" +rich = ">=12.3.0" shellingham = ">=1.3.0" -typing-extensions = ">=3.7.4.3" [[package]] name = "types-mock" @@ -4085,26 +4585,26 @@ files = [ [[package]] name = "types-passlib" -version = "1.7.7.20250602" +version = "1.7.7.20260211" description = "Typing stubs for passlib" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "types_passlib-1.7.7.20250602-py3-none-any.whl", hash = "sha256:ed73a91be9a22484ebd62cc0d127675ded542b892b99776db92dab760bbfe274"}, - {file = "types_passlib-1.7.7.20250602.tar.gz", hash = "sha256:cf2350e78d36b6b09e4db44284d96651b57285f499cfabf111b616065abab7b3"}, + {file = "types_passlib-1.7.7.20260211-py3-none-any.whl", hash = "sha256:c0f1ad440c513a6c07f333b28249530686056fd54a7b3ac6128ae31fd46305d3"}, + {file = "types_passlib-1.7.7.20260211.tar.gz", hash = "sha256:af73afffe1ce94c95c7f6072bd261572c29845de74fdffa3a265fc7634bca056"}, ] [[package]] name = "types-protobuf" -version = "6.32.1.20251210" +version = "6.32.1.20260221" description = "Typing stubs for protobuf" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140"}, - {file = "types_protobuf-6.32.1.20251210.tar.gz", hash = "sha256:c698bb3f020274b1a2798ae09dc773728ce3f75209a35187bd11916ebfde6763"}, + {file = "types_protobuf-6.32.1.20260221-py3-none-any.whl", hash = "sha256:da7cdd947975964a93c30bfbcc2c6841ee646b318d3816b033adc2c4eb6448e4"}, + {file = "types_protobuf-6.32.1.20260221.tar.gz", hash = "sha256:6d5fb060a616bfb076cbb61b4b3c3969f5fc8bec5810f9a2f7e648ee5cbcbf6e"}, ] [[package]] @@ -4121,14 +4621,14 @@ files = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.7.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, - {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, + {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, + {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, ] [package.extras] @@ -4223,73 +4723,95 @@ test = ["aiohttp (>=3.10.5)", "flake8 (>=6.1,<7.0)", "mypy (>=0.800)", "psutil", [[package]] name = "virtualenv" -version = "20.36.1" +version = "21.2.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f"}, - {file = "virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba"}, + {file = "virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f"}, + {file = "virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098"}, ] [package.dependencies] distlib = ">=0.3.7,<1" -filelock = {version = ">=3.20.1,<4", markers = "python_version >= \"3.10\""} +filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" +python-discovery = ">=1" typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] - [[package]] name = "wallycore" -version = "1.5.1" +version = "1.5.2" description = "libwally Bitcoin library" optional = true python-versions = "*" groups = ["main"] markers = "extra == \"liquid\"" files = [ - {file = "wallycore-1.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb72f18f90e85cb8fbd423d7ffa04037221290be4965a42e657516bd2b4a916f"}, - {file = "wallycore-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5ce19b90bb153f25f4e6c18cee23b6b0517791b9dfb6c462d7620fe79598258b"}, - {file = "wallycore-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c460c8111e26fb9aab3ba548f1ad989c88364b2e7154d8b7f285696bddd3a14d"}, - {file = "wallycore-1.5.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cb5fdcee29453541361782d4a22164299c3468cea142bbe380fe0f405f836955"}, - {file = "wallycore-1.5.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c7baa21ac524e130a8800d4ba173668f7164ed6c884bbafe431a9ec8a9bd5fde"}, - {file = "wallycore-1.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d365c7453ea2abeed668800b3fac5c8ab4971add26904ab667fbd962053a4147"}, - {file = "wallycore-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:018f2a6cc53b8465f4ed9f519f4b4bf14914588ca1f28bd2ca69cef8ebad7c6d"}, - {file = "wallycore-1.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:856af4c3c17c4d57f2b61cec248925302b9cdde1898f6553257f96ca55d7293b"}, - {file = "wallycore-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8303a7fbc48def1a070b54f88104782a469ac71b10c1e8dcc30afe562aab265"}, - {file = "wallycore-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:216e2e7d2e573c5e81b175c66db1dbf63b8932fda084c1f4b3ea6463ba754445"}, - {file = "wallycore-1.5.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5f19e8fd45933d4780ed2fcb7c23105156860bffadeb61e54fa4cd81b93ccd43"}, - {file = "wallycore-1.5.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bcc23a01efa070a88fa4952369d7e064d6a8e70f8cc11b8a2d2ab5140675343b"}, - {file = "wallycore-1.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:78635dcd112604ad86067d79bcb1dc834342f95da1481ccabaf23aba85be08b1"}, - {file = "wallycore-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:aa85dbd16e0506aae6accc8c9d71706f5f895f3143d3ec35160aaec94c29bc57"}, - {file = "wallycore-1.5.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:6535e9315aff369224ca57f0cb8ecd68e7134fa34762211c05ee7150bb03566e"}, - {file = "wallycore-1.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:94c4669c8721e1750d3c1580de892aba1aa69f5cbda348b881e0606ac27eca0d"}, - {file = "wallycore-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:619e5239dda0f2cc681942a8cde0a6f04809ed7f3982f19063c75dc820625abb"}, - {file = "wallycore-1.5.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2e86a45232f7dc9c306903b261ac08fa4090cf9396cfb45f355e23e3a5b9cd8d"}, - {file = "wallycore-1.5.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:acc59c95a3959121bac558581218647589836839a5a592cdb123e88dffbc3409"}, - {file = "wallycore-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d30ab245d761b62139c29cf3b1e7a2c186d63c4e586871b3a41e52b6a2e4b698"}, - {file = "wallycore-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:0b932510c859ac3e1fc57161420ecb2bb9b6562fce7acd1d9351337cc2cc3515"}, - {file = "wallycore-1.5.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6c7249cb0dc28891ef0df3467eee97b9195caf04a3bcce253af3a5782713e2f0"}, - {file = "wallycore-1.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:15f4c1d77134794535177bd5b5ca63865fcff953995e6fc3b1d26bc586585353"}, - {file = "wallycore-1.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2a4ee4da8aeefaa04d9199b634155b51fd6a8c93c7d1b8d5ec4507c3d89d248a"}, - {file = "wallycore-1.5.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c996234733929e757b60132a0583f481e5561b7aa73abb9602bb36380fe39b66"}, - {file = "wallycore-1.5.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ef5b127dc5ad6fd77519b2595b1f15e1610dd38f8c6bb9cc23b2f91b593e582f"}, - {file = "wallycore-1.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:90d39b0bf204426da3123b1428bb416d809bd29889b7b2f3edc929df98b70a6d"}, - {file = "wallycore-1.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:515344c0e85811473bac64f67f19baebdc829b649a9a2e85552f0b4b0394b205"}, - {file = "wallycore-1.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a3ef45c05501f1953ae37a7e19a8c0d9ce48275a3acb883f95e67fce37f0c8b6"}, - {file = "wallycore-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:16a379613493bbcf0964a3a53b1f41b1c591e8f88156b2c96290e1fafeb4c4c0"}, - {file = "wallycore-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6ff57f863bebacaba2d065062de76ce35913fba1968b3c0eb4729696d9450f8e"}, - {file = "wallycore-1.5.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f18854f4e474792db71894a11ce697979e73782173d6917e6bfff778eebd0224"}, - {file = "wallycore-1.5.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:53057128f787ac34b33f45cc9754b7a828c5717802991921a135832cace1d8f9"}, - {file = "wallycore-1.5.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3cc73efd8156c1e844c97c228c38cf89175d55936591e34e32e9bb3dfe8d507"}, - {file = "wallycore-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:9bd07a3197a3c11966bd49c781a26c6cc3c50d26261db87af1a6986d4c98e9f3"}, - {file = "wallycore-1.5.1.tar.gz", hash = "sha256:e691d713d449c5fcf91703dd7af9b0c7262db70abd4f69d3242b4fbe63bd7490"}, + {file = "wallycore-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9978acdb2fec4e2dc1588237a497a4b44d39cec413babb7e2b36031423e70334"}, + {file = "wallycore-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21547e736cc0c3778df5a25e42dcc44923b255bf6a85d0c39cc7822a2eaf9192"}, + {file = "wallycore-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83293aa86fadff5d7e422c926da0d55c937367fee11371305c77339fa50823cf"}, + {file = "wallycore-1.5.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3bbd396e44ca4c1779bbde38b5d1fda94a8b7ab05fa10b9fed4085d3a3663997"}, + {file = "wallycore-1.5.2-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:55de0a2051a6d148fa062858bc8862b34bad8aa7f98d3738ef35032eeb333187"}, + {file = "wallycore-1.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c7a9baa02d08c454489cbd860de03970b7f94ac6f42643a192045e5c7251a65"}, + {file = "wallycore-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:49dc66fc796410869a2a64e7626d1bea278f6fce11b08a6598bad2a69ff0713c"}, + {file = "wallycore-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13d32b3c8e156ba14262bea5f627842fa27bd0399f4e1953973a0cf064be61c0"}, + {file = "wallycore-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:97ab5d1555b1644008e8366b2816863b1fa32af4203cfe8fa3c0e19ce9e103c7"}, + {file = "wallycore-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ab272c9c1c66310d8f4569f96876ae5835462eaa73d103d8bf79aba7a964d95"}, + {file = "wallycore-1.5.2-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:8f70e8106e3a563a7d253e4cef569b7c0aca77010a16e56bf2d74d3b885fa343"}, + {file = "wallycore-1.5.2-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:3d77422c5fb1fd70d7cf5887a9c13c7e50e69b466a3b4177da5180d5f27f8e21"}, + {file = "wallycore-1.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4b05863495349ee30c66ad996e53d9a88851fb86db673df0c703974688e9ff46"}, + {file = "wallycore-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:5dcbef3d03dbdcf1a120afaefa927f54dd0932958135816f0764342ab0db0d99"}, + {file = "wallycore-1.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f84323ce7459a1fbcd82c8fb99b17f2c67ef6a94cf5816d68396ce5e78281513"}, + {file = "wallycore-1.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:70c67442df6c8b39b9239d1525deab3f021d97b9832824b557beb6a4a4722f65"}, + {file = "wallycore-1.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:499bfe185333c92b3f0b9f17805b35bb35115fc88dc1bcbe28c6c57fad5d196f"}, + {file = "wallycore-1.5.2-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ca2f6161e6662730d0c8ed713639f852a91fcc7d42b20341dd7524b12b8291ff"}, + {file = "wallycore-1.5.2-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:8fb1861b22e10f3536435db52c7b0363916a474a433db082335009d8d652b2cc"}, + {file = "wallycore-1.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a154a9f9f759a53691de4281bb55b71fb2ae19e5eeb5268f3809132402eb9f89"}, + {file = "wallycore-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:36da969b58cd32f95eba901027595ad35f0326c04c9e5227fa73e0c14203bb4c"}, + {file = "wallycore-1.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1161ce2d1f1ffc17510007463aa4203cddb1d134ccba7df324a69ea58f874252"}, + {file = "wallycore-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9e8090de1f8ebd1fb08a9948d9a3e7d0a44c322dd34f20d966171c6d939721eb"}, + {file = "wallycore-1.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a906fc41c9570c6169b4156afbdab64c8de0c8a87abe62133a10b19bc271c594"}, + {file = "wallycore-1.5.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:08199b3c8b40fc5fe4b20403f7178ee4b89cca359f39a827681c9889e19a04e1"}, + {file = "wallycore-1.5.2-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:352580118e5f8f0eb53d64b69148cf276de0bad7b867409834c5a17669f1c83a"}, + {file = "wallycore-1.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70afae25e2fe3fa449d2ebbc90bcad0addb53207736decf4c751c49085722066"}, + {file = "wallycore-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:53be0e26d94c5a958e0012f90a71289b00e7bf6633f2314c0ff1cb474822a02c"}, + {file = "wallycore-1.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fe14d34dd519070bc23b96bbe6ac61be6b3770bae4aac4fd16e9440db1a4aee"}, + {file = "wallycore-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d760efd6335242901fcb5c5ed90d2c4e736bf01afa3445d03d571762dd1c2386"}, + {file = "wallycore-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:912e4cc7f167da591f91666a6cd9f3146eb8ad889899b7c3d0c51d29e28959ac"}, + {file = "wallycore-1.5.2-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:49154841002c1c4118fb2589586bdbf384dfae1cf14e2a7b9092255a5635eecf"}, + {file = "wallycore-1.5.2-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:46ea056e10dc9f439b9949428126bcb7d0e9e99ebfdeffa2839dcf8d53fafb0d"}, + {file = "wallycore-1.5.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dfbd246d130ee6dd824d53af4cfdfb7eae189609b5a910fec651b287de62d069"}, + {file = "wallycore-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:4ddd4902a9bebc9e22edd6a0b50ecdd729338ce2a4908b68e487f71db303c152"}, + {file = "wallycore-1.5.2.tar.gz", hash = "sha256:352b7b215046d4fd0333a82dc4b3936b749e5b9ae22a078b991a6b10712b3748"}, ] +[[package]] +name = "wasmtime" +version = "46.0.1" +description = "A WebAssembly runtime powered by Wasmtime" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "wasmtime-46.0.1-py3-none-android_26_arm64_v8a.whl", hash = "sha256:cc8d52f9ad3bedc1e4de5002f7b22d7cac400be046711d177f6ce20a11eacb31"}, + {file = "wasmtime-46.0.1-py3-none-android_26_x86_64.whl", hash = "sha256:f8e4b0ec402b84b856d3c6c2f96c6e6889c56e685b5cfed0a4040775c751ca38"}, + {file = "wasmtime-46.0.1-py3-none-any.whl", hash = "sha256:85a092a63c20ccecb965b9aa12a19368d2e06203436d19701068efc390efa678"}, + {file = "wasmtime-46.0.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:9b46c546bf73ece2600403db7dc604c3ef12046ccf2fabe07d7bfaa00453ce8b"}, + {file = "wasmtime-46.0.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:de1a69573a173b5171f9413bcf0b88f4fed2721ed02c842fc25de5358730ccdf"}, + {file = "wasmtime-46.0.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:e53c65abe31aeeb19a3f794b6e53140d401c4c79ad91c89caefdc502ee2b10c1"}, + {file = "wasmtime-46.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:841b53fc17eedabaa6deb1e062a04a0a8953908d540fadb4149bc55c3f6d3e50"}, + {file = "wasmtime-46.0.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f295d10012b6ca6ecffa7757eed70b84ebaa2e33dc39275e7b6bed5eed5130b9"}, + {file = "wasmtime-46.0.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:05fc65164b4825bf1c3c8f007df070b25accc974cb81d0bfc1c5d76fdf6f70e0"}, + {file = "wasmtime-46.0.1-py3-none-win_amd64.whl", hash = "sha256:559b0753e3ea311fd16000fe51c08592a625e61ebb8640601ae7173fc516e430"}, + {file = "wasmtime-46.0.1-py3-none-win_arm64.whl", hash = "sha256:967625406fde8fc3c9d795ffbb7bdde77d0a38de776e8eb7a0416ca6d811a27a"}, + {file = "wasmtime-46.0.1.tar.gz", hash = "sha256:0da0388c21bc0f0e633c7a30f2b7939a657f5019258c9a3a63fd37298a0dbb8b"}, +] + +[package.extras] +testing = ["coverage", "pycparser", "pytest", "pytest-mypy"] + [[package]] name = "websocket-client" version = "1.9.0" @@ -4388,14 +4910,14 @@ files = [ [[package]] name = "werkzeug" -version = "3.1.5" +version = "3.1.6" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc"}, - {file = "werkzeug-3.1.5.tar.gz", hash = "sha256:6a548b0e88955dd07ccb25539d7d0cc97417ee9e179677d22c7041c8f078ce67"}, + {file = "werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131"}, + {file = "werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25"}, ] [package.dependencies] @@ -4422,207 +4944,243 @@ dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"] [[package]] name = "wrapt" -version = "1.17.3" +version = "2.1.2" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, - {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, - {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, - {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, - {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, - {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, - {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, - {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, - {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, - {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, - {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, - {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, - {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, - {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, - {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, - {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, - {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, - {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, - {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, - {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, - {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, - {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, - {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, - {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, - {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, - {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, - {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, - {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, - {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, - {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, - {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, - {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, - {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, - {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235"}, - {file = "wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c"}, - {file = "wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b"}, - {file = "wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa"}, - {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7"}, - {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4"}, - {file = "wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10"}, - {file = "wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6"}, - {file = "wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067"}, - {file = "wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454"}, - {file = "wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e"}, - {file = "wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f"}, - {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056"}, - {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804"}, - {file = "wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977"}, - {file = "wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116"}, - {file = "wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a"}, - {file = "wrapt-1.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f"}, - {file = "wrapt-1.17.3-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00"}, - {file = "wrapt-1.17.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56"}, - {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5"}, - {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22"}, - {file = "wrapt-1.17.3-cp38-cp38-win32.whl", hash = "sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c"}, - {file = "wrapt-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9"}, - {file = "wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d"}, - {file = "wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a"}, - {file = "wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139"}, - {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df"}, - {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b"}, - {file = "wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81"}, - {file = "wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f"}, - {file = "wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f"}, - {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, - {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, -] - -[[package]] -name = "yarl" -version = "1.20.1" -description = "Yet another URL library" -optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"}, - {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"}, - {file = "yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23"}, - {file = "yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24"}, - {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13"}, - {file = "yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8"}, - {file = "yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16"}, - {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e"}, - {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b"}, - {file = "yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8"}, - {file = "yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1"}, - {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e"}, - {file = "yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773"}, - {file = "yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e"}, - {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9"}, - {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a"}, - {file = "yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd"}, - {file = "yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a"}, - {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004"}, - {file = "yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5"}, - {file = "yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698"}, - {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a"}, - {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3"}, - {file = "yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5"}, - {file = "yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b"}, - {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1"}, - {file = "yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7"}, - {file = "yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c"}, - {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d"}, - {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf"}, - {file = "yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3"}, - {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458"}, - {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e"}, - {file = "yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d"}, - {file = "yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f"}, - {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3"}, - {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b"}, - {file = "yarl-1.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000"}, - {file = "yarl-1.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8"}, - {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d"}, - {file = "yarl-1.20.1-cp39-cp39-win32.whl", hash = "sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06"}, - {file = "yarl-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00"}, - {file = "yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77"}, - {file = "yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac"}, + {file = "wrapt-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a86d99a14f76facb269dc148590c01aaf47584071809a70da30555228158c"}, + {file = "wrapt-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a819e39017f95bf7aede768f75915635aa8f671f2993c036991b8d3bfe8dbb6f"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5681123e60aed0e64c7d44f72bbf8b4ce45f79d81467e2c4c728629f5baf06eb"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8b28e97a44d21836259739ae76284e180b18abbb4dcfdff07a415cf1016c3e"}, + {file = "wrapt-2.1.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cef91c95a50596fcdc31397eb6955476f82ae8a3f5a8eabdc13611b60ee380ba"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dad63212b168de8569b1c512f4eac4b57f2c6934b30df32d6ee9534a79f1493f"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d307aa6888d5efab2c1cde09843d48c843990be13069003184b67d426d145394"}, + {file = "wrapt-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c87cf3f0c85e27b3ac7d9ad95da166bf8739ca215a8b171e8404a2d739897a45"}, + {file = "wrapt-2.1.2-cp310-cp310-win32.whl", hash = "sha256:d1c5fea4f9fe3762e2b905fdd67df51e4be7a73b7674957af2d2ade71a5c075d"}, + {file = "wrapt-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:d8f7740e1af13dff2684e4d56fe604a7e04d6c94e737a60568d8d4238b9a0c71"}, + {file = "wrapt-2.1.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c6cc827c00dc839350155f316f1f8b4b0c370f52b6a19e782e2bda89600c7dc"}, + {file = "wrapt-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:96159a0ee2b0277d44201c3b5be479a9979cf154e8c82fa5df49586a8e7679bb"}, + {file = "wrapt-2.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98ba61833a77b747901e9012072f038795de7fc77849f1faa965464f3f87ff2d"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:767c0dbbe76cae2a60dd2b235ac0c87c9cccf4898aef8062e57bead46b5f6894"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c691a6bc752c0cc4711cc0c00896fcd0f116abc253609ef64ef930032821842"}, + {file = "wrapt-2.1.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f3b7d73012ea75aee5844de58c88f44cf62d0d62711e39da5a82824a7c4626a8"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:577dff354e7acd9d411eaf4bfe76b724c89c89c8fc9b7e127ee28c5f7bcb25b6"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d7b6fd105f8b24e5bd23ccf41cb1d1099796524bcc6f7fbb8fe576c44befbc9"}, + {file = "wrapt-2.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:866abdbf4612e0b34764922ef8b1c5668867610a718d3053d59e24a5e5fcfc15"}, + {file = "wrapt-2.1.2-cp311-cp311-win32.whl", hash = "sha256:5a0a0a3a882393095573344075189eb2d566e0fd205a2b6414e9997b1b800a8b"}, + {file = "wrapt-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:64a07a71d2730ba56f11d1a4b91f7817dc79bc134c11516b75d1921a7c6fcda1"}, + {file = "wrapt-2.1.2-cp311-cp311-win_arm64.whl", hash = "sha256:b89f095fe98bc12107f82a9f7d570dc83a0870291aeb6b1d7a7d35575f55d98a"}, + {file = "wrapt-2.1.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9"}, + {file = "wrapt-2.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8"}, + {file = "wrapt-2.1.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1"}, + {file = "wrapt-2.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2"}, + {file = "wrapt-2.1.2-cp312-cp312-win32.whl", hash = "sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0"}, + {file = "wrapt-2.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63"}, + {file = "wrapt-2.1.2-cp312-cp312-win_arm64.whl", hash = "sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf"}, + {file = "wrapt-2.1.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b"}, + {file = "wrapt-2.1.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca"}, + {file = "wrapt-2.1.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8"}, + {file = "wrapt-2.1.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413"}, + {file = "wrapt-2.1.2-cp313-cp313-win32.whl", hash = "sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6"}, + {file = "wrapt-2.1.2-cp313-cp313-win_amd64.whl", hash = "sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1"}, + {file = "wrapt-2.1.2-cp313-cp313-win_arm64.whl", hash = "sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf"}, + {file = "wrapt-2.1.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b"}, + {file = "wrapt-2.1.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015"}, + {file = "wrapt-2.1.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67"}, + {file = "wrapt-2.1.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a"}, + {file = "wrapt-2.1.2-cp313-cp313t-win32.whl", hash = "sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd"}, + {file = "wrapt-2.1.2-cp313-cp313t-win_amd64.whl", hash = "sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f"}, + {file = "wrapt-2.1.2-cp313-cp313t-win_arm64.whl", hash = "sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679"}, + {file = "wrapt-2.1.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9"}, + {file = "wrapt-2.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c"}, + {file = "wrapt-2.1.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586"}, + {file = "wrapt-2.1.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19"}, + {file = "wrapt-2.1.2-cp314-cp314-win32.whl", hash = "sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508"}, + {file = "wrapt-2.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04"}, + {file = "wrapt-2.1.2-cp314-cp314-win_arm64.whl", hash = "sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575"}, + {file = "wrapt-2.1.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb"}, + {file = "wrapt-2.1.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044"}, + {file = "wrapt-2.1.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2"}, + {file = "wrapt-2.1.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3"}, + {file = "wrapt-2.1.2-cp314-cp314t-win32.whl", hash = "sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7"}, + {file = "wrapt-2.1.2-cp314-cp314t-win_amd64.whl", hash = "sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5"}, + {file = "wrapt-2.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00"}, + {file = "wrapt-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5e0fa9cc32300daf9eb09a1f5bdc6deb9a79defd70d5356ba453bcd50aef3742"}, + {file = "wrapt-2.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:710f6e5dfaf6a5d5c397d2d6758a78fecd9649deb21f1b645f5b57a328d63050"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:305d8a1755116bfdad5dda9e771dcb2138990a1d66e9edd81658816edf51aed1"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0d8fc30a43b5fe191cf2b1a0c82bab2571dadd38e7c0062ee87d6df858dd06e"}, + {file = "wrapt-2.1.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a5d516e22aedb7c9c1d47cba1c63160b1a6f61ec2f3948d127cd38d5cfbb556f"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:45914e8efbe4b9d5102fcf0e8e2e3258b83a5d5fba9f8f7b6d15681e9d29ffe0"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:478282ebd3795a089154fb16d3db360e103aa13d3b2ad30f8f6aac0d2207de0e"}, + {file = "wrapt-2.1.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3756219045f73fb28c5d7662778e4156fbd06cf823c4d2d4b19f97305e52819c"}, + {file = "wrapt-2.1.2-cp39-cp39-win32.whl", hash = "sha256:b8aefb4dbb18d904b96827435a763fa42fc1f08ea096a391710407a60983ced8"}, + {file = "wrapt-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:e5aeab8fe15c3dff75cfee94260dcd9cded012d4ff06add036c28fae7718593b"}, + {file = "wrapt-2.1.2-cp39-cp39-win_arm64.whl", hash = "sha256:f069e113743a21a3defac6677f000068ebb931639f789b5b226598e247a4c89e"}, + {file = "wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8"}, + {file = "wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e"}, +] + +[package.extras] +dev = ["pytest", "setuptools"] + +[[package]] +name = "yarl" +version = "1.23.0" +description = "Yet another URL library" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107"}, + {file = "yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d"}, + {file = "yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4"}, + {file = "yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750"}, + {file = "yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6"}, + {file = "yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d"}, + {file = "yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb"}, + {file = "yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b35d13d549077713e4414f927cdc388d62e543987c572baee613bf82f11a4b99"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbb0fef01f0c6b38cb0f39b1f78fc90b807e0e3c86a7ff3ce74ad77ce5c7880c"}, + {file = "yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc52310451fc7c629e13c4e061cbe2dd01684d91f2f8ee2821b083c58bd72432"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598"}, + {file = "yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc"}, + {file = "yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2"}, + {file = "yarl-1.23.0-cp311-cp311-win32.whl", hash = "sha256:51430653db848d258336cfa0244427b17d12db63d42603a55f0d4546f50f25b5"}, + {file = "yarl-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf49a3ae946a87083ef3a34c8f677ae4243f5b824bfc4c69672e72b3d6719d46"}, + {file = "yarl-1.23.0-cp311-cp311-win_arm64.whl", hash = "sha256:b39cb32a6582750b6cc77bfb3c49c0f8760dc18dc96ec9fb55fbb0f04e08b928"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1932b6b8bba8d0160a9d1078aae5838a66039e8832d41d2992daa9a3a08f7860"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:411225bae281f114067578891bc75534cfb3d92a3b4dfef7a6ca78ba354e6069"}, + {file = "yarl-1.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13a563739ae600a631c36ce096615fe307f131344588b0bc0daec108cdb47b25"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cbf44c5cb4a7633d078788e1b56387e3d3cf2b8139a3be38040b22d6c3221c8"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:53ad387048f6f09a8969631e4de3f1bf70c50e93545d64af4f751b2498755072"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4a59ba56f340334766f3a4442e0efd0af895fae9e2b204741ef885c446b3a1a8"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:803a3c3ce4acc62eaf01eaca1208dcf0783025ef27572c3336502b9c232005e7"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3d2bff8f37f8d0f96c7ec554d16945050d54462d6e95414babaa18bfafc7f51"}, + {file = "yarl-1.23.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c75eb09e8d55bceb4367e83496ff8ef2bc7ea6960efb38e978e8073ea59ecb67"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877b0738624280e34c55680d6054a307aa94f7d52fa0e3034a9cc6e790871da7"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b5405bb8f0e783a988172993cfc627e4d9d00432d6bbac65a923041edacf997d"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1c3a3598a832590c5a3ce56ab5576361b5688c12cb1d39429cf5dba30b510760"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:8419ebd326430d1cbb7efb5292330a2cf39114e82df5cc3d83c9a0d5ebeaf2f2"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:be61f6fff406ca40e3b1d84716fde398fc08bc63dd96d15f3a14230a0973ed86"}, + {file = "yarl-1.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ceb13c5c858d01321b5d9bb65e4cf37a92169ea470b70fec6f236b2c9dd7e34"}, + {file = "yarl-1.23.0-cp312-cp312-win32.whl", hash = "sha256:fffc45637bcd6538de8b85f51e3df3223e4ad89bccbfca0481c08c7fc8b7ed7d"}, + {file = "yarl-1.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:f69f57305656a4852f2a7203efc661d8c042e6cc67f7acd97d8667fb448a426e"}, + {file = "yarl-1.23.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e87a6e8735b44816e7db0b2fbc9686932df473c826b0d9743148432e10bb9b9"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:16c6994ac35c3e74fb0ae93323bf8b9c2a9088d55946109489667c510a7d010e"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a42e651629dafb64fd5b0286a3580613702b5809ad3f24934ea87595804f2c5"}, + {file = "yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c6b9461a2a8b47c65eef63bb1c76a4f1c119618ffa99ea79bc5bb1e46c5821b"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2569b67d616eab450d262ca7cb9f9e19d2f718c70a8b88712859359d0ab17035"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e9d9a4d06d3481eab79803beb4d9bd6f6a8e781ec078ac70d7ef2dcc29d1bea5"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f514f6474e04179d3d33175ed3f3e31434d3130d42ec153540d5b157deefd735"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fda207c815b253e34f7e1909840fd14299567b1c0eb4908f8c2ce01a41265401"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34b6cf500e61c90f305094911f9acc9c86da1a05a7a3f5be9f68817043f486e4"}, + {file = "yarl-1.23.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d7504f2b476d21653e4d143f44a175f7f751cd41233525312696c76aa3dbb23f"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:578110dd426f0d209d1509244e6d4a3f1a3e9077655d98c5f22583d63252a08a"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:609d3614d78d74ebe35f54953c5bbd2ac647a7ddb9c30a5d877580f5e86b22f2"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4966242ec68afc74c122f8459abd597afd7d8a60dc93d695c1334c5fd25f762f"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:e0fd068364a6759bc794459f0a735ab151d11304346332489c7972bacbe9e72b"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:39004f0ad156da43e86aa71f44e033de68a44e5a31fc53507b36dd253970054a"}, + {file = "yarl-1.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e5723c01a56c5028c807c701aa66722916d2747ad737a046853f6c46f4875543"}, + {file = "yarl-1.23.0-cp313-cp313-win32.whl", hash = "sha256:1b6b572edd95b4fa8df75de10b04bc81acc87c1c7d16bcdd2035b09d30acc957"}, + {file = "yarl-1.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:baaf55442359053c7d62f6f8413a62adba3205119bcb6f49594894d8be47e5e3"}, + {file = "yarl-1.23.0-cp313-cp313-win_arm64.whl", hash = "sha256:fb4948814a2a98e3912505f09c9e7493b1506226afb1f881825368d6fb776ee3"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:aecfed0b41aa72b7881712c65cf764e39ce2ec352324f5e0837c7048d9e6daaa"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a41bcf68efd19073376eb8cf948b8d9be0af26256403e512bb18f3966f1f9120"}, + {file = "yarl-1.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cde9a2ecd91668bcb7f077c4966d8ceddb60af01b52e6e3e2680e4cf00ad1a59"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5023346c4ee7992febc0068e7593de5fa2bf611848c08404b35ebbb76b1b0512"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1009abedb49ae95b136a8904a3f71b342f849ffeced2d3747bf29caeda218c4"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a8d00f29b42f534cc8aa3931cfe773b13b23e561e10d2b26f27a8d309b0e82a1"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:95451e6ce06c3e104556d73b559f5da6c34a069b6b62946d3ad66afcd51642ea"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:531ef597132086b6cf96faa7c6c1dcd0361dd5f1694e5cc30375907b9b7d3ea9"}, + {file = "yarl-1.23.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88f9fb0116fbfcefcab70f85cf4b74a2b6ce5d199c41345296f49d974ddb4123"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e7b0460976dc75cb87ad9cc1f9899a4b97751e7d4e77ab840fc9b6d377b8fd24"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:115136c4a426f9da976187d238e84139ff6b51a20839aa6e3720cd1026d768de"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ead11956716a940c1abc816b7df3fa2b84d06eaed8832ca32f5c5e058c65506b"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:fe8f8f5e70e6dbdfca9882cd9deaac058729bcf323cf7a58660901e55c9c94f6"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a0e317df055958a0c1e79e5d2aa5a5eaa4a6d05a20d4b0c9c3f48918139c9fc6"}, + {file = "yarl-1.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f0fd84de0c957b2d280143522c4f91a73aada1923caee763e24a2b3fda9f8a5"}, + {file = "yarl-1.23.0-cp313-cp313t-win32.whl", hash = "sha256:93a784271881035ab4406a172edb0faecb6e7d00f4b53dc2f55919d6c9688595"}, + {file = "yarl-1.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dd00607bffbf30250fe108065f07453ec124dbf223420f57f5e749b04295e090"}, + {file = "yarl-1.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:ac09d42f48f80c9ee1635b2fcaa819496a44502737660d3c0f2ade7526d29144"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:21d1b7305a71a15b4794b5ff22e8eef96ff4a6d7f9657155e5aa419444b28912"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85610b4f27f69984932a7abbe52703688de3724d9f72bceb1cca667deff27474"}, + {file = "yarl-1.23.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23f371bd662cf44a7630d4d113101eafc0cfa7518a2760d20760b26021454719"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a80f77dc1acaaa61f0934176fccca7096d9b1ff08c8ba9cddf5ae034a24319"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:bd654fad46d8d9e823afbb4f87c79160b5a374ed1ff5bde24e542e6ba8f41434"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:682bae25f0a0dd23a056739f23a134db9f52a63e2afd6bfb37ddc76292bbd723"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a82836cab5f197a0514235aaf7ffccdc886ccdaa2324bc0aafdd4ae898103039"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c57676bdedc94cd3bc37724cf6f8cd2779f02f6aba48de45feca073e714fe52"}, + {file = "yarl-1.23.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c7f8dc16c498ff06497c015642333219871effba93e4a2e8604a06264aca5c5c"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5ee586fb17ff8f90c91cf73c6108a434b02d69925f44f5f8e0d7f2f260607eae"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:17235362f580149742739cc3828b80e24029d08cbb9c4bda0242c7b5bc610a8e"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0793e2bd0cf14234983bbb371591e6bea9e876ddf6896cdcc93450996b0b5c85"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:3650dc2480f94f7116c364096bc84b1d602f44224ef7d5c7208425915c0475dd"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f40e782d49630ad384db66d4d8b73ff4f1b8955dc12e26b09a3e3af064b3b9d6"}, + {file = "yarl-1.23.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94f8575fbdf81749008d980c17796097e645574a3b8c28ee313931068dad14fe"}, + {file = "yarl-1.23.0-cp314-cp314-win32.whl", hash = "sha256:c8aa34a5c864db1087d911a0b902d60d203ea3607d91f615acd3f3108ac32169"}, + {file = "yarl-1.23.0-cp314-cp314-win_amd64.whl", hash = "sha256:63e92247f383c85ab00dd0091e8c3fa331a96e865459f5ee80353c70a4a42d70"}, + {file = "yarl-1.23.0-cp314-cp314-win_arm64.whl", hash = "sha256:70efd20be968c76ece7baa8dafe04c5be06abc57f754d6f36f3741f7aa7a208e"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9a18d6f9359e45722c064c97464ec883eb0e0366d33eda61cb19a244bf222679"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2803ed8b21ca47a43da80a6fd1ed3019d30061f7061daa35ac54f63933409412"}, + {file = "yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:394906945aa8b19fc14a61cf69743a868bb8c465efe85eee687109cc540b98f4"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d006bee8397a4a89f469b8deb22469fe7508132d3c17fa6ed871e79832691c"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:62694e275c93d54f7ccedcfef57d42761b2aad5234b6be1f3e3026cae4001cd4"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31de1613658308efdb21ada98cbc86a97c181aa050ba22a808120bb5be3ab94"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb1e8b8d66c278b21d13b0a7ca22c41dd757a7c209c6b12c313e445c31dd3b28"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50f9d8d531dfb767c565f348f33dd5139a6c43f5cbdf3f67da40d54241df93f6"}, + {file = "yarl-1.23.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:575aa4405a656e61a540f4a80eaa5260f2a38fff7bfdc4b5f611840d76e9e277"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:041b1a4cefacf65840b4e295c6985f334ba83c30607441ae3cf206a0eed1a2e4"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d38c1e8231722c4ce40d7593f28d92b5fc72f3e9774fe73d7e800ec32299f63a"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d53834e23c015ee83a99377db6e5e37d8484f333edb03bd15b4bc312cc7254fb"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:2e27c8841126e017dd2a054a95771569e6070b9ee1b133366d8b31beb5018a41"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:76855800ac56f878847a09ce6dba727c93ca2d89c9e9d63002d26b916810b0a2"}, + {file = "yarl-1.23.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e09fd068c2e169a7070d83d3bde728a4d48de0549f975290be3c108c02e499b4"}, + {file = "yarl-1.23.0-cp314-cp314t-win32.whl", hash = "sha256:73309162a6a571d4cbd3b6a1dcc703c7311843ae0d1578df6f09be4e98df38d4"}, + {file = "yarl-1.23.0-cp314-cp314t-win_amd64.whl", hash = "sha256:4503053d296bc6e4cbd1fad61cf3b6e33b939886c4f249ba7c78b602214fabe2"}, + {file = "yarl-1.23.0-cp314-cp314t-win_arm64.whl", hash = "sha256:44bb7bef4ea409384e3f8bc36c063d77ea1b8d4a5b2706956c0d6695f07dcc25"}, + {file = "yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f"}, + {file = "yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5"}, ] [package.dependencies] @@ -4632,10 +5190,10 @@ propcache = ">=0.2.1" [extras] breez = ["breez-sdk", "breez-sdk-liquid"] -liquid = ["wallycore"] +liquid = ["boltz-client", "wallycore"] migration = ["psycopg2-binary"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.13" -content-hash = "f63a5be62359f837513e01a8b0e5282a3b4509ea97439ba0c8226ccf3c158ceb" +content-hash = "e41fd327115a1614f2e7b5dae7d7077e30f1cb723e1880a88132ec38df2b4b1a" diff --git a/pyproject.toml b/pyproject.toml index b7a6c66b3..8258b8c23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,56 +1,60 @@ [project] name = "lnbits" -version = "1.5.2-rc3" +version = "1.6.0-rc2" requires-python = ">=3.10,<3.13" description = "LNbits, free and open-source Lightning wallet and accounts system." authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }] urls = { Homepage = "https://lnbits.com", Repository = "https://github.com/lnbits/lnbits" } readme = "README.md" dependencies = [ - "bech32==1.2.0", - "click==8.3.1", - "fastapi==0.116.1", - "starlette==0.47.1", - "httpx==0.27.2", - "jinja2==3.1.6", - "lnurl==0.8.3", - "pydantic==1.10.26", - "pyqrcode==1.2.1", - "shortuuid==1.0.13", - "sse-starlette==2.3.6", - "typing-extensions==4.15.0", - "uvicorn==0.40.0", - "sqlalchemy==1.4.54", - "aiosqlite==0.22.1", - "asyncpg==0.31.0", - "uvloop==0.22.1", - "websockets==15.0.1", - "loguru==0.7.3", - "grpcio==1.76.0", - "protobuf==6.33.2", - "pyln-client==25.12", - "pywebpush==2.2.0", - "slowapi==0.1.9", - "websocket-client==1.9.0", - "pycryptodomex==3.23.0", - "packaging==25.0", - "bolt11==2.1.1", - "pyjwt==2.10.1", - "itsdangerous==2.2.0", - "fastapi-sso==0.19.0", + "bech32~=1.2.0", + "click~=8.3.1", + "fastapi~=0.116.1", + "starlette~=0.48.0", + "httpx~=0.27.2", + "jinja2~=3.1.6", + "lnurl~=0.10.0", + "pydantic~=1.10.26", + "pyqrcode~=1.2.1", + "shortuuid~=1.0.13", + "sse-starlette~=2.3.6", + "typing-extensions~=4.15.0", + "uvicorn~=0.40.0", + "sqlalchemy~=1.4.54", + "aiosqlite~=0.22.1", + "asyncpg~=0.31.0", + "uvloop~=0.22.1", + "websockets~=15.0.1", + "loguru~=0.7.3", + "grpcio~=1.76.0", + "protobuf~=6.33.5", + "pyln-client~=25.12.0", + "pywebpush~=2.2.0", + "slowapi~=0.1.9", + "websocket-client~=1.9.0", + "pycryptodomex~=3.23.0", + "packaging~=25.0.0", + "bolt11~=2.1.1", + "pyjwt~=2.12.0", + "itsdangerous~=2.2.0", + "fastapi-sso~=0.19.0", # needed for boltz, lnurldevice, watchonly extensions - "embit==0.8.0", + "embit~=0.8.0", # needed for scheduler extension - "python-crontab==3.3.0", - "pynostr==0.7.0", - "python-multipart==0.0.21", - "filetype==1.2.0", - "nostr-sdk==0.44.0", - "bcrypt==5.0.0", - "jsonpath-ng==1.7.0", - "pillow>=12.1.0", - "python-dotenv>=1.2.1", - "greenlet (>=3.3.0,<4.0.0)", + "python-crontab~=3.3.0", + "pynostr~=0.7.0", + "python-multipart~=0.0.22", + "filetype~=1.2.0", + "nostr-sdk~=0.44.0", + "bcrypt~=5.0.0", + "jsonpath-ng~=1.7.0", + "pillow~=12.3.0", + "python-dotenv~=1.2.1", + "greenlet~=3.3.0", + "urllib3>=2.7.0", + "pyinstrument>=5.1.2", + "wasmtime>=45.0.0", + "random-username~=1.0.2", ] [project.scripts] @@ -58,33 +62,37 @@ lnbits = "lnbits.server:main" lnbits-cli = "lnbits.commands:main" [project.optional-dependencies] -breez = ["breez-sdk==0.8.0", "breez-sdk-liquid==0.11.11"] -liquid = ["wallycore==1.5.1"] -migration = ["psycopg2-binary==2.9.11"] +breez = ["breez-sdk~=0.8.0", "breez-sdk-liquid~=0.11.11"] +liquid = ["wallycore~=1.5.1", "boltz-client==0.4.0"] +migration = ["psycopg2-binary~=2.9.11"] [dependency-groups] dev = [ - "black>=25.12.0,<26.0.0", - "mypy==1.17.1", - "types-protobuf>=6.32.1.20251210,<7.0.0", - "pre-commit>=4.5.1,<5.0.0", - "openapi-spec-validator>=0.7.2,<1.0.0", - "ruff>=0.14.10,<1.0.0", - "types-passlib>=1.7.7.20250602,<2.0.0", - "openai>=2.14.0", - "json5>=0.13.0,<1.0.0", - "asgi-lifespan>=2.1.0,<3.0.0", - "anyio>=4.12.1", - "pytest>=9.0.2", - "pytest-cov>=7.0.0", - "pytest-md>=0.2.0,<0.3.0", - "pytest-httpserver>=1.1.3,<2.0.0", - "pytest-mock>=3.15.1,<4.0.0", - "types-mock>=5.2.0.20250924,<6.0.0", - "mock>=5.2.0,<6.0.0", - "grpcio-tools>=1.76.0,<2.0.0" + "black~=26.3.1", + "mypy~=1.17.1", + "types-protobuf~=6.32.1.20251210", + "pre-commit~=4.5.1", + "openapi-spec-validator~=0.7.2", + "ruff~=0.14.10", + "types-passlib~=1.7.7.20250602", + "openai~=2.14.0", + "json5~=0.13.0", + "asgi-lifespan~=2.1.0", + "anyio~=4.12.1", + "pytest~=9.0.2", + "pytest-cov~=7.0.0", + "playwright~=1.61.0", + "pytest-md~=0.2.0", + "pytest-httpserver~=1.1.3", + "pytest-mock~=3.15.1", + "types-mock~=5.2.0.20250924", + "mock~=5.2.0", + "grpcio-tools~=1.76.0", ] +[tool.uv] +exclude-newer = "1 week" + [tool.poetry] packages = [ {include = "lnbits"}, diff --git a/tests/api/test_admin_api.py b/tests/api/test_admin_api.py index 8e8dfa03c..4ed51ffc6 100644 --- a/tests/api/test_admin_api.py +++ b/tests/api/test_admin_api.py @@ -1,7 +1,11 @@ +from pathlib import Path + import pytest from httpx import AsyncClient -from lnbits.settings import Settings +from lnbits.core.crud.settings import get_settings_field, set_settings_field +from lnbits.server import server_restart +from lnbits.settings import DEFAULT_WASM_MANIFESTS, Settings @pytest.mark.anyio @@ -19,6 +23,7 @@ async def test_admin_get_settings(client: AsyncClient, superuser_token: str): assert response.status_code == 200 result = response.json() assert "super_user" not in result + assert result["lnbits_wasm_extensions_manifests"] == DEFAULT_WASM_MANIFESTS @pytest.mark.anyio @@ -49,3 +54,137 @@ async def test_admin_update_noneditable_settings( headers={"Authorization": f"Bearer {superuser_token}"}, ) assert response.status_code == 400 + + +@pytest.mark.anyio +async def test_admin_audit_monitor_and_test_email( + client: AsyncClient, superuser_token: str, mocker +): + mocker.patch( + "lnbits.core.views.admin_api.get_balance_delta", + mocker.AsyncMock( + return_value={"lnbits_balance_sats": 21, "node_balance_sats": 13} + ), + ) + mocker.patch( + "lnbits.core.views.admin_api.send_email_notification", + mocker.AsyncMock(return_value={"status": "queued"}), + ) + + audit = await client.get( + "/admin/api/v1/audit", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert audit.status_code == 200 + assert audit.json()["lnbits_balance_sats"] == 21 + + monitor = await client.get( + "/admin/api/v1/monitor", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert monitor.status_code == 200 + task_names = [t["name"] for t in monitor.json()] + assert "core_invoice_listener" in task_names + assert "core_wasm_invoice_listener" in task_names + + test_email = await client.get( + "/admin/api/v1/testemail", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert test_email.status_code == 200 + assert test_email.json()["status"] == "queued" + + +@pytest.mark.anyio +async def test_admin_partial_reset_restart_and_backup( + client: AsyncClient, + superuser_token: str, + settings: Settings, + tmp_path, +): + response = await client.patch( + "/admin/api/v1/settings", + json={"lnbits_site_title": "PATCHED TITLE"}, + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert response.status_code == 200 + assert response.json()["status"] == "Success" + + default_value = await client.get( + "/admin/api/v1/settings/default", + params={"field_name": "lnbits_site_title"}, + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert default_value.status_code == 200 + assert "default_value" in default_value.json() + + backup_path = Path("lnbits-backup.zip") + original_data_folder = settings.lnbits_data_folder + + try: + data_folder = tmp_path / "backup_data" + data_folder.mkdir(parents=True, exist_ok=True) + (data_folder / "sample.txt").write_text("backup me") + settings.lnbits_data_folder = str(data_folder) + + backup = await client.get( + "/admin/api/v1/backup", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert backup.status_code == 200 + assert backup.headers["content-type"] == "application/zip" + assert backup.content.startswith(b"PK") + assert backup_path.is_file() + finally: + settings.lnbits_data_folder = original_data_folder + backup_path.unlink(missing_ok=True) + + server_restart.clear() + restart = await client.get( + "/admin/api/v1/restart", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert restart.status_code == 200 + assert restart.json()["status"] == "Success" + assert server_restart.is_set() is True + server_restart.clear() + + +@pytest.mark.anyio +async def test_admin_delete_settings_requires_superuser( + client: AsyncClient, superuser_token: str +): + await set_settings_field("lnbits_site_title", "Reset me") + await set_settings_field("lnbits_backend_wallet_class", "BoltzWallet") + await set_settings_field("boltz_mnemonic", "keep boltz seed") + await set_settings_field("boltz_mnemonic_backup_confirmed", True) + await set_settings_field("phoenixd_mnemonic", "keep phoenixd seed") + await set_settings_field("phoenixd_mnemonic_backup_confirmed", True) + await set_settings_field("spark_l2_mnemonic", "keep spark seed") + await set_settings_field("spark_l2_mnemonic_backup_confirmed", True) + + server_restart.clear() + response = await client.delete( + "/admin/api/v1/settings", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert response.status_code == 200 + assert server_restart.is_set() is True + assert await get_settings_field("lnbits_site_title") is None + + backend_wallet = await get_settings_field("lnbits_backend_wallet_class") + boltz_seed = await get_settings_field("boltz_mnemonic") + boltz_confirmed = await get_settings_field("boltz_mnemonic_backup_confirmed") + phoenixd_seed = await get_settings_field("phoenixd_mnemonic") + phoenixd_confirmed = await get_settings_field("phoenixd_mnemonic_backup_confirmed") + spark_l2_seed = await get_settings_field("spark_l2_mnemonic") + spark_l2_confirmed = await get_settings_field("spark_l2_mnemonic_backup_confirmed") + assert backend_wallet and backend_wallet.value == "BoltzWallet" + assert boltz_seed and boltz_seed.value == "keep boltz seed" + assert boltz_confirmed and boltz_confirmed.value is True + assert phoenixd_seed and phoenixd_seed.value == "keep phoenixd seed" + assert phoenixd_confirmed and phoenixd_confirmed.value is True + assert spark_l2_seed and spark_l2_seed.value == "keep spark seed" + assert spark_l2_confirmed and spark_l2_confirmed.value is True + + server_restart.clear() diff --git a/tests/api/test_api.py b/tests/api/test_api.py index a8b80dcfe..2401c71fe 100644 --- a/tests/api/test_api.py +++ b/tests/api/test_api.py @@ -233,6 +233,40 @@ async def test_create_fiat_invoice( assert invoice["extra"]["fiat_payment_request"] == fiat_payment_request +@pytest.mark.anyio +async def test_create_fiat_subscription_invoice_rejected( + client, inkey_headers_to, mocker: MockerFixture +): + fiat_mock = mocker.patch( + "lnbits.core.services.payments.create_fiat_invoice", + AsyncMock(), + ) + + response = await client.post( + "/api/v1/payments", + headers=inkey_headers_to, + json={ + "unit": "USD", + "out": False, + "amount": 2100, + "fiat_provider": "stripe", + "extra": { + "fiat_method": "subscription", + "subscription": { + "checking_id": "fiat_stripe_cs_paid_session", + "payment_request": "", + }, + }, + }, + ) + + assert response.status_code == 400 + assert response.json()["detail"] == ( + "Cannot create direct fiat subscription payments." + ) + fiat_mock.assert_not_awaited() + + @pytest.mark.anyio @pytest.mark.parametrize("currency", ("msat", "RRR")) async def test_create_invoice_validates_used_currency( @@ -507,9 +541,9 @@ async def test_api_payment_without_key(invoice: Payment): # check api_payment() internal function call (NOT API): payment status @pytest.mark.anyio -async def test_api_payment_with_key(invoice: Payment, inkey_headers_from): +async def test_api_payment_with_key(invoice: Payment, inkey_headers_to): # check the payment status - response = await api_payment(invoice.payment_hash, inkey_headers_from["X-Api-Key"]) + response = await api_payment(invoice.payment_hash, inkey_headers_to["X-Api-Key"]) assert isinstance(response, dict) assert response["paid"] is True assert "details" in response diff --git a/tests/api/test_asset_api.py b/tests/api/test_asset_api.py new file mode 100644 index 000000000..40efe0977 --- /dev/null +++ b/tests/api/test_asset_api.py @@ -0,0 +1,186 @@ +from uuid import uuid4 + +import pytest +from httpx import AsyncClient + +from lnbits.core.crud.assets import get_user_asset +from lnbits.core.services.assets import create_user_asset +from tests.helpers import get_png_bytes, get_user_token_headers, make_upload_file + + +@pytest.mark.anyio +async def test_asset_api_upload_list_update_and_delete( + client: AsyncClient, + user_headers_from: dict[str, str], +): + payload = get_png_bytes() + upload = await client.post( + "/api/v1/assets?public_asset=false", + headers={"Authorization": user_headers_from["Authorization"]}, + files={"file": ("note.png", payload, "image/png")}, + ) + assert upload.status_code == 200 + asset = upload.json() + assert asset["name"] == "note.png" + assert asset["is_public"] is False + + page = await client.get("/api/v1/assets/paginated", headers=user_headers_from) + assert page.status_code == 200 + assert any(item["id"] == asset["id"] for item in page.json()["data"]) + + info = await client.get(f"/api/v1/assets/{asset['id']}", headers=user_headers_from) + assert info.status_code == 200 + assert info.json()["name"] == "note.png" + + data = await client.get( + f"/api/v1/assets/{asset['id']}/data", headers=user_headers_from + ) + assert data.status_code == 200 + assert data.content == payload + assert data.headers["content-type"] == "image/png" + assert data.headers["content-disposition"] == 'inline; filename="note.png"' + assert data.headers["x-content-type-options"] == "nosniff" + assert data.headers["content-security-policy"].startswith("sandbox") + + updated = await client.put( + f"/api/v1/assets/{asset['id']}", + headers=user_headers_from, + json={"name": "renamed.png", "is_public": True}, + ) + assert updated.status_code == 200 + assert updated.json()["name"] == "renamed.png" + assert updated.json()["is_public"] is True + + public_data = await client.get(f"/api/v1/assets/{asset['id']}/data") + assert public_data.status_code == 200 + assert public_data.content == payload + + deleted = await client.delete( + f"/api/v1/assets/{asset['id']}", headers=user_headers_from + ) + assert deleted.status_code == 200 + assert deleted.json()["success"] is True + + missing = await client.get( + f"/api/v1/assets/{asset['id']}", headers=user_headers_from + ) + assert missing.status_code == 404 + + +@pytest.mark.anyio +async def test_asset_api_enforces_visibility_and_supports_admin_updates( + client: AsyncClient, + from_user, + to_user, + superuser_token: str, +): + private_asset = await create_user_asset( + from_user.id, + make_upload_file( + get_png_bytes(), + filename=f"private_{uuid4().hex[:8]}.png", + content_type="image/png", + ), + is_public=False, + ) + other_user_headers = await get_user_token_headers(client, to_user.id) + + anonymous = await client.get(f"/api/v1/assets/{private_asset.id}/data") + assert anonymous.status_code == 404 + + wrong_user = await client.get( + f"/api/v1/assets/{private_asset.id}/data", headers=other_user_headers + ) + assert wrong_user.status_code == 404 + + admin_updated = await client.put( + f"/api/v1/assets/{private_asset.id}", + headers={"Authorization": f"Bearer {superuser_token}"}, + json={"is_public": True, "name": "admin-visible.png"}, + ) + assert admin_updated.status_code == 200 + assert admin_updated.json()["is_public"] is True + assert admin_updated.json()["name"] == "admin-visible.png" + + image_data = await client.get(f"/api/v1/assets/{private_asset.id}/data") + assert image_data.status_code == 200 + assert image_data.headers["content-type"] == "image/png" + assert image_data.headers["content-disposition"] == ( + 'inline; filename="admin-visible.png"' + ) + assert image_data.headers["x-content-type-options"] == "nosniff" + + thumbnail = await client.get(f"/api/v1/assets/{private_asset.id}/thumbnail") + assert thumbnail.status_code == 200 + assert thumbnail.content + assert thumbnail.headers["content-type"] == "image/png" + assert thumbnail.headers["content-disposition"] == ( + 'inline; filename="admin-visible.png"' + ) + + +@pytest.mark.anyio +async def test_asset_api_blocks_non_image_uploads( + client: AsyncClient, + user_headers_from: dict[str, str], +): + payload = ( + b'' + b'' + b'' + b"" + b"" + b"" + ) + + blocked = await client.post( + "/api/v1/assets", + headers={"Authorization": user_headers_from["Authorization"]}, + files={"file": ("payload.xsl", payload, "text/xml")}, + ) + + assert blocked.status_code == 400 + assert blocked.json()["detail"] == "File type 'text/xml' not allowed." + + +@pytest.mark.anyio +async def test_asset_api_validates_uploads_and_missing_assets( + client: AsyncClient, + to_user, + user_headers_from: dict[str, str], +): + invalid = await client.post( + "/api/v1/assets", + headers={"Authorization": user_headers_from["Authorization"]}, + files={"file": ("payload.exe", b"boom", "application/x-msdownload")}, + ) + assert invalid.status_code == 400 + assert "not allowed" in invalid.json()["detail"] + + fake_image_headers = await get_user_token_headers(client, to_user.id) + fake_image = await client.post( + "/api/v1/assets", + headers={"Authorization": fake_image_headers["Authorization"]}, + files={"file": ("fake.png", b"", "image/png")}, + ) + assert fake_image.status_code == 400 + assert "does not match declared file type" in fake_image.json()["detail"] + + missing = await client.delete( + f"/api/v1/assets/{uuid4().hex}", + headers=user_headers_from, + ) + assert missing.status_code == 404 + + missing_thumb = await client.get(f"/api/v1/assets/{uuid4().hex}/thumbnail") + assert missing_thumb.status_code == 404 + + stored = await create_user_asset( + "missing-user-check", + make_upload_file( + get_png_bytes(), filename="content.png", content_type="image/png" + ), + is_public=True, + ) + fetched = await get_user_asset("missing-user-check", stored.id) + assert fetched is not None diff --git a/tests/api/test_audit_api.py b/tests/api/test_audit_api.py new file mode 100644 index 000000000..23080a68b --- /dev/null +++ b/tests/api/test_audit_api.py @@ -0,0 +1,64 @@ +from datetime import datetime, timezone +from uuid import uuid4 + +import pytest +from httpx import AsyncClient + +from lnbits.core.crud.audit import create_audit_entry +from lnbits.core.models import AuditEntry + + +@pytest.mark.anyio +async def test_audit_api_requires_admin(client: AsyncClient, user_headers_from): + response = await client.get("/audit/api/v1", headers=user_headers_from) + assert response.status_code == 403 + + +@pytest.mark.anyio +async def test_audit_api_returns_entries_and_stats( + client: AsyncClient, + superuser_token: str, +): + component = f"audit_component_{uuid4().hex[:8]}" + await create_audit_entry( + AuditEntry( + component=component, + ip_address="127.0.0.1", + user_id=uuid4().hex, + path="/api/v1/test", + request_method="GET", + response_code="200", + duration=0.12, + created_at=datetime.now(timezone.utc), + ) + ) + await create_audit_entry( + AuditEntry( + component=component, + ip_address="127.0.0.2", + user_id=uuid4().hex, + path="/api/v1/test", + request_method="POST", + response_code="400", + duration=2.5, + created_at=datetime.now(timezone.utc), + ) + ) + headers = {"Authorization": f"Bearer {superuser_token}"} + + page = await client.get(f"/audit/api/v1?component={component}", headers=headers) + assert page.status_code == 200 + page_data = page.json() + assert page_data["total"] == 2 + assert {item["request_method"] for item in page_data["data"]} == {"GET", "POST"} + + stats = await client.get( + f"/audit/api/v1/stats?component={component}", + headers=headers, + ) + assert stats.status_code == 200 + payload = stats.json() + assert {item["field"] for item in payload["request_method"]} == {"GET", "POST"} + assert {item["field"] for item in payload["response_code"]} == {"200", "400"} + assert payload["component"][0]["field"] == component + assert payload["long_duration"][0]["field"] == "/api/v1/test" diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py index aea787cff..82361e6d9 100644 --- a/tests/api/test_auth.py +++ b/tests/api/test_auth.py @@ -1745,10 +1745,14 @@ async def test_api_create_user_api_token_success( ), "Expiration time should be 60 minutes from now." token_id = payload["api_token_id"] - assert any( - token_id in [token.id for token in acl.token_id_list] + stored_token = next( + token for acl in acls.access_control_list - ), "API token should be part of at least one ACL." + for token in acl.token_id_list + if token.id == token_id + ) + assert stored_token.expires_at is not None + assert abs(stored_token.expires_at - expiration_time) <= 1 @pytest.mark.anyio diff --git a/tests/api/test_auth_api.py b/tests/api/test_auth_api.py new file mode 100644 index 000000000..83ea8dc55 --- /dev/null +++ b/tests/api/test_auth_api.py @@ -0,0 +1,255 @@ +from types import SimpleNamespace +from uuid import uuid4 + +import pytest +from fastapi.responses import RedirectResponse +from httpx import AsyncClient + +from lnbits.core.crud.users import get_account, update_account +from lnbits.core.models.users import Account +from lnbits.core.services.users import create_user_account +from lnbits.core.views.auth_api import get_account_by_email +from lnbits.settings import Settings + + +class _FakeSSO: + def __init__(self, userinfo: object | None = None, state: str = ""): + self.userinfo = userinfo + self.state = state + self.redirect_uri: str | None = None + + def __enter__(self): + return self + + def __exit__(self, *_args): + return False + + async def get_login_redirect(self, state: str): + self.state = state + return RedirectResponse("https://example.com/sso/login") + + async def verify_and_process(self, _request): + return self.userinfo + + +@pytest.mark.anyio +async def test_auth_api_logout_and_update_ui_customization( + http_client: AsyncClient, +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + + response = await http_client.patch( + f"/api/v1/auth/ui?usr={user.id}", + json={"theme": "amber", "walletLayout": "grid"}, + ) + assert response.status_code == 200 + assert response.json()["ui_customization"]["theme"] == "amber" + assert response.json()["ui_customization"]["walletLayout"] == "grid" + + logout = await http_client.post("/api/v1/auth/logout") + assert logout.status_code == 200 + assert logout.json()["status"] == "success" + assert "cookie_access_token=" in logout.headers["set-cookie"] + + +@pytest.mark.anyio +async def test_auth_api_keycloak_login_without_user_id_redirects_to_provider( + http_client: AsyncClient, mocker +): + provider = "keycloak" + login_sso = _FakeSSO() + mocker.patch("lnbits.core.views.auth_api._new_sso", return_value=login_sso) + + response = await http_client.get(f"/api/v1/auth/{provider}") + + assert response.status_code == 307 + assert response.headers["location"] == "https://example.com/sso/login" + assert login_sso.redirect_uri == ( + f"{http_client.base_url}/api/v1/auth/{provider}/token" + ) + assert login_sso.state is None + + +@pytest.mark.anyio +async def test_auth_api_sso_login_and_callback(http_client: AsyncClient, mocker): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + + provider = "github" + login_sso = _FakeSSO() + mocker.patch("lnbits.core.views.auth_api._new_sso", return_value=login_sso) + + unauthenticated = await http_client.get( + f"/api/v1/auth/{provider}", params={"user_id": user.id} + ) + assert unauthenticated.status_code == 403 + assert unauthenticated.json()["detail"] == "User ID mismatch." + + other_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + other_login = await http_client.post( + "/api/v1/auth/usr", json={"usr": other_user.id} + ) + http_client.cookies.clear() + assert other_login.status_code == 200 + other_headers = { + "Authorization": f"Bearer {other_login.json()['access_token']}", + } + wrong_user = await http_client.get( + f"/api/v1/auth/{provider}", + params={"user_id": user.id}, + headers=other_headers, + ) + assert wrong_user.status_code == 403 + assert wrong_user.json()["detail"] == "User ID mismatch." + + login = await http_client.post("/api/v1/auth/usr", json={"usr": user.id}) + http_client.cookies.clear() + assert login.status_code == 200 + headers = {"Authorization": f"Bearer {login.json()['access_token']}"} + + response = await http_client.get( + f"/api/v1/auth/{provider}", params={"user_id": user.id}, headers=headers + ) + assert response.status_code == 307 + assert response.headers["location"] == "https://example.com/sso/login" + assert login_sso.redirect_uri == f"{http_client.base_url}/api/v1/auth/github/token" + assert login_sso.state + + email = f"sso_{uuid4().hex[:8]}@lnbits.com" + callback_sso = _FakeSSO(userinfo=SimpleNamespace(email=email), state="") + mocker.patch("lnbits.core.views.auth_api._new_sso", return_value=callback_sso) + + callback = await http_client.get(f"/api/v1/auth/{provider}/token") + assert callback.status_code == 307 + assert callback.headers["location"] == "/wallet" + + account = await get_account_by_email(email, active_only=False) + assert account is not None + assert account.email == email + assert account.extra.email_verified is True + + +@pytest.mark.anyio +async def test_auth_api_first_install_success_and_validation( + http_client: AsyncClient, settings: Settings +): + superuser = await get_account(settings.super_user, active_only=False) + assert superuser is not None + + original_username = superuser.username + original_password_hash = superuser.password_hash + original_first_install = settings.first_install + original_first_install_token = settings.first_install_token + + first_install_token = f"install_{uuid4().hex[:8]}" + new_username = f"reinstall_{uuid4().hex[:8]}" + + try: + settings.first_install = True + settings.first_install_token = first_install_token + + missing_token = await http_client.put( + "/api/v1/auth/first_install", + json={ + "username": new_username, + "password": "secret1234", + "password_repeat": "secret1234", + }, + ) + assert missing_token.status_code == 401 + assert missing_token.json()["detail"] == "Missing first_install_token." + + success = await http_client.put( + "/api/v1/auth/first_install", + json={ + "username": new_username, + "password": "secret1234", + "password_repeat": "secret1234", + "first_install_token": first_install_token, + }, + ) + assert success.status_code == 200 + assert success.json()["access_token"] + assert "cookie_access_token=" in success.headers["set-cookie"] + assert "Secure" not in success.headers["set-cookie"] + + updated_superuser = await get_account(settings.super_user, active_only=False) + assert updated_superuser is not None + assert updated_superuser.username == new_username + assert settings.first_install is False + + forbidden = await http_client.put( + "/api/v1/auth/first_install", + json={ + "username": f"blocked_{uuid4().hex[:8]}", + "password": "secret1234", + "password_repeat": "secret1234", + }, + ) + assert forbidden.status_code == 403 + assert forbidden.json()["detail"] == "This is not your first install" + finally: + restored_superuser = await get_account(settings.super_user, active_only=False) + assert restored_superuser is not None + restored_superuser.username = original_username + restored_superuser.password_hash = original_password_hash + await update_account(restored_superuser) + settings.first_install = original_first_install + settings.first_install_token = original_first_install_token + + +@pytest.mark.anyio +async def test_auth_api_first_install_uses_secure_cookie_when_enabled( + http_client: AsyncClient, settings: Settings +): + superuser = await get_account(settings.super_user, active_only=False) + assert superuser is not None + + original_username = superuser.username + original_password_hash = superuser.password_hash + original_first_install = settings.first_install + original_auth_https_only = settings.auth_https_only + + new_username = f"secure_{uuid4().hex[:8]}" + + try: + settings.first_install = True + settings.auth_https_only = True + + success = await http_client.put( + "/api/v1/auth/first_install", + json={ + "username": new_username, + "password": "secret1234", + "password_repeat": "secret1234", + }, + ) + + assert success.status_code == 200 + assert "cookie_access_token=" in success.headers["set-cookie"] + assert "Secure" in success.headers["set-cookie"] + finally: + restored_superuser = await get_account(settings.super_user, active_only=False) + assert restored_superuser is not None + restored_superuser.username = original_username + restored_superuser.password_hash = original_password_hash + await update_account(restored_superuser) + settings.first_install = original_first_install + settings.auth_https_only = original_auth_https_only diff --git a/tests/api/test_callback_api.py b/tests/api/test_callback_api.py new file mode 100644 index 000000000..a910cd729 --- /dev/null +++ b/tests/api/test_callback_api.py @@ -0,0 +1,619 @@ +import json +from uuid import uuid4 + +import pytest +from httpx import AsyncClient + +from lnbits.core.models import Account, CreateInvoice, Payment +from lnbits.core.services.payments import create_wallet_invoice +from lnbits.core.services.users import create_user_account +from lnbits.core.views.callback_api import ( + handle_paypal_event, + handle_revolut_event, + handle_square_event, + handle_stripe_event, +) +from lnbits.fiat.revolut import RevolutWallet +from lnbits.fiat.square import SquareWallet +from lnbits.settings import Settings + + +@pytest.mark.anyio +async def test_callback_api_generic_webhook_handler_routes_providers( + http_client: AsyncClient, mocker +): + stripe_mock = mocker.patch( + "lnbits.core.views.callback_api.handle_stripe_event", mocker.AsyncMock() + ) + paypal_mock = mocker.patch( + "lnbits.core.views.callback_api.handle_paypal_event", mocker.AsyncMock() + ) + square_mock = mocker.patch( + "lnbits.core.views.callback_api.handle_square_event", mocker.AsyncMock() + ) + revolut_mock = mocker.patch( + "lnbits.core.views.callback_api.handle_revolut_event", mocker.AsyncMock() + ) + mocker.patch("lnbits.core.views.callback_api.check_stripe_signature") + mocker.patch("lnbits.core.views.callback_api.check_square_signature") + mocker.patch("lnbits.core.views.callback_api.check_revolut_signature") + mocker.patch( + "lnbits.core.views.callback_api.verify_paypal_webhook", mocker.AsyncMock() + ) + + stripe = await http_client.post( + "/api/v1/callback/stripe", + headers={"Stripe-Signature": "sig"}, + json={"id": "evt_1", "type": "payment_intent.succeeded"}, + ) + assert stripe.status_code == 200 + assert stripe.json()["success"] is True + stripe_mock.assert_awaited_once() + + paypal = await http_client.post( + "/api/v1/callback/paypal", + json={"id": "evt_2", "event_type": "CHECKOUT.ORDER.APPROVED"}, + ) + assert paypal.status_code == 200 + assert paypal.json()["success"] is True + paypal_mock.assert_awaited_once() + + square = await http_client.post( + "/api/v1/callback/square", + headers={"x-square-hmacsha256-signature": "sig"}, + json={"event_id": "evt_3", "type": "payment.updated"}, + ) + assert square.status_code == 200 + assert square.json()["success"] is True + square_mock.assert_awaited_once() + + revolut = await http_client.post( + "/api/v1/callback/revolut", + headers={ + "Revolut-Signature": "sig", + "Revolut-Request-Timestamp": "1700000000", + }, + json={"event": "ORDER_COMPLETED", "order_id": "order_1"}, + ) + assert revolut.status_code == 200 + assert revolut.json()["success"] is True + revolut_mock.assert_awaited_once() + + unknown = await http_client.post("/api/v1/callback/unknown", json={"id": "evt_3"}) + assert unknown.status_code == 200 + assert unknown.json()["success"] is False + + +@pytest.mark.anyio +async def test_callback_api_handles_paid_events_with_real_payments(mocker): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + payment = await create_wallet_invoice( + wallet.id, CreateInvoice(out=False, amount=11, memo="fiat callback") + ) + + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_stripe_event( + { + "id": "evt_stripe", + "type": "payment_intent.succeeded", + "data": { + "object": { + "object": "payment_intent", + "metadata": {"payment_hash": payment.payment_hash}, + } + }, + } + ) + await handle_paypal_event( + { + "id": "evt_paypal", + "event_type": "CHECKOUT.ORDER.APPROVED", + "resource": { + "purchase_units": [{"invoice_id": payment.payment_hash}], + }, + } + ) + await handle_stripe_event({"id": "evt_unhandled", "type": "customer.created"}) + + assert fiat_status_mock.await_count == 2 + + +@pytest.mark.anyio +async def test_callback_api_handles_square_paid_events(mocker): + payment = mocker.Mock() + get_payment = mocker.patch( + "lnbits.core.views.callback_api.get_standalone_payment", + mocker.AsyncMock(return_value=payment), + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_square_event( + { + "event_id": "evt_square", + "type": "payment.updated", + "data": { + "object": { + "payment": { + "id": "payment_1", + "order_id": "order_1", + "status": "COMPLETED", + } + } + }, + } + ) + + get_payment.assert_awaited_once_with("fiat_square_order_order_1") + fiat_status_mock.assert_awaited_once_with(payment) + + +@pytest.mark.anyio +async def test_callback_api_handles_revolut_paid_events(mocker): + payment = mocker.Mock() + get_payment = mocker.patch( + "lnbits.core.views.callback_api.get_standalone_payment", + mocker.AsyncMock(return_value=payment), + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_revolut_event( + { + "event": "ORDER_COMPLETED", + "order_id": "order_1", + } + ) + + get_payment.assert_awaited_once_with("fiat_revolut_order_order_1") + fiat_status_mock.assert_awaited_once_with(payment) + + +@pytest.mark.anyio +async def test_callback_api_handles_revolut_subscription_event( + mocker, settings: Settings +): + wallet_id = "wallet_1" + payment = mocker.Mock() + payment.extra = {} + payment.msat = 925_000 + + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + revolut_provider = RevolutWallet() + get_subscription_mock = mocker.patch.object( + revolut_provider, + "get_subscription", + return_value={ + "id": "SUBSCRIPTION_1", + "current_cycle_id": "CYCLE_1", + "external_reference": json.dumps( + { + "wallet_id": wallet_id, + "tag": "members", + "subscription_request_id": "request_1", + "extra": {"link": "link-1", "customer_id": "customer_1"}, + "memo": "Revolut Members", + } + ), + }, + ) + mocker.patch.object( + revolut_provider, + "get_subscription_cycle", + return_value={"id": "CYCLE_1", "order_id": "ORDER_SUB_1"}, + ) + mocker.patch.object( + revolut_provider, + "get_order", + return_value={ + "id": "ORDER_SUB_1", + "amount": 925, + "currency": "USD", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_1", + }, + ) + mocker.patch( + "lnbits.core.views.callback_api.get_fiat_provider", + mocker.AsyncMock(return_value=revolut_provider), + ) + mocker.patch( + "lnbits.core.views.callback_api.get_standalone_payment", + mocker.AsyncMock(side_effect=[None]), + ) + create_wallet_invoice_mock = mocker.patch( + "lnbits.core.views.callback_api.create_wallet_invoice", + mocker.AsyncMock(return_value=payment), + ) + mocker.patch("lnbits.core.views.callback_api.service_fee_fiat", return_value=2) + update_payment_mock = mocker.patch( + "lnbits.core.views.callback_api.update_payment", mocker.AsyncMock() + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_revolut_event( + { + "event": "SUBSCRIPTION_INITIATED", + "subscription_id": "SUBSCRIPTION_1", + } + ) + + get_subscription_mock.assert_not_awaited() + create_wallet_invoice_mock.assert_not_awaited() + update_payment_mock.assert_not_awaited() + fiat_status_mock.assert_not_awaited() + + +@pytest.mark.anyio +async def test_callback_api_handles_revolut_subscription_order_event( + mocker, settings: Settings +): + wallet_id = "wallet_1" + payment = mocker.Mock() + payment.extra = {} + payment.msat = 925_000 + + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + revolut_provider = RevolutWallet() + subscription = { + "id": "SUBSCRIPTION_1", + "state": "active", + "current_cycle_id": "CYCLE_1", + "external_reference": json.dumps( + { + "wallet_id": wallet_id, + "tag": "members", + "subscription_request_id": "request_1", + "extra": {"link": "link-1"}, + "memo": "Revolut Members", + } + ), + } + order = { + "id": "ORDER_SUB_1", + "type": "payment", + "state": "completed", + "amount": 925, + "currency": "USD", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_1", + "channel_data": { + "subscription_id": "SUBSCRIPTION_1", + "subscription_cycle_id": "CYCLE_1", + }, + } + get_order_mock = mocker.patch.object( + revolut_provider, "get_order", side_effect=[order, order] + ) + get_subscription_mock = mocker.patch.object( + revolut_provider, + "get_subscription", + return_value=subscription, + ) + mocker.patch.object( + revolut_provider, + "get_subscription_cycle", + return_value={"id": "CYCLE_1", "order_id": "ORDER_SUB_1"}, + ) + mocker.patch( + "lnbits.core.views.callback_api.get_fiat_provider", + mocker.AsyncMock(return_value=revolut_provider), + ) + get_payment_mock = mocker.patch( + "lnbits.core.views.callback_api.get_standalone_payment", + mocker.AsyncMock(side_effect=[None, None]), + ) + create_wallet_invoice_mock = mocker.patch( + "lnbits.core.views.callback_api.create_wallet_invoice", + mocker.AsyncMock(return_value=payment), + ) + mocker.patch("lnbits.core.views.callback_api.service_fee_fiat", return_value=2) + update_payment_mock = mocker.patch( + "lnbits.core.views.callback_api.update_payment", mocker.AsyncMock() + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_revolut_event( + { + "event": "ORDER_COMPLETED", + "order_id": "ORDER_SUB_1", + } + ) + + assert get_payment_mock.await_count == 2 + get_payment_mock.assert_any_await("fiat_revolut_order_ORDER_SUB_1") + assert get_order_mock.await_count == 1 + assert [call.args for call in get_subscription_mock.await_args_list] == [ + ("SUBSCRIPTION_1",), + ] + assert create_wallet_invoice_mock.await_count == 1 + called_wallet_id, invoice = create_wallet_invoice_mock.await_args.args + assert called_wallet_id == "wallet_1" + assert invoice.amount == 9.25 + assert invoice.memo == "Revolut Members" + assert invoice.external_id == "SUBSCRIPTION_1" + assert invoice.internal is True + assert invoice.extra["fiat_method"] == "subscription" + assert invoice.extra["subscription"]["checking_id"] == "order_ORDER_SUB_1" + assert payment.fiat_provider == "revolut" + assert payment.fee == -2 + assert payment.extra["fiat_checking_id"] == "order_ORDER_SUB_1" + assert payment.checking_id == "fiat_revolut_order_ORDER_SUB_1" + update_payment_mock.assert_awaited_once_with( + payment, "fiat_revolut_order_ORDER_SUB_1" + ) + fiat_status_mock.assert_awaited_once_with(payment) + + +@pytest.mark.anyio +async def test_callback_api_handles_subscription_flows_and_validation( + mocker, settings: Settings +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + payment = await create_wallet_invoice( + wallet.id, CreateInvoice(out=False, amount=15, memo="subscription") + ) + + create_fiat_invoice_mock = mocker.patch( + "lnbits.core.views.callback_api.create_fiat_invoice", + mocker.AsyncMock(return_value=payment), + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_stripe_event( + { + "id": "evt_invoice_paid", + "type": "invoice.paid", + "data": { + "object": { + "id": "invoice_1", + "currency": "usd", + "amount_paid": 500, + "hosted_invoice_url": "https://stripe.example/invoice", + "customer_email": "alice@example.com", + "lines": {"data": [{"description": "Gold Plan"}]}, + "parent": { + "type": "subscription_details", + "subscription_details": { + "metadata": { + "alan_action": "subscription", + "wallet_id": wallet.id, + "tag": "gold", + "memo": "Monthly Gold", + "extra": json.dumps({"plan": "gold"}), + } + }, + }, + } + }, + } + ) + create_fiat_invoice_mock.assert_awaited() + fiat_status_mock.assert_awaited() + + await handle_paypal_event( + { + "id": "evt_sale_completed", + "event_type": "PAYMENT.SALE.COMPLETED", + "resource": { + "id": "sale_1", + "billing_agreement_id": "agreement_1", + "amount": {"currency": "USD", "total": "7.50"}, + "custom_id": json.dumps( + [wallet.id, "vip", "subscription_1", "link-1", "VIP Plan"] + ), + }, + } + ) + assert create_fiat_invoice_mock.await_count == 2 + + await handle_square_event( + { + "event_id": "evt_square_subscription", + "type": "payment.updated", + "data": { + "object": { + "payment": { + "id": "PAYMENT_SUB_1", + "order_id": "ORDER_SUB_1", + "status": "COMPLETED", + "amount_money": {"amount": 925, "currency": "USD"}, + "note": json.dumps( + [ + wallet.id, + "members", + "subscription_square_1", + "link-1", + "Square Members", + ] + ), + } + } + }, + } + ) + assert create_fiat_invoice_mock.await_count == 3 + square_call = create_fiat_invoice_mock.await_args.kwargs + assert square_call["wallet_id"] == wallet.id + square_invoice = square_call["invoice_data"] + assert square_invoice.fiat_provider == "square" + assert square_invoice.amount == 9.25 + assert square_invoice.memo == "Square Members" + assert square_invoice.extra["fiat_method"] == "subscription" + assert square_invoice.extra["tag"] == "members" + assert ( + square_invoice.extra["subscription"]["checking_id"] == "payment_PAYMENT_SUB_1" + ) + + payment.extra = { + "subscription_request_id": "subscription_square_1", + "tag": "members", + "link": "link-1", + } + payment.external_id = "SUBSCRIPTION_1" + payment.memo = "Square Members" + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + square_provider = SquareWallet() + mocker.patch.object( + square_provider, + "get_payment_for_order", + return_value={ + "id": "PAYMENT_SUB_2", + "status": "COMPLETED", + "amount_money": {"amount": 925, "currency": "USD"}, + }, + ) + mocker.patch( + "lnbits.core.views.callback_api.get_fiat_provider", + mocker.AsyncMock(return_value=square_provider), + ) + mocker.patch( + "lnbits.core.views.callback_api.get_payments", + mocker.AsyncMock(return_value=[payment]), + ) + + await handle_square_event( + { + "event_id": "evt_square_invoice", + "type": "invoice.payment_made", + "data": { + "object": { + "invoice": { + "order_id": "ORDER_SUB_2", + "subscription_id": "SUBSCRIPTION_1", + "public_url": "https://square.example/invoice", + } + } + }, + } + ) + assert create_fiat_invoice_mock.await_count == 4 + square_invoice_call = create_fiat_invoice_mock.await_args.kwargs + square_invoice = square_invoice_call["invoice_data"] + assert square_invoice.external_id == "SUBSCRIPTION_1" + assert "square_subscription_id" not in square_invoice.extra + assert ( + square_invoice.extra["subscription"]["payment_request"] + == "https://square.example/invoice" + ) + + with pytest.raises( + ValueError, match="PayPal subscription event missing custom metadata." + ): + await handle_paypal_event( + { + "id": "evt_bad_sale", + "event_type": "PAYMENT.SALE.COMPLETED", + "resource": {"amount": {"currency": "USD", "total": "5.00"}}, + } + ) + + +@pytest.mark.anyio +async def test_square_invoice_payment_updates_existing_subscription_external_id( + settings: Settings, mocker +): + payment = Payment( + checking_id="fiat_square_payment_PAYMENT_SUB_1", + payment_hash="hash_square_subscription", + wallet_id="wallet_1", + amount=925000, + fee=0, + bolt11="lnbc1square", + fiat_provider="square", + extra={ + "subscription_request_id": "subscription_square_1", + "tag": "members", + "link": "link-1", + }, + memo="Square Members", + ) + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + square_provider = SquareWallet() + mocker.patch.object( + square_provider, + "get_payment_for_order", + return_value={ + "id": "PAYMENT_SUB_1", + "status": "COMPLETED", + "amount_money": {"amount": 925, "currency": "USD"}, + }, + ) + mocker.patch( + "lnbits.core.views.callback_api.get_fiat_provider", + mocker.AsyncMock(return_value=square_provider), + ) + get_standalone_payment_mock = mocker.patch( + "lnbits.core.views.callback_api.get_standalone_payment", + mocker.AsyncMock(return_value=payment), + ) + update_payment_mock = mocker.patch( + "lnbits.core.views.callback_api.update_payment", + mocker.AsyncMock(), + ) + get_payments_mock = mocker.patch( + "lnbits.core.views.callback_api.get_payments", + mocker.AsyncMock(return_value=[]), + ) + create_fiat_invoice_mock = mocker.patch( + "lnbits.core.views.callback_api.create_fiat_invoice", + mocker.AsyncMock(), + ) + fiat_status_mock = mocker.patch( + "lnbits.core.views.callback_api.check_fiat_status", mocker.AsyncMock() + ) + + await handle_square_event( + { + "event_id": "evt_square_invoice", + "type": "invoice.payment_made", + "data": { + "object": { + "invoice": { + "order_id": "ORDER_SUB_1", + "subscription_id": "SUBSCRIPTION_1", + } + } + }, + } + ) + + get_standalone_payment_mock.assert_awaited_with("fiat_square_payment_PAYMENT_SUB_1") + assert payment.external_id == "SUBSCRIPTION_1" + update_payment_mock.assert_awaited_once_with(payment) + fiat_status_mock.assert_awaited_once_with(payment) + get_payments_mock.assert_not_awaited() + create_fiat_invoice_mock.assert_not_awaited() diff --git a/tests/api/test_extension_api.py b/tests/api/test_extension_api.py new file mode 100644 index 000000000..583a7bb9c --- /dev/null +++ b/tests/api/test_extension_api.py @@ -0,0 +1,879 @@ +import json +import zipfile +from pathlib import Path +from types import SimpleNamespace +from uuid import uuid4 + +import pytest +from fastapi import HTTPException +from starlette.requests import Request + +from lnbits.core.crud.db_versions import get_db_version, update_migration_version +from lnbits.core.crud.extensions import ( + create_installed_extension, + delete_installed_extension, + get_installed_extension, + get_user_extension, +) +from lnbits.core.crud.users import get_account +from lnbits.core.crud.wallets import create_wallet +from lnbits.core.models import Account, CreateInvoice +from lnbits.core.models.extensions import ( + CreateExtension, + CreateExtensionReview, + ExplicitRelease, + Extension, + ExtensionArchiveValidationError, + ExtensionConfig, + ExtensionManifestType, + ExtensionPermission, + ExtensionPermissionsUpdate, + ExtensionRelease, + InstallableExtension, + Manifest, + PayToEnableInfo, + ReleasePaymentInfo, + UserExtensionInfo, + WasmRuntimeLimitsUpdate, + wasm_extension_icon_url, +) +from lnbits.core.models.users import AccountId +from lnbits.core.services.payments import create_wallet_invoice +from lnbits.core.services.users import create_user_account +from lnbits.core.views.extension_api import ( + api_activate_extension, + api_deactivate_extension, + api_disable_extension, + api_enable_extension, + api_extension_details, + api_get_user_extensions, + api_get_wasm_runtime_limit_extensions, + api_install_extension, + api_uninstall_extension, + api_update_extension_permissions, + api_update_pay_to_enable, + api_update_wasm_runtime_limits, + create_extension_review, + delete_extension_db, + extensions, + get_extension_release, + get_extension_releases, + get_extension_reviews, + get_extension_reviews_tags, + get_pay_to_enable_invoice, + get_pay_to_install_invoice, +) +from tests.helpers import make_extension_release, make_installable_extension + + +class _MockHTTPResponse: + def __init__( + self, + *, + json_data=None, + text: str = "", + status_code: int = 200, + is_error: bool = False, + ): + self._json_data = json_data + self.text = text + self.status_code = status_code + self.is_error = is_error + + def json(self): + return self._json_data + + def raise_for_status(self): + if self.status_code >= 400: + raise ValueError(self.text or "request failed") + + +class _MockHTTPClient: + def __init__(self, responses: dict[str, _MockHTTPResponse]): + self.responses = responses + + async def __aenter__(self): + return self + + async def __aexit__(self, *_args): + return False + + async def get(self, url: str): + return self.responses[url] + + async def post(self, url: str, json=None): + return self.responses[url] + + +@pytest.mark.anyio +async def test_extension_api_install_details_and_release_endpoints(mocker): + ext_id = f"ext_{uuid4().hex[:8]}" + release = make_extension_release(ext_id) + create_data = CreateExtension( + ext_id=ext_id, + archive=release.archive, + source_repo=release.source_repo, + version=release.version, + ) + + mocker.patch.object( + InstallableExtension, + "get_extension_release", + mocker.AsyncMock(return_value=release), + ) + mocker.patch( + "lnbits.core.views.extension_api.install_extension", + mocker.AsyncMock(return_value=Extension(code=ext_id, is_valid=True)), + ) + activate_mock = mocker.patch( + "lnbits.core.views.extension_api.activate_extension", mocker.AsyncMock() + ) + + installed = await api_install_extension(create_data) + assert installed.code == ext_id + activate_mock.assert_awaited_once() + + mocker.patch.object( + InstallableExtension, + "get_extension_releases", + mocker.AsyncMock(return_value=[release]), + ) + mocker.patch.object( + ExtensionRelease, + "fetch_release_details", + mocker.AsyncMock(return_value={"description": "Extension details"}), + ) + details = await api_extension_details(ext_id, release.details_link or "") + assert details["description"] == "Extension details" + assert details["icon"] == release.icon + assert details["repo"] == release.repo + + installed_ext = make_installable_extension( + ext_id, + payments=[ + ReleasePaymentInfo( + amount=55, + pay_link=release.pay_link, + payment_hash=f"payment_{uuid4().hex[:8]}", + ) + ], + ) + await create_installed_extension(installed_ext) + releases = await get_extension_releases(ext_id) + assert releases[0].paid_sats == 55 + + config = ExtensionConfig( + name=ext_id, + short_description="Config", + min_lnbits_version="0.1.0", + max_lnbits_version=None, + ) + mocker.patch.object( + ExtensionConfig, + "fetch_github_release_config", + mocker.AsyncMock(return_value=config), + ) + release_info = await get_extension_release("org", ext_id, "v1.0.0") + assert release_info["is_version_compatible"] is True + + +@pytest.mark.anyio +async def test_extension_api_archive_validation_failure_only_removes_zip( + tmp_path, + settings, + mocker, +): + ext_id = f"ext_{uuid4().hex[:8]}" + release = make_extension_release(ext_id) + create_data = CreateExtension( + ext_id=ext_id, + archive=release.archive, + source_repo=release.source_repo, + version=release.version, + ) + original_data_folder = settings.lnbits_data_folder + clean_python_mock = mocker.patch.object( + InstallableExtension, "clean_extension_files" + ) + clean_wasm_mock = mocker.patch.object( + InstallableExtension, "clean_wasm_extension_files" + ) + mocker.patch.object( + InstallableExtension, + "get_extension_release", + mocker.AsyncMock(return_value=release), + ) + mocker.patch( + "lnbits.core.views.extension_api.install_extension", + mocker.AsyncMock( + side_effect=ExtensionArchiveValidationError("Invalid extension archive.") + ), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + zip_path = Path(settings.lnbits_data_folder, "zips", f"{ext_id}.zip") + zip_path.parent.mkdir(parents=True) + zip_path.write_bytes(b"archive") + + with pytest.raises(HTTPException) as exc: + await api_install_extension(create_data) + finally: + settings.lnbits_data_folder = original_data_folder + + assert exc.value.status_code == 400 + assert exc.value.detail == "Invalid extension archive." + assert not zip_path.exists() + clean_python_mock.assert_not_called() + clean_wasm_mock.assert_not_called() + + +@pytest.mark.anyio +async def test_explicit_wasm_release_loads_install_permissions( + settings, + mocker, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + non_wasm_ext_id = f"python_{uuid4().hex[:8]}" + manifest_url = "https://extensions.example/manifest.json" + details_link = f"https://extensions.example/{ext_id}/config.json" + explicit_release = ExplicitRelease( + id=ext_id, + name="Explicit WASM Extension", + version="1.0.0", + archive=f"https://extensions.example/{ext_id}.zip", + hash="archive-hash", + repo=f"https://github.com/example/{ext_id}", + icon=None, + short_description="Explicit WASM release", + min_lnbits_version="0.1.0", + max_lnbits_version=None, + html_url=None, + warning=None, + info_notification=None, + critical_notification=None, + details_link=details_link, + paid_features=None, + pay_link=None, + extension_type="wasm", + ) + non_wasm_release = explicit_release.copy( + update={ + "id": non_wasm_ext_id, + "name": "Explicit Python Extension", + "details_link": f"https://extensions.example/{non_wasm_ext_id}/config.json", + "extension_type": None, + } + ) + config_permissions = [ExtensionPermission(id="wallet.list")] + config = ExtensionConfig( + name=ext_id, + short_description="Explicit WASM release", + min_lnbits_version="0.1.0", + max_lnbits_version=None, + extension_type="wasm", + permissions=config_permissions, + ) + + async def fetch_manifest(url): + if url == manifest_url: + return Manifest(extensions=[explicit_release, non_wasm_release]) + return Manifest() + + mocker.patch.object(settings, "lnbits_extensions_manifests", []) + mocker.patch.object(settings, "lnbits_wasm_extensions_manifests", [manifest_url]) + mocker.patch.object( + settings, + "lnbits_extensions_builder_manifest_url", + "https://extensions.example/builder.json", + ) + mocker.patch.object( + InstallableExtension, + "fetch_manifest", + mocker.AsyncMock(side_effect=fetch_manifest), + ) + fetch_config_mock = mocker.patch.object( + ExtensionConfig, + "fetch_release_config", + mocker.AsyncMock(return_value=config), + ) + + releases = await InstallableExtension.get_extension_releases(ext_id) + + assert len(releases) == 1 + assert releases[0].extension_type == "wasm" + assert releases[0].manifest_type == ExtensionManifestType.WASM + assert releases[0].permissions == config_permissions + fetch_config_mock.assert_awaited_once_with(details_link) + + fetch_config_mock.reset_mock() + non_wasm_releases = await InstallableExtension.get_extension_releases( + non_wasm_ext_id + ) + assert len(non_wasm_releases) == 1 + assert non_wasm_releases[0].extension_type is None + assert non_wasm_releases[0].manifest_type == ExtensionManifestType.WASM + assert non_wasm_releases[0].permissions == [] + fetch_config_mock.assert_not_awaited() + + mocker.patch.object( + InstallableExtension, + "get_extension_releases", + mocker.AsyncMock(return_value=releases), + ) + mocker.patch( + "lnbits.core.views.extension_api.get_installed_extension", + mocker.AsyncMock(return_value=None), + ) + api_releases = await get_extension_releases(ext_id) + assert api_releases[0].permissions == config_permissions + + +@pytest.mark.anyio +async def test_extension_api_installs_wasm_with_granted_permissions( + tmp_path, + settings, + mocker, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + release = make_extension_release(ext_id) + granted_permissions = [ + ExtensionPermission( + id="http.request", + policies=[{"host": "https://api.example.com"}], + ) + ] + create_data = CreateExtension( + ext_id=ext_id, + archive=release.archive, + source_repo=release.source_repo, + version=release.version, + permissions=granted_permissions, + ) + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + register_wasm_routes_mock = mocker.patch( + "lnbits.core.services.extensions.core_app_extra.register_new_wasm_ext_routes" + ) + mocker.patch.object( + InstallableExtension, + "get_extension_release", + mocker.AsyncMock(return_value=release), + ) + mocker.patch.object( + InstallableExtension, + "download_archive", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + _write_wasm_extension_archive(ext_id, release.version, settings) + + installed = await api_install_extension(create_data) + stored = await get_installed_extension(ext_id) + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + + assert installed.code == ext_id + assert installed.is_wasm is True + assert stored is not None + assert stored.permissions == [ + ExtensionPermission( + id="http.request", + description="Call example API.", + policies=[{"host": "https://api.example.com"}], + ) + ] + register_wasm_routes_mock.assert_called_once_with(ext_id) + + +@pytest.mark.anyio +async def test_extension_api_wasm_runtime_limits_and_catalog_use_installed_metadata( + tmp_path, + settings, + mocker, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + py_ext_id = f"py_{uuid4().hex[:8]}" + granted_permissions = [ + ExtensionPermission( + id="http.request", + description="Call example API.", + policies=[{"host": "https://api.example.com"}], + ) + ] + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + + try: + settings.lnbits_extensions_path = str(tmp_path) + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + _write_installed_wasm_config(ext_id, settings.wasm_extensions_dir) + await create_installed_extension( + InstallableExtension( + id=ext_id, + name="WASM Demo", + version="1.0.0", + active=True, + permissions=granted_permissions, + wasm_runtime_limits={"wasm_runtime_max_execution_ms": 1234}, + ) + ) + await create_installed_extension(make_installable_extension(py_ext_id)) + + runtime_extensions = await api_get_wasm_runtime_limit_extensions() + wasm_info = next(info for info in runtime_extensions if info.id == ext_id) + + updated_info = await api_update_wasm_runtime_limits( + ext_id, + WasmRuntimeLimitsUpdate( + limits={ + "wasm_runtime_max_execution_ms": "2345", + "wasm_runtime_max_fuel": 0, + } + ), + ) + stored = await get_installed_extension(ext_id) + + mocker.patch.object( + InstallableExtension, + "get_installable_extensions", + mocker.AsyncMock( + return_value=[ + make_installable_extension(ext_id), + make_installable_extension(py_ext_id), + ] + ), + ) + catalog = await extensions(AccountId(id=uuid4().hex)) + finally: + await delete_installed_extension(ext_id=ext_id) + await delete_installed_extension(ext_id=py_ext_id) + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + + assert wasm_info.wasm_runtime_limits == {"wasm_runtime_max_execution_ms": 1234} + assert py_ext_id not in {info.id for info in runtime_extensions} + assert updated_info.wasm_runtime_limits == { + "wasm_runtime_max_execution_ms": 2345, + "wasm_runtime_max_fuel": 0, + } + assert stored is not None + assert stored.wasm_runtime_limits == updated_info.wasm_runtime_limits + + catalog_item = next(item for item in catalog if item["id"] == ext_id) + assert catalog_item["isWasm"] is True + assert catalog_item["icon"] == wasm_extension_icon_url(ext_id) + assert catalog_item["permissions"] == [ + dict(permission) for permission in granted_permissions + ] + + +@pytest.mark.anyio +async def test_extension_api_admin_updates_wasm_extension_permission_limits( + tmp_path, + settings, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + manifest_permissions = [ + { + "id": "ext.storage.append_public", + "description": "Append public messages.", + "policies": [ + { + "table": "messages", + "source_table": "conversations", + "source_id_field": "conversation_id", + "allowed_fields": ["body"], + "max_rows_per_source": 100, + } + ], + } + ] + installed_permissions = [ + ExtensionPermission.parse_obj(permission) for permission in manifest_permissions + ] + updated_permissions = [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "conversations", + "source_id_field": "conversation_id", + "allowed_fields": ["body"], + "max_rows_per_source": 1000, + } + ], + ) + ] + + try: + settings.lnbits_extensions_path = str(tmp_path) + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + _write_installed_wasm_config( + ext_id, + settings.wasm_extensions_dir, + permissions=manifest_permissions, + ) + await create_installed_extension( + InstallableExtension( + id=ext_id, + name="WASM Demo", + version="1.0.0", + active=True, + permissions=installed_permissions, + ) + ) + + response = await api_update_extension_permissions( + ext_id, + ExtensionPermissionsUpdate(permissions=updated_permissions), + ) + stored = await get_installed_extension(ext_id) + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + + assert response.extension_permissions == [ + ExtensionPermission( + id="ext.storage.append_public", + description="Append public messages.", + policies=[ + { + "table": "messages", + "source_table": "conversations", + "source_id_field": "conversation_id", + "allowed_fields": ["body"], + "max_rows_per_source": 1000, + } + ], + ) + ] + assert stored is not None + assert stored.permissions == response.extension_permissions + + +@pytest.mark.anyio +async def test_extension_api_pay_to_enable_and_catalog_views(mocker, admin_user): + regular_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + admin_account = await get_account(admin_user.id) + assert admin_account is not None + admin_wallet = await create_wallet( + user_id=admin_account.id, wallet_name="extension sales" + ) + + ext_id = f"paid_{uuid4().hex[:8]}" + await create_installed_extension( + make_installable_extension( + ext_id, + pay_to_enable=PayToEnableInfo( + required=True, amount=10, wallet=admin_wallet.id + ), + ) + ) + + updated = await api_update_pay_to_enable( + ext_id, + PayToEnableInfo(required=True, amount=21, wallet=admin_wallet.id), + account=admin_account, + ) + assert updated.success is True + stored_extension = await get_installed_extension(ext_id) + assert stored_extension is not None + assert stored_extension.meta is not None + assert stored_extension.meta.pay_to_enable is not None + assert stored_extension.meta.pay_to_enable.amount == 21 + + enable_invoice = await create_wallet_invoice( + admin_wallet.id, CreateInvoice(out=False, amount=21, memo="enable extension") + ) + mocker.patch( + "lnbits.core.views.extension_api.create_invoice", + mocker.AsyncMock(return_value=enable_invoice), + ) + invoice_response = await get_pay_to_enable_invoice( + ext_id, + PayToEnableInfo(amount=21), + account_id=AccountId(id=regular_user.id), + ) + assert invoice_response["payment_hash"] == enable_invoice.payment_hash + + user_ext = await get_user_extension(regular_user.id, ext_id) + assert user_ext is not None + assert user_ext.extra is not None + assert user_ext.extra.payment_hash_to_enable == enable_invoice.payment_hash + + mocker.patch( + "lnbits.core.views.extension_api.get_valid_extensions", + mocker.AsyncMock(return_value=[Extension(code=ext_id, is_valid=True)]), + ) + mocker.patch( + "lnbits.core.views.extension_api.check_transaction_status", + mocker.AsyncMock(return_value=SimpleNamespace(paid=True)), + ) + + enabled = await api_enable_extension(ext_id, AccountId(id=regular_user.id)) + assert enabled.success is True + user_ext = await get_user_extension(regular_user.id, ext_id) + assert user_ext is not None + assert user_ext.active is True + assert user_ext.extra == UserExtensionInfo( + payment_hash_to_enable=enable_invoice.payment_hash, + paid_to_enable=True, + ) + + disabled = await api_disable_extension(ext_id, AccountId(id=regular_user.id)) + assert disabled.success is True + disabled_again = await api_disable_extension(ext_id, AccountId(id=regular_user.id)) + assert disabled_again.success is True + assert "already disabled" in disabled_again.message + + mocker.patch( + "lnbits.core.views.extension_api.get_valid_extensions", + mocker.AsyncMock( + return_value=[ + Extension(code=ext_id, is_valid=True, name="Paid Extension"), + Extension(code="other", is_valid=True), + ] + ), + ) + visible_extensions = await api_get_user_extensions(AccountId(id=regular_user.id)) + assert [ext.code for ext in visible_extensions] == [ext_id] + + catalog_entry = make_installable_extension( + ext_id, + pay_to_enable=PayToEnableInfo(required=True, amount=21, wallet=admin_wallet.id), + ) + mocker.patch.object( + InstallableExtension, + "get_installable_extensions", + mocker.AsyncMock(return_value=[catalog_entry]), + ) + catalog = await extensions(AccountId(id=regular_user.id)) + catalog_item = next(item for item in catalog if item["id"] == ext_id) + assert catalog_item["payToEnable"]["wallet"] is None + + +@pytest.mark.anyio +async def test_extension_api_activate_uninstall_install_invoice_and_cleanup(mocker): + base_ext = f"base_{uuid4().hex[:8]}" + dependent_ext = f"dependent_{uuid4().hex[:8]}" + uninstall_ext = f"uninstall_{uuid4().hex[:8]}" + db_ext = f"db_{uuid4().hex[:8]}" + + await create_installed_extension(make_installable_extension(base_ext)) + await create_installed_extension( + make_installable_extension(dependent_ext, dependencies=[base_ext]) + ) + await create_installed_extension(make_installable_extension(uninstall_ext)) + + mocker.patch( + "lnbits.core.views.extension_api.get_valid_extensions", + mocker.AsyncMock( + return_value=[ + Extension(code=base_ext, is_valid=True, name="Base"), + Extension(code=dependent_ext, is_valid=True, name="Dependent"), + Extension(code=uninstall_ext, is_valid=True, name="Remove"), + ] + ), + ) + + with pytest.raises(HTTPException, match="depends on this one"): + await api_uninstall_extension(base_ext) + + uninstall_mock = mocker.patch( + "lnbits.core.views.extension_api.uninstall_extension", mocker.AsyncMock() + ) + uninstalled = await api_uninstall_extension(uninstall_ext) + assert uninstalled.success is True + uninstall_mock.assert_awaited_once_with(uninstall_ext) + + mocker.patch( + "lnbits.core.views.extension_api.get_valid_extension", + mocker.AsyncMock(return_value=Extension(code=base_ext, is_valid=True)), + ) + activate_mock = mocker.patch( + "lnbits.core.views.extension_api.activate_extension", mocker.AsyncMock() + ) + deactivate_mock = mocker.patch( + "lnbits.core.views.extension_api.deactivate_extension", mocker.AsyncMock() + ) + activated = await api_activate_extension(base_ext) + assert activated.success is True + deactivated = await api_deactivate_extension(base_ext) + assert deactivated.success is True + activate_mock.assert_awaited_once() + deactivate_mock.assert_awaited_once() + + owner = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = owner.wallets[0] + install_invoice = await create_wallet_invoice( + wallet.id, CreateInvoice(out=False, amount=33, memo="install extension") + ) + release = make_extension_release(base_ext, version="2.0.0") + payment_info = ReleasePaymentInfo( + amount=33, + pay_link=release.pay_link, + payment_hash=install_invoice.payment_hash, + payment_request=install_invoice.bolt11, + ) + mocker.patch.object( + InstallableExtension, + "get_extension_release", + mocker.AsyncMock(return_value=release), + ) + mocker.patch.object( + ExtensionRelease, + "fetch_release_payment_info", + mocker.AsyncMock(return_value=payment_info), + ) + invoice = await get_pay_to_install_invoice( + base_ext, + CreateExtension( + ext_id=base_ext, + archive=release.archive, + source_repo=release.source_repo, + version=release.version, + cost_sats=33, + ), + ) + assert invoice.payment_hash == install_invoice.payment_hash + + await update_migration_version(None, db_ext, 1) + drop_mock = mocker.patch( + "lnbits.core.views.extension_api.drop_extension_db", mocker.AsyncMock() + ) + deleted = await delete_extension_db(db_ext) + assert deleted.success is True + drop_mock.assert_awaited_once_with(ext_id=db_ext) + assert await get_db_version(db_ext) is None + + +@pytest.mark.anyio +async def test_extension_api_review_endpoints(mocker): + ext_id = f"review_{uuid4().hex[:8]}" + reviews_base = "https://demo.lnbits.com/paidreviews/api/v1/AdFzLjzuKFLsdk4Bcnff6r" + tags_url = f"{reviews_base}/tags" + reviews_url = f"{reviews_base}/reviews/{ext_id}?offset=0&limit=5" + create_review_url = f"{reviews_base}/reviews" + request = Request( + { + "type": "http", + "method": "GET", + "path": f"/api/v1/extension/reviews/{ext_id}", + "query_string": b"offset=0&limit=5", + "headers": [], + } + ) + mock_client = _MockHTTPClient( + { + tags_url: _MockHTTPResponse( + json_data=[{"tag": "good", "avg_rating": 900, "review_count": 3}] + ), + reviews_url: _MockHTTPResponse( + json_data={ + "data": [ + { + "id": "1", + "name": "Alice", + "tag": "good", + "rating": 950, + "comment": "solid", + } + ], + "total": 1, + } + ), + create_review_url: _MockHTTPResponse( + json_data={ + "payment_hash": f"hash_{uuid4().hex[:8]}", + "payment_request": "lnbc1review", + } + ), + } + ) + mocker.patch( + "lnbits.core.views.extension_api.httpx.AsyncClient", return_value=mock_client + ) + + tags = await get_extension_reviews_tags() + assert tags[0].tag == "good" + + reviews = await get_extension_reviews(ext_id, request) + assert reviews.total == 1 + assert reviews.data[0].comment == "solid" + + payment_request = await create_extension_review( + CreateExtensionReview(tag=ext_id, name="Alice", rating=900, comment="Great") + ) + assert payment_request.payment_hash.startswith("hash_") + + +def _write_wasm_extension_archive( + ext_id: str, + version: str, + settings, + permissions: list[dict] | None = None, +) -> None: + zip_path = Path(settings.lnbits_data_folder, "zips", f"{ext_id}.zip") + zip_path.parent.mkdir(parents=True, exist_ok=True) + config = _wasm_config(ext_id, permissions=permissions) + root = f"{ext_id}-{version}" + with zipfile.ZipFile(zip_path, "w") as archive: + archive.writestr(f"{root}/config.json", json.dumps(config)) + archive.writestr(f"{root}/{config['wasm']['module']}", b"\0asm") + + +def _write_installed_wasm_config( + ext_id: str, + wasm_extensions_path, + permissions: list[dict] | None = None, +) -> None: + config_dir = wasm_extensions_path / ext_id + config_dir.mkdir(parents=True) + (config_dir / "config.json").write_text( + json.dumps(_wasm_config(ext_id, permissions=permissions)), + encoding="utf-8", + ) + + +def _wasm_config(ext_id: str, permissions: list[dict] | None = None) -> dict: + return { + "id": ext_id, + "name": "WASM Demo", + "short_description": "WASM extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + "permissions": permissions + or [ + { + "id": "http.request", + "description": "Call example API.", + "policies": [{"host": "https://api.example.com"}], + } + ], + } diff --git a/tests/api/test_extensions_builder_api.py b/tests/api/test_extensions_builder_api.py new file mode 100644 index 000000000..80e1cf620 --- /dev/null +++ b/tests/api/test_extensions_builder_api.py @@ -0,0 +1,109 @@ +from pathlib import Path +from uuid import uuid4 + +import pytest + +from lnbits.core.crud.extensions import create_user_extension, get_user_extension +from lnbits.core.crud.users import get_account +from lnbits.core.models.extensions import ( + Extension, + UserExtension, +) +from lnbits.core.models.users import AccountId +from lnbits.core.views.extensions_builder_api import ( + api_build_extension, + api_delete_extension_builder_data, + api_deploy_extension, + api_preview_extension, +) +from lnbits.settings import Settings +from tests.helpers import make_extension_data, make_extension_release + + +@pytest.mark.anyio +async def test_extensions_builder_api_build_preview_and_cleanup( + tmp_path, settings: Settings, mocker, from_user +): + ext_id = f"builder_{uuid4().hex[:8]}" + data = make_extension_data(ext_id) + build_dir = tmp_path / "build" + build_dir.mkdir(parents=True, exist_ok=True) + (build_dir / "index.txt").write_text("hello") + + original_data_folder = settings.lnbits_data_folder + build_mock = mocker.patch( + "lnbits.core.views.extensions_builder_api.build_extension_from_data", + mocker.AsyncMock( + return_value=(make_extension_release(ext_id, "0.1.0"), build_dir) + ), + ) + clean_mock = mocker.patch( + "lnbits.core.views.extensions_builder_api.clean_extension_builder_data" + ) + + try: + settings.lnbits_data_folder = str(tmp_path) + + build_response = await api_build_extension(data) + assert Path(build_response.path).is_file() + assert build_response.filename == f"{ext_id}.zip" + + preview = await api_preview_extension(data, AccountId(id=from_user.id)) + assert preview.success is True + assert ext_id in preview.message + + cleaned = await api_delete_extension_builder_data() + assert cleaned.success is True + clean_mock.assert_called_once() + assert build_mock.await_count == 2 + finally: + settings.lnbits_data_folder = original_data_folder + + +@pytest.mark.anyio +async def test_extensions_builder_api_deploy_updates_user_extension( + tmp_path, settings: Settings, mocker, admin_user +): + ext_id = f"deploy_{uuid4().hex[:8]}" + data = make_extension_data(ext_id) + account = await get_account(admin_user.id) + assert account is not None + + build_root = tmp_path / "deploy-root" / ext_id + build_root.mkdir(parents=True, exist_ok=True) + (build_root / "manifest.json").write_text("{}") + + original_data_folder = settings.lnbits_data_folder + await create_user_extension( + UserExtension(user=account.id, extension=ext_id, active=False) + ) + + mocker.patch( + "lnbits.core.views.extensions_builder_api.build_extension_from_data", + mocker.AsyncMock( + return_value=(make_extension_release(ext_id, "0.1.0"), build_root) + ), + ) + install_mock = mocker.patch( + "lnbits.core.views.extensions_builder_api.install_extension", + mocker.AsyncMock(return_value=Extension(code=ext_id, is_valid=True)), + ) + activate_mock = mocker.patch( + "lnbits.core.views.extensions_builder_api.activate_extension", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path) + deployed = await api_deploy_extension(data, account=account) + finally: + settings.lnbits_data_folder = original_data_folder + + assert deployed.success is True + assert ext_id in deployed.message + install_mock.assert_awaited_once() + activate_mock.assert_awaited_once() + + user_ext = await get_user_extension(account.id, ext_id) + assert user_ext is not None + assert user_ext.active is True diff --git a/tests/api/test_fiat_api.py b/tests/api/test_fiat_api.py new file mode 100644 index 000000000..3b86d260f --- /dev/null +++ b/tests/api/test_fiat_api.py @@ -0,0 +1,227 @@ +import pytest +from httpx import AsyncClient +from pytest_mock.plugin import MockerFixture + +from lnbits.core.models.misc import SimpleStatus +from lnbits.fiat.base import FiatSubscriptionResponse +from lnbits.fiat.revolut import REVOLUT_WEBHOOK_EVENTS +from lnbits.settings import Settings + + +class _UnsetSecret: + pass + + +UNSET_SECRET = _UnsetSecret() + + +class FakeStripeWallet: + def __init__(self, secret: str | None | _UnsetSecret = UNSET_SECRET): + self._secret = ( + "connection-token" if isinstance(secret, _UnsetSecret) else secret + ) + + async def create_terminal_connection_token(self) -> dict[str, str]: + if self._secret is None: + return {} + return {"secret": self._secret} + + +@pytest.mark.anyio +async def test_fiat_api_test_provider_and_subscription_lifecycle( + client: AsyncClient, + superuser_token: str, + adminkey_headers_from: dict[str, str], + from_wallet, + mocker: MockerFixture, +): + test_connection = mocker.patch( + "lnbits.core.views.fiat_api.test_connection", + mocker.AsyncMock(return_value=SimpleStatus(success=True, message="ok")), + ) + response = await client.put( + "/api/v1/fiat/check/stripe", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert response.status_code == 200 + assert response.json()["success"] is True + test_connection.assert_awaited_once_with("stripe") + + provider = mocker.Mock() + provider.create_subscription = mocker.AsyncMock( + return_value=FiatSubscriptionResponse( + ok=True, + subscription_request_id="sub-1", + checkout_session_url="https://stripe.example/checkout", + ) + ) + provider.cancel_subscription = mocker.AsyncMock( + return_value=FiatSubscriptionResponse(ok=True, subscription_request_id="sub-1") + ) + get_provider = mocker.patch( + "lnbits.core.views.fiat_api.get_fiat_provider", + mocker.AsyncMock(return_value=provider), + ) + + mismatch = await client.post( + "/api/v1/fiat/stripe/subscription", + headers=adminkey_headers_from, + json={ + "subscription_id": "sub-1", + "quantity": 2, + "payment_options": {"wallet_id": "wrong-wallet"}, + }, + ) + assert mismatch.status_code == 403 + + created = await client.post( + "/api/v1/fiat/stripe/subscription", + headers=adminkey_headers_from, + json={ + "subscription_id": "sub-1", + "quantity": 2, + "payment_options": {"memo": "hello", "wallet_id": from_wallet.id}, + }, + ) + assert created.status_code == 200 + assert created.json()["checkout_session_url"] == "https://stripe.example/checkout" + provider.create_subscription.assert_awaited_once() + assert provider.create_subscription.await_args is not None + assert provider.create_subscription.await_args.args[2].wallet_id == from_wallet.id + + cancelled = await client.delete( + "/api/v1/fiat/stripe/subscription/sub-1", + headers=adminkey_headers_from, + ) + assert cancelled.status_code == 200 + provider.cancel_subscription.assert_awaited_once_with("sub-1", from_wallet.id) + assert get_provider.await_count == 3 + + +@pytest.mark.anyio +async def test_fiat_api_connection_token_validates_provider_configuration( + client: AsyncClient, + superuser_token: str, + mocker: MockerFixture, +): + headers = {"Authorization": f"Bearer {superuser_token}"} + + not_found = mocker.patch( + "lnbits.core.views.fiat_api.get_fiat_provider", + mocker.AsyncMock(return_value=None), + ) + missing = await client.post("/api/v1/fiat/stripe/connection_token", headers=headers) + assert missing.status_code == 404 + assert not_found.await_count == 1 + + unsupported_provider = mocker.patch( + "lnbits.core.views.fiat_api.get_fiat_provider", + mocker.AsyncMock(return_value=object()), + ) + unsupported = await client.post( + "/api/v1/fiat/paypal/connection_token", headers=headers + ) + assert unsupported.status_code == 400 + assert unsupported_provider.await_count == 1 + + mocker.patch("lnbits.core.views.fiat_api.StripeWallet", FakeStripeWallet) + bad_wallet = FakeStripeWallet(secret=None) + bad_provider = mocker.patch( + "lnbits.core.views.fiat_api.get_fiat_provider", + mocker.AsyncMock(return_value=bad_wallet), + ) + no_secret = await client.post( + "/api/v1/fiat/stripe/connection_token", headers=headers + ) + assert no_secret.status_code == 500 + assert no_secret.json()["detail"] == "Failed to create connection token" + assert bad_provider.await_count == 1 + + good_wallet = FakeStripeWallet(secret="tok_live") + good_provider = mocker.patch( + "lnbits.core.views.fiat_api.get_fiat_provider", + mocker.AsyncMock(return_value=good_wallet), + ) + ok = await client.post("/api/v1/fiat/stripe/connection_token", headers=headers) + assert ok.status_code == 200 + assert ok.json() == {"secret": "tok_live"} + assert good_provider.await_count == 1 + + +@pytest.mark.anyio +async def test_fiat_api_creates_revolut_webhook( + client: AsyncClient, + superuser_token: str, + settings: Settings, + mocker: MockerFixture, +): + create_webhook = mocker.patch( + "lnbits.core.views.fiat_api.RevolutWallet.create_webhook", + mocker.AsyncMock( + return_value={ + "id": "webhook_1", + "url": "https://lnbits.example/api/v1/callback/revolut", + "events": REVOLUT_WEBHOOK_EVENTS, + "signing_secret": "whsec_1", + } + ), + ) + + response = await client.post( + "/api/v1/fiat/revolut/webhook", + headers={"Authorization": f"Bearer {superuser_token}"}, + json={ + "url": "https://lnbits.example/api/v1/callback/revolut", + "endpoint": "https://sandbox-merchant.revolut.com", + "api_secret_key": "secret_1", + "api_version": "2026-04-20", + }, + ) + + assert response.status_code == 200 + assert response.json() == { + "id": "webhook_1", + "url": "https://lnbits.example/api/v1/callback/revolut", + "events": REVOLUT_WEBHOOK_EVENTS, + "signing_secret": "whsec_1", + "already_exists": False, + } + create_webhook.assert_awaited_once_with( + url="https://lnbits.example/api/v1/callback/revolut", + endpoint="https://sandbox-merchant.revolut.com", + api_secret_key="secret_1", + api_version="2026-04-20", + ) + assert settings.revolut_payment_webhook_url == ( + "https://lnbits.example/api/v1/callback/revolut" + ) + assert settings.revolut_webhook_signing_secret == "whsec_1" + + +@pytest.mark.anyio +async def test_fiat_api_rejects_local_revolut_webhook( + client: AsyncClient, + superuser_token: str, + mocker: MockerFixture, +): + create_webhook = mocker.patch( + "lnbits.core.views.fiat_api.RevolutWallet.create_webhook", + mocker.AsyncMock( + side_effect=ValueError("Revolut webhook URL must be a clearnet URL.") + ), + ) + + response = await client.post( + "/api/v1/fiat/revolut/webhook", + headers={"Authorization": f"Bearer {superuser_token}"}, + json={ + "url": "http://localhost:5000/api/v1/callback/revolut", + "endpoint": "https://sandbox-merchant.revolut.com", + "api_secret_key": "secret_1", + "api_version": "2026-04-20", + }, + ) + + assert response.status_code == 400 + assert response.json()["detail"] == ("Revolut webhook URL must be a clearnet URL.") + create_webhook.assert_awaited_once() diff --git a/tests/api/test_lnurl_api.py b/tests/api/test_lnurl_api.py new file mode 100644 index 000000000..ed3e92452 --- /dev/null +++ b/tests/api/test_lnurl_api.py @@ -0,0 +1,232 @@ +import json +import re +from types import SimpleNamespace +from typing import cast +from uuid import uuid4 + +import pytest +from fastapi import HTTPException +from lnurl import ( + LnAddress, + LnurlAuthResponse, + LnurlErrorResponse, + LnurlException, + LnurlPayActionResponse, + LnurlPayResponse, + LnurlResponseException, +) +from lnurl.models import MessageAction +from lnurl.types import CallbackUrl, LightningInvoice +from pydantic import parse_obj_as + +from lnbits.core.crud.wallets import create_wallet, get_wallet +from lnbits.core.models import Account, CreateInvoice +from lnbits.core.models.lnurl import CreateLnurlPayment, LnurlScan +from lnbits.core.models.wallets import KeyType, WalletTypeInfo +from lnbits.core.services.lightning_address import wallet_lightning_address_callback +from lnbits.core.services.payments import create_wallet_invoice +from lnbits.core.services.users import create_user_account +from lnbits.core.views.lnurl_api import ( + api_lnurlscan, + api_lnurlscan_post, + api_payments_pay_lnurl, + api_perform_lnurlauth, +) +from tests.helpers import make_lnurl_pay_response + +TEST_BOLT11 = ( + "lnbc1pnsu5z3pp57getmdaxhg5kc9yh2a2qsh7cjf4gnccgkw0qenm8vsqv50w7s" + "ygqdqj0fjhymeqv9kk7atwwscqzzsxqyz5vqsp5e2yyqcp0a3ujeesp24ya0glej" + "srh703md8mrx0g2lyvjxy5w27ss9qxpqysgqyjreasng8a086kpkczv48er5c6l5" + "73aym6ynrdl9nkzqnag49vt3sjjn8qdfq5cr6ha0vrdz5c5r3v4aghndly0hplmv" + "6hjxepwp93cq398l3s" +) + + +@pytest.mark.anyio +async def test_wallet_lightning_address_lookup_and_callback( + client, to_user, settings, mocker +): + settings.lnbits_ln_address_mode = "core_first" + wallet = await create_wallet(user_id=to_user.id, wallet_name="ln address") + assert wallet.lightning_address + + response = await client.get(f"/.well-known/lnurlp/{wallet.lightning_address}") + assert response.status_code == 200 + data = response.json() + metadata = data["metadata"] + assert data["minSendable"] == 1000 + assert data["maxSendable"] == 2_100_000_000_000_000_000 + assert data["commentAllowed"] == 799 + assert f"{wallet.lightning_address}@" in metadata + assert "text/identifier" in metadata + + tagged_response = await client.get( + f"/.well-known/lnurlp/{wallet.lightning_address}+market" + ) + assert tagged_response.status_code == 200 + tagged_data = tagged_response.json() + tagged_metadata = json.loads(tagged_data["metadata"]) + assert ["text/tag", "market"] in tagged_metadata + assert any( + entry[0] == "text/identifier" + and entry[1].startswith(f"{wallet.lightning_address}+market@") + for entry in tagged_metadata + ) + + create_invoice_mock = mocker.patch( + "lnbits.core.services.lightning_address.create_invoice", + mocker.AsyncMock(return_value=SimpleNamespace(bolt11=TEST_BOLT11)), + ) + callback = tagged_data["callback"].split("testserver")[-1] + callback_response = await client.get(f"{callback}?amount=21000&comment=hello") + assert callback_response.status_code == 200 + assert callback_response.json()["pr"] == TEST_BOLT11 + create_invoice_mock.assert_awaited_once() + kwargs = create_invoice_mock.await_args.kwargs + assert kwargs["wallet_id"] == wallet.id + assert kwargs["amount"] == 21 + assert kwargs["extra"]["tag"] == "wallet_lightning_address" + assert kwargs["extra"]["comment"] == "hello" + assert kwargs["extra"]["lnaddress"].startswith(f"{wallet.lightning_address}+") + assert kwargs["extra"]["lnaddress_tag"] == "market" + + +@pytest.mark.anyio +async def test_wallet_lightning_address_generation_settings(to_user, settings): + settings.lnbits_ln_address_mode = "core_first" + wallet = await create_wallet(user_id=to_user.id) + assert wallet.lightning_address + assert re.fullmatch(r"[a-z]+[a-z]+[0-9]", wallet.lightning_address) + + settings.lnbits_ln_address_mode = "extension_only" + disabled_wallet = await create_wallet(user_id=to_user.id) + assert disabled_wallet.lightning_address is None + + settings.lnbits_ln_address_mode = "core_first" + backfilled = await get_wallet(disabled_wallet.id) + assert backfilled + assert backfilled.lightning_address + + +@pytest.mark.anyio +async def test_wallet_lightning_address_callback_validates_comment( + to_user, settings, mocker +): + settings.lnbits_ln_address_mode = "core_first" + wallet = await create_wallet(user_id=to_user.id) + assert wallet.lightning_address + request = mocker.Mock() + request.url.netloc = "example.com" + request.query_params.get.return_value = "x" * 800 + + result = await wallet_lightning_address_callback( + wallet.lightning_address, request, amount=1000 + ) + assert isinstance(result, LnurlErrorResponse) + assert "can only accept 799" in result.reason + + +@pytest.mark.anyio +async def test_lnurl_api_scan_routes_validate_and_forward(mocker): + pay_response = make_lnurl_pay_response() + mocker.patch( + "lnbits.core.views.lnurl_api.lnurl_handle", + mocker.AsyncMock(return_value=pay_response), + ) + + scanned = await api_lnurlscan("lnurl1example") + assert isinstance(scanned, LnurlPayResponse) + assert scanned.callback == pay_response.callback + + scanned_post = await api_lnurlscan_post( + scan=LnurlScan(lnurl=LnAddress("alice@example.com")) + ) + assert isinstance(scanned_post, LnurlPayResponse) + assert scanned_post.callback == pay_response.callback + + mocker.patch( + "lnbits.core.views.lnurl_api.lnurl_handle", + mocker.AsyncMock(return_value=LnurlErrorResponse(reason="blocked callback")), + ) + with pytest.raises(HTTPException, match="blocked callback"): + await api_lnurlscan("lnurl1blocked") + + mocker.patch( + "lnbits.core.views.lnurl_api.lnurl_handle", + mocker.AsyncMock(side_effect=LnurlException("invalid lnurl")), + ) + with pytest.raises(HTTPException, match="invalid lnurl"): + await api_lnurlscan("lnurl1invalid") + + +@pytest.mark.anyio +async def test_lnurl_api_auth_and_pay_flow(mocker): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + wallet_info = WalletTypeInfo(key_type=KeyType.admin, wallet=wallet) + pay_response = make_lnurl_pay_response() + payment = await create_wallet_invoice( + wallet.id, CreateInvoice(out=False, amount=21, memo="lnurl") + ) + + auth_response = LnurlAuthResponse( + callback=parse_obj_as(CallbackUrl, "https://example.com/auth"), + k1="k1-value", + ) + mocker.patch( + "lnbits.core.views.lnurl_api.lnurlauth", + mocker.AsyncMock(return_value=auth_response), + ) + authenticated = await api_perform_lnurlauth(auth_response, wallet_info) + assert isinstance(authenticated, LnurlAuthResponse) + assert authenticated.k1 == "k1-value" + + mocker.patch( + "lnbits.core.views.lnurl_api.lnurlauth", + mocker.AsyncMock(side_effect=LnurlResponseException("denied")), + ) + with pytest.raises(HTTPException, match="denied"): + await api_perform_lnurlauth(auth_response, wallet_info) + + action_response = LnurlPayActionResponse( + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), + disposable=False, + successAction=parse_obj_as(MessageAction, {"message": "paid"}), + ) + fetch_mock = mocker.patch( + "lnbits.core.views.lnurl_api.fetch_lnurl_pay_request", + mocker.AsyncMock(return_value=(pay_response, action_response)), + ) + pay_mock = mocker.patch( + "lnbits.core.views.lnurl_api.pay_invoice", + mocker.AsyncMock(return_value=payment), + ) + + paid = await api_payments_pay_lnurl( + CreateLnurlPayment( + res=pay_response, amount=2_000, unit="USD", comment="thanks" + ), + wallet_info, + ) + assert paid.payment_hash == payment.payment_hash + fetch_mock.assert_awaited_once() + pay_mock.assert_awaited_once() + assert pay_mock.await_args is not None + assert action_response.successAction is not None + assert pay_mock.await_args.kwargs["extra"] == { + "stored": True, + "success_action": action_response.successAction.json(), + "comment": "thanks", + "fiat_currency": "USD", + "fiat_amount": 2.0, + } + + with pytest.raises(HTTPException, match="Missing LNURL or LnurlPayResponse data."): + await api_payments_pay_lnurl(CreateLnurlPayment(amount=1), wallet_info) diff --git a/tests/api/test_node_api.py b/tests/api/test_node_api.py new file mode 100644 index 000000000..158c2db14 --- /dev/null +++ b/tests/api/test_node_api.py @@ -0,0 +1,366 @@ +from collections.abc import Callable +from typing import Any, cast +from uuid import uuid4 + +import httpx +import pytest +from fastapi import HTTPException +from pytest_mock.plugin import MockerFixture + +from lnbits.core.views import node_api +from lnbits.db import Filters, Page +from lnbits.nodes.base import ( + ChannelBalance, + ChannelPoint, + ChannelState, + ChannelStats, + Node, + NodeChannel, + NodeFees, + NodeInfoResponse, + NodeInvoice, + NodePayment, + NodePeerInfo, + PublicNodeInfo, +) +from lnbits.settings import Settings +from lnbits.wallets.base import Feature + + +class FakeNode: + def __init__(self): + self.channel = NodeChannel( + id="chan-1", + short_id="123x1x0", + peer_id="peer-1", + name="Peer One", + color="#ffffff", + state=ChannelState.ACTIVE, + balance=ChannelBalance(local_msat=1000, remote_msat=2000, total_msat=3000), + point=ChannelPoint(funding_txid="ab" * 32, output_index=1), + fee_ppm=10, + fee_base_msat=1000, + ) + self.peer = NodePeerInfo(id="peer-1", alias="Peer One", addresses=["127.0.0.1"]) + self.info = NodeInfoResponse( + id="node-id", + backend_name="FakeNode", + alias="Fake Alias", + color="#ffffff", + num_peers=1, + blockheight=1, + channel_stats=ChannelStats( + counts={ChannelState.ACTIVE: 1}, + avg_size=3000, + biggest_size=3000, + smallest_size=3000, + total_capacity=3000, + ), + addresses=["127.0.0.1:9735"], + onchain_balance_sat=1, + onchain_confirmed_sat=1, + fees=NodeFees(total_msat=0), + balance_msat=3000, + ) + self.fees_updated: tuple[str, int | None, int | None] | None = None + + async def get_public_info(self) -> PublicNodeInfo: + return PublicNodeInfo(**self.info.dict()) + + async def get_info(self) -> NodeInfoResponse: + return self.info + + async def get_channels(self) -> list[NodeChannel]: + return [self.channel] + + async def get_channel(self, channel_id: str) -> NodeChannel | None: + return self.channel if channel_id == self.channel.id else None + + async def open_channel( + self, + peer_id: str, + funding_amount: int, + push_amount: int | None = None, + fee_rate: int | None = None, + ) -> ChannelPoint: + assert peer_id == "peer-1" + assert funding_amount == 10_000 + assert push_amount == 100 + assert fee_rate == 5 + return ChannelPoint(funding_txid="cd" * 32, output_index=0) + + async def close_channel( + self, + short_id: str | None = None, + point: ChannelPoint | None = None, + force: bool = False, + ) -> list[NodeChannel]: + assert short_id == self.channel.short_id + assert point is None + assert force is True + return [self.channel] + + async def set_channel_fee( + self, channel_id: str, fee_base_msat: int | None, fee_ppm: int | None + ) -> None: + self.fees_updated = (channel_id, fee_base_msat, fee_ppm) + + async def get_payments(self, filters: Filters[Any]) -> Page[NodePayment]: + return Page( + data=[ + NodePayment( + pending=False, + amount=1, + fee=0, + memo="payment", + time=1, + preimage="11" * 32, + payment_hash="22" * 32, + ) + ], + total=1, + ) + + async def get_invoices(self, filters: Filters[Any]) -> Page[NodeInvoice]: + return Page( + data=[ + NodeInvoice( + pending=False, + amount=1, + memo="invoice", + bolt11="lnbc1dummy", + preimage="11" * 32, + payment_hash="33" * 32, + ) + ], + total=1, + ) + + async def get_peers(self) -> list[NodePeerInfo]: + return [self.peer] + + async def connect_peer(self, uri: str) -> dict[str, str]: + return {"uri": uri} + + async def disconnect_peer(self, peer_id: str) -> dict[str, str]: + return {"peer_id": peer_id} + + async def get_id(self) -> str: + return "fake-node-id" + + +class FakeFundingSource: + def __init__( + self, + features: list[Feature], + node_factory: Callable[[Any], Any] | None, + ): + self.features = features + self.__node_cls__ = node_factory + + +class MockHTTPResponse: + def __init__( + self, json_data: dict[str, Any], status_error: Exception | None = None + ): + self._json_data = json_data + self._status_error = status_error + + def raise_for_status(self) -> None: + if self._status_error: + raise self._status_error + + def json(self) -> dict[str, Any]: + return self._json_data + + +class MockHTTPClient: + def __init__(self, response: MockHTTPResponse): + self.response = response + self.calls: list[str] = [] + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + async def get(self, url: str, timeout: int): + self.calls.append(url) + return self.response + + +@pytest.mark.anyio +async def test_node_api_dependency_guards(settings: Settings, mocker: MockerFixture): + original_node_ui = settings.lnbits_node_ui + original_public = settings.lnbits_public_node_ui + try: + settings.lnbits_node_ui = True + funding_source = FakeFundingSource([], None) + mocker.patch( + "lnbits.core.views.node_api.get_funding_source", + return_value=funding_source, + ) + with pytest.raises(HTTPException) as excinfo: + node_api.require_node() + assert excinfo.value.status_code == 501 + + node_enabled_source = FakeFundingSource( + [Feature.nodemanager], lambda wallet: "fake-node" + ) + mocker.patch( + "lnbits.core.views.node_api.get_funding_source", + return_value=node_enabled_source, + ) + settings.lnbits_node_ui = False + with pytest.raises(HTTPException) as disabled: + node_api.require_node() + assert disabled.value.status_code == 503 + + settings.lnbits_node_ui = True + assert node_api.require_node() == "fake-node" + + settings.lnbits_public_node_ui = False + with pytest.raises(HTTPException) as public_disabled: + node_api.check_public() + assert public_disabled.value.status_code == 503 + finally: + settings.lnbits_node_ui = original_node_ui + settings.lnbits_public_node_ui = original_public + + +@pytest.mark.anyio +async def test_node_api_route_functions_with_fake_node( + settings: Settings, + mocker: MockerFixture, +): + fake_node = FakeNode() + node = cast(Node, fake_node) + original_transactions = settings.lnbits_node_ui_transactions + settings.lnbits_node_ui_transactions = True + rank_response = MockHTTPResponse( + { + "noderank": { + "capacity": 1, + "channelcount": 2, + "age": 3, + "growth": 4, + "availability": 5, + } + } + ) + mocker.patch( + "lnbits.core.views.node_api.httpx.AsyncClient", + return_value=MockHTTPClient(rank_response), + ) + + try: + assert await node_api.api_get_ok() is None + + public_info = await node_api.api_get_public_info(node=node) + assert public_info.backend_name == "FakeNode" + + info = await node_api.api_get_info(node=node) + assert info is not None + assert info.id == "node-id" + + channels = await node_api.api_get_channels(node=node) + assert channels is not None + assert channels[0].id == "chan-1" + + channel = await node_api.api_get_channel("chan-1", node=node) + assert channel is not None + assert channel.peer_id == "peer-1" + + created = await node_api.api_create_channel( + node=node, + peer_id="peer-1", + funding_amount=10_000, + push_amount=100, + fee_rate=5, + ) + assert created.output_index == 0 + + deleted = await node_api.api_delete_channel( + short_id="123x1x0", + funding_txid=None, + output_index=None, + force=True, + node=node, + ) + assert deleted is not None + assert deleted[0].id == "chan-1" + + await node_api.api_set_channel_fees( + "chan-1", + node=node, + fee_ppm=42, + fee_base_msat=7, + ) + assert fake_node.fees_updated == ("chan-1", 7, 42) + + payments = await node_api.api_get_payments(node=node, filters=Filters()) + assert payments is not None + assert payments.total == 1 + + invoices = await node_api.api_get_invoices(node=node, filters=Filters()) + assert invoices is not None + assert invoices.total == 1 + + peers = await node_api.api_get_peers(node=node) + assert peers[0].id == "peer-1" + + connect = await node_api.api_connect_peer( + uri="peer-1@127.0.0.1:9735", node=node + ) + assert connect["uri"] == "peer-1@127.0.0.1:9735" + + disconnect = await node_api.api_disconnect_peer("peer-1", node=node) + assert disconnect["peer_id"] == "peer-1" + + rank = await node_api.api_get_1ml_stats(node=node) + assert rank is not None + rank_data = node_api.NodeRank.parse_obj(rank) + assert rank_data.channelcount == 2 + finally: + settings.lnbits_node_ui_transactions = original_transactions + + +@pytest.mark.anyio +async def test_node_api_transactions_and_rank_errors( + settings: Settings, + mocker: MockerFixture, +): + fake_node = FakeNode() + node = cast(Node, fake_node) + original_transactions = settings.lnbits_node_ui_transactions + settings.lnbits_node_ui_transactions = False + + request = httpx.Request("GET", f"https://1ml.com/node/{uuid4().hex}/json") + mocker.patch( + "lnbits.core.views.node_api.httpx.AsyncClient", + return_value=MockHTTPClient( + MockHTTPResponse( + {}, + status_error=httpx.HTTPStatusError( + "not found", request=request, response=httpx.Response(404) + ), + ) + ), + ) + + try: + with pytest.raises(HTTPException) as payments: + await node_api.api_get_payments(node=node, filters=Filters()) + assert payments.value.status_code == 503 + + with pytest.raises(HTTPException) as invoices: + await node_api.api_get_invoices(node=node, filters=Filters()) + assert invoices.value.status_code == 503 + + with pytest.raises(HTTPException) as rank: + await node_api.api_get_1ml_stats(node=node) + assert rank.value.status_code == 404 + assert rank.value.detail == "Node not found on 1ml.com" + finally: + settings.lnbits_node_ui_transactions = original_transactions diff --git a/tests/api/test_payment_api.py b/tests/api/test_payment_api.py new file mode 100644 index 000000000..1a08eaa1a --- /dev/null +++ b/tests/api/test_payment_api.py @@ -0,0 +1,526 @@ +import json +from hashlib import sha256 +from uuid import uuid4 + +import pytest +from fastapi import HTTPException +from pydantic import ValidationError + +from lnbits.core.crud.payments import ( + create_payment, + get_payment, + get_payments, + update_payment, +) +from lnbits.core.models import Account, CreateInvoice, PaymentFilters, PaymentState +from lnbits.core.models.payments import CancelInvoice, CreatePayment, SettleInvoice +from lnbits.core.models.users import AccountId +from lnbits.core.models.wallets import BaseWalletTypeInfo, KeyType, WalletTypeInfo +from lnbits.core.services.payments import create_wallet_invoice +from lnbits.core.services.users import create_user_account +from lnbits.core.views.payment_api import ( + api_all_payments_paginated, + api_payments_cancel, + api_payments_counting_stats, + api_payments_daily_stats, + api_payments_fee_reserve, + api_payments_settle, + api_payments_total_breakdown, + api_payments_wallets_stats, +) +from lnbits.db import Filter, Filters +from lnbits.wallets.base import InvoiceResponse + +ZERO_AMOUNT_INVOICE = ( + "lnbc1pnsu5z3pp57getmdaxhg5kc9yh2a2qsh7cjf4gnccgkw0qenm8vsqv50w7s" + "ygqdqj0fjhymeqv9kk7atwwscqzzsxqyz5vqsp5e2yyqcp0a3ujeesp24ya0glej" + "srh703md8mrx0g2lyvjxy5w27ss9qxpqysgqyjreasng8a086kpkczv48er5c6l5" + "73aym6ynrdl9nkzqnag49vt3sjjn8qdfq5cr6ha0vrdz5c5r3v4aghndly0hplmv" + "6hjxepwp93cq398l3s" +) + + +@pytest.mark.anyio +async def test_payment_api_stats_and_all_paginated(admin_user): + first_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + second_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + first_wallet = first_user.wallets[0] + second_wallet = second_user.wallets[0] + + await _create_payment(first_wallet.id, amount_msat=2_000, tag="coffee") + await _create_payment(first_wallet.id, amount_msat=-1_000, tag="coffee") + await _create_payment(second_wallet.id, amount_msat=5_000, tag="books") + + count_stats = await api_payments_counting_stats( + count_by="tag", + filters=Filters(limit=20), + account_id=AccountId(id=first_user.id), + ) + assert any(item.field == "coffee" for item in count_stats) + assert all(item.field != "books" for item in count_stats) + + wallet_stats = await api_payments_wallets_stats( + filters=Filters(limit=20), account_id=AccountId(id=first_user.id) + ) + assert any(item.wallet_id == first_wallet.id for item in wallet_stats) + assert all(item.wallet_id != second_wallet.id for item in wallet_stats) + + daily_stats = await api_payments_daily_stats( + account_id=AccountId(id=first_user.id), + filters=Filters(limit=20), + ) + assert daily_stats + assert daily_stats[0].payments_count >= 1 + + regular_page = await api_all_payments_paginated( + filters=Filters(limit=20), account_id=AccountId(id=first_user.id) + ) + assert regular_page.total >= 2 + assert all(payment.wallet_id == first_wallet.id for payment in regular_page.data) + + admin_page = await api_all_payments_paginated( + filters=Filters(limit=50), account_id=AccountId(id=admin_user.id) + ) + wallet_ids = {payment.wallet_id for payment in admin_page.data} + assert first_wallet.id in wallet_ids + assert second_wallet.id in wallet_ids + + +@pytest.mark.anyio +async def test_payment_external_id_is_stored_and_validated(): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + + first_payment = await create_wallet_invoice( + wallet.id, + CreateInvoice( + out=False, + amount=21, + memo="external reference", + external_id="provider_payment_123", + ), + ) + second_payment = await create_wallet_invoice( + wallet.id, + CreateInvoice( + out=False, + amount=22, + memo="external reference newest", + external_id="provider_payment_123", + ), + ) + + assert first_payment.external_id == "provider_payment_123" + assert second_payment.external_id == "provider_payment_123" + stored_payments = await get_payments( + wallet_id=wallet.id, + filters=Filters( + filters=[ + Filter.parse_query( + "external_id", ["provider_payment_123"], PaymentFilters + ) + ], + model=PaymentFilters, + sortby="created_at", + direction="desc", + ), + ) + assert [payment.checking_id for payment in stored_payments] == [ + second_payment.checking_id, + first_payment.checking_id, + ] + + with pytest.raises(ValidationError, match="Invalid external id"): + CreateInvoice(out=False, amount=21, external_id="provider payment 123") + + +@pytest.mark.anyio +async def test_payment_api_total_breakdown_groups_wallet_tags_and_fiat(): + first_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + second_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + first_wallet = first_user.wallets[0] + second_wallet = second_user.wallets[0] + + await _create_payment(first_wallet.id, amount_msat=2_000, tag="coffee") + await _create_payment( + first_wallet.id, + amount_msat=4_000, + tag="coffee", + fiat_provider="stripe", + extra={"fiat_payment_request": "https://stripe.test/session"}, + ) + await _create_payment(first_wallet.id, amount_msat=-1_000) + await _create_payment(second_wallet.id, amount_msat=8_000, tag="books") + + breakdown = await api_payments_total_breakdown( + BaseWalletTypeInfo(key_type=KeyType.invoice, wallet=first_wallet) + ) + + assert any( + item.tag == "coffee" + and item.is_fiat is False + and item.total == 2_000 + and item.payments_count == 1 + for item in breakdown + ) + assert any( + item.tag == "coffee" + and item.is_fiat is True + and item.total == 4_000 + and item.payments_count == 1 + for item in breakdown + ) + assert any( + item.tag is None and item.is_fiat is False and item.total == -1_000 + for item in breakdown + ) + assert all(item.tag != "books" for item in breakdown) + + +@pytest.mark.anyio +async def test_payment_api_fee_reserve_and_hold_invoice_actions(mocker): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + + invoice = await create_wallet_invoice( + wallet.id, CreateInvoice(out=False, amount=42, memo="reserve") + ) + reserve = await api_payments_fee_reserve(invoice.bolt11) + assert json.loads(bytes(reserve.body))["fee_reserve"] >= 0 + + with pytest.raises(HTTPException, match="Invoice has no amount."): + await api_payments_fee_reserve(ZERO_AMOUNT_INVOICE) + + preimage = "11" * 32 + payment_hash = sha256(bytes.fromhex(preimage)).hexdigest() + await _create_payment( + wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + status=PaymentState.PENDING, + ) + settle_mock = mocker.patch( + "lnbits.core.views.payment_api.settle_hold_invoice", + mocker.AsyncMock( + return_value=InvoiceResponse( + ok=True, + checking_id="settled", + preimage=preimage, + ) + ), + ) + + settled = await api_payments_settle( + SettleInvoice(preimage=preimage), + WalletTypeInfo(key_type=KeyType.admin, wallet=wallet), + ) + assert settled.success is True + settle_mock.assert_awaited_once() + + cancel_hash = (uuid4().hex * 2)[:64] + await _create_payment( + wallet.id, + amount_msat=2_000, + payment_hash=cancel_hash, + status=PaymentState.PENDING, + ) + cancel_mock = mocker.patch( + "lnbits.core.views.payment_api.cancel_hold_invoice", + mocker.AsyncMock( + return_value=InvoiceResponse( + ok=False, + checking_id="cancelled", + error_message="cancelled", + ) + ), + ) + + cancelled = await api_payments_cancel( + CancelInvoice(payment_hash=cancel_hash), + WalletTypeInfo(key_type=KeyType.admin, wallet=wallet), + ) + assert cancelled.failed is True + cancel_mock.assert_awaited_once() + + +@pytest.mark.anyio +async def test_payment_extra_update_appends_new_keys( + client, + to_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + checking_id = await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + tag="splitpayments", + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=adminkey_headers_to, + json={ + "payment_hash": payment_hash, + "extra": {"child": "daughter", "compliance_note": "reviewed"}, + }, + ) + + assert response.status_code == 200 + extra = response.json()["extra"] + assert extra["tag"] == "splitpayments" + assert extra["child"] == "daughter" + assert extra["compliance_note"] == "reviewed" + + payment = await get_payment(checking_id) + assert payment.extra == extra + + +@pytest.mark.anyio +async def test_payment_extra_update_creates_extra_when_missing( + client, + to_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + checking_id = await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=adminkey_headers_to, + json={"payment_hash": payment_hash, "extra": {"note": "reviewed"}}, + ) + + assert response.status_code == 200 + assert response.json()["extra"] == {"note": "reviewed"} + + payment = await get_payment(checking_id) + assert payment.extra == {"note": "reviewed"} + + +@pytest.mark.anyio +async def test_payment_extra_update_rejects_existing_keys( + client, + to_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + checking_id = await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + tag="original", + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=adminkey_headers_to, + json={"payment_hash": payment_hash, "extra": {"tag": "overwritten"}}, + ) + + assert response.status_code == 400 + assert response.json()["detail"] == "Extra keys already exist: tag." + + payment = await get_payment(checking_id) + assert payment.extra == {"tag": "original"} + + +@pytest.mark.anyio +async def test_payment_extra_update_requires_admin_key( + client, + to_wallet, + inkey_headers_to, +): + payment_hash = uuid4().hex + await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=inkey_headers_to, + json={"payment_hash": payment_hash, "extra": {"note": "invoice key"}}, + ) + + assert response.status_code == 403 + assert response.json()["detail"] == "Invalid adminkey." + + +@pytest.mark.anyio +async def test_payment_extra_update_is_wallet_scoped( + client, + from_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + await _create_payment( + from_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=adminkey_headers_to, + json={"payment_hash": payment_hash, "extra": {"note": "wrong wallet"}}, + ) + + assert response.status_code == 404 + assert response.json()["detail"] == "Payment does not exist." + + +@pytest.mark.anyio +async def test_payment_extra_update_requires_successful_payment( + client, + to_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + status=PaymentState.PENDING, + ) + + response = await client.patch( + "/api/v1/payments/extra", + headers=adminkey_headers_to, + json={"payment_hash": payment_hash, "extra": {"note": "too early"}}, + ) + + assert response.status_code == 400 + assert ( + response.json()["detail"] == "Payment extra can only be updated after success." + ) + + +@pytest.mark.anyio +async def test_api_update_payment_labels( + client, + to_wallet, + adminkey_headers_to, +): + payment_hash = uuid4().hex + checking_id = await _create_payment( + to_wallet.id, + amount_msat=1_000, + payment_hash=payment_hash, + status=PaymentState.SUCCESS, + ) + + # 1. Update labels with new valid labels + response = await client.put( + f"/api/v1/payments/{payment_hash}/labels", + headers=adminkey_headers_to, + json={"labels": ["income", "restaurant"]}, + ) + assert response.status_code == 200 + assert response.json()["success"] is True + + # 2. Check that the labels were updated on the payment + payment = await get_payment(checking_id) + assert payment.labels == ["income", "restaurant"] + + # 3. Check that the new labels were auto-created in the user's account config + from lnbits.core.crud.users import get_account + + account = await get_account(to_wallet.user) + assert account is not None + user_labels = {label.name: label.color for label in account.extra.labels} + assert "income" in user_labels + assert "restaurant" in user_labels + assert ( + user_labels["income"] is not None + and user_labels["income"].startswith("#") + and len(user_labels["income"]) == 7 + ) + assert ( + user_labels["restaurant"] is not None + and user_labels["restaurant"].startswith("#") + and len(user_labels["restaurant"]) == 7 + ) + + # 4. Check that invalid labels are rejected + response = await client.put( + f"/api/v1/payments/{payment_hash}/labels", + headers=adminkey_headers_to, + json={"labels": ["invalid!label"]}, + ) + assert response.status_code == 400 + assert "Invalid label name" in response.json()["detail"] + + +async def _create_payment( + wallet_id: str, + *, + amount_msat: int, + status: PaymentState = PaymentState.SUCCESS, + payment_hash: str | None = None, + tag: str | None = None, + fiat_provider: str | None = None, + extra: dict | None = None, +) -> str: + checking_id = f"checking_{uuid4().hex[:8]}" + payment_extra = extra or {} + if tag: + payment_extra["tag"] = tag + await create_payment( + checking_id=checking_id, + data=CreatePayment( + wallet_id=wallet_id, + payment_hash=payment_hash or uuid4().hex, + bolt11=f"bolt11_{checking_id}", + amount_msat=amount_msat, + memo=f"payment_{checking_id}", + extra=payment_extra, + ), + status=status, + ) + if fiat_provider: + payment = await get_payment(checking_id) + payment.fiat_provider = fiat_provider + await update_payment(payment) + return checking_id diff --git a/tests/api/test_tinyurl_api.py b/tests/api/test_tinyurl_api.py new file mode 100644 index 000000000..931ccf5ef --- /dev/null +++ b/tests/api/test_tinyurl_api.py @@ -0,0 +1,71 @@ +from http import HTTPStatus + +import pytest +from httpx import AsyncClient + + +@pytest.mark.anyio +async def test_tinyurl_api_create_get_redirect_and_delete( + client: AsyncClient, + adminkey_headers_from: dict[str, str], + inkey_headers_from: dict[str, str], + inkey_headers_to: dict[str, str], +): + created = await client.post( + "/api/v1/tinyurl", + params={"url": "https://example.com/landing", "endless": "true"}, + headers=adminkey_headers_from, + ) + assert created.status_code == HTTPStatus.OK + tinyurl = created.json() + assert tinyurl["url"] == "https://example.com/landing" + assert tinyurl["endless"] is True + + fetched = await client.get( + f"/api/v1/tinyurl/{tinyurl['id']}", + headers=inkey_headers_from, + ) + assert fetched.status_code == HTTPStatus.OK + assert fetched.json()["id"] == tinyurl["id"] + + wrong_wallet = await client.get( + f"/api/v1/tinyurl/{tinyurl['id']}", + headers=inkey_headers_to, + ) + assert wrong_wallet.status_code == HTTPStatus.NOT_FOUND + assert wrong_wallet.json()["detail"] == "Unable to fetch tinyurl" + + redirect = await client.get(f"/t/{tinyurl['id']}") + assert redirect.status_code == HTTPStatus.TEMPORARY_REDIRECT + assert redirect.headers["location"] == "https://example.com/landing" + + deleted = await client.delete( + f"/api/v1/tinyurl/{tinyurl['id']}", + headers=adminkey_headers_from, + ) + assert deleted.status_code == HTTPStatus.OK + assert deleted.json()["deleted"] is True + + missing_redirect = await client.get(f"/t/{tinyurl['id']}") + assert missing_redirect.status_code == HTTPStatus.NOT_FOUND + + +@pytest.mark.anyio +async def test_tinyurl_api_reuses_existing_entries_for_same_wallet( + client: AsyncClient, + adminkey_headers_from: dict[str, str], +): + first = await client.post( + "/api/v1/tinyurl", + params={"url": "https://example.com/reused"}, + headers=adminkey_headers_from, + ) + second = await client.post( + "/api/v1/tinyurl", + params={"url": "https://example.com/reused"}, + headers=adminkey_headers_from, + ) + + assert first.status_code == HTTPStatus.OK + assert second.status_code == HTTPStatus.OK + assert first.json()["id"] == second.json()["id"] diff --git a/tests/api/test_user_api.py b/tests/api/test_user_api.py new file mode 100644 index 000000000..68eb10b02 --- /dev/null +++ b/tests/api/test_user_api.py @@ -0,0 +1,141 @@ +from uuid import uuid4 + +import pytest +from httpx import AsyncClient + +from lnbits.core.crud.wallets import create_wallet, get_wallet, get_wallets +from lnbits.core.models import UpdateBalance +from lnbits.core.models.users import Account +from lnbits.core.services.users import create_user_account +from lnbits.core.views.user_api import api_users_create_user_wallet +from lnbits.settings import settings + + +@pytest.mark.anyio +async def test_user_api_toggle_admin_and_update_balance( + http_client: AsyncClient, superuser_token: str +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + + promote = await http_client.put( + f"/users/api/v1/user/{user.id}/admin", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert promote.status_code == 200 + assert settings.is_admin_user(user.id) is True + + demote = await http_client.put( + f"/users/api/v1/user/{user.id}/admin", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert demote.status_code == 200 + assert settings.is_admin_user(user.id) is False + + balance = await http_client.put( + "/users/api/v1/balance", + headers={"Authorization": f"Bearer {superuser_token}"}, + json=UpdateBalance(id=wallet.id, amount=7).dict(), + ) + assert balance.status_code == 200 + assert balance.json()["success"] is True + + updated_wallet = await get_wallet(wallet.id) + assert updated_wallet is not None + assert updated_wallet.balance == 7 + + +@pytest.mark.anyio +async def test_user_api_get_wallets_and_delete_all_wallets( + http_client: AsyncClient, superuser_token: str +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + extra_wallet = await create_wallet(user_id=user.id, wallet_name="spare") + + wallets = await http_client.get( + f"/users/api/v1/user/{user.id}/wallet", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert wallets.status_code == 200 + wallet_ids = {wallet["id"] for wallet in wallets.json()} + assert extra_wallet.id in wallet_ids + + deleted = await http_client.delete( + f"/users/api/v1/user/{user.id}/wallets", + headers={"Authorization": f"Bearer {superuser_token}"}, + ) + assert deleted.status_code == 200 + assert deleted.json()["success"] is True + + active_wallets = await get_wallets(user.id, deleted=False) + assert active_wallets == [] + + +@pytest.mark.anyio +async def test_user_api_superuser_sets_wallet_lightning_address( + http_client: AsyncClient, superuser_token: str +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + + settings.lnbits_ln_address_mode = "core_first" + settings.lnbits_wallet_lightning_address_blacklist = ["admin"] + settings.lnbits_charge_wallet_lightning_addresses = True + settings.lnbits_wallet_lightning_address_price_sats = 1_000 + settings.lnbits_service_fee_wallet = None + + unauthorized = await http_client.put( + f"/users/api/v1/user/{user.id}/wallet/{wallet.id}/lightning-address", + json={"lightning_address": "admin"}, + ) + assert unauthorized.status_code == 401 + + response = await http_client.put( + f"/users/api/v1/user/{user.id}/wallet/{wallet.id}/lightning-address", + headers={"Authorization": f"Bearer {superuser_token}"}, + json={"lightning_address": "admin"}, + ) + assert response.status_code == 200 + assert response.json()["lightning_address"] == "admin" + + updated_wallet = await get_wallet(wallet.id) + assert updated_wallet + assert updated_wallet.lightning_address == "admin" + assert updated_wallet.balance == 0 + + +@pytest.mark.anyio +async def test_user_api_create_wallet_validates_currency(): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + + with pytest.raises(ValueError, match="Currency 'INVALID' not allowed."): + await api_users_create_user_wallet(user.id, name="invalid", currency="INVALID") + + wallet = await api_users_create_user_wallet( + user.id, name="eur wallet", currency="EUR" + ) + assert wallet.currency == "EUR" diff --git a/tests/api/test_wallet_api.py b/tests/api/test_wallet_api.py new file mode 100644 index 000000000..0afeac633 --- /dev/null +++ b/tests/api/test_wallet_api.py @@ -0,0 +1,313 @@ +from uuid import uuid4 + +import pytest +from httpx import AsyncClient + +from lnbits.core.crud.wallets import create_wallet, get_wallet +from lnbits.core.models.users import Account +from lnbits.core.services import update_wallet_balance +from lnbits.core.services.users import create_user_account +from lnbits.settings import settings + + +@pytest.mark.anyio +async def test_wallet_api_share_invite_reject_accept_and_delete( + http_client: AsyncClient, +): + owner = await create_user_account( + Account( + id=uuid4().hex, + username=f"owner_{uuid4().hex[:8]}", + email=f"owner_{uuid4().hex[:8]}@lnbits.com", + ) + ) + invited = await create_user_account( + Account( + id=uuid4().hex, + username=f"invited_{uuid4().hex[:8]}", + email=f"invited_{uuid4().hex[:8]}@lnbits.com", + ) + ) + source_wallet = owner.wallets[0] + owner_headers = _admin_headers(source_wallet.adminkey) + + invite = await http_client.put( + "/api/v1/wallet/share/invite", + headers=owner_headers, + json={ + "username": invited.username, + "permissions": ["view-payments"], + "status": "invite_sent", + }, + ) + assert invite.status_code == 200 + share_request = invite.json() + assert share_request["request_id"] + + reject = await http_client.delete( + f"/api/v1/wallet/share/invite/{share_request['request_id']}?usr={invited.id}" + ) + assert reject.status_code == 200 + assert reject.json()["success"] is True + + removed_share = await http_client.delete( + f"/api/v1/wallet/share/{share_request['request_id']}", + headers=owner_headers, + ) + assert removed_share.status_code == 200 + assert removed_share.json()["success"] is True + + invite = await http_client.put( + "/api/v1/wallet/share/invite", + headers=owner_headers, + json={ + "username": invited.username, + "permissions": ["view-payments", "receive-payments"], + "status": "invite_sent", + }, + ) + assert invite.status_code == 200 + share_request = invite.json() + + create_shared = await http_client.post( + f"/api/v1/wallet?usr={invited.id}", + json={ + "name": "shared", + "wallet_type": "lightning-shared", + "shared_wallet_id": source_wallet.id, + }, + ) + assert create_shared.status_code == 200 + mirror_wallet = create_shared.json() + assert mirror_wallet["shared_wallet_id"] == source_wallet.id + + approve = await http_client.put( + "/api/v1/wallet/share", + headers=owner_headers, + json={ + "username": invited.username, + "shared_with_wallet_id": mirror_wallet["id"], + "permissions": ["view-payments", "receive-payments"], + "status": "approved", + }, + ) + assert approve.status_code == 200 + assert approve.json()["status"] == "approved" + + delete_share = await http_client.delete( + f"/api/v1/wallet/share/{share_request['request_id']}", + headers=owner_headers, + ) + assert delete_share.status_code == 200 + assert delete_share.json()["success"] is True + assert await get_wallet(mirror_wallet["id"]) is None + + +@pytest.mark.anyio +async def test_wallet_api_paginated_update_reset_and_store_paylinks( + http_client: AsyncClient, +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + extra_wallet = await create_wallet(user_id=user.id, wallet_name="second") + first_wallet = user.wallets[0] + + page = await http_client.get(f"/api/v1/wallet/paginated?usr={user.id}&limit=10") + assert page.status_code == 200 + assert page.json()["total"] >= 2 + + renamed = await http_client.put( + "/api/v1/wallet/renamed-wallet", + headers=_admin_headers(first_wallet.adminkey), + ) + assert renamed.status_code == 200 + assert renamed.json()["name"] == "renamed-wallet" + + original_admin_key = extra_wallet.adminkey + reset = await http_client.put( + f"/api/v1/wallet/reset/{extra_wallet.id}?usr={user.id}" + ) + assert reset.status_code == 200 + assert reset.json()["adminkey"] != original_admin_key + + stored = await http_client.put( + f"/api/v1/wallet/stored_paylinks/{extra_wallet.id}", + headers=_admin_headers(reset.json()["adminkey"]), + json={ + "links": [ + { + "lnurl": "alice@example.com", + "label": "Alice", + } + ] + }, + ) + assert stored.status_code == 200 + assert stored.json()[0]["lnurl"] == "alice@example.com" + + forbidden = await http_client.put( + f"/api/v1/wallet/stored_paylinks/{extra_wallet.id}", + headers=_admin_headers(first_wallet.adminkey), + json={"links": []}, + ) + assert forbidden.status_code == 403 + + updated = await http_client.patch( + "/api/v1/wallet", + headers=_admin_headers(first_wallet.adminkey), + json={"icon": "bolt", "color": "amber", "pinned": True}, + ) + assert updated.status_code == 200 + assert updated.json()["extra"]["icon"] == "bolt" + assert updated.json()["extra"]["color"] == "amber" + assert updated.json()["extra"]["pinned"] is True + + +@pytest.mark.anyio +async def test_wallet_api_custom_lightning_address_owner_rules( + http_client: AsyncClient, +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + headers = _admin_headers(wallet.adminkey) + + settings.lnbits_ln_address_mode = "core_first" + settings.lnbits_allow_custom_wallet_lightning_addresses = False + disabled = await http_client.patch( + "/api/v1/wallet", + headers=headers, + json={"lightning_address": "custom.name"}, + ) + assert disabled.status_code == 403 + + settings.lnbits_allow_custom_wallet_lightning_addresses = True + settings.lnbits_wallet_lightning_address_blacklist = ["admin"] + blacklisted = await http_client.patch( + "/api/v1/wallet", + headers=headers, + json={"lightning_address": "admin"}, + ) + assert blacklisted.status_code == 400 + + invalid = await http_client.patch( + "/api/v1/wallet", + headers=headers, + json={"lightning_address": "custom+tag"}, + ) + assert invalid.status_code == 400 + + existing_wallet = await create_wallet( + user_id=user.id, + wallet_name="existing lightning address", + ) + existing = await http_client.patch( + "/api/v1/wallet", + headers=_admin_headers(existing_wallet.adminkey), + json={"lightning_address": "pay.link"}, + ) + assert existing.status_code == 200 + + conflict = await http_client.patch( + "/api/v1/wallet", + headers=headers, + json={"lightning_address": "pay.link"}, + ) + assert conflict.status_code == 400 + + updated = await http_client.patch( + "/api/v1/wallet", + headers=headers, + json={"lightning_address": "custom.name"}, + ) + assert updated.status_code == 200 + assert updated.json()["lightning_address"] == "custom.name" + + +@pytest.mark.anyio +async def test_wallet_api_custom_lightning_address_charges_fee( + http_client: AsyncClient, +): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + fee_user = await create_user_account( + Account( + id=uuid4().hex, + username=f"fees_{uuid4().hex[:8]}", + email=f"fees_{uuid4().hex[:8]}@lnbits.com", + ) + ) + wallet = user.wallets[0] + fee_wallet = fee_user.wallets[0] + await update_wallet_balance(wallet=wallet, amount=2_000) + + settings.lnbits_ln_address_mode = "core_first" + settings.lnbits_allow_custom_wallet_lightning_addresses = True + settings.lnbits_charge_wallet_lightning_addresses = True + settings.lnbits_wallet_lightning_address_price_sats = 1_000 + settings.lnbits_service_fee_wallet = fee_wallet.id + + updated = await http_client.patch( + "/api/v1/wallet", + headers=_admin_headers(wallet.adminkey), + json={"lightning_address": "paid.name"}, + ) + assert updated.status_code == 200 + assert updated.json()["lightning_address"] == "paid.name" + + charged_wallet = await get_wallet(wallet.id) + credited_wallet = await get_wallet(fee_wallet.id) + assert charged_wallet + assert credited_wallet + assert charged_wallet.balance == 1_000 + assert credited_wallet.balance == 1_000 + + settings.lnbits_service_fee_wallet = None + missing_fee_wallet = await http_client.patch( + "/api/v1/wallet", + headers=_admin_headers(wallet.adminkey), + json={"lightning_address": "paid.other"}, + ) + assert missing_fee_wallet.status_code == 400 + assert missing_fee_wallet.json()["detail"] == ( + "Lightning Address fee wallet is not configured." + ) + + +@pytest.mark.anyio +async def test_wallet_api_shared_wallet_requires_source_id(http_client: AsyncClient): + user = await create_user_account( + Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + email=f"user_{uuid4().hex[:8]}@lnbits.com", + ) + ) + + response = await http_client.post( + f"/api/v1/wallet?usr={user.id}", + json={"wallet_type": "lightning-shared"}, + ) + assert response.status_code == 400 + assert ( + response.json()["detail"] == "Shared wallet ID is required for shared wallets." + ) + + +def _admin_headers(adminkey: str) -> dict[str, str]: + return {"X-Api-Key": adminkey, "Content-type": "application/json"} diff --git a/tests/api/test_websocket_api.py b/tests/api/test_websocket_api.py new file mode 100644 index 000000000..fdd14ced2 --- /dev/null +++ b/tests/api/test_websocket_api.py @@ -0,0 +1,31 @@ +from unittest.mock import AsyncMock + +from pytest_mock.plugin import MockerFixture + + +def test_websocket_api_connects_and_updates(test_client): + with test_client.websocket_connect("/api/v1/ws/demo-item") as websocket: + response = test_client.post("/api/v1/ws/demo-item", params={"data": "hello"}) + assert response.status_code == 200 + assert response.json() == {"sent": True, "data": "hello"} + assert websocket.receive_text() == "hello" + + response = test_client.get("/api/v1/ws/demo-item/world") + assert response.status_code == 200 + assert response.json() == {"sent": True, "data": "world"} + assert websocket.receive_text() == "world" + + +def test_websocket_api_reports_send_failures(test_client, mocker: MockerFixture): + mocker.patch( + "lnbits.core.views.websocket_api.websocket_manager.send", + AsyncMock(side_effect=RuntimeError("boom")), + ) + + post_response = test_client.post("/api/v1/ws/demo-item", params={"data": "oops"}) + assert post_response.status_code == 200 + assert post_response.json() == {"sent": False, "data": "oops"} + + get_response = test_client.get("/api/v1/ws/demo-item/oops") + assert get_response.status_code == 200 + assert get_response.json() == {"sent": False, "data": "oops"} diff --git a/tests/conftest.py b/tests/conftest.py index 95ab104d6..0076fafa3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ import asyncio +import copy +import inspect from datetime import datetime, timezone from uuid import uuid4 @@ -23,7 +25,12 @@ from lnbits.core.services import create_user_account, update_wallet_balance from lnbits.core.services.payments import create_wallet_invoice from lnbits.core.views.auth_api import first_install from lnbits.db import DB_TYPE, SQLITE, Database -from lnbits.settings import AuthMethods, FiatProviderLimits, Settings +from lnbits.settings import ( + AuthMethods, + EditableSettings, + FiatProviderLimits, + Settings, +) from lnbits.settings import settings as lnbits_settings from lnbits.wallets.fake import FakeWallet from tests.helpers import ( @@ -33,6 +40,23 @@ from tests.helpers import ( asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) ADMIN_USER_ID = uuid4().hex +# Snapshot the initialized module settings instead of a fresh Settings() instance. +# The module settings include runtime-populated values like `version`. +_PURE_SETTINGS = copy.deepcopy(lnbits_settings) +_PURE_SETTINGS_FIELDS = tuple( + sorted( + { + field_name + for field_name in Settings.readonly_fields() + if field_name != "super_user" + } + | { + name + for name in inspect.signature(EditableSettings).parameters + if not name.startswith("_") + } + ) +) @pytest.fixture(scope="session") @@ -43,8 +67,10 @@ def anyio_backend(): @pytest.fixture(scope="session") def settings(): # override settings for tests + lnbits_settings.auth_https_only = False lnbits_settings.lnbits_admin_extensions = [] lnbits_settings.lnbits_data_folder = "./tests/data" + lnbits_settings.lnbits_wasm_extensions_path = "./tests/data/wasm_extensions" lnbits_settings.lnbits_admin_ui = True lnbits_settings.lnbits_extensions_default_install = [] lnbits_settings.lnbits_extensions_deactivate_all = True @@ -64,13 +90,14 @@ def run_before_and_after_tests(settings: Settings): @pytest.fixture(scope="session") async def app(settings: Settings): app = create_app() - async with LifespanManager(app) as manager: + async with LifespanManager(app, startup_timeout=30) as manager: settings.first_install = True await first_install( UpdateSuperuserPassword( username="superadmin", password="secret1234", password_repeat="secret1234", + first_install_token=settings.first_install_token, ) ) @@ -326,7 +353,22 @@ async def new_user(username: str | None = None) -> User: return user +def _restore_pure_settings(settings: Settings): + for field_name in _PURE_SETTINGS_FIELDS: + setattr( + settings, field_name, copy.deepcopy(getattr(_PURE_SETTINGS, field_name)) + ) + + def _settings_cleanup(settings: Settings): + _restore_pure_settings(settings) + settings.auth_https_only = False + settings.lnbits_data_folder = "./tests/data" + settings.lnbits_wasm_extensions_path = "./tests/data/wasm_extensions" + settings.bundle_assets = True + settings.lnbits_admin_ui = True + settings.lnbits_extensions_default_install = [] + settings.lnbits_extensions_deactivate_all = True settings.lnbits_allow_new_accounts = True settings.lnbits_allowed_users = [] settings.auth_allowed_methods = AuthMethods.all() diff --git a/tests/docker-compose.yaml b/tests/docker-compose.yaml new file mode 100644 index 000000000..814d9fd2c --- /dev/null +++ b/tests/docker-compose.yaml @@ -0,0 +1,24 @@ +networks: + lnbits-net: + +services: + postgres-db: + container_name: postgres_container_test + image: postgres:14 + environment: + POSTGRES_DB: lnbits + POSTGRES_USER: lnbits + POSTGRES_PASSWORD: lnbits + PGDATA: /lnbits/data/postgres + volumes: + - ./data/postgres_test:/lnbits/data/postgres + ports: + - '5444:5432' + restart: unless-stopped + healthcheck: + test: ['CMD-SHELL', 'pg_isready -d lnbits_db'] + interval: 5s + timeout: 5s + retries: 5 + networks: + - lnbits-net diff --git a/tests/e2e/bigpayment.spec.ts b/tests/e2e/bigpayment.spec.ts new file mode 100644 index 000000000..6ab31b15c --- /dev/null +++ b/tests/e2e/bigpayment.spec.ts @@ -0,0 +1,75 @@ +import {test, expect, randomHex} from './fixtures' +import { + createInvoice, + createWallet, + extensionApi, + extensionFrame, + fundWalletWithFakeBalance, + installAndEnableExtension, + invoicePaymentRequest, + login, + waitForWalletBalance +} from './extension-helpers' +import {BIGPAYMENT} from './extensions' + +test('install BigPayment and pay large invoice with fake wallet', async ({ + page, + lnbitsServer +}) => { + await login(page, lnbitsServer) + await installAndEnableExtension(page, BIGPAYMENT) + + const collector = await createWallet( + page, + `BigPayment collector ${randomHex()}` + ) + const source = await createWallet(page, `BigPayment source ${randomHex()}`) + const recipient = await createWallet( + page, + `BigPayment recipient ${randomHex()}` + ) + await fundWalletWithFakeBalance(page, source.id, {amountSats: 750}) + + await page.goto('/ext/bigpayment') + const frame = await extensionFrame(page, 'BigPayment') + await expect(frame.getByText('Pay large Lightning invoices')).toBeVisible({ + timeout: 60_000 + }) + + const invoice = await createInvoice(page, recipient, { + amountSats: 500, + memo: 'BigPayment Playwright recipient' + }) + const selection = await extensionApi( + page, + BIGPAYMENT.extId, + 'POST', + '/selection', + { + walletIds: [collector.id, source.id], + collectorWalletId: collector.id + } + ) + expect(selection.collectorWalletId).toBe(collector.id) + + const payment = await extensionApi( + page, + BIGPAYMENT.extId, + 'POST', + '/payments', + { + paymentRequest: invoicePaymentRequest(invoice), + walletIds: [collector.id, source.id], + collectorWalletId: collector.id, + memo: 'BigPayment Playwright payment' + } + ) + expect(payment.paid).toBe(true) + expect(payment.direct).toBe(false) + expect(payment.amountSat).toBe(500) + expect(Array.isArray(payment.transfers)).toBe(true) + expect((payment.transfers as Record[])[0].fromWalletId).toBe( + source.id + ) + await waitForWalletBalance(page, recipient, {expectedSats: 500}) +}) diff --git a/tests/e2e/extension-helpers.ts b/tests/e2e/extension-helpers.ts new file mode 100644 index 000000000..0508d1eba --- /dev/null +++ b/tests/e2e/extension-helpers.ts @@ -0,0 +1,641 @@ +import {expect, type Frame, type Locator, type Page} from '@playwright/test' + +import { + browserJson, + delay, + isRecord, + type LNbitsE2EServer, + waitForResult +} from './fixtures' + +const INSTALLABLE_EXTENSION_REFRESH_TASK = + 'refresh_installable_extensions_cache' + +export type ExtensionUnderTest = { + configUrl?: string + extId: string + name: string + permissionTexts?: string[] +} + +export type E2EWallet = { + adminkey: string + id: string + inkey: string + name: string +} + +export async function login( + page: Page, + server: LNbitsE2EServer +): Promise { + await page.goto('/') + await page.locator('input[name="username"]').fill(server.username) + await page.locator('input[name="password"]').fill(server.password) + await page.getByRole('button', {name: /^login$/i}).click() + await expect(page).toHaveURL(/\/wallet\/[^/]+$/) + await dismissDisclaimer(page) +} + +export async function dismissDisclaimer(page: Page): Promise { + try { + await page + .getByRole('button', {name: 'I understand'}) + .click({timeout: 5_000}) + } catch (_error) {} +} + +export async function superuserWallet(page: Page): Promise { + const wallet = await page.evaluate(() => { + const global = window as typeof window & { + g: { + user: { + wallets: Array<{ + adminkey: string + id: string + inkey: string + name: string + }> + } + } + } + return { + adminkey: global.g.user.wallets[0].adminkey, + id: global.g.user.wallets[0].id, + inkey: global.g.user.wallets[0].inkey, + name: global.g.user.wallets[0].name + } + }) + return walletFromResponse(wallet) +} + +export async function createWallet( + page: Page, + name: string +): Promise { + const wallet = await browserJson(page, 'POST', '/api/v1/wallet', {name}) + return walletFromResponse(wallet) +} + +export async function fundWalletWithFakeBalance( + page: Page, + walletId: string, + {amountSats}: {amountSats: number} +): Promise { + const response = await browserJson(page, 'PUT', '/users/api/v1/balance', { + id: walletId, + amount: amountSats + }) + if (!isRecord(response) || response.success !== true) { + throw new Error(`Fake balance update failed: ${JSON.stringify(response)}`) + } +} + +export async function walletBalanceSat( + page: Page, + wallet: E2EWallet +): Promise { + const response = await browserJson( + page, + 'GET', + '/api/v1/wallet', + undefined, + wallet.inkey + ) + if (!isRecord(response) || typeof response.balance !== 'number') { + throw new Error( + `Wallet response missing balance: ${JSON.stringify(response)}` + ) + } + return Math.trunc(response.balance / 1000) +} + +export async function waitForWalletBalance( + page: Page, + wallet: E2EWallet, + {expectedSats, timeout = 30_000}: {expectedSats: number; timeout?: number} +): Promise { + return waitForResult( + `wallet ${wallet.id} balance to reach ${expectedSats} sats`, + async () => { + const balance = await walletBalanceSat(page, wallet) + return balance >= expectedSats ? balance : null + }, + {timeout} + ) +} + +export async function createInvoice( + page: Page, + wallet: E2EWallet, + { + amountSats, + memo, + extra = {} + }: {amountSats: number; extra?: Record; memo: string} +): Promise> { + const invoice = await browserJson( + page, + 'POST', + '/api/v1/payments', + { + out: false, + amount: amountSats, + unit: 'sat', + memo, + extra + }, + wallet.inkey + ) + if (!isRecord(invoice)) { + throw new Error( + `Invoice response is not an object: ${JSON.stringify(invoice)}` + ) + } + expect(invoicePaymentRequest(invoice).toLowerCase()).toMatch(/^lnbc/) + return invoice +} + +export async function payInvoiceWithWallet( + page: Page, + wallet: E2EWallet, + paymentRequest: string +): Promise> { + const payment = await browserJson( + page, + 'POST', + '/api/v1/payments', + {out: true, bolt11: paymentRequest}, + wallet.adminkey + ) + if (!isRecord(payment)) { + throw new Error( + `Payment response is not an object: ${JSON.stringify(payment)}` + ) + } + return payment +} + +export function invoicePaymentRequest( + invoice: Record +): string { + const paymentRequest = invoice.payment_request ?? invoice.bolt11 + if (typeof paymentRequest !== 'string') { + throw new Error( + `Invoice response missing payment request: ${JSON.stringify(invoice)}` + ) + } + return paymentRequest +} + +export async function installAndEnableExtension( + page: Page, + extension: ExtensionUnderTest +): Promise { + await installExtension(page, extension) + await enableExtension(page, extension) +} + +export async function installExtension( + page: Page, + extension: ExtensionUnderTest +): Promise { + const state = await extensionState(page, extension.extId) + if (state?.isInstalled) { + if (!state.isActive) { + await activateInstalledExtension(page, extension) + await waitForInstalledExtension(page, extension.extId) + } + return + } + + const installable = await waitForInstallableExtension(page, extension) + const release = latestReleaseFor(installable) + + await page.goto('/extensions') + await dismissDisclaimer(page) + await selectExtensionsTab(page, 'All') + await filterExtensions(page, extension.name) + const extensionCard = extensionCardFor(page, extension) + await expect(extensionCard).toBeVisible({timeout: 120_000}) + await extensionCard.getByRole('button', {name: /^manage$/i}).click() + + const manageDialog = manageExtensionDialog(page) + await expect(manageDialog).toBeVisible({timeout: 60_000}) + await expect( + manageDialog.getByRole('tab', {name: /^releases$/i}) + ).toBeVisible({ + timeout: 60_000 + }) + + const version = String(release.version) + const sourceRepo = String(release.source_repo) + const repositoryLabel = manageDialog.getByText(sourceRepo).first() + await expect(repositoryLabel).toBeVisible({timeout: 120_000}) + await repositoryLabel.click() + + const releaseLabel = manageDialog.getByText(version).first() + await expect(releaseLabel).toBeVisible({timeout: 120_000}) + await releaseLabel.click() + + const installButton = manageDialog + .getByRole('button', {name: /^install$/i}) + .first() + await expect(installButton).toBeVisible({timeout: 120_000}) + await installButton.click() + + const permissionsDialog = page + .locator('.q-dialog') + .filter({hasText: 'Grant extension permissions'}) + .last() + let hasPermissionsDialog = false + try { + await expect(permissionsDialog).toBeVisible({ + timeout: 10_000 + }) + hasPermissionsDialog = true + } catch (_error) {} + + if (hasPermissionsDialog) { + for (const permissionText of extension.permissionTexts ?? []) { + await expect( + permissionsDialog.getByText(permissionText).first() + ).toBeVisible({ + timeout: 60_000 + }) + } + const grantButton = permissionsDialog.getByRole('button', { + name: /^grant and install$/i + }) + await expect(grantButton).toBeEnabled({timeout: 60_000}) + await grantButton.click() + } + + await waitForInstalledExtension(page, extension.extId) + const latestConfig = await latestReleaseConfig(release) + const permissions = Array.isArray(latestConfig.permissions) + ? latestConfig.permissions.filter(isRecord) + : [] + let installed = await extensionState(page, extension.extId) + let grantedPermissionIds = installedPermissionIds(installed) + const missingPermissionIds = permissions + .map(permission => permission.id) + .filter(permissionId => !grantedPermissionIds.has(permissionId)) + + if (extension.configUrl && missingPermissionIds.length) { + const response = await page + .context() + .request.put( + `/api/v1/extension/${encodeURIComponent(extension.extId)}/permissions`, + {data: {permissions}} + ) + expect( + response.ok(), + `Could not grant local fixture permissions: ${await response.text()}` + ).toBe(true) + installed = await extensionState(page, extension.extId) + grantedPermissionIds = installedPermissionIds(installed) + } + + for (const permission of permissions) { + expect( + grantedPermissionIds.has(permission.id), + `Missing extension permission: ${String(permission.id)}` + ).toBe(true) + } +} + +export async function enableExtension( + page: Page, + extension: ExtensionUnderTest +): Promise { + if (await userExtensionEnabled(page, extension.extId)) return + + await page.goto(`/extensions#${encodeURIComponent(extension.extId)}`) + await dismissDisclaimer(page) + const extensionCard = extensionCardFor(page, extension) + await expect(extensionCard).toBeVisible({timeout: 120_000}) + const enableButton = extensionCard.getByRole('button', {name: /^enable$/i}) + await expect(enableButton).toBeVisible({timeout: 60_000}) + await enableButton.click() + await expect(page.getByText('Extension enabled!')).toBeVisible({ + timeout: 60_000 + }) + await waitForResult( + `${extension.extId} extension to be enabled for the user`, + async () => + (await userExtensionEnabled(page, extension.extId)) ? true : null, + {timeout: 60_000, interval: 1_000} + ) + await expect(extensionCard.getByRole('link', {name: /^open$/i})).toBeVisible({ + timeout: 60_000 + }) +} + +export async function activateInstalledExtension( + page: Page, + extension: ExtensionUnderTest +): Promise { + await page.goto('/extensions') + await selectExtensionsTab(page, 'Installed') + await filterExtensions(page, extension.name) + const extensionCard = extensionCardFor(page, extension) + await expect(extensionCard).toBeVisible({timeout: 120_000}) + const inactiveToggle = extensionCard.getByText(/^deactivated$/i) + try { + await inactiveToggle.click({timeout: 5_000}) + } catch (_error) { + return + } + await expect( + page.getByText( + new RegExp(`Extension '${escapeRegExp(extension.extId)}' activated!`) + ) + ).toBeVisible({timeout: 60_000}) +} + +export async function waitForInstallableExtension( + page: Page, + extension: ExtensionUnderTest, + {timeout = 360_000}: {timeout?: number} = {} +): Promise> { + let lastResponse: unknown + let lastError: unknown + const deadline = Date.now() + timeout + + while (Date.now() < deadline) { + try { + lastError = undefined + await waitForInstallableExtensionRefresh(page, deadline) + const extensions = await browserJson(page, 'GET', '/api/v1/extension/all') + lastResponse = extensions + const extensionList = Array.isArray(extensions) ? extensions : [] + const installable = extensionList + .filter(isRecord) + .find(item => item.id === extension.extId) + if (installable) return installable + await waitForInstallableExtensionRefresh(page, deadline) + } catch (error) { + lastError = error + } + await delay(2_000) + } + + throw new Error( + `${extension.name} extension did not become installable: ${JSON.stringify(lastResponse)}. Last error: ${String(lastError)}` + ) +} + +export async function waitForInstalledExtension( + page: Page, + extensionId: string, + {timeout = 120_000}: {timeout?: number} = {} +): Promise { + await waitForResult( + `${extensionId} extension to be installed and active`, + async () => { + const state = await extensionState(page, extensionId) + return state?.isInstalled && state.isActive ? true : null + }, + {timeout, interval: 2_000} + ) +} + +export async function extensionState( + page: Page, + extensionId: string +): Promise | null> { + const extensions = await browserJson(page, 'GET', '/api/v1/extension/all') + if (!Array.isArray(extensions)) { + throw new Error( + `Extensions response is not a list: ${JSON.stringify(extensions)}` + ) + } + return ( + extensions + .filter(isRecord) + .find(extension => extension.id === extensionId) ?? null + ) +} + +async function userExtensionEnabled( + page: Page, + extensionId: string +): Promise { + const extensions = await browserJson(page, 'GET', '/api/v1/extension') + if (!Array.isArray(extensions)) { + throw new Error( + `User extensions response is not a list: ${JSON.stringify(extensions)}` + ) + } + return extensions + .filter(isRecord) + .some(extension => extension.code === extensionId) +} + +export async function grantBackgroundPaymentPermission( + page: Page, + extensionId: string, + walletId: string, + { + maxAmountSats, + destinationPolicy = 'external_allowed' + }: {destinationPolicy?: string; maxAmountSats: number} +): Promise> { + const response = await browserJson( + page, + 'POST', + `/api/v1/extension/${extensionId}/permissions/background-payment`, + { + wallet_id: walletId, + max_amount: maxAmountSats, + destination_policy: destinationPolicy + } + ) + if (!isRecord(response)) { + throw new Error( + `Permission response is not an object: ${JSON.stringify(response)}` + ) + } + return response +} + +export async function grantWalletPaymentsWatchPermission( + page: Page, + extensionId: string, + walletId: string +): Promise> { + const response = await browserJson( + page, + 'POST', + `/api/v1/extension/${extensionId}/permissions/wallet-payments-watch`, + {wallet_id: walletId} + ) + if (!isRecord(response)) { + throw new Error( + `Permission response is not an object: ${JSON.stringify(response)}` + ) + } + return response +} + +export async function extensionApi( + page: Page, + extensionId: string, + method: string, + path: string, + data?: Record +): Promise> { + const body = await browserJson( + page, + method, + `/api/v1/ext/${extensionId}${path}`, + data + ) + if (isRecord(body) && body.ok === false) { + throw new Error(`${method} ${path} failed: ${JSON.stringify(body)}`) + } + const responseData = isRecord(body) && isRecord(body.data) ? body.data : body + if (!isRecord(responseData)) { + throw new Error( + `${method} ${path} returned non-object data: ${JSON.stringify(body)}` + ) + } + return responseData +} + +export async function extensionFrame( + page: Page, + title: string +): Promise { + const iframe = page.locator(`iframe[title="${title}"]`) + await expect(iframe).toBeVisible({timeout: 60_000}) + const handle = await iframe.elementHandle() + const frame = await handle?.contentFrame() + if (!frame) throw new Error(`Extension iframe not found: ${title}`) + return frame +} + +function extensionCardFor(page: Page, extension: ExtensionUnderTest): Locator { + return page.locator('.q-card').filter({hasText: extension.name}).first() +} + +async function filterExtensions(page: Page, searchTerm: string): Promise { + await page + .locator('.q-field') + .filter({hasText: 'Search extensions'}) + .locator('input') + .fill(searchTerm) +} + +async function selectExtensionsTab(page: Page, tabName: string): Promise { + const tab = page.getByRole('tab', { + name: new RegExp(`^${escapeRegExp(tabName)}$`, 'i') + }) + await expect(tab).toBeVisible({timeout: 60_000}) + for (let attempt = 0; attempt < 3; attempt += 1) { + await tab.click() + try { + await expect(tab).toHaveAttribute('aria-selected', 'true', { + timeout: 5_000 + }) + return + } catch (_error) { + await page.waitForTimeout(500) + } + } + await expect(tab).toHaveAttribute('aria-selected', 'true', {timeout: 60_000}) +} + +function manageExtensionDialog(page: Page): Locator { + return page.locator('.q-dialog').filter({hasText: 'Releases'}).last() +} + +async function waitForInstallableExtensionRefresh( + page: Page, + deadline: number +): Promise { + while (Date.now() < deadline) { + const tasks = await browserJson(page, 'GET', '/admin/api/v1/monitor') + if (!Array.isArray(tasks)) return + if ( + !tasks + .filter(isRecord) + .some(task => task.name === INSTALLABLE_EXTENSION_REFRESH_TASK) + ) { + return + } + await delay(2_000) + } +} + +function latestReleaseFor( + installable: Record +): Record { + const release = installable.latestRelease + if ( + !isRecord(release) || + typeof release.version !== 'string' || + typeof release.source_repo !== 'string' || + typeof release.details_link !== 'string' + ) { + throw new Error( + `Installable extension is missing release metadata: ${JSON.stringify(installable)}` + ) + } + return release +} + +function installedPermissionIds( + extension: Record | null +): Set { + return new Set( + Array.isArray(extension?.permissions) + ? extension.permissions.filter(isRecord).map(permission => permission.id) + : [] + ) +} + +async function latestReleaseConfig( + release: Record +): Promise> { + const config = await fetchJson(String(release.details_link)) + if (!isRecord(config)) { + throw new Error( + `Invalid extension config response: ${JSON.stringify(config)}` + ) + } + return config +} + +async function fetchJson(url: string): Promise { + const response = await fetch(url, { + headers: { + Accept: 'application/json', + 'User-Agent': 'LNbits Playwright e2e' + } + }) + const text = await response.text() + if (!response.ok) { + throw new Error(`${url} failed with ${response.status}: ${text}`) + } + return text ? JSON.parse(text) : {} +} + +function walletFromResponse(wallet: unknown): E2EWallet { + if (!isRecord(wallet)) { + throw new Error( + `Wallet response is not an object: ${JSON.stringify(wallet)}` + ) + } + return { + adminkey: String(wallet.adminkey), + id: String(wallet.id), + inkey: String(wallet.inkey), + name: String(wallet.name ?? wallet.id) + } +} + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} diff --git a/tests/e2e/extensions.ts b/tests/e2e/extensions.ts new file mode 100644 index 000000000..b4063a623 --- /dev/null +++ b/tests/e2e/extensions.ts @@ -0,0 +1,39 @@ +import type {ExtensionUnderTest} from './extension-helpers' + +const extensionFixtureUrl = + process.env.LNBITS_E2E_EXTENSION_FIXTURE_URL ?? 'http://127.0.0.1:5010' + +export const SUPPORTCHAT: ExtensionUnderTest = { + extId: 'supportchat', + name: 'Support Chat', + configUrl: `${extensionFixtureUrl}/config.json`, + permissionTexts: [ + 'Read public extension storage', + 'Append public extension storage', + 'Use extension websockets' + ] +} + +export const TIPS: ExtensionUnderTest = { + extId: 'tips', + name: 'Tips', + permissionTexts: ['Make background payments'] +} + +export const BIGPAYMENT: ExtensionUnderTest = { + extId: 'bigpayment', + name: 'BigPayment', + permissionTexts: ['Pay invoices'] +} + +export const PINGPONG: ExtensionUnderTest = { + extId: 'pingpong', + name: 'Ping Pong', + permissionTexts: ['Make background payments'] +} + +export const PAYSPLIT: ExtensionUnderTest = { + extId: 'paysplit', + name: 'PaySplit', + permissionTexts: ['Watch wallet payments'] +} diff --git a/tests/e2e/fixtures.ts b/tests/e2e/fixtures.ts new file mode 100644 index 000000000..13c9b92af --- /dev/null +++ b/tests/e2e/fixtures.ts @@ -0,0 +1,626 @@ +import {randomUUID} from 'node:crypto' +import {unlink} from 'node:fs/promises' + +import {test as base, expect, type Page, type TestInfo} from '@playwright/test' + +export type LNbitsE2EServer = { + baseUrl: string + password: string + username: string +} + +const server: LNbitsE2EServer = { + baseUrl: process.env.LNBITS_E2E_BASE_URL ?? 'http://127.0.0.1:5009', + username: 'superadmin', + password: 'secret1234' +} + +const detailedScreenshotStates = new WeakMap< + TestInfo, + DetailedScreenshotState +>() + +const DETAILED_SCREENSHOT_SCRIPT = ` +(() => { + if (window.__lnbitsDetailedScreenshotsInstalled) return + window.__lnbitsDetailedScreenshotsInstalled = true + + let nextSnapshot = 0 + let scanScheduled = false + const visibleElements = new WeakMap() + + const notify = payload => { + setTimeout(() => { + try { + window.__lnbitsDetailedScreenshot({ + ...payload, + snapshotId: payload.snapshotId || (payload.kind + '-' + Date.now() + '-' + ++nextSnapshot), + url: payload.url || window.location.href + }) + } catch (_error) {} + }, 0) + } + + const notifyUrl = () => { + notify({ + kind: 'url', + label: window.location.href, + url: window.location.href + }) + } + + for (const name of ['pushState', 'replaceState']) { + const original = window.history[name] + window.history[name] = function (...args) { + const result = original.apply(this, args) + setTimeout(notifyUrl, 0) + return result + } + } + + window.addEventListener('hashchange', () => setTimeout(notifyUrl, 0)) + window.addEventListener('popstate', () => setTimeout(notifyUrl, 0)) + window.addEventListener('DOMContentLoaded', () => setTimeout(notifyUrl, 0)) + setTimeout(notifyUrl, 0) + + const groups = [ + { kind: 'dialog', selector: '.q-dialog, [role="dialog"]' }, + { kind: 'toast', selector: '.q-notification' } + ] + + const isVisible = element => { + if (!(element instanceof HTMLElement)) return false + if (element.getAttribute('aria-hidden') === 'true') return false + if (element.classList.contains('q-dialog--hidden')) return false + + const style = window.getComputedStyle(element) + if ( + style.display === 'none' || + style.visibility === 'hidden' || + style.opacity === '0' + ) { + return false + } + + const rect = element.getBoundingClientRect() + return rect.width > 0 && rect.height > 0 + } + + const textFor = element => ( + element.getAttribute('aria-label') || + element.innerText || + element.textContent || + '' + ).replace(/\\s+/g, ' ').trim().slice(0, 120) + + const labelFor = element => { + const headings = element.querySelectorAll([ + '[role="heading"]', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + '.text-h1', + '.text-h2', + '.text-h3', + '.text-h4', + '.text-h5', + '.text-h6' + ].join(', ')) + + for (const heading of headings) { + if (isVisible(heading)) { + const headingText = textFor(heading) + if (headingText) return headingText + } + } + + return textFor(element) + } + + const scan = () => { + for (const group of groups) { + for (const element of document.querySelectorAll(group.selector)) { + if (isVisible(element)) { + const label = labelFor(element) + if (visibleElements.get(element) !== label) { + visibleElements.set(element, label) + notify({ + kind: group.kind, + label, + url: window.location.href + }) + } + } else { + visibleElements.delete(element) + } + } + } + } + + const scheduleScan = () => { + if (scanScheduled) return + scanScheduled = true + requestAnimationFrame(() => { + scanScheduled = false + scan() + }) + } + + const installObserver = () => { + if (!document.documentElement) return + new MutationObserver(scheduleScan).observe(document.documentElement, { + attributes: true, + attributeFilter: ['aria-hidden', 'class', 'style'], + childList: true, + subtree: true + }) + scheduleScan() + } + + window.addEventListener('DOMContentLoaded', installObserver) + setTimeout(installObserver, 0) +})() +` + +export const test = base.extend< + {}, + { + lnbitsServer: LNbitsE2EServer + } +>({ + lnbitsServer: [ + async ({}, use) => { + await completeFirstInstall(server) + await use(server) + }, + {scope: 'worker'} + ], + page: async ({page, lnbitsServer}, use, testInfo) => { + void lnbitsServer + await page.addInitScript( + "window.localStorage.setItem('lnbits.disclaimerShown', 'true')" + ) + const recorder = await installDetailedScreenshots(page, testInfo) + page.setDefaultTimeout(60_000) + let failed = false + try { + await use(page) + } catch (error) { + failed = true + throw error + } finally { + await recorder.finish({ + retain: failed || testInfo.status !== testInfo.expectedStatus + }) + } + } +}) + +export {expect} + +async function completeFirstInstall(e2eServer: LNbitsE2EServer): Promise { + const deadline = Date.now() + 90_000 + let lastError = '' + + while (Date.now() < deadline) { + try { + const response = await requestJson( + `${e2eServer.baseUrl}/api/v1/auth/first_install`, + { + method: 'PUT', + data: { + username: e2eServer.username, + password: e2eServer.password, + password_repeat: e2eServer.password, + first_install_token: '' + }, + timeoutMs: 2_000 + } + ) + if (response.status === 200) return + if ( + response.status === 403 && + isRecord(response.body) && + response.body.detail === 'This is not your first install' + ) { + return + } + lastError = `${response.status}: ${JSON.stringify(response.body)}` + } catch (error) { + lastError = String(error) + } + await delay(500) + } + + throw new Error( + `LNbits e2e server did not complete first install. Last error: ${lastError}` + ) +} + +type RequestJsonOptions = { + apiKey?: string + data?: Record + method: string + timeoutMs?: number +} + +export async function apiJson( + baseUrl: string, + method: string, + path: string, + data?: Record, + apiKey?: string, + timeoutMs = 30_000 +): Promise> { + const response = await requestJson(`${baseUrl}${path}`, { + method, + data, + apiKey, + timeoutMs + }) + if (response.status < 200 || response.status >= 300) { + throw new Error( + `${method} ${path} failed with ${response.status}: ${JSON.stringify(response.body)}` + ) + } + if (!isRecord(response.body)) { + throw new Error( + `${method} ${path} returned non-object JSON: ${JSON.stringify(response.body)}` + ) + } + return response.body +} + +async function requestJson( + url: string, + {method, data, apiKey, timeoutMs = 30_000}: RequestJsonOptions +): Promise<{body: unknown; status: number}> { + const controller = new AbortController() + const timeout = setTimeout(() => controller.abort(), timeoutMs) + + try { + const response = await fetch(url, { + method, + headers: { + 'Content-Type': 'application/json', + ...(apiKey ? {'X-Api-Key': apiKey} : {}) + }, + body: data === undefined ? undefined : JSON.stringify(data), + signal: controller.signal + }) + const text = await response.text() + let body: unknown = {} + try { + body = text ? JSON.parse(text) : {} + } catch (_error) { + body = {detail: text} + } + return {status: response.status, body} + } finally { + clearTimeout(timeout) + } +} + +export function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) +} + +export async function browserJson( + page: Page, + method: string, + path: string, + data?: Record, + apiKey?: string +): Promise { + const response = await page.evaluate( + async ({method, path, data, apiKey}) => { + const headers: Record = { + 'Content-Type': 'application/json' + } + if (apiKey) headers['X-Api-Key'] = apiKey + const response = await fetch(path, { + method, + headers, + credentials: 'same-origin', + body: data === undefined ? undefined : JSON.stringify(data) + }) + const text = await response.text() + let body: unknown = {} + try { + body = text ? JSON.parse(text) : {} + } catch (_error) { + body = {detail: text} + } + return {status: response.status, body} + }, + {method, path, data, apiKey} + ) + if (response.status < 200 || response.status >= 300) { + throw new Error( + `${method} ${path} failed with ${response.status}: ${JSON.stringify(response.body)}` + ) + } + return response.body +} + +export async function waitForResult( + description: string, + callback: () => Promise, + {timeout = 30_000, interval = 500}: {interval?: number; timeout?: number} = {} +): Promise { + const deadline = Date.now() + timeout + let lastResult: T | null | undefined + let lastError: unknown + + while (Date.now() < deadline) { + try { + lastError = undefined + lastResult = await callback() + if (lastResult !== null && lastResult !== undefined) return lastResult + } catch (error) { + lastError = error + } + await delay(interval) + } + + throw new Error( + `Timed out waiting for ${description}. Last result: ${JSON.stringify(lastResult)}. Last error: ${String(lastError)}` + ) +} + +export function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +export function randomHex(): string { + return randomUUID().replace(/-/g, '').slice(0, 8) +} + +export type DetailedScreenshotHandle = { + finish(options?: {retain?: boolean}): Promise +} + +export async function installDetailedScreenshots( + page: Page, + testInfo: TestInfo +): Promise { + const recorder = new DetailedScreenshotRecorder(page, testInfo) + await recorder.install() + return recorder +} + +type DetailedScreenshotPayload = { + kind?: unknown + label?: unknown + snapshotId?: unknown + url?: unknown +} + +type DetailedScreenshotRequest = { + kind: 'dialog' | 'toast' | 'url' + label: string + snapshotId: string + url: string +} + +type DetailedScreenshotCapture = { + name: string + path: string +} + +type DetailedScreenshotState = { + captures: DetailedScreenshotCapture[] + finalized: boolean + screenshotIndex: number +} + +class DetailedScreenshotRecorder { + private readonly capturedUrlKeys = new Set() + private readonly page: Page + private readonly pending: DetailedScreenshotRequest[] = [] + private readonly testInfo: TestInfo + private flushPromise?: Promise + private flushTimer?: ReturnType + private lastQueuedKey = '' + private readonly state: DetailedScreenshotState + private stopped = false + + constructor(page: Page, testInfo: TestInfo) { + this.page = page + this.testInfo = testInfo + this.state = detailedScreenshotStateFor(testInfo) + } + + async install(): Promise { + await this.page.exposeBinding( + '__lnbitsDetailedScreenshot', + (_source, payload: DetailedScreenshotPayload) => { + this.queue(this.requestFromPayload(payload)) + } + ) + await this.page.addInitScript(DETAILED_SCREENSHOT_SCRIPT) + this.page.on('framenavigated', frame => { + const url = frame.url() + this.queue({ + kind: 'url', + label: url, + snapshotId: `frame-${Date.now()}`, + url + }) + }) + } + + async finish(options: {retain?: boolean} = {}): Promise { + this.queue({ + kind: 'url', + label: this.page.url(), + snapshotId: `final-${Date.now()}`, + url: this.page.url() + }) + this.stopped = true + if (this.flushTimer) { + clearTimeout(this.flushTimer) + this.flushTimer = undefined + } + await this.flush() + if (typeof options.retain === 'boolean') { + await finalizeDetailedScreenshots(this.testInfo, options.retain) + } + } + + private requestFromPayload( + payload: DetailedScreenshotPayload + ): DetailedScreenshotRequest | null { + const kind = typeof payload.kind === 'string' ? payload.kind : '' + if (!['dialog', 'toast', 'url'].includes(kind)) return null + + const url = + typeof payload.url === 'string' && payload.url + ? payload.url + : this.page.url() + const label = + typeof payload.label === 'string' && payload.label ? payload.label : kind + const snapshotId = + typeof payload.snapshotId === 'string' && payload.snapshotId + ? payload.snapshotId + : `${kind}-${Date.now()}` + + return { + kind: kind as DetailedScreenshotRequest['kind'], + label, + snapshotId, + url + } + } + + private queue(request: DetailedScreenshotRequest | null): void { + if (this.stopped || !request) return + if (!request.url || request.url === 'about:blank') return + + const key = + request.kind === 'url' + ? `${request.kind}:${request.url}` + : `${request.kind}:${request.snapshotId}:${request.url}:${request.label}` + if (request.kind === 'url' && this.capturedUrlKeys.has(key)) return + if (key === this.lastQueuedKey) return + + this.lastQueuedKey = key + this.pending.push(request) + this.scheduleFlush() + } + + private scheduleFlush(): void { + if (this.flushTimer) return + this.flushTimer = setTimeout(() => { + this.flushTimer = undefined + void this.flush() + }, 75) + } + + private async flush(): Promise { + if (this.flushPromise) { + await this.flushPromise + return + } + + this.flushPromise = this.flushQueue() + try { + await this.flushPromise + } finally { + this.flushPromise = undefined + } + } + + private async flushQueue(): Promise { + while (this.pending.length) { + const request = this.pending.shift() + if (!request) continue + await this.capture(request) + } + } + + private async capture(request: DetailedScreenshotRequest): Promise { + if (this.page.isClosed()) return + + if (request.kind === 'url') { + const key = `${request.kind}:${request.url}` + if (this.capturedUrlKeys.has(key)) return + this.capturedUrlKeys.add(key) + } + + const name = this.screenshotName(request) + const path = this.testInfo.outputPath(`${name}.png`) + try { + await this.page.waitForLoadState('domcontentloaded', {timeout: 2_000}) + } catch (_error) {} + try { + await this.page.waitForTimeout(250) + await this.page.screenshot({path, fullPage: true, timeout: 5_000}) + this.state.captures.push({name, path}) + } catch (_error) {} + } + + private screenshotName(request: DetailedScreenshotRequest): string { + this.state.screenshotIndex += 1 + return [ + 'screenshot', + this.state.screenshotIndex.toString().padStart(3, '0'), + request.kind, + slugFor(request.kind === 'url' ? request.url : request.label) + ].join('-') + } +} + +async function finalizeDetailedScreenshots( + testInfo: TestInfo, + retain: boolean +): Promise { + const state = detailedScreenshotStateFor(testInfo) + if (state.finalized) return + state.finalized = true + + if (retain) { + for (const capture of state.captures) { + await testInfo.attach(capture.name, { + path: capture.path, + contentType: 'image/png' + }) + } + return + } + + await Promise.all( + state.captures.map(async capture => { + try { + await unlink(capture.path) + } catch (_error) {} + }) + ) +} + +function detailedScreenshotStateFor( + testInfo: TestInfo +): DetailedScreenshotState { + const existing = detailedScreenshotStates.get(testInfo) + if (existing) return existing + const state = { + captures: [], + finalized: false, + screenshotIndex: 0 + } + detailedScreenshotStates.set(testInfo, state) + return state +} + +function slugFor(value: string): string { + const slug = value + .replace(/^[a-z]+:\/\//i, '') + .split(/[?#]/, 1)[0] + .replace(/[^A-Za-z0-9._-]+/g, '-') + .replace(/^[-._]+|[-._]+$/g, '') + .slice(0, 80) + return slug || 'capture' +} diff --git a/tests/e2e/lnurl-helpers.ts b/tests/e2e/lnurl-helpers.ts new file mode 100644 index 000000000..0ed719f7c --- /dev/null +++ b/tests/e2e/lnurl-helpers.ts @@ -0,0 +1,203 @@ +import http from 'node:http' + +import {apiJson} from './fixtures' +import {type E2EWallet, invoicePaymentRequest} from './extension-helpers' + +export class LNURLPayServer { + private readonly baseUrl: string + private readonly targetWallet: E2EWallet + private server?: http.Server + private serverUrl?: string + + private constructor(baseUrl: string, targetWallet: E2EWallet) { + this.baseUrl = baseUrl + this.targetWallet = targetWallet + } + + static async start( + baseUrl: string, + targetWallet: E2EWallet + ): Promise { + const lnurlServer = new LNURLPayServer(baseUrl, targetWallet) + await lnurlServer.listen() + return lnurlServer + } + + get url(): string { + if (!this.serverUrl) throw new Error('LNURL server is not listening') + return this.serverUrl + } + + get lnurl(): string { + return bech32Encode( + 'lnurl', + convertBits([...new TextEncoder().encode(this.url)], 8, 5, true) + ) + } + + async close(): Promise { + const server = this.server + if (!server) return + await new Promise((resolve, reject) => { + server.close(error => { + if (error) reject(error) + else resolve() + }) + }) + } + + private async listen(): Promise { + this.server = http.createServer((request, response) => { + void this.handleRequest(request, response) + }) + await new Promise((resolve, reject) => { + this.server?.once('error', reject) + this.server?.listen(0, '127.0.0.1', () => resolve()) + }) + const address = this.server.address() + if (!address || typeof address === 'string') { + throw new Error('LNURL server did not bind a TCP address') + } + this.serverUrl = `http://127.0.0.1:${address.port}/pay` + } + + private async handleRequest( + request: http.IncomingMessage, + response: http.ServerResponse + ): Promise { + try { + const requestUrl = new URL(request.url ?? '/', this.url) + if (requestUrl.pathname === '/pay') { + sendJson(response, 200, { + tag: 'payRequest', + callback: this.callbackUrl(), + minSendable: 1000, + maxSendable: 1_000_000, + metadata: JSON.stringify([['text/plain', 'LNbits e2e LNURL-pay']]) + }) + return + } + + if (requestUrl.pathname === '/callback') { + const amountMsat = Number(requestUrl.searchParams.get('amount') ?? '0') + const invoice = await apiJson( + this.baseUrl, + 'POST', + '/api/v1/payments', + { + out: false, + amount: Math.trunc(amountMsat / 1000), + unit: 'sat', + memo: 'LNbits e2e LNURL-pay target' + }, + this.targetWallet.inkey + ) + sendJson(response, 200, { + pr: invoicePaymentRequest(invoice), + routes: [] + }) + return + } + + sendJson(response, 404, { + status: 'ERROR', + reason: 'LNURL route not found.' + }) + } catch (error) { + sendJson(response, 500, { + status: 'ERROR', + reason: String(error) + }) + } + } + + private callbackUrl(): string { + const url = new URL(this.url) + url.pathname = '/callback' + return url.toString() + } +} + +function sendJson( + response: http.ServerResponse, + status: number, + body: Record +): void { + const rawBody = JSON.stringify(body) + response.writeHead(status, { + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(rawBody) + }) + response.end(rawBody) +} + +const BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' + +function bech32Encode(hrp: string, data: number[]): string { + const combined = [...data, ...bech32CreateChecksum(hrp, data)] + return `${hrp}1${combined.map(value => BECH32_CHARSET[value]).join('')}` +} + +function bech32CreateChecksum(hrp: string, data: number[]): number[] { + const values = [...bech32HrpExpand(hrp), ...data, 0, 0, 0, 0, 0, 0] + const polymod = bech32Polymod(values) ^ 1 + const result: number[] = [] + for (let index = 0; index < 6; index += 1) { + result.push((polymod >> (5 * (5 - index))) & 31) + } + return result +} + +function bech32HrpExpand(hrp: string): number[] { + const highBits = [...hrp].map(char => char.charCodeAt(0) >> 5) + const lowBits = [...hrp].map(char => char.charCodeAt(0) & 31) + return [...highBits, 0, ...lowBits] +} + +function bech32Polymod(values: number[]): number { + const generators = [ + 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3 + ] + let checksum = 1 + for (const value of values) { + const top = checksum >> 25 + checksum = ((checksum & 0x1ffffff) << 5) ^ value + for (let index = 0; index < 5; index += 1) { + if ((top >> index) & 1) checksum ^= generators[index] + } + } + return checksum +} + +function convertBits( + data: number[], + fromBits: number, + toBits: number, + pad: boolean +): number[] { + let acc = 0 + let bits = 0 + const result: number[] = [] + const maxValue = (1 << toBits) - 1 + const maxAcc = (1 << (fromBits + toBits - 1)) - 1 + + for (const value of data) { + if (value < 0 || value >> fromBits) { + throw new Error('Invalid bech32 data value') + } + acc = ((acc << fromBits) | value) & maxAcc + bits += fromBits + while (bits >= toBits) { + bits -= toBits + result.push((acc >> bits) & maxValue) + } + } + + if (pad) { + if (bits > 0) result.push((acc << (toBits - bits)) & maxValue) + } else if (bits >= fromBits || (acc << (toBits - bits)) & maxValue) { + throw new Error('Invalid bech32 padding') + } + + return result +} diff --git a/tests/e2e/paysplit.spec.ts b/tests/e2e/paysplit.spec.ts new file mode 100644 index 000000000..24591eb0c --- /dev/null +++ b/tests/e2e/paysplit.spec.ts @@ -0,0 +1,86 @@ +import {test, expect, randomHex} from './fixtures' +import { + createInvoice, + createWallet, + extensionApi, + extensionFrame, + fundWalletWithFakeBalance, + grantBackgroundPaymentPermission, + grantWalletPaymentsWatchPermission, + installAndEnableExtension, + invoicePaymentRequest, + login, + payInvoiceWithWallet, + waitForWalletBalance +} from './extension-helpers' +import {LNURLPayServer} from './lnurl-helpers' +import {PAYSPLIT} from './extensions' + +test('install PaySplit and split incoming payment with fake wallet', async ({ + page, + lnbitsServer +}) => { + await login(page, lnbitsServer) + const source = await createWallet(page, `PaySplit source ${randomHex()}`) + const target = await createWallet(page, `PaySplit target ${randomHex()}`) + const payer = await createWallet(page, `PaySplit payer ${randomHex()}`) + await fundWalletWithFakeBalance(page, payer.id, {amountSats: 250}) + + await installAndEnableExtension(page, PAYSPLIT) + await grantWalletPaymentsWatchPermission(page, PAYSPLIT.extId, source.id) + await grantBackgroundPaymentPermission(page, PAYSPLIT.extId, source.id, { + maxAmountSats: 100 + }) + + const lnurlServer = await LNURLPayServer.start(lnbitsServer.baseUrl, target) + try { + const saved = await extensionApi(page, PAYSPLIT.extId, 'POST', '/sources', { + enabled: true, + maxAmount: 100, + targets: [ + { + alias: 'Playwright target', + lnurl: lnurlServer.lnurl, + percent: 25 + } + ], + walletId: source.id, + walletName: source.name + }) + const sourceConfig = saved.source as Record + const targets = saved.targets as Record[] + expect(sourceConfig.wallet_id).toBe(source.id) + expect(targets[0].percent).toBe(25) + + await page.goto('/ext/paysplit') + const frame = await extensionFrame(page, 'PaySplit') + await frame.locator('#walletSelect').selectOption(source.id) + await expect(frame.locator('.target-lnurl').first()).toHaveValue( + lnurlServer.lnurl, + {timeout: 60_000} + ) + + const invoice = await createInvoice(page, source, { + amountSats: 100, + memo: 'PaySplit Playwright source' + }) + await payInvoiceWithWallet(page, payer, invoicePaymentRequest(invoice)) + await waitForWalletBalance(page, target, { + expectedSats: 25, + timeout: 45_000 + }) + } finally { + await lnurlServer.close() + } + + const sourceConfig = await extensionApi( + page, + PAYSPLIT.extId, + 'GET', + `/sources/${source.id}` + ) + const sourceData = sourceConfig.source as Record + const targets = sourceConfig.targets as Record[] + expect(sourceData.enabled).toBe(true) + expect(targets[0].alias).toBe('Playwright target') +}) diff --git a/tests/e2e/pingpong.spec.ts b/tests/e2e/pingpong.spec.ts new file mode 100644 index 000000000..7b2d98616 --- /dev/null +++ b/tests/e2e/pingpong.spec.ts @@ -0,0 +1,380 @@ +import type {Page, Response} from '@playwright/test' + +import { + test, + expect, + installDetailedScreenshots, + randomHex, + waitForResult, + isRecord +} from './fixtures' +import { + createWallet, + extensionApi, + extensionFrame, + fundWalletWithFakeBalance, + grantBackgroundPaymentPermission, + installAndEnableExtension, + login, + payInvoiceWithWallet, + superuserWallet, + waitForWalletBalance +} from './extension-helpers' +import {LNURLPayServer} from './lnurl-helpers' +import {PINGPONG} from './extensions' + +type GameInvoice = { + gameId: string + invoice: { + checkingId: string + paymentHash: string + paymentRequest: string + } + playerSlot: 'player1' | 'player2' + playerToken: string +} + +test('install Ping Pong, play public game, and pay winner with fake wallet', async ({ + page, + browser, + lnbitsServer +}, testInfo) => { + await login(page, lnbitsServer) + const escrow = await superuserWallet(page) + const player1EntryWallet = await createWallet( + page, + `PingPong player 1 entry ${randomHex()}` + ) + const player2EntryWallet = await createWallet( + page, + `PingPong player 2 entry ${randomHex()}` + ) + const player1PayoutTarget = await createWallet( + page, + `PingPong player 1 payout ${randomHex()}` + ) + const player2PayoutTarget = await createWallet( + page, + `PingPong player 2 payout ${randomHex()}` + ) + await fundWalletWithFakeBalance(page, player1EntryWallet.id, { + amountSats: 100 + }) + await fundWalletWithFakeBalance(page, player2EntryWallet.id, { + amountSats: 100 + }) + + await installAndEnableExtension(page, PINGPONG) + await grantBackgroundPaymentPermission(page, PINGPONG.extId, escrow.id, { + maxAmountSats: 100 + }) + + await page.goto('/ext/pingpong') + const adminFrame = await extensionFrame(page, 'Ping Pong') + await expect(adminFrame.getByText('Lightning Pong tables')).toBeVisible({ + timeout: 60_000 + }) + + const tableName = `Playwright Pong ${randomHex()}` + const table = await extensionApi(page, PINGPONG.extId, 'POST', '/tables', { + name: tableName, + description: 'Playwright fake wallet table', + walletId: escrow.id, + entrySats: 3, + gamesToWin: 1, + hostPercent: 0 + }) + expect(table.name).toBe(tableName) + + const player1LnurlServer = await LNURLPayServer.start( + lnbitsServer.baseUrl, + player1PayoutTarget + ) + const player2LnurlServer = await LNURLPayServer.start( + lnbitsServer.baseUrl, + player2PayoutTarget + ) + + const player2Context = await browser.newContext({ + baseURL: lnbitsServer.baseUrl, + viewport: {width: 1280, height: 900} + }) + const player2Page = await player2Context.newPage() + player2Page.setDefaultTimeout(60_000) + const player2Recorder = await installDetailedScreenshots( + player2Page, + testInfo + ) + + try { + const player1Game = await createPublicGame( + page, + String(table.id), + tableName, + player1LnurlServer.lnurl + ) + await payInvoiceWithWallet( + page, + player1EntryWallet, + player1Game.invoice.paymentRequest + ) + await waitForResult( + 'Ping Pong player 1 payment to be recorded', + async () => + pingpongGameIfPlayer1Paid( + page, + player1Game.gameId, + player1Game.playerToken + ), + {timeout: 30_000} + ) + await page.goto(publicGamePath(player1Game.gameId)) + const player1WaitingFrame = await extensionFrame(page, 'Ping Pong') + const waitingGame = await publicGame( + page, + player1Game.gameId, + player1Game.playerToken + ) + expect(waitingGame.status).toBe('waiting_opponent') + await expect(player1WaitingFrame.locator('#game-note')).toContainText( + 'Share the game link with player 2.' + ) + + const player2Game = await joinPublicGame( + player2Page, + player1Game.gameId, + tableName, + player2LnurlServer.lnurl + ) + await payInvoiceWithWallet( + player2Page, + player2EntryWallet, + player2Game.invoice.paymentRequest + ) + await waitForResult( + 'Ping Pong game to start playing after both players paid', + async () => { + const game = await publicGame( + page, + player1Game.gameId, + player1Game.playerToken + ) + return game.status === 'playing' && + game.player1Paid === true && + game.player2Paid === true + ? game + : null + }, + {timeout: 60_000} + ) + + await page.goto(publicGamePath(player1Game.gameId)) + await player2Page.goto(publicGamePath(player1Game.gameId)) + const player1PlayingFrame = await extensionFrame(page, 'Ping Pong') + const player2PlayingFrame = await extensionFrame(player2Page, 'Ping Pong') + await expect(player1PlayingFrame.locator('#game-status')).toHaveText( + 'playing', + {timeout: 60_000} + ) + await expect(player2PlayingFrame.locator('#game-status')).toHaveText( + 'playing', + {timeout: 60_000} + ) + await expect(player1PlayingFrame.locator('#game-note')).toContainText( + 'You control the left paddle.' + ) + await expect(player2PlayingFrame.locator('#game-note')).toContainText( + 'You control the right paddle.' + ) + + const finished = await extensionApi( + page, + PINGPONG.extId, + 'POST', + `/games/${player1Game.gameId}/finish`, + { + playerToken: player1Game.playerToken, + winnerSlot: 'player1', + player1Wins: 1, + player2Wins: 0, + currentPlayer1Score: 11, + currentPlayer2Score: 0 + } + ) + expect(finished.winnerSlot).toBe('player1') + + const paidGame = await waitForResult( + 'Ping Pong winner payout to be paid', + async () => { + const game = await publicGame( + page, + player1Game.gameId, + player1Game.playerToken + ) + return game.status === 'paid' && game.payoutStatus === 'paid' + ? game + : null + }, + {timeout: 60_000, interval: 2_000} + ) + expect(paidGame.winnerSlot).toBe('player1') + await waitForWalletBalance(page, player1PayoutTarget, { + expectedSats: Number( + (paidGame.table as Record).winnerPayoutSats + ), + timeout: 60_000 + }) + + await page.goto(publicGamePath(player1Game.gameId)) + await player2Page.goto(publicGamePath(player1Game.gameId)) + const player1PaidFrame = await extensionFrame(page, 'Ping Pong') + const player2PaidFrame = await extensionFrame(player2Page, 'Ping Pong') + await expect(player1PaidFrame.locator('#game-status')).toHaveText( + 'Player 1 won', + {timeout: 60_000} + ) + await expect(player2PaidFrame.locator('#game-status')).toHaveText( + 'Player 1 won', + {timeout: 60_000} + ) + await expect(player1PaidFrame.locator('#game-note')).toContainText( + 'Player 1 won. Payout status: paid.' + ) + } finally { + await player2Recorder.finish() + await player2Context.close() + await player1LnurlServer.close() + await player2LnurlServer.close() + } + + await page.goto('/ext/pingpong') + const updatedFrame = await extensionFrame(page, 'Ping Pong') + await expect(updatedFrame.getByText(tableName)).toBeVisible({timeout: 60_000}) +}) + +async function pingpongGameIfPlayer1Paid( + page: Page, + gameId: string, + playerToken: string +): Promise | null> { + const game = await publicGame(page, gameId, playerToken) + return game.player1Paid === true ? game : null +} + +async function createPublicGame( + page: Page, + tableId: string, + tableName: string, + lnurl: string +): Promise { + await page.goto(publicTablePath(tableId)) + const frame = await extensionFrame(page, 'Ping Pong') + await expect(frame.locator('#table-view')).toBeVisible({timeout: 60_000}) + await expect(frame.locator('#table-name')).toHaveText(tableName) + await frame.locator('#create-lnurl').fill(lnurl) + + const responsePromise = page.waitForResponse( + response => + response.request().method() === 'POST' && + response + .url() + .includes(`/api/v1/ext/${PINGPONG.extId}/tables/${tableId}/games`) + ) + await frame.locator('#create-game').click() + const game = await gameInvoiceFromResponse(await responsePromise) + await expect(frame.locator('#payment-view')).toBeVisible({timeout: 60_000}) + await expect(frame.locator('#invoice-text')).toHaveText( + game.invoice.paymentRequest, + {timeout: 60_000} + ) + return game +} + +async function joinPublicGame( + page: Page, + gameId: string, + tableName: string, + lnurl: string +): Promise { + await page.goto(publicGamePath(gameId)) + const frame = await extensionFrame(page, 'Ping Pong') + await expect(frame.locator('#game-view')).toBeVisible({timeout: 60_000}) + await expect(frame.locator('#game-meta')).toContainText(tableName) + await expect(frame.locator('#join-panel')).toBeVisible({timeout: 60_000}) + await frame.locator('#join-lnurl').fill(lnurl) + + const responsePromise = page.waitForResponse( + response => + response.request().method() === 'POST' && + response + .url() + .includes(`/api/v1/ext/${PINGPONG.extId}/games/${gameId}/join`) + ) + await frame.locator('#join-game').click() + const game = await gameInvoiceFromResponse(await responsePromise) + await expect(frame.locator('#payment-view')).toBeVisible({timeout: 60_000}) + await expect(frame.locator('#invoice-text')).toHaveText( + game.invoice.paymentRequest, + {timeout: 60_000} + ) + return game +} + +async function publicGame( + page: Page, + gameId: string, + playerToken: string +): Promise> { + return extensionApi( + page, + PINGPONG.extId, + 'GET', + `/games/${gameId}/public?playerToken=${playerToken}` + ) +} + +async function gameInvoiceFromResponse( + response: Response +): Promise { + const body = await response.json() + const data = isRecord(body) && isRecord(body.data) ? body.data : body + if (!isRecord(data) || !isRecord(data.invoice)) { + throw new Error( + `Ping Pong game invoice response is invalid: ${JSON.stringify(body)}` + ) + } + const paymentRequest = data.invoice.paymentRequest + const paymentHash = data.invoice.paymentHash + const checkingId = data.invoice.checkingId + if ( + typeof data.gameId !== 'string' || + typeof data.playerSlot !== 'string' || + typeof data.playerToken !== 'string' || + typeof paymentRequest !== 'string' || + typeof paymentHash !== 'string' || + typeof checkingId !== 'string' + ) { + throw new Error( + `Ping Pong game invoice response is incomplete: ${JSON.stringify(body)}` + ) + } + expect(paymentRequest.toLowerCase()).toMatch(/^lnbc/) + return { + gameId: data.gameId, + playerSlot: data.playerSlot as GameInvoice['playerSlot'], + playerToken: data.playerToken, + invoice: { + checkingId, + paymentHash, + paymentRequest + } + } +} + +function publicTablePath(tableId: string): string { + return `/ext/${PINGPONG.extId}/t/${encodeURIComponent(tableId)}` +} + +function publicGamePath(gameId: string): string { + return `/ext/${PINGPONG.extId}/g/${encodeURIComponent(gameId)}` +} diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts new file mode 100644 index 000000000..b61b1d023 --- /dev/null +++ b/tests/e2e/playwright.config.ts @@ -0,0 +1,69 @@ +import {defineConfig} from '@playwright/test' +import {resolve} from 'node:path' + +const appBaseUrl = process.env.LNBITS_E2E_BASE_URL ?? 'http://127.0.0.1:5009' +const e2eDir = __dirname +const isCi = Boolean(process.env.CI) +const projectRoot = resolve(e2eDir, '../..') +const reportRoot = resolve(projectRoot, 'test-reports') +const configuredWorkers = Number.parseInt( + process.env.PLAYWRIGHT_WORKERS ?? '', + 10 +) + +export default defineConfig({ + testDir: e2eDir, + testMatch: '**/*.spec.ts', + outputDir: resolve(reportRoot, 'test-results'), + timeout: 600_000, + fullyParallel: false, + forbidOnly: isCi, + retries: isCi ? 1 : 0, + workers: + Number.isInteger(configuredWorkers) && configuredWorkers > 0 + ? configuredWorkers + : 1, + expect: { + timeout: 15_000 + }, + reporter: isCi + ? [ + ['github'], + [ + 'html', + { + open: 'never', + outputFolder: resolve(reportRoot, 'playwright-report') + } + ] + ] + : [ + ['list'], + [ + 'html', + { + open: 'never', + outputFolder: resolve(reportRoot, 'playwright-report') + } + ] + ], + use: { + baseURL: appBaseUrl, + browserName: 'chromium', + headless: true, + viewport: { + width: 1280, + height: 900 + }, + trace: 'off', + screenshot: 'only-on-failure', + video: 'off' + }, + webServer: { + command: 'node ./tests/e2e/start-lnbits-server.cjs', + cwd: projectRoot, + url: appBaseUrl, + reuseExistingServer: false, + timeout: 180_000 + } +}) diff --git a/tests/e2e/start-lnbits-server.cjs b/tests/e2e/start-lnbits-server.cjs new file mode 100644 index 000000000..c1a66be8c --- /dev/null +++ b/tests/e2e/start-lnbits-server.cjs @@ -0,0 +1,191 @@ +const childProcess = require('node:child_process') +const crypto = require('node:crypto') +const fs = require('node:fs') +const http = require('node:http') +const os = require('node:os') +const path = require('node:path') + +const rootDir = path.resolve(__dirname, '../..') +const baseUrl = new URL( + process.env.LNBITS_E2E_BASE_URL ?? 'http://127.0.0.1:5009' +) +const host = baseUrl.hostname +const port = baseUrl.port || (baseUrl.protocol === 'https:' ? '443' : '80') +const dataDir = + process.env.LNBITS_E2E_DATA_FOLDER ?? + fs.mkdtempSync(path.join(os.tmpdir(), 'lnbits-e2e-')) +const logDir = path.join(rootDir, 'test-reports', 'test-results') +const logFile = path.join(logDir, 'lnbits-e2e-server.log') +const extensionFixtureUrl = new URL( + process.env.LNBITS_E2E_EXTENSION_FIXTURE_URL ?? 'http://127.0.0.1:5010' +) + +fs.mkdirSync(dataDir, {recursive: true}) +fs.mkdirSync(logDir, {recursive: true}) + +const supportchatFixture = createSupportchatFixture(extensionFixtureUrl) +const wasmExtensionManifests = [ + ...(supportchatFixture + ? [new URL('/manifest.json', extensionFixtureUrl).toString()] + : []), + 'https://raw.githubusercontent.com/lnbits/lnbits-extensions-wasm/refs/heads/main/extensions.json' +] +const extensionFixtureServer = supportchatFixture + ? http.createServer((request, response) => { + const pathname = new URL(request.url ?? '/', extensionFixtureUrl).pathname + const fixture = supportchatFixture.responses[pathname] + if (!fixture) { + response.writeHead(404, {'Content-Type': 'text/plain; charset=utf-8'}) + response.end('Not found') + return + } + response.writeHead(200, { + 'Cache-Control': 'no-store', + 'Content-Type': fixture.contentType + }) + response.end(fixture.body) + }) + : null +extensionFixtureServer?.listen( + Number(extensionFixtureUrl.port || 80), + extensionFixtureUrl.hostname +) + +const log = fs.openSync(logFile, 'a') +const server = childProcess.spawn( + 'uv', + [ + 'run', + 'uvicorn', + 'lnbits.__main__:app', + '--host', + host, + '--port', + port, + '--log-level', + 'warning' + ], + { + cwd: rootDir, + env: { + ...process.env, + AUTH_HTTPS_ONLY: 'false', + DEBUG: 'true', + HOST: host, + LNBITS_ADMIN_UI: 'true', + LNBITS_BACKEND_WALLET_CLASS: 'FakeWallet', + LNBITS_DATA_FOLDER: dataDir, + LNBITS_ENABLE_LOG_TO_FILE: 'false', + LNBITS_EXTENSIONS_PATH: dataDir, + LNBITS_WASM_EXTENSIONS_MANIFESTS: JSON.stringify(wasmExtensionManifests), + PORT: port, + PYTHONUNBUFFERED: '1' + }, + stdio: ['ignore', log, log] + } +) + +let shuttingDown = false + +const shutdown = signal => { + if (shuttingDown) return + shuttingDown = true + extensionFixtureServer?.close() + + if (server.pid && server.exitCode === null) { + try { + server.kill(signal) + } catch (_error) {} + } + + setTimeout(() => { + if (server.pid && server.exitCode === null) { + try { + server.kill('SIGKILL') + } catch (_error) {} + } + process.exit(0) + }, 15_000).unref() +} + +process.on('SIGTERM', () => shutdown('SIGTERM')) +process.on('SIGINT', () => shutdown('SIGINT')) + +server.on('exit', (code, signal) => { + extensionFixtureServer?.close() + fs.closeSync(log) + if (!shuttingDown) { + process.exit(code ?? (signal ? 1 : 0)) + } +}) + +function createSupportchatFixture(fixtureUrl) { + const sourceDir = + process.env.LNBITS_E2E_SUPPORTCHAT_DIR ?? + path.join(rootDir, 'data', 'extensions', 'supportchat') + if (!fs.existsSync(path.join(sourceDir, 'config.json'))) return null + const config = JSON.parse( + fs.readFileSync(path.join(sourceDir, 'config.json'), 'utf8') + ) + const fixtureRoot = fs.mkdtempSync( + path.join(os.tmpdir(), 'lnbits-supportchat-e2e-') + ) + const archiveRootName = `supportchat-${config.version}` + const archiveRoot = path.join(fixtureRoot, archiveRootName) + fs.mkdirSync(archiveRoot, {recursive: true}) + + for (const name of ['config.json', 'static', 'storage', 'ui', 'wasm']) { + fs.cpSync(path.join(sourceDir, name), path.join(archiveRoot, name), { + recursive: true + }) + } + + const archivePath = path.join(fixtureRoot, 'supportchat.zip') + const zipped = childProcess.spawnSync( + 'zip', + ['-q', '-r', archivePath, archiveRootName], + { + cwd: fixtureRoot, + encoding: 'utf8' + } + ) + if (zipped.status !== 0) { + throw new Error(`Could not create supportchat fixture: ${zipped.stderr}`) + } + const archive = fs.readFileSync(archivePath) + const hash = crypto.createHash('sha256').update(archive).digest('hex') + const archiveUrl = new URL('/supportchat.zip', fixtureUrl).toString() + const configUrl = new URL('/config.json', fixtureUrl).toString() + const manifest = { + extensions: [ + { + id: 'supportchat', + name: config.name, + version: config.version, + archive: archiveUrl, + hash, + repo: 'local-e2e', + short_description: config.short_description, + min_lnbits_version: config.min_lnbits_version, + details_link: configUrl + } + ] + } + + return { + responses: { + '/config.json': { + body: Buffer.from(JSON.stringify(config)), + contentType: 'application/json; charset=utf-8' + }, + '/manifest.json': { + body: Buffer.from(JSON.stringify(manifest)), + contentType: 'application/json; charset=utf-8' + }, + '/supportchat.zip': { + body: archive, + contentType: 'application/zip' + } + } + } +} diff --git a/tests/e2e/supportchat.spec.ts b/tests/e2e/supportchat.spec.ts new file mode 100644 index 000000000..c1f9c0b67 --- /dev/null +++ b/tests/e2e/supportchat.spec.ts @@ -0,0 +1,268 @@ +import {existsSync} from 'node:fs' +import {join, resolve} from 'node:path' + +import { + expect, + installDetailedScreenshots, + isRecord, + randomHex, + test +} from './fixtures' +import { + extensionApi, + extensionFrame, + installAndEnableExtension, + login +} from './extension-helpers' +import {SUPPORTCHAT} from './extensions' + +const supportchatDir = + process.env.LNBITS_E2E_SUPPORTCHAT_DIR ?? + resolve('data/extensions/supportchat') + +test.skip( + !existsSync(join(supportchatDir, 'config.json')), + 'Support Chat E2E requires LNBITS_E2E_SUPPORTCHAT_DIR or data/extensions/supportchat.' +) + +test('install Support Chat and run the visitor-to-agent support workflow', async ({ + page, + browser, + lnbitsServer +}, testInfo) => { + await login(page, lnbitsServer) + await installAndEnableExtension(page, SUPPORTCHAT) + + await page.goto('/ext/supportchat') + let adminFrame = await extensionFrame(page, 'Support Chat') + await expect( + adminFrame.getByRole('heading', {name: 'Support Chat'}) + ).toBeVisible({timeout: 60_000}) + + const inboxName = `Playwright Support ${randomHex()}` + const inboxForm = adminFrame.locator('#inbox-form') + const createInboxButton = inboxForm.getByRole('button', { + name: 'Create inbox' + }) + await expect(createInboxButton).toBeEnabled() + await inboxForm.locator('[name="name"]').fill(inboxName) + await inboxForm + .locator('[name="welcomeMessage"]') + .fill('How can the Playwright support team help?') + await inboxForm.locator('[name="launcherText"]').fill('Ask Playwright') + await inboxForm + .locator('[name="offlineMessage"]') + .fill('Playwright support is offline; leave a message.') + await inboxForm.locator('[name="officeHoursEnabled"]').check() + await inboxForm.locator('[name="officeHoursStart"]').fill('0') + await inboxForm.locator('[name="officeHoursEnd"]').fill('0') + await createInboxButton.click() + await expect(adminFrame.getByText(inboxName).first()).toBeVisible({ + timeout: 60_000 + }) + + const inbox = await supportInbox(page, inboxName) + const publicPath = `/ext/supportchat/i/${encodeURIComponent(String(inbox.id))}` + const visitorContext = await browser.newContext({ + baseURL: lnbitsServer.baseUrl, + viewport: {width: 430, height: 820} + }) + const visitorPage = await visitorContext.newPage() + visitorPage.setDefaultTimeout(60_000) + const visitorRecorder = await installDetailedScreenshots( + visitorPage, + testInfo + ) + + try { + await visitorPage.goto(publicPath) + let visitorFrame = await extensionFrame(visitorPage, 'Support Chat') + await expect(visitorFrame.getByText(inboxName)).toBeVisible() + await expect( + visitorFrame.getByText('Playwright support is offline; leave a message.') + ).toBeVisible() + + const startForm = visitorFrame.locator('#start-box') + await startForm.locator('[name="name"]').fill('Alice Visitor') + await startForm + .locator('[name="email"]') + .fill('alice.playwright@example.com') + await startForm.locator('[name="subject"]').fill('Checkout is stuck') + await startForm + .locator('[name="body"]') + .fill('The checkout spinner never finishes.') + await startForm.getByTestId('start-conversation').click() + await expect(visitorPage).toHaveURL(/\/ext\/supportchat\/c\/[a-f0-9]+$/i, { + timeout: 60_000 + }) + visitorFrame = await extensionFrame(visitorPage, 'Support Chat') + await expect( + visitorFrame.getByText('The checkout spinner never finishes.') + ).toBeVisible() + + await page.goto('/ext/supportchat') + adminFrame = await extensionFrame(page, 'Support Chat') + await expect(adminFrame.getByText('Checkout is stuck')).toBeVisible({ + timeout: 60_000 + }) + await expect(adminFrame.getByTestId('unread-count')).toHaveText('1') + await adminFrame.getByText('Checkout is stuck').click() + await expect( + adminFrame.getByText('The checkout spinner never finishes.') + ).toBeVisible() + await expect( + adminFrame + .locator('.sc-message--theirs') + .filter({hasText: 'The checkout spinner never finishes.'}) + ).toHaveCSS('justify-content', 'flex-end') + + const cannedForm = adminFrame.locator('#canned-reply-form') + await cannedForm.locator('[name="title"]').fill('Investigating') + await cannedForm + .locator('[name="body"]') + .fill('Thanks — we are investigating this now.') + await cannedForm.getByRole('button', {name: 'Add canned reply'}).click() + await expect( + adminFrame.getByRole('button', {name: 'Investigating', exact: true}) + ).toBeVisible() + + await adminFrame.getByTestId('conversation-status').selectOption('pending') + await adminFrame.getByTestId('conversation-priority').selectOption('urgent') + await adminFrame.getByTestId('conversation-tags').fill('checkout, browser') + const ticketUpdated = page.waitForResponse( + response => + response.request().method() === 'PUT' && + response.url().includes('/api/v1/ext/supportchat/conversations/') + ) + await adminFrame.getByRole('button', {name: 'Save ticket'}).click() + await ticketUpdated + await expect(adminFrame.locator('main.sc-shell')).toHaveAttribute( + 'data-loading', + '' + ) + await expect(adminFrame.getByTestId('conversation-status')).toHaveValue( + 'pending' + ) + await expect(adminFrame.getByTestId('conversation-priority')).toHaveValue( + 'urgent' + ) + await expect(adminFrame.getByTestId('conversation-tags')).toHaveValue( + 'checkout, browser' + ) + + await adminFrame + .getByTestId('internal-note') + .fill('Only agents should see this diagnostic note.') + await adminFrame.getByRole('button', {name: 'Add internal note'}).click() + await expect( + adminFrame.getByText('Only agents should see this diagnostic note.') + ).toBeVisible() + + await adminFrame + .getByRole('button', {name: 'Investigating', exact: true}) + .click() + await expect(adminFrame.getByTestId('agent-reply')).toHaveValue( + 'Thanks — we are investigating this now.' + ) + await adminFrame.getByRole('button', {name: 'Send'}).click() + await expect( + visitorFrame.getByText('Thanks — we are investigating this now.') + ).toBeVisible({timeout: 60_000}) + await expect( + adminFrame + .locator('.sc-message--mine') + .filter({hasText: 'Thanks — we are investigating this now.'}) + ).toHaveCSS('justify-content', 'flex-start') + await expect( + visitorFrame + .locator('.sc-message--theirs') + .filter({hasText: 'Thanks — we are investigating this now.'}) + ).toHaveCSS('justify-content', 'flex-end') + await expect( + visitorFrame.getByText('Only agents should see this diagnostic note.') + ).toHaveCount(0) + + await visitorPage.waitForTimeout(1_100) + await visitorFrame + .locator('#message-box [name="body"]') + .fill('It also happens in a private window.') + await visitorFrame.getByTestId('visitor-send').click() + await expect( + adminFrame.getByText('It also happens in a private window.') + ).toBeVisible({timeout: 60_000}) + await expect(adminFrame.getByTestId('unread-count')).toHaveText('1') + + const ticketResolved = page.waitForResponse( + response => + response.request().method() === 'POST' && + response.url().includes('/api/v1/ext/supportchat/conversations/') && + response.url().endsWith('/resolve') + ) + await adminFrame.getByRole('button', {name: 'Resolve'}).click() + const ticketResolvedResponse = await ticketResolved + expect( + ticketResolvedResponse.ok(), + `Could not resolve ticket: ${await ticketResolvedResponse.text()}` + ).toBe(true) + await expect(visitorFrame.getByText('resolved').first()).toBeVisible({ + timeout: 60_000 + }) + await expect(adminFrame.locator('main.sc-shell')).toHaveAttribute( + 'data-loading', + '' + ) + await expect(adminFrame.getByTestId('conversation-status')).toHaveValue( + 'resolved' + ) + await adminFrame.getByTestId('conversation-status').selectOption('open') + const ticketReopened = page.waitForResponse( + response => + response.request().method() === 'PUT' && + response.url().includes('/api/v1/ext/supportchat/conversations/') + ) + await adminFrame.getByRole('button', {name: 'Save ticket'}).click() + const ticketReopenedResponse = await ticketReopened + expect( + ticketReopenedResponse.ok(), + `Could not reopen ticket: ${await ticketReopenedResponse.text()}` + ).toBe(true) + await expect(adminFrame.locator('main.sc-shell')).toHaveAttribute( + 'data-loading', + '' + ) + await visitorPage.reload() + visitorFrame = await extensionFrame(visitorPage, 'Support Chat') + await expect(visitorFrame.getByText('open').first()).toBeVisible({ + timeout: 60_000 + }) + + await visitorPage.goto(publicPath) + visitorFrame = await extensionFrame(visitorPage, 'Support Chat') + await expect( + visitorFrame.getByText('Thanks — we are investigating this now.') + ).toBeVisible({timeout: 60_000}) + } finally { + await visitorRecorder.finish() + await visitorContext.close() + } +}) + +async function supportInbox( + page: Parameters[0], + inboxName: string +): Promise> { + const response = await extensionApi( + page, + SUPPORTCHAT.extId, + 'GET', + '/inboxes?rowsPerPage=100' + ) + const inboxes = Array.isArray(response.inboxes) + ? response.inboxes.filter(isRecord) + : [] + const inbox = inboxes.find(item => item.name === inboxName) + if (!inbox) { + throw new Error(`Support inbox not found: ${JSON.stringify(response)}`) + } + return inbox +} diff --git a/tests/e2e/tips.spec.ts b/tests/e2e/tips.spec.ts new file mode 100644 index 000000000..b53573ea6 --- /dev/null +++ b/tests/e2e/tips.spec.ts @@ -0,0 +1,124 @@ +import type {Page} from '@playwright/test' + +import {test, expect, apiJson, randomHex} from './fixtures' +import { + extensionFrame, + fundWalletWithFakeBalance, + installAndEnableExtension, + login, + superuserWallet +} from './extension-helpers' +import {TIPS} from './extensions' + +test('install Tips extension and pay tip with fake wallet', async ({ + page, + lnbitsServer +}) => { + await login(page, lnbitsServer) + const wallet = await superuserWallet(page) + + await installAndEnableExtension(page, TIPS) + await fundWalletWithFakeBalance(page, wallet.id, {amountSats: 10_000}) + + const jarTitle = `Playwright Tips ${randomHex()}` + const tipMessage = `fake wallet tip ${randomHex()}` + const publicUrl = await createTipJar(page, jarTitle) + const paymentRequest = await createPublicTipInvoice( + page, + publicUrl, + tipMessage + ) + + await apiJson( + lnbitsServer.baseUrl, + 'POST', + '/api/v1/payments', + {out: true, bolt11: paymentRequest}, + wallet.adminkey + ) + + const publicFrame = await tipsFrame(page) + await expect(publicFrame.locator('#invoice-status')).toHaveText( + 'Payment received', + {timeout: 30_000} + ) + + await page.goto('/ext/tips') + const adminFrame = await tipsFrame(page) + await expect( + adminFrame.getByRole('cell', {name: jarTitle}).first() + ).toBeVisible({ + timeout: 60_000 + }) + await adminFrame.getByRole('button', {name: 'Refresh'}).click() + await expect( + adminFrame.getByRole('cell', {name: tipMessage}).first() + ).toBeVisible({ + timeout: 60_000 + }) + await expect( + adminFrame.getByRole('cell', {name: 'Paid'}).first() + ).toBeVisible() +}) + +async function createTipJar(page: Page, jarTitle: string): Promise { + await page.goto('/ext/tips') + const frame = await tipsFrame(page) + await expect(frame.getByText('Create Jar')).toBeVisible({timeout: 60_000}) + await frame.getByLabel('Title').fill(jarTitle) + await frame.getByRole('button', {name: /^create$/i}).click() + await expect(frame.getByRole('cell', {name: jarTitle})).toBeVisible({ + timeout: 60_000 + }) + await frame.waitForFunction(() => + [...document.querySelectorAll('input')].some(input => + input.value.includes('/ext/tips/jars/') + ) + ) + const publicUrl = await frame.evaluate(() => + [...document.querySelectorAll('input')] + .map(input => input.value) + .find(value => value.includes('/ext/tips/jars/')) + ) + if (typeof publicUrl !== 'string' || !publicUrl.includes('/ext/tips/jars/')) { + throw new Error(`Tip jar public URL was not found: ${String(publicUrl)}`) + } + return publicUrl +} + +async function createPublicTipInvoice( + page: Page, + publicUrl: string, + tipMessage: string +): Promise { + await page.goto(publicUrl) + const frame = await tipsFrame(page) + await expect(frame.getByRole('heading', {name: 'Leave a Tip'})).toBeVisible({ + timeout: 60_000 + }) + await frame.getByLabel('Name').fill('Playwright') + await frame.getByLabel('Message').fill(tipMessage) + await frame.getByRole('button', {name: 'Create Invoice'}).click() + await expect(frame.getByText('Waiting for payment')).toBeVisible({ + timeout: 60_000 + }) + await frame.waitForFunction(() => + Boolean(document.querySelector('#copy-invoice-button')?.dataset.invoice) + ) + const paymentRequest = await frame + .locator('#copy-invoice-button') + .evaluate(button => button.dataset.invoice) + if ( + typeof paymentRequest !== 'string' || + !paymentRequest.toLowerCase().startsWith('lnbc') + ) { + throw new Error( + `Tip invoice payment request was not found: ${String(paymentRequest)}` + ) + } + return paymentRequest +} + +async function tipsFrame(page: Page) { + return extensionFrame(page, 'Tips') +} diff --git a/tests/helpers.py b/tests/helpers.py index 45e7b2b0d..393fcddb5 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -1,8 +1,33 @@ import random import string +from io import BytesIO -from pydantic import BaseModel +from bolt11.types import MilliSatoshi +from fastapi import UploadFile +from httpx import AsyncClient +from lnurl import LnurlPayResponse +from lnurl.types import CallbackUrl, LnurlPayMetadata +from PIL import Image +from pydantic import BaseModel, parse_obj_as +from starlette.datastructures import Headers +from lnbits.core.models.extensions import ( + ExtensionMeta, + ExtensionRelease, + InstallableExtension, + PayToEnableInfo, + ReleasePaymentInfo, +) +from lnbits.core.models.extensions_builder import ( + ActionFields, + ClientDataFields, + DataField, + DataFields, + ExtensionData, + OwnerDataFields, + PublicPageFields, + SettingsFields, +) from lnbits.wallets import get_funding_source, set_funding_source @@ -40,7 +65,125 @@ async def get_random_invoice_data(): return {"out": False, "amount": 10, "memo": f"test_memo_{get_random_string(10)}"} +def get_png_bytes(*, color: str = "blue", size: tuple[int, int] = (32, 32)) -> bytes: + image = Image.new("RGB", size, color=color) + buffer = BytesIO() + image.save(buffer, format="PNG") + return buffer.getvalue() + + +def make_upload_file( + contents: bytes, + *, + filename: str, + content_type: str | None, +) -> UploadFile: + headers = ( + Headers({"content-type": content_type}) if content_type is not None else None + ) + return UploadFile(BytesIO(contents), filename=filename, headers=headers) + + +async def get_user_token_headers(client: AsyncClient, user_id: str) -> dict[str, str]: + response = await client.post("/api/v1/auth/usr", json={"usr": user_id}) + client.cookies.clear() + return { + "Authorization": f"Bearer {response.json()['access_token']}", + "Content-type": "application/json", + } + + +def make_extension_data(ext_id: str = "demoext") -> ExtensionData: + return ExtensionData( + id=ext_id, + name="Demo Extension", + stub_version="0.1.0", + short_description="Generated extension", + owner_data=DataFields( + name="OwnerData", + fields=[DataField(name="wallet_id", type="wallet")], + ), + client_data=DataFields( + name="ClientData", + fields=[DataField(name="amount", type="int")], + ), + settings_data=SettingsFields(name="SettingsData", fields=[]), + public_page=PublicPageFields( + owner_data_fields=OwnerDataFields(), + client_data_fields=ClientDataFields(), + action_fields=ActionFields(), + ), + ) + + +def make_extension_release(ext_id: str, version: str = "1.0.0") -> ExtensionRelease: + return ExtensionRelease( + name=ext_id, + version=version, + archive=f"https://example.com/{ext_id}.zip", + source_repo="org/repo", + hash=f"hash-{ext_id}", + details_link=f"https://example.com/{ext_id}/details.json", + repo=f"https://github.com/org/{ext_id}", + icon=f"/{ext_id}/static/icon.png", + pay_link=f"https://pay.example/{ext_id}", + is_github_release=False, + is_version_compatible=True, + ) + + +def make_installable_extension( + ext_id: str, + *, + version: str = "1.0.0", + compatible: bool = True, + active: bool = True, + pay_to_enable: PayToEnableInfo | None = None, + dependencies: list[str] | None = None, + payments: list[ReleasePaymentInfo] | None = None, +) -> InstallableExtension: + release = make_extension_release(ext_id, version) + release.is_version_compatible = compatible + return InstallableExtension( + id=ext_id, + name=f"Extension {ext_id}", + version=version, + active=active, + short_description="Demo extension", + icon=release.icon, + meta=ExtensionMeta( + installed_release=release, + pay_to_enable=pay_to_enable, + dependencies=dependencies or [], + payments=payments or [], + ), + ) + + +def make_lnurl_pay_response( + *, + min_sendable_msat: int = 1_000, + max_sendable_msat: int = 10_000, + text: str = "Test payment", + identifier: str = "alice@example.com", + callback: str = "https://example.com/callback", +) -> LnurlPayResponse: + return LnurlPayResponse( + callback=parse_obj_as(CallbackUrl, callback), + minSendable=MilliSatoshi(min_sendable_msat), + maxSendable=MilliSatoshi(max_sendable_msat), + metadata=LnurlPayMetadata( + f"[[" + f'"text/plain","{text}"' + f"],[" + f'"text/identifier","{identifier}"' + f"]]" + ), + ) + + set_funding_source() + funding_source = get_funding_source() is_fake: bool = funding_source.__class__.__name__ == "FakeWallet" is_regtest: bool = not is_fake diff --git a/tests/regtest/helpers.py b/tests/regtest/helpers.py index b90a577a5..ca1327fea 100644 --- a/tests/regtest/helpers.py +++ b/tests/regtest/helpers.py @@ -26,8 +26,6 @@ docker_bitcoin_cli = [ "exec", "lnbits-bitcoind-1", "bitcoin-cli", - "-rpcuser=lnbits", - "-rpcpassword=lnbits", "-regtest", ] diff --git a/tests/regtest/test_electrum.py b/tests/regtest/test_electrum.py new file mode 100644 index 000000000..57083a2c2 --- /dev/null +++ b/tests/regtest/test_electrum.py @@ -0,0 +1,184 @@ +""" +Electrum client integration tests against the regtest electrs container. +Requires the regtest docker-compose stack (docker/regtest/docker-compose.yml). +electrs is exposed on localhost:19001 (plain TCP) and localhost:3002 (HTTP). +""" + +import asyncio + +import httpx +import pytest +from loguru import logger + +from lnbits.utils.electrum import ElectrumClient, scripthash_from_scriptpubkey + +from .helpers import docker_bitcoin_cli, run_cmd, run_cmd_json + +ELECTRS_HOST = "localhost" +ELECTRS_PORT = 19001 +ELECTRS_HTTP = "http://localhost:3002" + + +def bitcoin_height() -> int: + return run_cmd_json([*docker_bitcoin_cli, "getblockchaininfo"])["blocks"] + + +def mine_blocks(n: int = 1) -> int: + """Mine n blocks and return the new chain height.""" + run_cmd([*docker_bitcoin_cli, "-generate", str(n)]) + return bitcoin_height() + + +def new_address() -> str: + return run_cmd([*docker_bitcoin_cli, "getnewaddress", "bech32"]) + + +def get_scriptpubkey(address: str) -> bytes: + info = run_cmd_json([*docker_bitcoin_cli, "getaddressinfo", address]) + return bytes.fromhex(info["scriptPubKey"]) + + +def send_to_address(address: str, sats: int) -> str: + btc = f"{sats * 1e-8:.8f}" + return run_cmd([*docker_bitcoin_cli, "sendtoaddress", address, btc]) + + +async def wait_for_electrs(height: int, timeout: float = 15.0) -> None: + """Poll electrs HTTP until it has indexed up to `height`.""" + loop = asyncio.get_running_loop() + deadline = loop.time() + timeout + async with httpx.AsyncClient() as http: + while loop.time() < deadline: + try: + r = await http.get(f"{ELECTRS_HTTP}/blocks/tip/height", timeout=2) + if int(r.text) >= height: + return + except Exception: + logger.debug("electrs not ready yet") + await asyncio.sleep(0.25) + raise TimeoutError(f"electrs did not reach height {height} within {timeout}s") + + +@pytest.fixture(scope="module", autouse=True) +async def wait_after_electrum_tests(): + yield + await asyncio.sleep(1) + + +@pytest.mark.anyio +async def test_connect_and_height(): + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + before = await client.get_height() + + target = mine_blocks(3) + await wait_for_electrs(target) + + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + after = await client.get_height() + + assert isinstance(before, int) and before >= 0 + assert after == before + 3 + + +@pytest.mark.anyio +async def test_get_tip(): + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + tip = await client.get_tip() + assert isinstance(tip.height, int) + assert isinstance(tip.hex, str) + assert len(tip.hex) == 160 # 80-byte serialised header + + +@pytest.mark.anyio +async def test_server_banner(): + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + banner = await client.server_banner() + assert isinstance(banner, str) + + +@pytest.mark.anyio +async def test_balance_after_payment(): + address = new_address() + scripthash = scripthash_from_scriptpubkey(get_scriptpubkey(address)) + + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + empty = await client.get_balance(scripthash) + assert empty.confirmed == 0 + assert empty.unconfirmed == 0 + + send_to_address(address, 500_000) + target = mine_blocks(1) + await wait_for_electrs(target) + + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + confirmed = await client.get_balance(scripthash) + assert confirmed.confirmed == 500_000 + assert confirmed.unconfirmed == 0 + + +@pytest.mark.anyio +async def test_history_and_utxos(): + address = new_address() + scripthash = scripthash_from_scriptpubkey(get_scriptpubkey(address)) + + send_to_address(address, 250_000) + target = mine_blocks(1) + await wait_for_electrs(target) + + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + history = await client.get_history(scripthash) + assert len(history) >= 1 + assert history[0].tx_hash + assert history[0].height > 0 + + utxos = await client.listunspent(scripthash) + assert len(utxos) == 1 + assert utxos[0].value == 250_000 + + raw_tx = await client.get_transaction(utxos[0].tx_hash) + assert isinstance(raw_tx, str) and len(raw_tx) > 0 + + +@pytest.mark.anyio +async def test_subscribe_scripthash_payment(): + address = new_address() + scripthash = scripthash_from_scriptpubkey(get_scriptpubkey(address)) + + received: list = [] + event = asyncio.Event() + + def on_change(params: list) -> None: + received.append(params) + event.set() + + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + initial_status = await client.subscribe_scripthash( + scripthash, callback=on_change + ) + assert initial_status is None # fresh address has no history + + send_to_address(address, 777_000) + target = mine_blocks(1) + await wait_for_electrs(target) + + await asyncio.wait_for(event.wait(), timeout=10) + + assert len(received) == 1 + assert received[0][0] == scripthash # first param is the scripthash + assert received[0][1] is not None # second param is the new status hash + + balance = await client.get_balance(scripthash) + assert balance.confirmed == 777_000 + + +@pytest.mark.anyio +async def test_subscribe_headers(): + async with ElectrumClient(f"tcp://{ELECTRS_HOST}:{ELECTRS_PORT}") as client: + notifications: list = [] + tip = await client.subscribe_headers(callback=lambda p: notifications.append(p)) + height_before = tip.height + + target = mine_blocks(1) + await wait_for_electrs(target) + + assert await client.get_height() == height_before + 1 diff --git a/tests/regtest/test_real_invoice.py b/tests/regtest/test_real_invoice.py index cb65b9937..6fbed901a 100644 --- a/tests/regtest/test_real_invoice.py +++ b/tests/regtest/test_real_invoice.py @@ -13,10 +13,13 @@ from lnbits.core.services import ( fee_reserve_total, get_balance_delta, ) -from lnbits.core.services.payments import pay_invoice, update_wallet_balance +from lnbits.core.services.payments import ( + pay_invoice, + update_wallet_balance, +) from lnbits.core.services.users import create_user_account from lnbits.exceptions import PaymentError -from lnbits.tasks import create_task, wait_for_paid_invoices +from lnbits.task_manager import task_manager from lnbits.wallets import get_funding_source from ..helpers import is_fake, is_regtest @@ -160,12 +163,11 @@ async def test_create_real_invoice( assert not payment_status["paid"] on_paid_mock = mocker.AsyncMock() - create_task(wait_for_paid_invoices("test_create_invoice", on_paid_mock)()) + task_manager.register_invoice_listener(on_paid_mock, "test_create_invoice") pay_real_invoice(invoice["bolt11"]) await asyncio.sleep(1) - assert on_paid_mock.call_count == 1 payment = on_paid_mock.call_args_list[0][0][0] @@ -393,12 +395,11 @@ async def test_receive_real_invoice_set_pending_and_check_state( assert not payment_status["paid"] on_paid_mock = mocker.AsyncMock() - create_task(wait_for_paid_invoices("test_create_invoice", on_paid_mock)()) + task_manager.register_invoice_listener(on_paid_mock, "test_create_invoice") pay_real_invoice(invoice["bolt11"]) await asyncio.sleep(1) - assert on_paid_mock.call_count == 1 payment = on_paid_mock.call_args_list[0][0][0] @@ -412,6 +413,8 @@ async def test_receive_real_invoice_set_pending_and_check_state( payment_status = response.json() assert payment_status["paid"] + assert payment + # set the incoming invoice to pending payment.status = PaymentState.PENDING await update_payment(payment) diff --git a/tests/unit/test_app_extensions.py b/tests/unit/test_app_extensions.py new file mode 100644 index 000000000..3561a8006 --- /dev/null +++ b/tests/unit/test_app_extensions.py @@ -0,0 +1,71 @@ +import json +from pathlib import Path + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.app import build_all_installed_extensions_list +from lnbits.settings import Settings + + +@pytest.mark.anyio +async def test_wasm_extension_discovery_uses_configured_directory( + tmp_path: Path, + settings: Settings, + mocker: MockerFixture, +): + discovered_id = "discovered_wasm" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + original_installed_ids = set(settings.lnbits_installed_extensions_ids) + + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + Path(settings.lnbits_extensions_path, "extensions").mkdir(parents=True) + _write_wasm_config(settings.wasm_extensions_dir / discovered_id, discovered_id) + + mocker.patch( + "lnbits.app.get_installed_extensions", + mocker.AsyncMock(return_value=[]), + ) + create_mock = mocker.patch( + "lnbits.app.create_installed_extension", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.app.get_db_version", + mocker.AsyncMock(return_value=None), + ) + migrate_mock = mocker.patch( + "lnbits.app.migrate_extension_database", + mocker.AsyncMock(), + ) + + try: + installed = await build_all_installed_extensions_list() + finally: + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + settings.lnbits_installed_extensions_ids = original_installed_ids + + assert [extension.id for extension in installed] == [discovered_id] + create_mock.assert_awaited_once() + assert create_mock.await_args is not None + assert create_mock.await_args.args[0].id == discovered_id + migrate_mock.assert_awaited_once() + + +def _write_wasm_config(ext_dir: Path, ext_id: str) -> None: + ext_dir.mkdir(parents=True) + (ext_dir / "config.json").write_text( + json.dumps( + { + "id": ext_id, + "name": ext_id, + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + } + ), + encoding="utf-8", + ) diff --git a/tests/unit/test_cache.py b/tests/unit/test_cache.py index f7ec4a906..d08a1c03d 100644 --- a/tests/unit/test_cache.py +++ b/tests/unit/test_cache.py @@ -1,8 +1,12 @@ import asyncio +from time import time import pytest +from pytest_mock.plugin import MockerFixture -from lnbits.utils.cache import Cache +from lnbits.settings import Settings +from lnbits.task_manager import task_manager +from lnbits.utils.cache import Cache, Cached key = "foo" value = "bar" @@ -10,11 +14,10 @@ value = "bar" @pytest.fixture async def cache(): - cache = Cache(interval=0.1) - - task = asyncio.create_task(cache.invalidate_forever()) + cache = Cache() + task = task_manager.create_permanent_task(cache.invalidate_cache, interval=1) yield cache - task.cancel() + task_manager.cancel_task(task) @pytest.mark.anyio @@ -28,13 +31,13 @@ async def test_cache_get_set(cache): @pytest.mark.anyio async def test_cache_expiry(cache): # gets expired by `get` call - cache.set(key, value, expiry=0.01) - await asyncio.sleep(0.02) + cache.set(key, value, expiry=1) + await asyncio.sleep(2) assert not cache.get(key) # gets expired by invalidation task - cache.set(key, value, expiry=0.1) - await asyncio.sleep(0.2) + cache.set(key, value, expiry=1) + await asyncio.sleep(2) assert key not in cache._values assert not cache.get(key) @@ -59,3 +62,65 @@ async def test_cache_coro(cache): await cache.save_result(test, key="test") result = await cache.save_result(test, key="test") assert result == called == 1 + + +def test_cached_older_than(): + cached = Cached(value="value", expiry=time() - 5) + + assert cached.older_than(1) is True + assert cached.older_than(10) is False + + +@pytest.mark.anyio +async def test_cache_value_returns_cached_metadata(cache): + cache.set(key, value, expiry=1) + + cached = cache.value(key) + + assert cached is not None + assert cached.value == value + assert cached.expiry > time() + + +@pytest.mark.anyio +async def test_cache_pop_expired_returns_default(cache): + cache.set(key, value, expiry=0.01) + await asyncio.sleep(0.02) + + assert cache.pop(key, default="fallback") == "fallback" + + +@pytest.mark.anyio +async def test_invalidate_forever_logs_and_recovers_from_errors( + settings: Settings, mocker: MockerFixture +): + test_cache = Cache() + original_running = settings.lnbits_running + calls = 0 + + original_invalidate = test_cache.invalidate_cache + + async def fake_invalidate(): + nonlocal calls + calls += 1 + if calls == 1: + raise RuntimeError("boom") + settings.lnbits_running = False + await original_invalidate() + + mocker.patch.object(test_cache, "invalidate_cache", side_effect=fake_invalidate) + mocker.patch("lnbits.task_manager.asyncio.sleep") + logger_error = mocker.patch("lnbits.task_manager.logger.error") + + bg_task = None + try: + settings.lnbits_running = True + bg_task = task_manager.create_permanent_task(test_cache.invalidate_cache) + await bg_task.task + finally: + settings.lnbits_running = original_running + if bg_task: + task_manager.cancel_task(bg_task) + + assert logger_error.called + assert calls == 2 diff --git a/tests/unit/test_crud_users.py b/tests/unit/test_crud_users.py index 6427ce619..e52f4ef41 100644 --- a/tests/unit/test_crud_users.py +++ b/tests/unit/test_crud_users.py @@ -2,10 +2,16 @@ from uuid import uuid4 import pytest -from lnbits.core.crud.users import get_user_from_account -from lnbits.core.crud.wallets import delete_wallet, get_wallets -from lnbits.core.models.users import Account -from lnbits.core.services.users import create_user_account +from lnbits.core.crud.users import ( + create_account, + delete_account, + get_accounts, + get_user_from_account, +) +from lnbits.core.crud.wallets import delete_wallet, force_delete_wallet, get_wallets +from lnbits.core.models.users import Account, AccountFilters +from lnbits.core.services.users import create_user_account, create_user_account_no_ckeck +from lnbits.db import Filter, Filters, Operator @pytest.mark.anyio @@ -36,3 +42,151 @@ async def test_get_user_from_account_is_wallet_created(): assert ( len(user.wallets) == 1 ), "A new wallet should be created for the user if none exist after deletion" + + +@pytest.mark.anyio +async def test_get_accounts_success_flow(): + # Create a new account + username = f"user_{uuid4().hex[:8]}" + account = Account( + id=uuid4().hex, + username=username, + email=f"{username}@lnbits.com", + ) + await create_account(account) + # Should return the created account + filters = Filters[AccountFilters](filters=[], model=AccountFilters) + filters.sortby = "created_at" + filters.direction = "desc" + page = await get_accounts(filters=filters) + assert page.total >= 1 + found = any(a.username == username for a in page.data) + assert found + await delete_account(account.id) + + +@pytest.mark.anyio +async def test_get_accounts_with_wallet_id_filter(): + # Create account and wallet + username = f"user_{uuid4().hex[:8]}" + account = Account( + id=uuid4().hex, + username=username, + email=f"{username}@lnbits.com", + ) + await create_user_account_no_ckeck(account) + + wallets = await get_wallets(account.id, deleted=False) + assert wallets + wallet = wallets[0] + # Filter by wallet_id + filters = Filters[AccountFilters]( + filters=[ + Filter( + field="wallet_id", + op=Operator.EQ, + model=AccountFilters, + values={"wallet_id__0": wallet.id}, + ) + ], + model=AccountFilters, + ) + page = await get_accounts(filters=filters) + assert page.total == 1 + assert page.data[0].id == account.id + await delete_account(account.id) + + +@pytest.mark.anyio +async def test_get_accounts_wallet_id_not_found(): + + filters = Filters[AccountFilters]( + filters=[ + Filter( + field="wallet_id", + op=Operator.EQ, + model=AccountFilters, + values={"wallet_id__0": uuid4().hex}, + ) + ], + model=AccountFilters, + ) + page = await get_accounts(filters=filters) + assert page.total == 0 + assert page.data == [] + + +@pytest.mark.anyio +async def test_get_accounts_empty_filters(): + # Should not raise, should return a Page + page = await get_accounts() + assert hasattr(page, "data") + assert hasattr(page, "total") + + +@pytest.mark.anyio +async def test_get_accounts_with_deleted_wallet(): + # Create account and wallet, then delete wallet + username = f"user_{uuid4().hex[:8]}" + account = Account( + id=uuid4().hex, + username=username, + email=f"{username}@lnbits.com", + ) + await create_user_account_no_ckeck(account) + + wallets = await get_wallets(account.id, deleted=False) + assert wallets + wallet = wallets[0] + await delete_wallet(user_id=account.id, wallet_id=wallet.id) + + filters = Filters[AccountFilters]( + filters=[ + Filter( + field="wallet_id", + op=Operator.EQ, + model=AccountFilters, + values={"wallet_id__0": wallet.id}, + ) + ], + model=AccountFilters, + ) + page = await get_accounts(filters=filters) + assert page.total == 1 + assert page.data[0].id == account.id + + await force_delete_wallet(wallet_id=wallet.id) + + filters = Filters[AccountFilters]( + filters=[ + Filter( + field="wallet_id", + op=Operator.EQ, + model=AccountFilters, + values={"wallet_id__0": wallet.id}, + ) + ], + model=AccountFilters, + ) + page = await get_accounts(filters=filters) + assert page.total == 0 + assert page.data == [] + + +@pytest.mark.anyio +async def test_get_accounts_group_by_and_pagination(): + # Create multiple accounts + accounts = [] + for _ in range(3): + username = f"user_{uuid4().hex[:8]}" + account = Account( + id=uuid4().hex, + username=username, + email=f"{username}@lnbits.com", + ) + await create_user_account_no_ckeck(account) + accounts.append(account) + filters = Filters[AccountFilters](model=AccountFilters, limit=2, offset=0) + page = await get_accounts(filters=filters) + assert page.total >= 3 + assert len(page.data) <= 2 diff --git a/tests/unit/test_crypto_aes.py b/tests/unit/test_crypto_aes.py index 3e098afde..bd0b7ae5d 100644 --- a/tests/unit/test_crypto_aes.py +++ b/tests/unit/test_crypto_aes.py @@ -1,6 +1,15 @@ -import pytest +from base64 import b64encode +from hashlib import sha256 -from lnbits.utils.crypto import AESCipher +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.utils.crypto import ( + AESCipher, + fake_privkey, + random_secret_and_hash, + verify_preimage, +) @pytest.mark.anyio @@ -18,3 +27,83 @@ async def test_aes_encrypt_decrypt(key): encrypted_text = aes.encrypt(original_text.encode()) decrypted_text = aes.decrypt(encrypted_text) assert original_text == decrypted_text + + +def test_random_secret_and_hash(): + secret, payment_hash = random_secret_and_hash(16) + + assert len(secret) == 32 + assert payment_hash == sha256(bytes.fromhex(secret)).hexdigest() + + +def test_fake_privkey_is_deterministic(): + assert fake_privkey("secret") == fake_privkey("secret") + assert fake_privkey("secret") != fake_privkey("other-secret") + + +def test_verify_preimage_success_and_failure(): + preimage = "00" * 32 + payment_hash = sha256(bytes.fromhex(preimage)).hexdigest() + + assert verify_preimage(preimage, payment_hash) is True + assert verify_preimage(preimage, "0" * 64) is False + + +@pytest.mark.anyio +async def test_aes_urlsafe_encrypt_decrypt(): + aes = AESCipher("normal_string") + + encrypted_text = aes.encrypt(b"url-safe", urlsafe=True) + + assert aes.decrypt(encrypted_text, urlsafe=True) == "url-safe" + + +def test_aes_derive_iv_and_key_requires_eight_byte_salt(): + aes = AESCipher("normal_string") + + with pytest.raises(ValueError, match="Salt must be 8 bytes"): + aes.derive_iv_and_key(b"short") + + +def test_aes_decrypt_rejects_invalid_salt_prefix(): + aes = AESCipher("normal_string") + encrypted_text = b64encode(b"NotSalted__12345678ciphertext").decode() + + with pytest.raises(ValueError, match="Invalid salt."): + aes.decrypt(encrypted_text) + + +def test_aes_decrypt_raises_for_cipher_errors(mocker: MockerFixture): + aes = AESCipher("normal_string") + fake_cipher = mocker.Mock() + fake_cipher.decrypt.side_effect = RuntimeError("boom") + + mocker.patch.object( + aes, + "derive_iv_and_key", + return_value=(b"0" * aes.block_size, b"1" * 32), + ) + mocker.patch("lnbits.utils.crypto.AES.new", return_value=fake_cipher) + + encrypted_text = b64encode(b"Salted__12345678ciphertext").decode() + + with pytest.raises(ValueError, match="Could not decrypt payload"): + aes.decrypt(encrypted_text) + + +def test_aes_decrypt_raises_for_invalid_utf8_output(mocker: MockerFixture): + aes = AESCipher("normal_string") + fake_cipher = mocker.Mock() + fake_cipher.decrypt.return_value = b"\xff\x01" + + mocker.patch.object( + aes, + "derive_iv_and_key", + return_value=(b"0" * aes.block_size, b"1" * 32), + ) + mocker.patch("lnbits.utils.crypto.AES.new", return_value=fake_cipher) + + encrypted_text = b64encode(b"Salted__12345678ciphertext").decode() + + with pytest.raises(ValueError, match="invalid UTF-8 data"): + aes.decrypt(encrypted_text) diff --git a/tests/unit/test_db.py b/tests/unit/test_db.py index 94b4239f7..e0bf10bbf 100644 --- a/tests/unit/test_db.py +++ b/tests/unit/test_db.py @@ -1,4 +1,4 @@ -from datetime import date, timezone +from datetime import date, datetime, timezone import pytest @@ -9,9 +9,41 @@ from lnbits.core.crud import ( get_wallet_for_key, ) from lnbits.core.crud.payments import get_payment -from lnbits.core.models import CreateInvoice +from lnbits.core.models import CreateInvoice, PaymentFilters from lnbits.core.services.payments import create_wallet_invoice -from lnbits.db import POSTGRES +from lnbits.db import POSTGRES, SQLITE, Filter, Filters + + +@pytest.mark.parametrize( + ("db_type", "lower_statement", "upper_statement"), + [ + ( + POSTGRES, + "(time >= to_timestamp(:time__0_0))", + "(time <= to_timestamp(:time__1_0))", + ), + (SQLITE, "(time >= :time__0_0)", "(time <= :time__1_0)"), + ], +) +def test_datetime_filter_uses_database_timestamp_placeholder( + monkeypatch, db_type, lower_statement, upper_statement +): + monkeypatch.setattr("lnbits.db.DB_TYPE", db_type) + lower_bound = Filter.parse_query( + "time[ge]", ["2026-06-16T00:00:00"], PaymentFilters, 0 + ) + upper_bound = Filter.parse_query( + "time[le]", ["2026-06-23T23:59:59"], PaymentFilters, 1 + ) + filters = Filters(filters=[lower_bound, upper_bound], model=PaymentFilters) + values = filters.values() + + assert isinstance(values["time__0_0"], datetime) + assert values["time__0_0"] == datetime(2026, 6, 16) + assert values["time__1_0"] == datetime(2026, 6, 23, 23, 59, 59) + assert filters.where() == f"WHERE {lower_statement} AND {upper_statement}" + assert lower_bound.statement == lower_statement + assert upper_bound.statement == upper_statement @pytest.mark.anyio diff --git a/tests/unit/test_db_fetch_page.py b/tests/unit/test_db_fetch_page.py index 58a032592..6cca11fa7 100644 --- a/tests/unit/test_db_fetch_page.py +++ b/tests/unit/test_db_fetch_page.py @@ -1,30 +1,51 @@ import pytest +from lnbits.db import Filters from tests.helpers import DbTestModel +TEST_DB_FETCH_PAGE_ROWS: tuple[dict[str, str], ...] = ( + {"id": "1", "name": "Alice", "value": "foo"}, + {"id": "2", "name": "Bob", "value": "bar"}, + {"id": "3", "name": "Carol", "value": "bar"}, + {"id": "4", "name": "Dave", "value": "bar"}, + {"id": "5", "name": "Dave", "value": "foo"}, + {"id": "6", "name": "Eve", "value": "foo"}, + {"id": "7", "name": "Frank", "value": "bar"}, + {"id": "8", "name": "Grace", "value": "foo"}, + {"id": "9", "name": "Heidi", "value": "bar"}, + {"id": "10", "name": "Ivan", "value": "foo"}, + {"id": "11", "name": "Judy", "value": "bar"}, + {"id": "12", "name": "Mallory", "value": "foo"}, + {"id": "13", "name": "Niaj", "value": "bar"}, + {"id": "14", "name": "Olivia", "value": "foo"}, + {"id": "15", "name": "Peggy", "value": "bar"}, + {"id": "16", "name": "Rupert", "value": "foo"}, + {"id": "17", "name": "Sybil", "value": "bar"}, + {"id": "18", "name": "Trent", "value": "foo"}, + {"id": "19", "name": "Victor", "value": "bar"}, + {"id": "20", "name": "Walter", "value": "foo"}, + {"id": "21", "name": "Zoe", "value": "bar"}, +) + @pytest.fixture(scope="session") async def fetch_page(db): await db.execute("DROP TABLE IF EXISTS test_db_fetch_page") - await db.execute( - """ + await db.execute(""" CREATE TABLE test_db_fetch_page ( id TEXT PRIMARY KEY, value TEXT NOT NULL, name TEXT NOT NULL ) - """ - ) - await db.execute( - """ - INSERT INTO test_db_fetch_page (id, name, value) VALUES - ('1', 'Alice', 'foo'), - ('2', 'Bob', 'bar'), - ('3', 'Carol', 'bar'), - ('4', 'Dave', 'bar'), - ('5', 'Dave', 'foo') - """ - ) + """) + for row in TEST_DB_FETCH_PAGE_ROWS: + await db.execute( + """ + INSERT INTO test_db_fetch_page (id, name, value) + VALUES (:id, :name, :value) + """, + row, + ) yield await db.execute("DROP TABLE test_db_fetch_page") @@ -37,8 +58,35 @@ async def test_db_fetch_page_simple(fetch_page, db): ) assert row - assert row.total == 5 - assert len(row.data) == 5 + assert row.total == len(TEST_DB_FETCH_PAGE_ROWS) + assert len(row.data) == Filters().limit + + +@pytest.mark.anyio +async def test_db_fetch_page_limit_zero_returns_all(fetch_page, db): + row = await db.fetch_page( + query="select * from test_db_fetch_page", + filters=Filters(limit=0), + model=DbTestModel, + ) + + assert row + assert row.total == len(TEST_DB_FETCH_PAGE_ROWS) + assert len(row.data) == len(TEST_DB_FETCH_PAGE_ROWS) + + +@pytest.mark.anyio +async def test_db_fetch_page_limit(fetch_page, db): + limit = 5 + row = await db.fetch_page( + query="select * from test_db_fetch_page", + filters=Filters(limit=limit), + model=DbTestModel, + ) + + assert row + assert row.total == len(TEST_DB_FETCH_PAGE_ROWS) + assert len(row.data) == limit @pytest.mark.anyio @@ -49,7 +97,7 @@ async def test_db_fetch_page_group_by(fetch_page, db): group_by=["name"], ) assert row - assert row.total == 4 + assert row.total == len({test_row["name"] for test_row in TEST_DB_FETCH_PAGE_ROWS}) @pytest.mark.anyio @@ -60,7 +108,9 @@ async def test_db_fetch_page_group_by_multiple(fetch_page, db): group_by=["value", "name"], ) assert row - assert row.total == 5 + assert row.total == len( + {(test_row["value"], test_row["name"]) for test_row in TEST_DB_FETCH_PAGE_ROWS} + ) @pytest.mark.anyio diff --git a/tests/unit/test_decorators.py b/tests/unit/test_decorators.py index 5aa425e58..7a5da134b 100644 --- a/tests/unit/test_decorators.py +++ b/tests/unit/test_decorators.py @@ -11,7 +11,17 @@ from pydantic.types import UUID4 from lnbits.core.crud.users import delete_account from lnbits.core.models import User from lnbits.core.models.users import AccessTokenPayload -from lnbits.decorators import check_user_exists +from lnbits.decorators import ( + _extension_id_from_request_path, + access_token_payload, + check_access_token, + check_admin_ui, + check_extension_builder, + check_first_install, + check_user_exists, + optional_user_id, +) +from lnbits.helpers import create_access_token from lnbits.settings import AuthMethods, Settings, settings @@ -136,3 +146,92 @@ async def test_check_user_exists_with_user_id_only_not_allowed(user_alan: User): await check_user_exists(request, access_token=None, usr=UUID4(user_alan.id)) assert exc_info.value.status_code == 401 assert exc_info.value.detail == "Missing user ID or access token." + + +@pytest.mark.anyio +async def test_check_access_token_prefers_available_source(): + assert await check_access_token("header", "cookie", "bearer") == "header" + assert await check_access_token(None, "cookie", "bearer") == "cookie" + assert await check_access_token(None, None, "bearer") == "bearer" + + +@pytest.mark.anyio +async def test_access_token_payload_success_and_missing(settings: Settings): + token = create_access_token({"sub": "alice", "usr": "user-id"}) + + payload = await access_token_payload(token) + + assert isinstance(payload, AccessTokenPayload) + assert payload.sub == "alice" + assert payload.usr == "user-id" + + with pytest.raises(HTTPException, match="Missing access token."): + await access_token_payload(None) + + +@pytest.mark.anyio +async def test_optional_user_id_uses_user_id_or_access_token( + user_alan: User, settings: Settings +): + settings.auth_allowed_methods = [AuthMethods.user_id_only.value] + request = Request({"type": "http", "path": "/wallet", "method": "GET"}) + + assert ( + await optional_user_id(request, access_token=None, usr=UUID4(user_alan.id)) + == user_alan.id + ) + + settings.auth_allowed_methods = [] + token = create_access_token({"sub": user_alan.username, "usr": user_alan.id}) + assert await optional_user_id(request, access_token=token, usr=None) == user_alan.id + assert await optional_user_id(request, access_token=None, usr=None) is None + + +@pytest.mark.anyio +async def test_check_admin_ui_and_first_install(settings: Settings): + original_admin_ui = settings.lnbits_admin_ui + original_first_install = settings.first_install + try: + settings.lnbits_admin_ui = False + with pytest.raises(HTTPException, match="Admin UI is disabled."): + await check_admin_ui() + + settings.lnbits_admin_ui = True + await check_admin_ui() + + settings.first_install = False + with pytest.raises( + HTTPException, match="Super user account has already been configured." + ): + await check_first_install() + + settings.first_install = True + await check_first_install() + finally: + settings.lnbits_admin_ui = original_admin_ui + settings.first_install = original_first_install + + +@pytest.mark.anyio +async def test_check_extension_builder_requires_admin_when_disabled_for_users( + settings: Settings, user_alan: User +): + settings.lnbits_extensions_builder_activate_non_admins = False + + with pytest.raises( + HTTPException, match="Extension Builder is disabled for non admin users." + ): + await check_extension_builder(user_alan) + + admin_user = user_alan.copy(deep=True) + admin_user.admin = True + await check_extension_builder(admin_user) + + +def test_extension_id_from_request_path_handles_wasm_routes(): + assert _extension_id_from_request_path("/ext/wasm_demo") == "wasm_demo" + assert _extension_id_from_request_path("/ext/wasm_demo/page/1") == "wasm_demo" + assert ( + _extension_id_from_request_path("/api/v1/ext/wasm_demo/invoices") == "wasm_demo" + ) + assert _extension_id_from_request_path("/lnurlp/api/v1") == "lnurlp" diff --git a/tests/unit/test_exchange_rates.py b/tests/unit/test_exchange_rates.py index 9b3263b49..e373fbfa3 100644 --- a/tests/unit/test_exchange_rates.py +++ b/tests/unit/test_exchange_rates.py @@ -1,8 +1,54 @@ +from unittest.mock import AsyncMock + +import httpx +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.settings import ExchangeRateProvider, Settings from lnbits.utils.exchange_rates import ( + allowed_currencies, apply_trimmed_mean_filter, + btc_price, + btc_rates, + fiat_amount_as_satoshis, + get_fiat_rate_and_price_satoshis, + get_fiat_rate_satoshis, + satoshis_amount_as_fiat, ) +class MockResponse: + def __init__( + self, *, text: str = "", json_data=None, error: Exception | None = None + ): + self.text = text + self._json_data = json_data or {} + self._error = error + + def raise_for_status(self): + if self._error: + raise self._error + + def json(self): + return self._json_data + + +class MockAsyncClient: + def __init__(self, response: MockResponse): + self.response = response + self.calls: list[tuple[str, int]] = [] + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + async def get(self, url: str, timeout: int = 3): + self.calls.append((url, timeout)) + return self.response + + class TestApplyTrimmedMeanFilter: """Test the trimmed mean filtering function""" @@ -123,3 +169,168 @@ class TestApplyTrimmedMeanFilter: # Should keep the rate at exactly 1% deviation assert len(result) == 2 assert result == rates + + +def test_allowed_currencies_returns_full_list_by_default(settings: Settings): + original_allowed_currencies = settings.lnbits_allowed_currencies + try: + settings.lnbits_allowed_currencies = [] + + currencies = allowed_currencies() + + assert "USD" in currencies + assert "EUR" in currencies + finally: + settings.lnbits_allowed_currencies = original_allowed_currencies + + +def test_allowed_currencies_respects_allow_list(settings: Settings): + original_allowed_currencies = settings.lnbits_allowed_currencies + try: + settings.lnbits_allowed_currencies = ["USD", "EUR"] + + assert allowed_currencies() == ["EUR", "USD"] + finally: + settings.lnbits_allowed_currencies = original_allowed_currencies + + +@pytest.mark.anyio +async def test_btc_rates_rejects_disallowed_currency(settings: Settings): + original_allowed_currencies = settings.lnbits_allowed_currencies + try: + settings.lnbits_allowed_currencies = ["EUR"] + + with pytest.raises(ValueError, match="Currency 'usd' not allowed."): + await btc_rates("usd") + finally: + settings.lnbits_allowed_currencies = original_allowed_currencies + + +@pytest.mark.anyio +async def test_btc_rates_parses_plain_text_response( + settings: Settings, mocker: MockerFixture +): + provider = ExchangeRateProvider( + name="PlainText", + api_url="https://plain.test/{TO}", + path="", + ) + client = MockAsyncClient(MockResponse(text="12,345.67")) + mocker.patch.object(settings, "lnbits_allowed_currencies", []) + mocker.patch.object(settings, "lnbits_exchange_rate_providers", [provider]) + mocker.patch("lnbits.utils.exchange_rates.httpx.AsyncClient", return_value=client) + + rates = await btc_rates("usd") + + assert rates == [("PlainText", 12345.67)] + assert client.calls == [("https://plain.test/USD", 3)] + + +@pytest.mark.anyio +async def test_btc_rates_parses_json_path_response( + settings: Settings, mocker: MockerFixture +): + provider = ExchangeRateProvider( + name="JsonProvider", + api_url="https://json.test/{TO}", + path="$.data.rates.{TO}", + ) + client = MockAsyncClient( + MockResponse(json_data={"data": {"rates": {"USD": "54321.0"}}}) + ) + mocker.patch.object(settings, "lnbits_allowed_currencies", []) + mocker.patch.object(settings, "lnbits_exchange_rate_providers", [provider]) + mocker.patch("lnbits.utils.exchange_rates.httpx.AsyncClient", return_value=client) + + rates = await btc_rates("usd") + + assert rates == [("JsonProvider", 54321.0)] + assert client.calls == [("https://json.test/USD", 3)] + + +@pytest.mark.anyio +async def test_btc_rates_skips_unsupported_and_failing_providers( + settings: Settings, mocker: MockerFixture +): + unsupported = ExchangeRateProvider( + name="Unsupported", + api_url="https://unsupported.test/{TO}", + path="$.price", + exclude_to=["usd"], + ) + failing = ExchangeRateProvider( + name="Failing", + api_url="https://failing.test/{TO}", + path="$.price", + ) + client = MockAsyncClient(MockResponse(error=httpx.HTTPError("boom"))) + mocker.patch.object(settings, "lnbits_allowed_currencies", []) + mocker.patch.object( + settings, "lnbits_exchange_rate_providers", [unsupported, failing] + ) + mocker.patch("lnbits.utils.exchange_rates.httpx.AsyncClient", return_value=client) + + assert await btc_rates("usd") == [] + + +@pytest.mark.anyio +async def test_btc_price_handles_empty_single_and_multiple_rates(mocker: MockerFixture): + mocker.patch( + "lnbits.utils.exchange_rates.btc_price_from_aggregator", + AsyncMock(return_value=None), + ) + mocker.patch("lnbits.utils.exchange_rates.btc_rates", AsyncMock(return_value=[])) + assert await btc_price("usd") == 0.0 + + mocker.patch( + "lnbits.utils.exchange_rates.btc_rates", + AsyncMock(return_value=[("Only", 50000.0)]), + ) + assert await btc_price("usd") == 50000.0 + + mocker.patch( + "lnbits.utils.exchange_rates.btc_rates", + AsyncMock(return_value=[("A", 40000.0), ("B", 50000.0)]), + ) + assert await btc_price("usd") == 45000.0 + + +@pytest.mark.anyio +async def test_rate_and_amount_conversion_helpers(mocker: MockerFixture): + cache_result = AsyncMock(return_value=50000.0) + mocker.patch("lnbits.utils.exchange_rates.cache.save_result", cache_result) + + rate, price = await get_fiat_rate_and_price_satoshis("usd") + + assert price == 50000.0 + assert rate == 2000.0 + cache_result.assert_awaited_once() + + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_and_price_satoshis", + AsyncMock(return_value=(1250.0, 80000.0)), + ) + assert await get_fiat_rate_satoshis("usd") == 1250.0 + + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_satoshis", + AsyncMock(return_value=100.0), + ) + assert await fiat_amount_as_satoshis(2.5, "usd") == 250 + assert await satoshis_amount_as_fiat(500, "usd") == 5.0 + + +@pytest.mark.anyio +async def test_amount_conversion_helpers_raise_when_rate_missing( + mocker: MockerFixture, +): + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_satoshis", + AsyncMock(return_value=0.0), + ) + + with pytest.raises(ValueError, match="Could not get exchange rate for usd."): + await fiat_amount_as_satoshis(1, "usd") + + with pytest.raises(ValueError, match="Could not get exchange rate for usd."): + await satoshis_amount_as_fiat(100, "usd") diff --git a/tests/unit/test_fiat_providers.py b/tests/unit/test_fiat_providers.py index 26ef66661..baf73000d 100644 --- a/tests/unit/test_fiat_providers.py +++ b/tests/unit/test_fiat_providers.py @@ -1,28 +1,126 @@ import hashlib import hmac +import json import time +from base64 import b64encode from unittest.mock import AsyncMock import pytest from pytest_mock.plugin import MockerFixture -from lnbits.core.crud.payments import get_payments +from lnbits.core.crud.payments import get_payment, get_payments from lnbits.core.crud.users import get_user from lnbits.core.crud.wallets import create_wallet -from lnbits.core.models.payments import CreateInvoice, PaymentState +from lnbits.core.models.payments import CreateInvoice, Payment, PaymentState from lnbits.core.models.users import User from lnbits.core.models.wallets import Wallet from lnbits.core.services import check_payment_status, payments from lnbits.core.services.fiat_providers import ( + check_fiat_status, + check_revolut_signature, + check_square_signature, check_stripe_signature, handle_fiat_payment_confirmation, + verify_paypal_webhook, +) +from lnbits.core.services.fiat_providers import ( + test_connection as fiat_provider_connection, ) from lnbits.core.services.users import create_user_account -from lnbits.fiat.base import FiatInvoiceResponse, FiatPaymentStatus +from lnbits.fiat.base import ( + FiatInvoiceResponse, + FiatPaymentStatus, + FiatStatusResponse, + FiatSubscriptionPaymentOptions, +) +from lnbits.fiat.revolut import REVOLUT_WEBHOOK_EVENTS, RevolutWallet +from lnbits.fiat.square import SquareWallet from lnbits.settings import Settings from tests.helpers import get_random_string +class MockHTTPResponse: + def __init__(self, json_data=None, error: Exception | None = None): + self._json_data = json_data or {} + self._error = error + + def raise_for_status(self): + if self._error: + raise self._error + + def json(self): + return self._json_data + + +class MockHTTPClient: + def __init__(self, responses: list[MockHTTPResponse]): + self._responses = responses + self.calls: list[tuple[str, dict]] = [] + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + async def post(self, path: str, **kwargs): + self.calls.append((path, kwargs)) + return self._responses.pop(0) + + async def get(self, path: str, **kwargs): + self.calls.append((path, kwargs)) + return self._responses.pop(0) + + +@pytest.fixture(autouse=True) +def fiat_provider_test_settings(settings: Settings): + original_lnbits_running = settings.lnbits_running + original_allowed_currencies = settings.lnbits_allowed_currencies + original_paypal_enabled = settings.paypal_enabled + original_square_enabled = settings.square_enabled + original_square_api_endpoint = settings.square_api_endpoint + original_square_access_token = settings.square_access_token + original_square_location_id = settings.square_location_id + original_square_api_version = settings.square_api_version + original_square_payment_success_url = settings.square_payment_success_url + original_square_payment_webhook_url = settings.square_payment_webhook_url + original_square_webhook_signature_key = settings.square_webhook_signature_key + original_square_limits = settings.square_limits.copy(deep=True) + original_revolut_enabled = settings.revolut_enabled + original_revolut_api_endpoint = settings.revolut_api_endpoint + original_revolut_api_secret_key = settings.revolut_api_secret_key + original_revolut_api_version = settings.revolut_api_version + original_revolut_payment_success_url = settings.revolut_payment_success_url + original_revolut_payment_webhook_url = settings.revolut_payment_webhook_url + original_revolut_webhook_signing_secret = settings.revolut_webhook_signing_secret + original_revolut_limits = settings.revolut_limits.copy(deep=True) + settings.lnbits_allowed_currencies = [] + settings.paypal_enabled = False + settings.square_enabled = False + settings.revolut_enabled = False + yield + settings.lnbits_running = original_lnbits_running + settings.lnbits_allowed_currencies = original_allowed_currencies + settings.paypal_enabled = original_paypal_enabled + settings.square_enabled = original_square_enabled + settings.square_api_endpoint = original_square_api_endpoint + settings.square_access_token = original_square_access_token + settings.square_location_id = original_square_location_id + settings.square_api_version = original_square_api_version + settings.square_payment_success_url = original_square_payment_success_url + settings.square_payment_webhook_url = original_square_payment_webhook_url + settings.square_webhook_signature_key = original_square_webhook_signature_key + settings.square_limits = original_square_limits + settings.revolut_enabled = original_revolut_enabled + settings.revolut_api_endpoint = original_revolut_api_endpoint + settings.revolut_api_secret_key = original_revolut_api_secret_key + settings.revolut_api_version = original_revolut_api_version + settings.revolut_payment_success_url = original_revolut_payment_success_url + settings.revolut_payment_webhook_url = original_revolut_payment_webhook_url + settings.revolut_webhook_signing_secret = original_revolut_webhook_signing_secret + settings.revolut_limits = original_revolut_limits + + @pytest.mark.anyio async def test_create_wallet_fiat_invoice_missing_provider(): invoice_data = CreateInvoice( @@ -85,6 +183,39 @@ async def test_create_wallet_fiat_invoice_allowed_users( assert user assert user.fiat_providers == [] + settings.square_enabled = True + settings.square_limits.allowed_users = [] + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == ["square"] + + settings.square_limits.allowed_users = ["some_other_user_id"] + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == [] + + settings.square_limits.allowed_users.append(to_user.id) + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == ["square"] + + settings.square_enabled = False + settings.revolut_enabled = True + settings.revolut_limits.allowed_users = [] + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == ["revolut"] + + settings.revolut_limits.allowed_users = ["some_other_user_id"] + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == [] + + settings.revolut_limits.allowed_users.append(to_user.id) + user = await get_user(to_user.id) + assert user + assert user.fiat_providers == ["revolut"] + @pytest.mark.anyio async def test_create_wallet_fiat_invoice_fiat_limits_fail( @@ -235,6 +366,1097 @@ async def test_create_wallet_fiat_invoice_success( assert status.success is True +@pytest.mark.anyio +async def test_create_wallet_square_fiat_invoice_success( + to_wallet: Wallet, settings: Settings, mocker: MockerFixture +): + settings.square_enabled = True + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_limits.service_min_amount_sats = 0 + settings.square_limits.service_max_amount_sats = 0 + settings.square_limits.service_faucet_wallet_id = None + + invoice_data = CreateInvoice( + unit="USD", amount=1.0, memo="Test", fiat_provider="square" + ) + fiat_mock_response = FiatInvoiceResponse( + ok=True, + checking_id="order_123", + payment_request="https://square.link/u/session_123", + ) + + mocker.patch( + "lnbits.fiat.SquareWallet.create_invoice", + AsyncMock(return_value=fiat_mock_response), + ) + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_satoshis", + AsyncMock(return_value=1000), + ) + payment = await payments.create_fiat_invoice(to_wallet.id, invoice_data) + assert payment.status == PaymentState.PENDING + assert payment.fiat_provider == "square" + assert payment.extra.get("fiat_checking_id") == fiat_mock_response.checking_id + assert payment.checking_id.startswith("fiat_square_order_123") + + +@pytest.mark.anyio +async def test_square_wallet_create_invoice(settings: Settings): + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + settings.square_payment_success_url = "https://lnbits.example/success" + + wallet = SquareWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "payment_link": { + "order_id": "ORDER123", + "url": "https://square.link/u/abc123", + } + } + ) + ] + ) + wallet.client = client # type: ignore[assignment] + + response = await wallet.create_invoice( + amount=1.23, + payment_hash="hash123", + currency="USD", + memo="LNbits Square invoice", + extra={"checkout": {"metadata": {"source": "test"}}}, + ) + + assert response.ok is True + assert response.checking_id == "order_ORDER123" + assert response.payment_request == "https://square.link/u/abc123" + assert client.calls[0][0] == "/v2/online-checkout/payment-links" + payload = client.calls[0][1]["json"] + assert payload["idempotency_key"] == "hash123" + assert payload["order"]["location_id"] == "LOC123" + assert payload["order"]["metadata"]["payment_hash"] == "hash123" + assert payload["order"]["metadata"]["alan_action"] == "invoice" + assert payload["order"]["metadata"]["source"] == "test" + assert payload["order"]["line_items"][0]["base_price_money"]["amount"] == 123 + + +@pytest.mark.anyio +async def test_square_wallet_create_subscription(settings: Settings): + settings.lnbits_running = False + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + settings.square_payment_success_url = "https://lnbits.example/success" + + wallet = SquareWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "object": { + "type": "SUBSCRIPTION_PLAN_VARIATION", + "id": "PLAN_VARIATION_123", + "subscription_plan_variation_data": { + "phases": [ + { + "ordinal": 0, + "pricing": { + "type": "STATIC", + "price_money": { + "amount": 1500, + "currency": "USD", + }, + }, + } + ] + }, + } + } + ), + MockHTTPResponse( + json_data={ + "payment_link": { + "id": "plink_123", + "url": "https://square.link/u/sub_123", + } + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + memo="Monthly Gold", + tag="gold", + extra={"link": "link-1"}, + success_url="https://lnbits.example/subscription-success", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is True + assert response.checkout_session_url == "https://square.link/u/sub_123" + assert response.subscription_request_id is not None + assert client.calls[0][0] == "/v2/catalog/object/PLAN_VARIATION_123" + assert client.calls[1][0] == "/v2/online-checkout/payment-links" + payload = client.calls[1][1]["json"] + assert payload["idempotency_key"] == response.subscription_request_id + assert payload["quick_pay"]["location_id"] == "LOC123" + assert payload["quick_pay"]["price_money"] == {"amount": 1500, "currency": "USD"} + assert payload["checkout_options"] == { + "redirect_url": "https://lnbits.example/subscription-success", + "subscription_plan_id": "PLAN_VARIATION_123", + } + metadata = json.loads(payload["payment_note"]) + assert metadata[:3] == ["wallet_1", "gold", response.subscription_request_id] + assert metadata[3:] == ["link-1", "Monthly Gold"] + + +@pytest.mark.anyio +async def test_square_wallet_create_subscription_from_plan_id(settings: Settings): + settings.lnbits_running = False + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + settings.square_payment_success_url = "https://lnbits.example/success" + + wallet = SquareWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "object": { + "type": "SUBSCRIPTION_PLAN", + "id": "PLAN123", + "subscription_plan_data": { + "name": "LNbits Test Weekly Personal Plan", + "subscription_plan_variations": [ + { + "type": "SUBSCRIPTION_PLAN_VARIATION", + "id": "PLAN_VARIATION_123", + "subscription_plan_variation_data": { + "name": "LNbits Test Weekly Personal Plan", + "phases": [ + { + "uid": "PHASE123", + "cadence": "WEEKLY", + "ordinal": 0, + "pricing": {"type": "RELATIVE"}, + } + ], + "subscription_plan_id": "PLAN123", + }, + } + ], + "eligible_item_ids": ["ITEM123"], + "all_items": False, + }, + } + } + ), + MockHTTPResponse( + json_data={ + "object": { + "type": "ITEM", + "id": "ITEM123", + "item_data": { + "name": "LNbits Test Weekly Personal Plan", + "variations": [ + { + "type": "ITEM_VARIATION", + "id": "ITEM_VARIATION_123", + "item_variation_data": { + "item_id": "ITEM123", + "name": "Regular", + "pricing_type": "FIXED_PRICING", + "price_money": { + "amount": 1500, + "currency": "USD", + }, + }, + } + ], + }, + } + } + ), + MockHTTPResponse( + json_data={ + "payment_link": { + "id": "plink_123", + "url": "https://square.link/u/sub_123", + } + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + response = await wallet.create_subscription( + "PLAN123", + 1, + FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + memo="Weekly Plan", + success_url="https://lnbits.example/success", + ), + ) + + assert response.ok is True + assert client.calls[0][0] == "/v2/catalog/object/PLAN123" + assert client.calls[1][0] == "/v2/catalog/object/ITEM123" + assert client.calls[2][0] == "/v2/online-checkout/payment-links" + payload = client.calls[2][1]["json"] + assert payload["quick_pay"]["price_money"] == {"amount": 1500, "currency": "USD"} + assert payload["checkout_options"] == { + "redirect_url": "https://lnbits.example/success", + "subscription_plan_id": "PLAN_VARIATION_123", + } + + +@pytest.mark.anyio +async def test_square_wallet_create_subscription_invoice(settings: Settings): + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + + wallet = SquareWallet() + + response = await wallet.create_invoice( + amount=15, + payment_hash="hash123", + currency="USD", + memo="Square subscription payment", + extra={ + "fiat_method": "subscription", + "subscription": { + "checking_id": "payment_PAYMENT123", + "payment_request": "https://square.example/invoice", + }, + }, + ) + + assert response.ok is True + assert response.checking_id == "payment_PAYMENT123" + assert response.payment_request == "https://square.example/invoice" + + +@pytest.mark.anyio +async def test_square_wallet_cancel_subscription(settings: Settings): + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + + wallet = SquareWallet() + client = MockHTTPClient([MockHTTPResponse(json_data={"subscription": {}})]) + wallet.client = client # type: ignore[assignment] + + response = await wallet.cancel_subscription("SUBSCRIPTION123", "wallet_1") + + assert response.ok is True + assert client.calls[0][0] == "/v2/subscriptions/SUBSCRIPTION123/cancel" + + +@pytest.mark.anyio +async def test_square_wallet_cancel_subscription_by_request_id( + settings: Settings, mocker: MockerFixture +): + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + + wallet = SquareWallet() + client = MockHTTPClient([MockHTTPResponse(json_data={"subscription": {}})]) + wallet.client = client # type: ignore[assignment] + payment = Payment( + checking_id="fiat_square_payment_PAYMENT123", + payment_hash="hash123", + wallet_id="wallet_1", + amount=1000, + fee=0, + bolt11="lnbc1square", + fiat_provider="square", + extra={"subscription_request_id": "REQUEST123"}, + external_id="SUBSCRIPTION123", + ) + get_payments_mock = mocker.patch( + "lnbits.core.crud.payments.get_payments", + AsyncMock(side_effect=[[], [payment]]), + ) + + response = await wallet.cancel_subscription("REQUEST123", "wallet_1") + + assert response.ok is True + assert client.calls[0][0] == "/v2/subscriptions/SUBSCRIPTION123/cancel" + assert get_payments_mock.await_count == 2 + + +@pytest.mark.anyio +async def test_square_wallet_get_invoice_status(settings: Settings): + settings.square_api_endpoint = "https://connect.squareupsandbox.com" + settings.square_access_token = "square-token" + settings.square_location_id = "LOC123" + settings.square_api_version = "2026-01-22" + + wallet = SquareWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "order": { + "id": "ORDER123", + "state": "COMPLETED", + "tenders": [{"payment_id": "PAYMENT123"}], + } + } + ), + MockHTTPResponse(json_data={"payment": {"status": "COMPLETED"}}), + ] + ) + wallet.client = client # type: ignore[assignment] + + status = await wallet.get_invoice_status("fiat_square_order_ORDER123") + + assert status.success is True + assert client.calls[0][0] == "/v2/orders/ORDER123" + assert client.calls[1][0] == "/v2/payments/PAYMENT123" + + +@pytest.mark.anyio +async def test_create_wallet_revolut_fiat_invoice_success( + to_wallet: Wallet, settings: Settings, mocker: MockerFixture +): + settings.revolut_enabled = True + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_limits.service_min_amount_sats = 0 + settings.revolut_limits.service_max_amount_sats = 0 + settings.revolut_limits.service_faucet_wallet_id = None + + invoice_data = CreateInvoice( + unit="USD", amount=1.0, memo="Test", fiat_provider="revolut" + ) + fiat_mock_response = FiatInvoiceResponse( + ok=True, + checking_id="order_ORDER123", + payment_request="https://checkout.revolut.com/payment-link/ORDER123", + ) + + mocker.patch( + "lnbits.fiat.RevolutWallet.create_invoice", + AsyncMock(return_value=fiat_mock_response), + ) + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_satoshis", + AsyncMock(return_value=1000), + ) + payment = await payments.create_fiat_invoice(to_wallet.id, invoice_data) + assert payment.status == PaymentState.PENDING + assert payment.fiat_provider == "revolut" + assert payment.extra.get("fiat_checking_id") == fiat_mock_response.checking_id + assert payment.checking_id.startswith("fiat_revolut_order_ORDER123") + + +@pytest.mark.anyio +async def test_revolut_wallet_create_invoice(settings: Settings): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + settings.revolut_payment_success_url = "https://lnbits.example/success" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/abc123", + } + ) + ] + ) + wallet.client = client # type: ignore[assignment] + + response = await wallet.create_invoice( + amount=1.23, + payment_hash="hash123", + currency="USD", + memo="LNbits Revolut invoice", + extra={"checkout": {"metadata": {"source": "test"}}}, + ) + + assert response.ok is True + assert response.checking_id == "order_ORDER123" + assert ( + response.payment_request == "https://checkout.revolut.com/payment-link/abc123" + ) + assert client.calls[0][0] == "/api/orders" + payload = client.calls[0][1]["json"] + assert payload["amount"] == 123 + assert payload["currency"] == "USD" + assert payload["metadata"]["payment_hash"] == "hash123" + assert payload["metadata"]["alan_action"] == "invoice" + assert payload["metadata"]["source"] == "test" + assert payload["redirect_url"] == "https://lnbits.example/success" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_invoice_uses_currency_minor_units( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "id": "ORDER_JPY", + "checkout_url": "https://checkout.revolut.com/payment-link/jpy", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER_KWD", + "checkout_url": "https://checkout.revolut.com/payment-link/kwd", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + await wallet.create_invoice( + amount=123, + payment_hash="hash_jpy", + currency="JPY", + ) + await wallet.create_invoice( + amount=1.234, + payment_hash="hash_kwd", + currency="KWD", + ) + + assert client.calls[0][1]["json"]["amount"] == 123 + assert client.calls[1][1]["json"]["amount"] == 1234 + + +@pytest.mark.anyio +async def test_revolut_wallet_get_invoice_status(settings: Settings): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient([MockHTTPResponse(json_data={"state": "COMPLETED"})]) + wallet.client = client # type: ignore[assignment] + + status = await wallet.get_invoice_status("fiat_revolut_order_ORDER123") + + assert status.success is True + assert client.calls[0][0] == "/api/orders/ORDER123" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription(settings: Settings): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + settings.revolut_payment_success_url = "https://lnbits.example/subscription-success" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "customers": [ + { + "id": "CUSTOMER123", + "email": "customer@example.com", + } + ] + } + ), + MockHTTPResponse( + json_data={ + "id": "SUBSCRIPTION123", + "setup_order_id": "ORDER123", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_123", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + memo="Monthly Gold", + tag="gold", + customer_email="customer@example.com", + extra={"link": "link-1"}, + success_url="https://lnbits.example/subscription-success", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + subscription_request_id = payment_options.subscription_request_id + assert response.ok is True + assert response.subscription_request_id == "SUBSCRIPTION123" + assert subscription_request_id is not None + assert ( + response.checkout_session_url + == "https://checkout.revolut.com/payment-link/sub_123" + ) + assert client.calls[0][0] == "/api/customers" + assert client.calls[0][1]["params"] == {"limit": 500} + assert client.calls[0][1]["timeout"] == 30 + assert client.calls[1][0] == "/api/subscriptions" + payload = client.calls[1][1]["json"] + assert payload["plan_variation_id"] == "PLAN_VARIATION_123" + assert payload["customer_id"] == "CUSTOMER123" + assert client.calls[1][1]["timeout"] == 30 + assert client.calls[1][1]["headers"]["Idempotency-Key"] == (subscription_request_id) + assert payload["setup_order_redirect_url"] == ( + "https://lnbits.example/subscription-success" + ) + reference = json.loads(payload["external_reference"]) + assert reference["wallet_id"] == "wallet_1" + assert reference["tag"] == "gold" + assert reference["subscription_request_id"] == subscription_request_id + assert reference["memo"] == "Monthly Gold" + assert reference["extra"]["link"] == "link-1" + assert client.calls[2][0] == "/api/orders/ORDER123" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription_uses_customer_email( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "customers": [ + { + "id": "CUSTOMER123", + "email": "customer@example.com", + } + ] + } + ), + MockHTTPResponse( + json_data={ + "id": "SUBSCRIPTION123", + "setup_order_id": "ORDER123", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_123", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + customer_email="customer@example.com", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is True + assert client.calls[0][0] == "/api/customers" + assert client.calls[0][1]["params"] == {"limit": 500} + assert client.calls[0][1]["timeout"] == 30 + assert client.calls[1][0] == "/api/subscriptions" + assert client.calls[1][1]["json"]["customer_id"] == "CUSTOMER123" + assert client.calls[1][1]["timeout"] == 30 + assert client.calls[2][0] == "/api/orders/ORDER123" + assert client.calls[2][1]["timeout"] == 30 + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription_uses_paginated_customer_email( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "next_page_token": "PAGE2", + "customers": [ + { + "id": "OTHER_CUSTOMER", + "email": "other@example.com", + } + ], + } + ), + MockHTTPResponse( + json_data={ + "customers": [ + { + "id": "CUSTOMER123", + "email": "customer@example.com", + } + ], + } + ), + MockHTTPResponse( + json_data={ + "id": "SUBSCRIPTION123", + "setup_order_id": "ORDER123", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_123", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + customer_email="customer@example.com", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is True + assert client.calls[0][0] == "/api/customers" + assert client.calls[0][1]["params"] == {"limit": 500} + assert client.calls[1][0] == "/api/customers" + assert client.calls[1][1]["params"] == { + "limit": 500, + "page_token": "PAGE2", + } + assert client.calls[1][1]["timeout"] == 30 + assert client.calls[2][0] == "/api/subscriptions" + assert client.calls[2][1]["json"]["customer_id"] == "CUSTOMER123" + assert client.calls[3][0] == "/api/orders/ORDER123" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription_creates_customer(settings: Settings): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "next_page_token": "PAGE2", + "customers": [ + { + "id": "OTHER_CUSTOMER", + "email": "other@example.com", + } + ], + } + ), + MockHTTPResponse(json_data={"customers": []}), + MockHTTPResponse(json_data={"id": "CUSTOMER123"}), + MockHTTPResponse( + json_data={ + "id": "SUBSCRIPTION123", + "setup_order_id": "ORDER123", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_123", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + customer_email="customer@example.com", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is True + assert client.calls[0][0] == "/api/customers" + assert client.calls[0][1]["params"] == {"limit": 500} + assert client.calls[1][0] == "/api/customers" + assert client.calls[1][1]["params"] == { + "limit": 500, + "page_token": "PAGE2", + } + assert client.calls[2][0] == "/api/customers" + assert client.calls[2][1]["json"] == {"email": "customer@example.com"} + assert client.calls[2][1]["timeout"] == 30 + assert client.calls[3][0] == "/api/subscriptions" + assert client.calls[3][1]["json"]["customer_id"] == "CUSTOMER123" + assert client.calls[4][0] == "/api/orders/ORDER123" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription_stops_customer_lookup_after_20_pages( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + customer_pages = [ + MockHTTPResponse( + json_data={ + "next_page_token": f"PAGE{page + 2}", + "customers": [ + { + "id": f"OTHER_CUSTOMER_{page}", + "email": f"other-{page}@example.com", + } + ], + } + ) + for page in range(20) + ] + client = MockHTTPClient( + [ + *customer_pages, + MockHTTPResponse(json_data={"id": "CUSTOMER123"}), + MockHTTPResponse( + json_data={ + "id": "SUBSCRIPTION123", + "setup_order_id": "ORDER123", + } + ), + MockHTTPResponse( + json_data={ + "id": "ORDER123", + "checkout_url": "https://checkout.revolut.com/payment-link/sub_123", + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions( + wallet_id="wallet_1", + customer_email="customer@example.com", + ) + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is True + assert [call[0] for call in client.calls[:20]] == ["/api/customers"] * 20 + assert client.calls[0][1]["params"] == {"limit": 500} + assert client.calls[19][1]["params"] == { + "limit": 500, + "page_token": "PAGE20", + } + assert client.calls[20][0] == "/api/customers" + assert client.calls[20][1]["json"] == {"email": "customer@example.com"} + assert client.calls[21][0] == "/api/subscriptions" + assert client.calls[21][1]["json"]["customer_id"] == "CUSTOMER123" + assert client.calls[22][0] == "/api/orders/ORDER123" + + +@pytest.mark.anyio +async def test_revolut_wallet_create_subscription_requires_customer_email( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient([]) + wallet.client = client # type: ignore[assignment] + + payment_options = FiatSubscriptionPaymentOptions(wallet_id="wallet_1") + + response = await wallet.create_subscription( + "PLAN_VARIATION_123", 1, payment_options + ) + + assert response.ok is False + assert response.error_message == "Revolut subscriptions require customer_email." + assert client.calls == [] + + +@pytest.mark.anyio +async def test_revolut_wallet_cancel_subscription(settings: Settings): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "external_reference": json.dumps({"wallet_id": "wallet_1"}), + } + ), + MockHTTPResponse(json_data={}), + ] + ) + wallet.client = client # type: ignore[assignment] + + response = await wallet.cancel_subscription("SUBSCRIPTION123", "wallet_1") + + assert response.ok is True + assert client.calls[0][0] == "/api/subscriptions/SUBSCRIPTION123" + assert client.calls[1][0] == "/api/subscriptions/SUBSCRIPTION123/cancel" + + +@pytest.mark.anyio +async def test_revolut_wallet_cancel_subscription_checks_wallet_id( + settings: Settings, +): + settings.revolut_api_endpoint = "https://sandbox-merchant.revolut.com" + settings.revolut_api_secret_key = "revolut-secret" + settings.revolut_api_version = "2026-04-20" + + wallet = RevolutWallet() + client = MockHTTPClient( + [ + MockHTTPResponse( + json_data={ + "external_reference": json.dumps({"wallet_id": "wallet_2"}), + } + ), + ] + ) + wallet.client = client # type: ignore[assignment] + + response = await wallet.cancel_subscription("SUBSCRIPTION123", "wallet_1") + + assert response.ok is False + assert response.error_message == "Subscription not found." + assert client.calls == [ + ( + "/api/subscriptions/SUBSCRIPTION123", + {"timeout": 30}, + ) + ] + + +@pytest.mark.anyio +async def test_revolut_wallet_create_webhook(mocker: MockerFixture): + client = MockHTTPClient( + [ + MockHTTPResponse({"webhooks": []}), + MockHTTPResponse( + { + "id": "webhook_1", + "url": "https://lnbits.example/api/v1/callback/revolut", + "events": REVOLUT_WEBHOOK_EVENTS, + "signing_secret": "whsec_1", + } + ), + ] + ) + async_client = mocker.patch("lnbits.fiat.revolut.httpx.AsyncClient") + async_client.return_value = client + + response = await RevolutWallet.create_webhook( + url="https://lnbits.example/api/v1/callback/revolut", + endpoint="https://sandbox-merchant.revolut.com", + api_secret_key="revolut-secret", + api_version="2026-04-20", + ) + + assert response["signing_secret"] == "whsec_1" + async_client.assert_called_once() + assert async_client.call_args.kwargs["base_url"] == ( + "https://sandbox-merchant.revolut.com" + ) + assert async_client.call_args.kwargs["headers"]["Authorization"] == ( + "Bearer revolut-secret" + ) + assert client.calls == [ + ( + "/api/webhooks", + { + "timeout": 30, + }, + ), + ( + "/api/webhooks", + { + "json": { + "url": "https://lnbits.example/api/v1/callback/revolut", + "events": REVOLUT_WEBHOOK_EVENTS, + }, + "timeout": 30, + }, + ), + ] + + +@pytest.mark.anyio +async def test_revolut_wallet_reuses_existing_webhook(mocker: MockerFixture): + client = MockHTTPClient( + [ + MockHTTPResponse( + { + "webhooks": [ + { + "id": "webhook_1", + "url": "https://lnbits.example/api/v1/callback/revolut", + "events": REVOLUT_WEBHOOK_EVENTS, + "signing_secret": "whsec_1", + } + ] + } + ) + ] + ) + async_client = mocker.patch("lnbits.fiat.revolut.httpx.AsyncClient") + async_client.return_value = client + + response = await RevolutWallet.create_webhook( + url="https://lnbits.example/api/v1/callback/revolut", + endpoint="https://sandbox-merchant.revolut.com", + api_secret_key="revolut-secret", + api_version="2026-04-20", + ) + + assert response["already_exists"] is True + assert response["signing_secret"] == "whsec_1" + assert client.calls == [ + ( + "/api/webhooks", + { + "timeout": 30, + }, + ) + ] + + +@pytest.mark.anyio +async def test_revolut_wallet_rejects_local_webhook_url(): + with pytest.raises(ValueError, match="clearnet URL"): + await RevolutWallet.create_webhook( + url="http://localhost:5000/api/v1/callback/revolut", + endpoint="https://sandbox-merchant.revolut.com", + api_secret_key="revolut-secret", + api_version="2026-04-20", + ) + + +def test_check_revolut_signature(): + payload = b'{"event":"ORDER_COMPLETED","order_id":"ORDER123"}' + timestamp = str(int(time.time() * 1000)) + secret = "revolut-secret" + signed_payload = b"v1." + timestamp.encode() + b"." + payload + sig = "v1=" + hmac.new(secret.encode(), signed_payload, hashlib.sha256).hexdigest() + + check_revolut_signature(payload, sig, timestamp, secret) + + +def test_check_revolut_signature_rejects_payload_only_signature(): + payload = b'{"event":"ORDER_COMPLETED","order_id":"ORDER123"}' + timestamp = str(int(time.time() * 1000)) + secret = "revolut-secret" + sig = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest() + + with pytest.raises(ValueError, match="signature verification failed"): + check_revolut_signature(payload, sig, timestamp, secret) + + +def test_check_revolut_signature_v1_header(): + payload = b'{"event":"ORDER_COMPLETED","order_id":"ORDER123"}' + timestamp = str(int(time.time() * 1000)) + secret = "revolut-secret" + signed_payload = b"v1." + timestamp.encode() + b"." + payload + sig = "v1=" + hmac.new(secret.encode(), signed_payload, hashlib.sha256).hexdigest() + + check_revolut_signature(payload, sig, timestamp, secret) + + +def test_check_revolut_signature_multiple_v1_headers(): + payload = b'{"event":"ORDER_COMPLETED","order_id":"ORDER123"}' + timestamp = str(int(time.time() * 1000)) + secret = "revolut-secret" + signed_payload = b"v1." + timestamp.encode() + b"." + payload + valid_sig = ( + "v1=" + hmac.new(secret.encode(), signed_payload, hashlib.sha256).hexdigest() + ) + sig_header = f"v1=deadbeef,{valid_sig}" + + check_revolut_signature(payload, sig_header, timestamp, secret) + + +def test_check_revolut_signature_docs_vector(mocker: MockerFixture): + payload = ( + b'{"data":{"id":"645a7696-22f3-aa47-9c74-cbae0449cc46",' + b'"new_state":"completed","old_state":"pending",' + b'"request_id":"app_charges-9f5d5eb3-1e06-46c5-b1c0-3914763e0bcb"},' + b'"event":"TransactionStateChanged",' + b'"timestamp":"2023-05-09T16:36:38.028960Z"}' + ) + timestamp = "1683650202360" + secret = "wsk_r59a4HfWVAKycbCaNO1RvgCJec02gRd8" + sig = "v1=bca326fb378d0da7f7c490ad584a8106bab9723d8d9cdd0d50b4c5b3be3837c0" + + # This is a fixed vector straight from Revolut's docs, so its timestamp is + # necessarily in the past. Freeze time to it instead of growing + # tolerance_seconds indefinitely as real time marches on. + mocker.patch( + "lnbits.core.services.fiat_providers.time.time", + return_value=int(timestamp) / 1000, + ) + check_revolut_signature(payload, sig, timestamp, secret) + + check_revolut_signature(payload, sig, timestamp, secret) + + @pytest.mark.anyio async def test_fiat_service_fee(settings: Settings): # settings.stripe_limits.service_min_amount_sats = 0 @@ -424,6 +1646,31 @@ def test_check_stripe_signature_non_utf8_payload(): check_stripe_signature(payload, sig_header, secret) +def test_check_square_signature_success(): + payload = b'{"type":"payment.updated"}' + secret = "signature-key" + notification_url = "https://lnbits.example/api/v1/callback/square" + signature = b64encode( + hmac.new( + key=secret.encode(), + msg=notification_url.encode() + payload, + digestmod=hashlib.sha256, + ).digest() + ).decode() + + check_square_signature(payload, signature, secret, notification_url) + + +def test_check_square_signature_rejects_invalid_signature(): + with pytest.raises(ValueError, match="Square signature verification failed."): + check_square_signature( + b'{"type":"payment.updated"}', + "invalid-signature", + "signature-key", + "https://lnbits.example/api/v1/callback/square", + ) + + # Helper to generate a valid Stripe signature header def _make_stripe_sig_header(payload, secret, timestamp=None): if timestamp is None: @@ -433,3 +1680,237 @@ def _make_stripe_sig_header(payload, secret, timestamp=None): secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() return f"t={timestamp},v1={signature}", timestamp, signature + + +@pytest.mark.anyio +async def test_check_fiat_status_handles_internal_states(mocker: MockerFixture): + pending_payment = Payment( + checking_id="external_payment", + payment_hash="hash_pending", + wallet_id="wallet_id", + amount=1000, + fee=0, + bolt11="bolt11", + status=PaymentState.PENDING, + ) + success_payment = Payment( + checking_id="fiat_success", + payment_hash="hash_success", + wallet_id="wallet_id", + amount=1000, + fee=0, + bolt11="bolt11", + status=PaymentState.SUCCESS, + fiat_provider="stripe", + ) + failed_payment = Payment( + checking_id="fiat_failed", + payment_hash="hash_failed", + wallet_id="wallet_id", + amount=1000, + fee=0, + bolt11="bolt11", + status=PaymentState.FAILED, + fiat_provider="stripe", + ) + + assert (await check_fiat_status(pending_payment)).pending is True + assert (await check_fiat_status(success_payment)).success is True + assert (await check_fiat_status(failed_payment)).failed is True + + provider = mocker.Mock() + provider.get_invoice_status = AsyncMock(return_value=FiatPaymentStatus(paid=True)) + mocker.patch( + "lnbits.core.services.fiat_providers.get_fiat_provider", + AsyncMock(return_value=provider), + ) + queue_put = mocker.patch( + "lnbits.task_manager.task_manager.internal_invoice_queue.put_nowait" + ) + + success_status = await check_fiat_status( + Payment( + checking_id="fiat_pending", + payment_hash="hash_queue", + wallet_id="wallet_id", + amount=1000, + fee=0, + bolt11="bolt11", + status=PaymentState.PENDING, + fiat_provider="stripe", + extra={"fiat_checking_id": "stripe_checking_id"}, + ) + ) + + assert success_status.success is True + queue_put.assert_called_once() + assert queue_put.call_args[0][0].checking_id == "fiat_pending" + + await check_fiat_status( + Payment( + checking_id="fiat_pending_skip", + payment_hash="hash_skip", + wallet_id="wallet_id", + amount=1000, + fee=0, + bolt11="bolt11", + status=PaymentState.SUCCESS, + fiat_provider="stripe", + extra={"fiat_checking_id": "stripe_checking_id"}, + ) + ) + assert queue_put.call_count == 1 + + +@pytest.mark.anyio +async def test_check_fiat_status_persists_successful_payment( + to_wallet: Wallet, settings: Settings, mocker: MockerFixture +): + settings.stripe_enabled = True + settings.stripe_api_secret_key = "mock_sk_test_4eC39HqLyjWDarjtT1zdp7dc" + settings.stripe_limits.service_min_amount_sats = 0 + settings.stripe_limits.service_max_amount_sats = 0 + settings.stripe_limits.service_fee_wallet_id = None + settings.stripe_limits.service_faucet_wallet_id = None + + invoice_data = CreateInvoice( + unit="USD", amount=1.0, memo="Test", fiat_provider="stripe" + ) + fiat_mock_response = FiatInvoiceResponse( + ok=True, + checking_id=f"session_paid_{get_random_string(10)}", + payment_request="https://stripe.com/pay/session_paid", + ) + mocker.patch( + "lnbits.fiat.StripeWallet.create_invoice", + AsyncMock(return_value=fiat_mock_response), + ) + mocker.patch( + "lnbits.utils.exchange_rates.get_fiat_rate_satoshis", + AsyncMock(return_value=1000), + ) + payment = await payments.create_fiat_invoice(to_wallet.id, invoice_data) + assert payment.status == PaymentState.PENDING + + mocker.patch( + "lnbits.fiat.StripeWallet.get_invoice_status", + AsyncMock(return_value=FiatPaymentStatus(paid=True)), + ) + queue_put = mocker.patch( + "lnbits.task_manager.task_manager.internal_invoice_queue.put_nowait" + ) + + status = await check_fiat_status(payment) + + assert status.success is True + assert payment.status == PaymentState.SUCCESS + updated_payment = await get_payment(payment.checking_id) + assert updated_payment.status == PaymentState.SUCCESS + queue_put.assert_called_once_with(payment) + + +@pytest.mark.anyio +async def test_verify_paypal_webhook_requires_configuration(settings: Settings): + settings.paypal_webhook_id = None + + with pytest.raises( + ValueError, match="PayPal webhook cannot be verified. Missing webhook ID." + ): + await verify_paypal_webhook({}, b"{}") + + +@pytest.mark.anyio +async def test_verify_paypal_webhook_requires_headers(settings: Settings): + settings.paypal_webhook_id = "webhook-id" + + with pytest.raises( + ValueError, match="PayPal webhook cannot be verified. Missing headers." + ): + await verify_paypal_webhook({}, b"{}") + + +@pytest.mark.anyio +async def test_verify_paypal_webhook_success(settings: Settings, mocker: MockerFixture): + settings.paypal_webhook_id = "webhook-id" + client = MockHTTPClient( + [ + MockHTTPResponse(json_data={"access_token": "token"}), + MockHTTPResponse(json_data={"verification_status": "SUCCESS"}), + ] + ) + mocker.patch( + "lnbits.core.services.fiat_providers.httpx.AsyncClient", + return_value=client, + ) + + await verify_paypal_webhook( + { + "PAYPAL-TRANSMISSION-ID": "tx-id", + "PAYPAL-TRANSMISSION-TIME": "2024-01-01T00:00:00Z", + "PAYPAL-TRANSMISSION-SIG": "signature", + "PAYPAL-CERT-URL": "https://cert.example.com", + "PAYPAL-AUTH-ALGO": "SHA256withRSA", + }, + b'{"id":"event-1"}', + ) + + assert client.calls[0][0] == "/v1/oauth2/token" + assert client.calls[1][0] == "/v1/notifications/verify-webhook-signature" + assert client.calls[1][1]["headers"]["Authorization"] == "Bearer token" + + +@pytest.mark.anyio +async def test_verify_paypal_webhook_raises_on_failed_verification( + settings: Settings, mocker: MockerFixture +): + settings.paypal_webhook_id = "webhook-id" + client = MockHTTPClient( + [ + MockHTTPResponse(json_data={"access_token": "token"}), + MockHTTPResponse(json_data={"verification_status": "FAILURE"}), + ] + ) + mocker.patch( + "lnbits.core.services.fiat_providers.httpx.AsyncClient", + return_value=client, + ) + + with pytest.raises(ValueError, match="PayPal webhook cannot be verified."): + await verify_paypal_webhook( + { + "PAYPAL-TRANSMISSION-ID": "tx-id", + "PAYPAL-TRANSMISSION-TIME": "2024-01-01T00:00:00Z", + "PAYPAL-TRANSMISSION-SIG": "signature", + "PAYPAL-CERT-URL": "https://cert.example.com", + "PAYPAL-AUTH-ALGO": "SHA256withRSA", + }, + b'{"id":"event-1"}', + ) + + +@pytest.mark.anyio +async def test_test_connection_reports_provider_status(mocker: MockerFixture): + mocker.patch( + "lnbits.core.services.fiat_providers.get_fiat_provider", + AsyncMock(return_value=None), + ) + missing_status = await fiat_provider_connection("stripe") + assert missing_status.success is False + assert missing_status.message == "Fiat provider 'stripe' not found." + + provider = mocker.Mock() + provider.status = AsyncMock( + return_value=FiatStatusResponse(error_message="bad key") + ) + mocker.patch( + "lnbits.core.services.fiat_providers.get_fiat_provider", + AsyncMock(return_value=provider), + ) + error_status = await fiat_provider_connection("stripe") + assert error_status.success is False + assert error_status.message == "Cconnection test failed: bad key" + + provider.status = AsyncMock(return_value=FiatStatusResponse(balance=21.0)) + success_status = await fiat_provider_connection("stripe") + assert success_status.success is True + assert success_status.message == "Connection test successful. Balance: 21.0." diff --git a/tests/unit/test_first_install.py b/tests/unit/test_first_install.py new file mode 100644 index 000000000..478719a90 --- /dev/null +++ b/tests/unit/test_first_install.py @@ -0,0 +1,140 @@ +from pathlib import Path +from uuid import uuid4 + +import pytest + +from lnbits.core.crud import create_account, delete_account, get_account +from lnbits.core.crud.settings import get_settings_field, set_settings_field +from lnbits.core.db import db +from lnbits.core.models import Account, UpdateSuperuserPassword, UserExtra +from lnbits.core.services.users import check_admin_settings +from lnbits.core.views.auth_api import first_install +from lnbits.settings import settings + + +async def _restore_setting_field(field_name: str, original_row) -> None: + if original_row is None: + await db.execute( + "DELETE FROM system_settings WHERE id = :id AND tag = :tag", + {"id": field_name, "tag": "core"}, + ) + return + + await set_settings_field(field_name, original_row.value, original_row.tag) + + +def test_has_first_install_token_changed_requires_a_confirmed_mismatch(): + original_token = settings.first_install_token + original_confirmed = settings.first_install_token_confirmed + + try: + settings.first_install_token = "new-token" + settings.first_install_token_confirmed = "old-token" + assert settings.has_first_install_token_changed() is True + + settings.first_install_token_confirmed = "new-token" + assert settings.has_first_install_token_changed() is False + + settings.first_install_token_confirmed = None + assert settings.has_first_install_token_changed() is False + + settings.first_install_token = None + assert settings.has_first_install_token_changed() is False + finally: + settings.first_install_token = original_token + settings.first_install_token_confirmed = original_confirmed + + +@pytest.mark.anyio +async def test_first_install_confirms_first_install_token(app): + temp_super_user = uuid4().hex + username = f"super_{temp_super_user[:8]}" + original_super_user = settings.super_user + original_first_install = settings.first_install + original_first_install_token = settings.first_install_token + original_first_install_token_confirmed = settings.first_install_token_confirmed + original_confirmed_row = await get_settings_field("first_install_token_confirmed") + + await create_account(Account(id=temp_super_user, extra=UserExtra(provider="env"))) + + try: + settings.super_user = temp_super_user + settings.first_install = True + settings.first_install_token = "expected-token" + settings.first_install_token_confirmed = None + + response = await first_install( + UpdateSuperuserPassword( + username=username, + password="secret1234", + password_repeat="secret1234", + first_install_token="expected-token", + ) + ) + + assert response.status_code == 200 + assert settings.first_install is False + assert settings.first_install_token_confirmed == "expected-token" + + confirmed_row = await get_settings_field("first_install_token_confirmed") + assert confirmed_row is not None + assert confirmed_row.value == "expected-token" + + account = await get_account(temp_super_user) + assert account is not None + assert account.username == username + assert account.extra.provider == "lnbits" + assert account.verify_password("secret1234") + finally: + await _restore_setting_field( + "first_install_token_confirmed", original_confirmed_row + ) + settings.super_user = original_super_user + settings.first_install = original_first_install + settings.first_install_token = original_first_install_token + settings.first_install_token_confirmed = original_first_install_token_confirmed + await delete_account(temp_super_user) + + +@pytest.mark.anyio +async def test_check_admin_settings_clears_persisted_super_user_when_token_changes(app): + temp_super_user = uuid4().hex + original_super_user = settings.super_user + original_first_install = settings.first_install + original_first_install_token = settings.first_install_token + original_first_install_token_confirmed = settings.first_install_token_confirmed + original_super_user_row = await get_settings_field("super_user") + original_confirmed_row = await get_settings_field("first_install_token_confirmed") + super_user_file = Path(settings.lnbits_data_folder) / ".super_user" + + await create_account( + Account(id=temp_super_user, extra=UserExtra(provider="lnbits")) + ) + + try: + await set_settings_field("super_user", temp_super_user) + await set_settings_field("first_install_token_confirmed", "old-token") + + settings.lnbits_admin_ui = True + settings.super_user = temp_super_user + settings.first_install = False + settings.first_install_token = "new-token" + settings.first_install_token_confirmed = "old-token" + + await check_admin_settings() + + super_user_row = await get_settings_field("super_user") + assert super_user_row is not None + assert super_user_row.value + assert settings.first_install is True + finally: + await _restore_setting_field("super_user", original_super_user_row) + await _restore_setting_field( + "first_install_token_confirmed", original_confirmed_row + ) + settings.super_user = original_super_user + settings.first_install = original_first_install + settings.first_install_token = original_first_install_token + settings.first_install_token_confirmed = original_first_install_token_confirmed + super_user_file.write_text(original_super_user) + await delete_account(temp_super_user) diff --git a/tests/unit/test_helpers.py b/tests/unit/test_helpers.py index 924640f80..1d21598d8 100644 --- a/tests/unit/test_helpers.py +++ b/tests/unit/test_helpers.py @@ -1,6 +1,39 @@ -import pytest +import hashlib -from lnbits.helpers import check_callback_url +import jwt +import pytest +from fastapi import FastAPI + +from lnbits.helpers import ( + camel_to_snake, + camel_to_words, + check_callback_url, + create_access_token, + decrypt_internal_message, + download_url, + encrypt_internal_message, + file_hash, + filter_dict_keys, + get_api_routes, + get_db_vendor_name, + is_camel_case, + is_lnbits_version_ok, + is_snake_case, + is_valid_email_address, + is_valid_external_id, + is_valid_label, + is_valid_pubkey, + is_valid_username, + lowercase_first_letter, + normalize_endpoint, + normalize_path, + path_segments, + sha256s, + snake_to_camel, + static_url_for, + url_for, + version_parse, +) from lnbits.settings import Settings @@ -82,3 +115,165 @@ def test_check_callback_url_multiple_rules(settings: Settings): settings.lnbits_callback_url_rules.append("https://localhost:3000") check_callback_url("https://localhost:3000/callback") # should not raise + + +def test_get_db_vendor_name(settings: Settings): + original_database_url = settings.lnbits_database_url + try: + settings.lnbits_database_url = None + assert get_db_vendor_name() == "SQLite" + + settings.lnbits_database_url = "postgres://localhost/db" + assert get_db_vendor_name() == "PostgreSQL" + + settings.lnbits_database_url = "cockroachdb://localhost/db" + assert get_db_vendor_name() == "CockroachDB" + finally: + settings.lnbits_database_url = original_database_url + + +def test_url_helpers(settings: Settings): + assert url_for("/api/v1/wallet", external=False, usr="user") == ( + "/api/v1/wallet?usr=user&" + ) + assert url_for("/api/v1/wallet", external=True, usr="user") == ( + f"http://{settings.host}:{settings.port}/api/v1/wallet?usr=user&" + ) + assert static_url_for("static", "bundle.min.js") == ( + f"/static/bundle.min.js?v={settings.server_startup_time}" + ) + + +@pytest.mark.parametrize( + ("value", "validator"), + [ + ("alice@example.com", is_valid_email_address), + ("alice_1", is_valid_username), + ("Label 1", is_valid_label), + ("external-id-1", is_valid_external_id), + ("a" * 64, is_valid_pubkey), + ], +) +def test_validation_helpers_valid(value, validator): + assert validator(value) is True + + +@pytest.mark.parametrize( + ("value", "validator"), + [ + ("alice@example", is_valid_email_address), + ("_alice", is_valid_username), + ("bad/label", is_valid_label), + ("contains spaces", is_valid_external_id), + ("xyz", is_valid_pubkey), + ], +) +def test_validation_helpers_invalid(value, validator): + assert validator(value) is False + + +def test_is_valid_external_id_rejects_long_and_multiline_values(): + assert is_valid_external_id("x" * 257) is False + assert is_valid_external_id("evil\nnewline") is False + + +def test_access_token_and_internal_message_helpers(settings: Settings): + token = create_access_token( + {"sub": "alice", "usr": None, "email": "alice@example.com"}, + token_expire_minutes=1, + ) + payload = jwt.decode(token, settings.auth_secret_key, ["HS256"]) + assert payload["sub"] == "alice" + assert payload["email"] == "alice@example.com" + assert "usr" not in payload + assert "exp" in payload + + assert encrypt_internal_message(None) is None + assert decrypt_internal_message(None) is None + + encrypted = encrypt_internal_message("secret-message", urlsafe=True) + assert encrypted is not None + assert decrypt_internal_message(encrypted, urlsafe=True) == "secret-message" + + +def test_filter_dict_keys_returns_copy_when_no_filters(): + original = {"a": 1, "b": 2} + + clone = filter_dict_keys(original, None) + filtered = filter_dict_keys(original, ["b", "missing"]) + + assert clone == original + assert clone is not original + assert filtered == {"b": 2} + + +def test_version_helpers(settings: Settings): + original_version = settings.version + try: + settings.version = "1.2.3" + assert version_parse("1.2.3rc4") == version_parse("1.2.3") + assert version_parse("invalid-version") == version_parse("0.0.0") + assert is_lnbits_version_ok("1.2.0", "2.0.0") is True + assert is_lnbits_version_ok("2.0.0", None) is False + assert is_lnbits_version_ok(None, "1.2.3") is False + finally: + settings.version = original_version + + +def test_download_url_rejects_non_http_schemes(tmp_path): + with pytest.raises( + ValueError, match="Invalid URL: ftp://example.com. Must start with 'http'" + ): + download_url("ftp://example.com", tmp_path / "download.bin") + + +def test_file_hash(tmp_path): + filename = tmp_path / "payload.txt" + filename.write_text("hello world") + + assert file_hash(filename) == hashlib.sha256(b"hello world").hexdigest() + + +def test_get_api_routes_extracts_v1_paths(): + app = FastAPI() + + @app.get("/api/v1/payments") + async def payments(): + return {} + + @app.get("/myext/api/v1/settings") + async def extension_settings(): + return {} + + @app.get("/health") + async def health(): + return {} + + routes = get_api_routes([*app.routes, object()]) + + assert routes == { + "/api/v1/payments": "Payments", + "/myext/api/v1": "Myext", + } + + +def test_path_and_case_helpers(): + assert path_segments("/wallet/path") == ["wallet", "path"] + assert normalize_path(None) == "/" + assert normalize_endpoint("example.com/") == "https://example.com" + assert normalize_endpoint("ws://socket.example.com") == "ws://socket.example.com" + assert ( + normalize_endpoint("http://example.com/", add_proto=False) + == "http://example.com" + ) + + assert camel_to_words("CamelCaseName") == "Camel Case Name" + assert camel_to_snake("CamelCaseName") == "camel_case_name" + assert snake_to_camel("snake_case_name") == "snakeCaseName" + assert snake_to_camel("snake_case_name", capitalize_first=True) == "SnakeCaseName" + assert is_camel_case("CamelCase1") is True + assert is_camel_case("camelCase") is False + assert is_snake_case("snake_case_1") is True + assert is_snake_case("SnakeCase") is False + assert lowercase_first_letter("Hello") == "hello" + assert sha256s("hello") == hashlib.sha256(b"hello").hexdigest() diff --git a/tests/unit/test_helpers_query.py b/tests/unit/test_helpers_query.py index 5e2469f4a..da52a29a0 100644 --- a/tests/unit/test_helpers_query.py +++ b/tests/unit/test_helpers_query.py @@ -2,8 +2,10 @@ import json import pytest +from lnbits.core.models.extensions import ExtensionPermission from lnbits.db import ( dict_to_model, + dict_to_submodel, insert_query, model_to_dict, update_query, @@ -83,3 +85,38 @@ async def test_helpers_dict_to_model(): assert m.active is True assert type(m.child) is DbTestModel2 assert type(m.child.child) is DbTestModel + + +@pytest.mark.anyio +async def test_helpers_dict_to_submodel(): + model = dict_to_submodel( + DbTestModel, + '{"id": 9, "name": "submodel", "value": "value"}', + ) + + assert model == DbTestModel(id=9, name="submodel", value="value") + assert dict_to_submodel(DbTestModel, "") is None + assert dict_to_submodel(DbTestModel, "null") is None + + +@pytest.mark.anyio +async def test_helpers_dict_to_model_ignores_unknown_fields(): + model = dict_to_model({**test_dict, "ignored": "field"}, DbTestModel3) + + assert model == test_data + + +@pytest.mark.anyio +async def test_helpers_dict_to_model_handles_list_any_fields(): + model = dict_to_model( + { + "id": "http.request", + "policies": '[{"host": "https://api.example.com"}]', + }, + ExtensionPermission, + ) + + assert model == ExtensionPermission( + id="http.request", + policies=[{"host": "https://api.example.com"}], + ) diff --git a/tests/unit/test_models_extensions.py b/tests/unit/test_models_extensions.py new file mode 100644 index 000000000..cbae15f97 --- /dev/null +++ b/tests/unit/test_models_extensions.py @@ -0,0 +1,187 @@ +import httpx +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.models.extensions import ( + ExtensionConfig, + ExtensionManifestType, + InstallableExtension, + Manifest, + github_api_get, +) +from lnbits.settings import Settings + + +def _mock_json_response(mocker: MockerFixture, url: str, payload: dict): + response = httpx.Response( + 200, + json=payload, + request=httpx.Request("GET", url), + ) + client = mocker.AsyncMock() + client.get.return_value = response + client_context = mocker.MagicMock() + client_context.__aenter__ = mocker.AsyncMock(return_value=client) + client_context.__aexit__ = mocker.AsyncMock(return_value=None) + client_factory = mocker.patch( + "lnbits.core.models.extensions.httpx.AsyncClient", + return_value=client_context, + ) + return client_factory, client + + +def _extension_config_payload() -> dict: + return { + "name": "Test Extension", + "short_description": "Test extension metadata", + "min_lnbits_version": None, + "max_lnbits_version": None, + } + + +@pytest.mark.anyio +async def test_get_installable_extensions_loads_wasm_manifests( + settings: Settings, mocker: MockerFixture +): + regular_manifest_url = "https://example.com/extensions.json" + wasm_manifest_url = "https://example.com/wasm-extensions.json" + settings.lnbits_extensions_manifests = [regular_manifest_url] + settings.lnbits_wasm_extensions_manifests = [ + wasm_manifest_url, + regular_manifest_url, + ] + fetch_manifest = mocker.patch.object( + InstallableExtension, + "fetch_manifest", + mocker.AsyncMock( + side_effect=[ + Manifest(), + Manifest.parse_obj( + { + "extensions": [ + { + "id": "tips", + "name": "Tips", + "version": "0.1.4", + "archive": "https://example.com/tips.zip", + "hash": "tips-hash", + } + ] + } + ), + ] + ), + ) + + extensions = await InstallableExtension._get_installable_extensions() + + assert [extension.id for extension in extensions] == ["tips"] + assert extensions[0].meta + assert extensions[0].meta.latest_release + assert extensions[0].meta.latest_release.manifest_type == ExtensionManifestType.WASM + assert [call.args[0] for call in fetch_manifest.await_args_list] == [ + regular_manifest_url, + wasm_manifest_url, + ] + + +@pytest.mark.anyio +@pytest.mark.parametrize( + "url", + [ + "https://api.github.com/repos/example/extension", + "https://raw.githubusercontent.com/example/extension/main/config.json", + ], +) +async def test_release_config_sends_token_only_to_trusted_github_origins( + settings: Settings, + mocker: MockerFixture, + url: str, +): + settings.lnbits_ext_github_token = "github-secret" + client_factory, client = _mock_json_response( + mocker, url, _extension_config_payload() + ) + + await ExtensionConfig.fetch_release_config(url) + + assert client_factory.call_args.kwargs["headers"]["Authorization"] == ( + "Bearer github-secret" + ) + assert client_factory.call_args.kwargs["follow_redirects"] is False + client.get.assert_awaited_once_with(url) + + +@pytest.mark.anyio +@pytest.mark.parametrize( + "url", + [ + "https://extensions.example/config.json", + "https://api.github.com.evil.example/config.json", + "https://api.github.com./config.json", + "https://raw.githubusercontent.com.evil.example/config.json", + "http://api.github.com/config.json", + "https://api.github.com:444/config.json", + ], +) +async def test_release_config_does_not_send_token_to_untrusted_origins( + settings: Settings, + mocker: MockerFixture, + url: str, +): + settings.lnbits_ext_github_token = "github-secret" + client_factory, client = _mock_json_response( + mocker, url, _extension_config_payload() + ) + + await ExtensionConfig.fetch_release_config(url) + + assert "Authorization" not in client_factory.call_args.kwargs["headers"] + assert client_factory.call_args.kwargs["follow_redirects"] is False + client.get.assert_awaited_once_with(url) + + +@pytest.mark.anyio +async def test_manifest_does_not_send_token_to_untrusted_origin( + settings: Settings, + mocker: MockerFixture, +): + url = "https://extensions.example/manifest.json" + settings.lnbits_ext_github_token = "github-secret" + client_factory, client = _mock_json_response(mocker, url, {}) + + await InstallableExtension.fetch_manifest(url) + + assert "Authorization" not in client_factory.call_args.kwargs["headers"] + assert client_factory.call_args.kwargs["follow_redirects"] is False + client.get.assert_awaited_once_with(url) + + +@pytest.mark.anyio +async def test_release_config_rejects_url_credentials( + settings: Settings, + mocker: MockerFixture, +): + settings.lnbits_ext_github_token = "github-secret" + client_factory = mocker.patch("lnbits.core.models.extensions.httpx.AsyncClient") + + with pytest.raises(ValueError, match="must not contain credentials"): + await ExtensionConfig.fetch_release_config( + "https://github-secret@api.github.com/config.json" + ) + + client_factory.assert_not_called() + + +@pytest.mark.anyio +async def test_github_api_get_rejects_untrusted_origin( + settings: Settings, + mocker: MockerFixture, +): + settings.lnbits_ext_github_token = "github-secret" + client_factory = mocker.patch("lnbits.core.models.extensions.httpx.AsyncClient") + + with pytest.raises(ValueError, match="untrusted origin"): + await github_api_get("https://api.github.com.evil.example/", "Cannot fetch") + + client_factory.assert_not_called() diff --git a/tests/unit/test_pay_invoice.py b/tests/unit/test_pay_invoice.py index e8ad7ce9a..5fdcfdf73 100644 --- a/tests/unit/test_pay_invoice.py +++ b/tests/unit/test_pay_invoice.py @@ -12,10 +12,12 @@ from lnbits.core.crud import create_wallet, get_standalone_payment, get_wallet from lnbits.core.crud.payments import get_payment, get_payments_paginated from lnbits.core.models import PaymentState, Wallet from lnbits.core.services import create_invoice, create_user_account, pay_invoice -from lnbits.core.services.payments import update_wallet_balance +from lnbits.core.services.payments import ( + update_wallet_balance, +) from lnbits.exceptions import InvoiceError, PaymentError from lnbits.settings import Settings -from lnbits.tasks import create_task, wait_for_paid_invoices +from lnbits.task_manager import task_manager from lnbits.wallets.base import PaymentResponse from lnbits.wallets.fake import FakeWallet @@ -231,17 +233,31 @@ async def test_notification_for_internal_payment( ): test_name = "test_notification_for_internal_payment" + # Drain stale items left by session-scoped fixtures (e.g. update_wallet_balance) + while not task_manager.internal_invoice_queue.empty(): + try: + task_manager.internal_invoice_queue.get_nowait() + except asyncio.QueueEmpty: + break + on_paid_mock = mocker.AsyncMock() - create_task(wait_for_paid_invoices(test_name, on_paid_mock)()) + # create_task(internal_invoice_listener()) + + task_manager.register_invoice_listener(on_paid_mock, test_name) + payment = await create_invoice( wallet_id=to_wallet.id, amount=123, memo=test_name, webhook="http://test.404.lnbits.com", ) - await pay_invoice( + paid_payment = await pay_invoice( wallet_id=to_wallet.id, payment_request=payment.bolt11, extra={"tag": "lnurlp"} ) + assert paid_payment.status == PaymentState.SUCCESS.value + assert paid_payment.bolt11 == payment.bolt11 + assert paid_payment.amount == -123_000 + await asyncio.sleep(1) assert on_paid_mock.call_count == 1 @@ -251,8 +267,15 @@ async def test_notification_for_internal_payment( assert _payment.status == PaymentState.SUCCESS.value assert _payment.bolt11 == payment.bolt11 assert _payment.amount == 123_000 + assert _payment.checking_id == payment.checking_id + updated_payment = await get_payment(_payment.checking_id) - assert updated_payment.webhook_status == "404" + assert ( + updated_payment.webhook_status is not None + ), "Webhook should have been called." + assert ( + int(updated_payment.webhook_status) >= 400 + ), "Webhook should have been called and failed." @pytest.mark.anyio @@ -264,6 +287,10 @@ async def test_pay_failed( "lnbits.wallets.FakeWallet.pay_invoice", AsyncMock(return_value=payment_reponse_failed), ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=external_funding_source, + ) external_invoice = await external_funding_source.create_invoice(2101) assert external_invoice.payment_request @@ -352,25 +379,33 @@ async def test_retry_failed_invoice( @pytest.mark.anyio +@pytest.mark.parametrize("returns_checking_id", [True, False]) async def test_pay_external_invoice_pending( from_wallet: Wallet, mocker: MockerFixture, external_funding_source: FakeWallet, settings: Settings, + returns_checking_id: bool, ): settings.lnbits_reserve_fee_min = 1000 # msats invoice_amount = 2103 external_invoice = await external_funding_source.create_invoice(invoice_amount) assert external_invoice.payment_request assert external_invoice.checking_id - - payment_reponse_pending = PaymentResponse( - ok=None, checking_id=external_invoice.checking_id + backend_checking_id = ( + f"backend_{external_invoice.checking_id}" if returns_checking_id else None ) + expected_checking_id = backend_checking_id or external_invoice.checking_id + + payment_reponse_pending = PaymentResponse(ok=None, checking_id=backend_checking_id) mocker.patch( "lnbits.wallets.FakeWallet.pay_invoice", AsyncMock(return_value=payment_reponse_pending), ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=external_funding_source, + ) ws_notification = mocker.patch( "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), @@ -386,7 +421,9 @@ async def test_pay_external_invoice_pending( _payment = await get_standalone_payment(payment.payment_hash) assert _payment assert _payment.status == PaymentState.PENDING.value - assert _payment.checking_id == payment.payment_hash + assert _payment.checking_id == expected_checking_id + assert _payment.payment_hash == external_invoice.checking_id + assert payment.checking_id == expected_checking_id assert _payment.amount == -2103_000 assert _payment.bolt11 == external_invoice.payment_request @@ -542,36 +579,43 @@ async def test_retry_pay_success( @pytest.mark.anyio -async def test_pay_external_invoice_success_bad_checking_id( +async def test_pay_external_invoice_success_with_backend_checking_id( from_wallet: Wallet, mocker: MockerFixture, external_funding_source: FakeWallet ): invoice_amount = 2108 external_invoice = await external_funding_source.create_invoice(invoice_amount) assert external_invoice.payment_request assert external_invoice.checking_id - bad_checking_id = f"bad_{external_invoice.checking_id}" + backend_checking_id = f"backend_{external_invoice.checking_id}" preimage = "0000000000000000000000000000000000000000000000000000000000002108" payment_reponse_success = PaymentResponse( - ok=True, checking_id=bad_checking_id, preimage=preimage + ok=True, checking_id=backend_checking_id, preimage=preimage ) mocker.patch( "lnbits.wallets.FakeWallet.pay_invoice", AsyncMock(return_value=payment_reponse_success), ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=external_funding_source, + ) - with pytest.raises(PaymentError): - await pay_invoice( - wallet_id=from_wallet.id, - payment_request=external_invoice.payment_request, - ) + payment = await pay_invoice( + wallet_id=from_wallet.id, + payment_request=external_invoice.payment_request, + ) - payment = await get_standalone_payment(bad_checking_id) - assert payment is None, "Payment should not be created with bad checking_id" + stored_payment = await get_standalone_payment(external_invoice.checking_id) + assert stored_payment + assert stored_payment.status == PaymentState.SUCCESS.value + assert stored_payment.checking_id == backend_checking_id + assert stored_payment.payment_hash == external_invoice.checking_id + assert payment.checking_id == backend_checking_id @pytest.mark.anyio -async def test_no_checking_id( +async def test_pay_external_invoice_success_without_checking_id( from_wallet: Wallet, mocker: MockerFixture, external_funding_source: FakeWallet ): invoice_amount = 2110 @@ -580,29 +624,33 @@ async def test_no_checking_id( assert external_invoice.checking_id preimage = "0000000000000000000000000000000000000000000000000000000000002110" - payment_reponse_pending = PaymentResponse( + payment_response_success = PaymentResponse( ok=True, checking_id=None, preimage=preimage ) mocker.patch( "lnbits.wallets.FakeWallet.pay_invoice", - AsyncMock(return_value=payment_reponse_pending), + AsyncMock(return_value=payment_response_success), + ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=external_funding_source, ) - with pytest.raises(PaymentError): - await pay_invoice( - wallet_id=from_wallet.id, - payment_request=external_invoice.payment_request, - ) + returned_payment = await pay_invoice( + wallet_id=from_wallet.id, + payment_request=external_invoice.payment_request, + ) payment = await get_standalone_payment(external_invoice.checking_id) assert payment - assert payment.status == PaymentState.FAILED.value + assert payment.status == PaymentState.SUCCESS.value assert payment.checking_id == external_invoice.checking_id assert payment.payment_hash == external_invoice.checking_id assert payment.amount == -2110_000 - assert payment.preimage is None + assert payment.preimage == preimage + assert returned_payment.checking_id == external_invoice.checking_id @pytest.mark.anyio diff --git a/tests/unit/test_services_assets.py b/tests/unit/test_services_assets.py new file mode 100644 index 000000000..c952b7f58 --- /dev/null +++ b/tests/unit/test_services_assets.py @@ -0,0 +1,186 @@ +from io import BytesIO +from uuid import uuid4 + +import pytest +from PIL import Image +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import create_account +from lnbits.core.crud.assets import get_user_asset, get_user_assets_count +from lnbits.core.models import Account +from lnbits.core.services.assets import create_user_asset, thumbnail_from_bytes +from lnbits.settings import Settings +from tests.helpers import make_upload_file + + +@pytest.mark.anyio +async def test_create_user_asset_validates_upload_constraints( + app, settings: Settings, mocker: MockerFixture +): + file_without_type = make_upload_file(b"hello", filename="a.txt", content_type=None) + with pytest.raises(ValueError, match="File must have a content type."): + await create_user_asset("user-1", file_without_type, is_public=False) + + bad_type = make_upload_file( + b"hello", + filename="bad.bin", + content_type="application/x-msdownload", + ) + with pytest.raises( + ValueError, match="File type 'application/x-msdownload' not allowed." + ): + await create_user_asset("user-1", bad_type, is_public=False) + + xsl_upload = make_upload_file( + b"hello", + filename="style.xsl", + content_type="text/xml", + ) + with pytest.raises(ValueError, match="File type 'text/xml' not allowed."): + await create_user_asset("user-1", xsl_upload, is_public=False) + + original_allowed_mime_types = list(settings.lnbits_assets_allowed_mime_types) + try: + settings.lnbits_assets_allowed_mime_types = [ + *original_allowed_mime_types, + "text/xml", + ] + xsl_content = make_upload_file( + b'', + filename="style.xml", + content_type="text/xml", + ) + with pytest.raises(ValueError, match="File type 'text/xml' not allowed."): + await create_user_asset("user-1", xsl_content, is_public=False) + finally: + settings.lnbits_assets_allowed_mime_types = original_allowed_mime_types + + fake_image = make_upload_file( + b"", + filename="fake.png", + content_type="image/png", + ) + with pytest.raises( + ValueError, match="Image file content does not match declared file type." + ): + await create_user_asset("user-1", fake_image, is_public=False) + + original_max_assets = settings.lnbits_max_assets_per_user + original_max_size = settings.lnbits_max_asset_size_mb + original_no_limit_users = list(settings.lnbits_assets_no_limit_users) + try: + settings.lnbits_max_assets_per_user = 1 + settings.lnbits_max_asset_size_mb = 1 + settings.lnbits_assets_no_limit_users = [] + limited_user = await _create_user() + allowed_type = make_upload_file( + _png_bytes(), filename="ok.png", content_type="image/png" + ) + await create_user_asset(limited_user, allowed_type, is_public=False) + + blocked_by_count = make_upload_file( + _png_bytes(), + filename="again.png", + content_type="image/png", + ) + with pytest.raises(ValueError, match="Max upload count of 1 exceeded."): + await create_user_asset(limited_user, blocked_by_count, is_public=False) + + settings.lnbits_max_asset_size_mb = 0.000001 + oversized_user = await _create_user() + large_file = make_upload_file( + _png_bytes(), + filename="ok.png", + content_type="image/png", + ) + with pytest.raises(ValueError, match="File limit of 1e-06MB exceeded."): + await create_user_asset(oversized_user, large_file, is_public=False) + finally: + settings.lnbits_max_assets_per_user = original_max_assets + settings.lnbits_max_asset_size_mb = original_max_size + settings.lnbits_assets_no_limit_users = original_no_limit_users + + +@pytest.mark.anyio +async def test_create_user_asset_success(app, mocker: MockerFixture): + user_id = await _create_user() + mocker.patch( + "lnbits.core.services.assets.thumbnail_from_bytes", + return_value=None, + ) + contents = _png_bytes() + file = make_upload_file(contents, filename="hello.png", content_type="image/png") + + asset = await create_user_asset(user_id, file, is_public=True) + stored = await get_user_asset(user_id, asset.id) + + assert asset.id + assert asset.user_id == user_id + assert asset.name == "hello.png" + assert asset.size_bytes == len(contents) + assert asset.data == contents + assert asset.is_public is True + assert stored is not None + assert stored.id == asset.id + assert stored.data == contents + assert await get_user_assets_count(user_id) == 1 + + +@pytest.mark.anyio +async def test_create_user_asset_stores_detected_image_mime_type(app): + user_id = await _create_user() + buffer = BytesIO() + Image.new("RGB", (32, 32), color="blue").save(buffer, format="JPEG") + file = make_upload_file( + buffer.getvalue(), filename="photo.jpg", content_type="image/jpg" + ) + + asset = await create_user_asset(user_id, file, is_public=True) + stored = await get_user_asset(user_id, asset.id) + + assert asset.mime_type == "image/jpeg" + assert stored is not None + assert stored.mime_type == "image/jpeg" + + +@pytest.mark.anyio +async def test_create_user_asset_rejects_mismatched_image_content(app): + user_id = await _create_user() + buffer = BytesIO() + Image.new("RGB", (32, 32), color="blue").save(buffer, format="JPEG") + file = make_upload_file( + buffer.getvalue(), filename="photo.png", content_type="image/png" + ) + + with pytest.raises( + ValueError, + match=( + "Image file content does not match declared file type. " + "Declared: 'image/png', detected: 'image/jpeg'." + ), + ): + await create_user_asset(user_id, file, is_public=False) + + +def test_thumbnail_from_bytes_success_and_failure(): + image = Image.new("RGB", (512, 512), color="red") + buffer = BytesIO() + image.save(buffer, format="PNG") + + thumbnail = thumbnail_from_bytes(buffer.getvalue()) + + assert thumbnail is not None + assert isinstance(thumbnail.getvalue(), bytes) + assert thumbnail_from_bytes(b"not-an-image") is None + + +async def _create_user() -> str: + user_id = uuid4().hex + await create_account(Account(id=user_id, username=f"user_{user_id[:8]}")) + return user_id + + +def _png_bytes() -> bytes: + buffer = BytesIO() + Image.new("RGB", (32, 32), color="green").save(buffer, format="PNG") + return buffer.getvalue() diff --git a/tests/unit/test_services_extensions.py b/tests/unit/test_services_extensions.py new file mode 100644 index 000000000..a9be5a087 --- /dev/null +++ b/tests/unit/test_services_extensions.py @@ -0,0 +1,957 @@ +import json +import zipfile +from datetime import datetime, timedelta, timezone +from types import SimpleNamespace +from uuid import uuid4 + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import ( + create_installed_extension, + delete_installed_extension, + get_installed_extension, +) +from lnbits.core.models.extensions import ( + Extension, + ExtensionManifestType, + ExtensionPermission, + InstallableExtension, + ReleasePaymentInfo, +) +from lnbits.core.services import extensions as extension_services +from lnbits.core.services.extensions import ( + activate_extension, + attach_wasm_invocation_runtime, + deactivate_extension, + finish_wasm_invocation, + get_current_wasm_invocations, + get_valid_extension, + get_valid_extensions, + install_extension, + record_wasm_invocation_host_call, + start_extension_background_work, + start_wasm_invocation, + stop_extension_background_work, + stop_wasm_invocation, + uninstall_extension, +) +from lnbits.settings import Settings +from tests.helpers import make_installable_extension + + +@pytest.mark.anyio +async def test_install_extension_rejects_incompatible_release( + tmp_path, settings: Settings +): + ext_info = make_installable_extension(f"ext_{uuid4().hex[:8]}", compatible=False) + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + + with pytest.raises(ValueError, match="Incompatible extension version"): + await install_extension(ext_info) + finally: + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + + +@pytest.mark.anyio +async def test_install_extension_creates_new_extension_and_starts_background_work( + tmp_path, settings: Settings, mocker: MockerFixture +): + ext_id = f"ext_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + assert ext_info.meta + assert ext_info.meta.installed_release + ext_info.meta.installed_release.manifest_type = ExtensionManifestType.PYTHON + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + download_mock = mocker.patch.object( + InstallableExtension, "download_archive", mocker.AsyncMock() + ) + extract_mock = mocker.patch.object(InstallableExtension, "extract_archive") + start_mock = mocker.patch( + "lnbits.core.services.extensions.start_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + mocker.patch( + "lnbits.core.services.extensions.core_app_extra.register_new_ext_routes" + ) + mocker.patch( + "lnbits.core.services.extensions.get_db_version", + mocker.AsyncMock(return_value=0), + ) + mocker.patch( + "lnbits.core.services.extensions.migrate_extension_database", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + + extension = await install_extension(ext_info) + await activate_extension(extension) # starts background task + stored = await get_installed_extension(ext_id) + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + + assert extension.code == ext_id + assert stored is not None + download_mock.assert_awaited_once() + extract_mock.assert_called_once() + start_mock.assert_awaited_once_with(ext_id) + + +@pytest.mark.anyio +async def test_install_extension_updates_existing_upgrade_and_preserves_payments( + tmp_path, settings: Settings, mocker: MockerFixture +): + ext_id = f"ext_{uuid4().hex[:8]}" + existing_payment = ReleasePaymentInfo( + pay_link="https://pay.example", + payment_hash="payment-hash", + ) + existing_ext = make_installable_extension(ext_id, payments=[existing_payment]) + updated_ext = make_installable_extension(ext_id, version="2.0.0") + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + extract_mock = mocker.patch.object(InstallableExtension, "extract_archive") + start_mock = mocker.patch( + "lnbits.core.services.extensions.start_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + stop_mock = mocker.patch( + "lnbits.core.services.extensions.stop_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + mocker.patch( + "lnbits.core.services.extensions.core_app_extra.register_new_ext_routes" + ) + mocker.patch( + "lnbits.core.services.extensions.get_db_version", + mocker.AsyncMock(return_value=1), + ) + mocker.patch( + "lnbits.core.services.extensions.migrate_extension_database", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + await create_installed_extension(existing_ext) + extension = await install_extension(updated_ext, skip_download=True) + await activate_extension(extension) # starts background task + stored = await get_installed_extension(ext_id) + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + + assert extension.code == ext_id + assert stored is not None + assert stored.meta is not None + assert stored.meta.payments == [existing_payment] + extract_mock.assert_called_once() + stop_mock.assert_awaited_once_with(ext_id) + start_mock.assert_awaited_once_with(ext_id) + + +@pytest.mark.anyio +async def test_install_wasm_extension_requires_permissions_and_skips_background_work( + tmp_path, + settings: Settings, + mocker: MockerFixture, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + assert ext_info.meta + assert ext_info.meta.installed_release + ext_info.meta.installed_release.manifest_type = ExtensionManifestType.WASM + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + start_mock = mocker.patch( + "lnbits.core.services.extensions.start_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + _write_wasm_extension_archive(ext_info, _wasm_install_config(ext_id)) + wasm_ext_dir = settings.wasm_extensions_dir / ext_id + py_ext_dir = ext_info.ext_dir + upgrade_dir = ext_info.ext_upgrade_dir + + with pytest.raises(ValueError, match="requires permission approval"): + await install_extension(ext_info, skip_download=True) + + granted_permissions = [ + ExtensionPermission( + id="http.request", + policies=[{"host": "https://api.example.com"}], + ) + ] + extension = await install_extension( + ext_info, + skip_download=True, + granted_permissions=granted_permissions, + ) + stored = await get_installed_extension(ext_id) + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + + assert extension.code == ext_id + assert extension.is_wasm is True + assert stored is not None + assert stored.permissions == [ + ExtensionPermission( + id="http.request", + description="Call example API.", + policies=[{"host": "https://api.example.com"}], + ) + ] + start_mock.assert_not_awaited() + assert wasm_ext_dir.is_dir() + assert not py_ext_dir.exists() + assert not upgrade_dir.exists() + + +@pytest.mark.parametrize( + ("manifest_type", "error"), + [ + ( + ExtensionManifestType.PYTHON, + "Python extension manifest cannot install WASM extension", + ), + ( + ExtensionManifestType.WASM, + "WASM extension manifest requires extension_type 'wasm'", + ), + ], +) +@pytest.mark.anyio +async def test_install_extension_rejects_archive_from_wrong_manifest_type( + tmp_path, + settings: Settings, + mocker: MockerFixture, + manifest_type: ExtensionManifestType, + error: str, +): + ext_id = f"ext_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + assert ext_info.meta + assert ext_info.meta.installed_release + ext_info.meta.installed_release.manifest_type = manifest_type + original_data_folder = settings.lnbits_data_folder + mocker.patch( + "lnbits.core.services.extensions.get_installed_extension", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.check_extensions_limit", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + config = ( + _wasm_install_config(ext_id) + if manifest_type == ExtensionManifestType.PYTHON + else {"id": ext_id, "name": ext_id} + ) + _write_extension_archive(ext_info, config) + + with pytest.raises(ValueError, match=error): + await install_extension(ext_info, skip_download=True) + finally: + settings.lnbits_data_folder = original_data_folder + + +@pytest.mark.parametrize( + "python_file", + ["main.py", "cache.pyc", "legacy.PYO", "native.so", "native.PYD"], +) +@pytest.mark.anyio +async def test_install_wasm_extension_rejects_python_files( + tmp_path, + settings: Settings, + mocker: MockerFixture, + python_file: str, +): + ext_id = f"wasm_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + assert ext_info.meta + assert ext_info.meta.installed_release + ext_info.meta.installed_release.manifest_type = ExtensionManifestType.WASM + original_data_folder = settings.lnbits_data_folder + mocker.patch( + "lnbits.core.services.extensions.get_installed_extension", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.check_extensions_limit", + mocker.AsyncMock(), + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + _write_extension_archive( + ext_info, + _wasm_install_config(ext_id), + extra_files=[f"nested/{python_file}"], + ) + + with pytest.raises(ValueError, match="contains forbidden Python file"): + await install_extension(ext_info, skip_download=True) + finally: + settings.lnbits_data_folder = original_data_folder + + +@pytest.mark.anyio +async def test_uninstall_activate_and_deactivate_extensions( + tmp_path, settings: Settings, mocker: MockerFixture +): + ext_id = f"ext_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + original_deactivated = set(settings.lnbits_deactivated_extensions) + stop_mock = mocker.patch( + "lnbits.core.services.extensions.stop_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + start_mock = mocker.patch( + "lnbits.core.services.extensions.start_extension_background_work", + mocker.AsyncMock(return_value=True), + ) + clean_mock = mocker.patch.object(InstallableExtension, "clean_extension_files") + register_routes_mock = mocker.patch( + "lnbits.core.services.extensions.core_app_extra.register_new_ext_routes" + ) + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + await create_installed_extension(ext_info) + + await uninstall_extension(ext_id) + assert await get_installed_extension(ext_id) is None + assert ext_id in settings.lnbits_deactivated_extensions + + await create_installed_extension(ext_info) + await activate_extension(Extension(code=ext_id, is_valid=True)) + active_ext = await get_installed_extension(ext_id) + assert active_ext is not None + assert active_ext.active is True + + await deactivate_extension(ext_id) + inactive_ext = await get_installed_extension(ext_id) + assert inactive_ext is not None + assert inactive_ext.active is False + assert ext_id in settings.lnbits_deactivated_extensions + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_deactivated_extensions = original_deactivated + + clean_mock.assert_called_once() + register_routes_mock.assert_called_once() + assert stop_mock.await_count == 2 + assert start_mock.await_count == 1 + + +@pytest.mark.anyio +async def test_uninstall_wasm_extension_unregisters_live_routes( + tmp_path, settings: Settings, mocker: MockerFixture +): + ext_id = f"wasm_{uuid4().hex[:8]}" + ext_info = make_installable_extension(ext_id) + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + original_deactivated = set(settings.lnbits_deactivated_extensions) + unregister_routes_mock = mocker.patch( + "lnbits.core.services.extensions.core_app_extra.unregister_wasm_ext_routes" + ) + clean_mock = mocker.patch.object(InstallableExtension, "clean_wasm_extension_files") + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + ext_dir = settings.wasm_extensions_dir / ext_id + ext_dir.mkdir(parents=True, exist_ok=True) + (ext_dir / "config.json").write_text( + json.dumps(_wasm_install_config(ext_id)), + encoding="utf-8", + ) + await create_installed_extension(ext_info) + + await uninstall_extension(ext_id) + + assert await get_installed_extension(ext_id) is None + assert ext_id in settings.lnbits_deactivated_extensions + finally: + await delete_installed_extension(ext_id=ext_id) + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + settings.lnbits_deactivated_extensions = original_deactivated + + unregister_routes_mock.assert_called_once_with(ext_id) + clean_mock.assert_called_once() + + +@pytest.mark.anyio +async def test_wasm_invocation_monitoring_marks_stale_once_and_cleans_periodically( + settings: Settings, + mocker: MockerFixture, +): + _reset_wasm_invocation_state() + now = datetime(2026, 1, 1, tzinfo=timezone.utc) + mark_stale_mock = mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + cleanup_mock = mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions._now", + side_effect=[now, now + timedelta(minutes=1), now + timedelta(hours=2)], + ) + + await extension_services.ensure_wasm_invocation_monitoring_ready() + await extension_services.ensure_wasm_invocation_monitoring_ready() + await extension_services.ensure_wasm_invocation_monitoring_ready() + + mark_stale_mock.assert_awaited_once() + assert cleanup_mock.await_count == 2 + cleanup_mock.assert_awaited_with(settings.lnbits_wasm_invocation_retention_days) + + +@pytest.mark.anyio +async def test_stop_extension_background_work_handles_missing_and_async_stops( + mocker: MockerFixture, +): + import_module_mock = mocker.patch( + "lnbits.core.services.extensions.importlib.import_module", + return_value=object(), + ) + + assert await stop_extension_background_work("demoext") is False + + called = {"stop": False} + + async def demoext_stop(): + called["stop"] = True + + import_module_mock.return_value = SimpleNamespace(demoext_stop=demoext_stop) + + assert await stop_extension_background_work("demoext") is True + assert called["stop"] is True + + +@pytest.mark.anyio +async def test_wasm_invocation_tracking_counts_and_stops(mocker: MockerFixture): + _reset_wasm_invocation_state() + mocker.patch( + "lnbits.core.services.extensions.create_wasm_invocation", + mocker.AsyncMock(), + ) + update_mock = mocker.patch( + "lnbits.core.services.extensions.update_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.get_wasm_invocation", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + + invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + trigger_type="http", + method="POST", + path="/api/v1/ext/demoext/run", + context={"origin": "https://example.com"}, + ) + store = SimpleNamespace(deadline=None) + store.set_epoch_deadline = lambda deadline: setattr(store, "deadline", deadline) + engine = SimpleNamespace(increments=0) + + def increment_epoch(): + engine.increments += 1 + + engine.increment_epoch = increment_epoch + + attach_wasm_invocation_runtime(invocation.id, engine=engine, store=store) + record_wasm_invocation_host_call(invocation.id, "http.request") + record_wasm_invocation_host_call(invocation.id, "storage.get") + + assert await stop_wasm_invocation(invocation.id, reason="test stop") is True + current = get_current_wasm_invocations() + assert current[0].status == "stopping" + assert store.deadline == 1 + assert engine.increments == 1 + + await finish_wasm_invocation(invocation.id, status="failed") + assert update_mock.await_args is not None + saved = update_mock.await_args.args[0] + assert saved.status == "stopped" + assert saved.stop_reason == "test stop" + assert saved.host_call_count == 2 + assert saved.http_call_count == 1 + assert saved.storage_call_count == 1 + + +@pytest.mark.anyio +async def test_wasm_invocation_context_and_error_message_are_sanitized( + mocker: MockerFixture, +): + _reset_wasm_invocation_state() + create_mock = mocker.patch( + "lnbits.core.services.extensions.create_wasm_invocation", + mocker.AsyncMock(), + ) + update_mock = mocker.patch( + "lnbits.core.services.extensions.update_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.get_wasm_invocation", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + long_key = "k" * 80 + secret_hex = "a" * 64 + + invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + context={ + long_key: "v" * 300, + "attempt": 2, + "enabled": True, + "nested": {"raw": "value"}, + 7: "ignored", + }, + ) + await finish_wasm_invocation( + invocation.id, + status="failed", + error_type="RuntimeError", + error_message=f"api_key=supersecret Bearer abc.def {secret_hex} " + ("x" * 600), + ) + + create_mock.assert_awaited_once() + assert create_mock.await_args is not None + created_invocation = create_mock.await_args.args[0] + assert created_invocation.context == { + "k" * 64: "v" * 256, + "attempt": 2, + "enabled": True, + } + update_mock.assert_awaited_once() + assert update_mock.await_args is not None + saved_invocation = update_mock.await_args.args[0] + assert saved_invocation.error_message is not None + assert "supersecret" not in saved_invocation.error_message + assert "abc.def" not in saved_invocation.error_message + assert secret_hex not in saved_invocation.error_message + assert "api_key=[redacted]" in saved_invocation.error_message + assert "Bearer [redacted]" in saved_invocation.error_message + assert "[redacted-hex]" in saved_invocation.error_message + + +def _reset_wasm_invocation_state(): + with extension_services._wasm_invocation_lock: + extension_services._wasm_invocation_handles.clear() + extension_services._wasm_invocations_marked_stale = False + extension_services._wasm_invocations_last_cleanup_at = None + + +def _write_wasm_extension_archive( + ext_info: InstallableExtension, + config: dict, +) -> None: + _write_extension_archive( + ext_info, + config, + extra_files=[config["wasm"]["module"]], + ) + + +def _write_extension_archive( + ext_info: InstallableExtension, + config: dict, + *, + extra_files: list[str] | None = None, +) -> None: + ext_info.zip_path.parent.mkdir(parents=True, exist_ok=True) + root = f"{ext_info.id}-{ext_info.version}" + with zipfile.ZipFile(ext_info.zip_path, "w") as archive: + archive.writestr(f"{root}/config.json", json.dumps(config)) + for filename in extra_files or []: + archive.writestr(f"{root}/{filename}", b"\0asm") + + +def _wasm_install_config(ext_id: str) -> dict: + return { + "id": ext_id, + "name": f"WASM {ext_id}", + "short_description": "WASM extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + "permissions": [ + { + "id": "http.request", + "description": "Call example API.", + "policies": [{"host": "https://api.example.com"}], + } + ], + } + + +def test_wasm_runtime_limits_merge_sparse_extension_overrides(settings: Settings): + original_execution_ms = settings.wasm_runtime_max_execution_ms + original_memory_bytes = settings.wasm_runtime_max_memory_bytes + try: + settings.wasm_runtime_max_execution_ms = 5_000 + settings.wasm_runtime_max_memory_bytes = 64 * 1024 * 1024 + extension = InstallableExtension( + id="wasm_demo", + name="WASM Demo", + version="1.0.0", + wasm_runtime_limits={ + "wasm_runtime_max_execution_ms": 20_000, + "wasm_runtime_max_fuel": 0, + }, + ) + + limits = extension_services.resolve_wasm_runtime_limits(extension) + + assert limits["wasm_runtime_max_execution_ms"] == 20_000 + assert limits["wasm_runtime_max_fuel"] == 0 + assert limits["wasm_runtime_max_memory_bytes"] == 64 * 1024 * 1024 + finally: + settings.wasm_runtime_max_execution_ms = original_execution_ms + settings.wasm_runtime_max_memory_bytes = original_memory_bytes + + +def test_wasm_runtime_limit_override_validation(): + assert extension_services.validate_wasm_runtime_limit_overrides( + { + "wasm_runtime_max_execution_ms": "7000", + "wasm_runtime_max_fuel": 0, + "wasm_runtime_max_memory_bytes": "", + } + ) == { + "wasm_runtime_max_execution_ms": 7000, + "wasm_runtime_max_fuel": 0, + } + + with pytest.raises(ValueError, match="Unknown WASM runtime limit field"): + extension_services.validate_wasm_runtime_limit_overrides({"unknown": 1}) + + with pytest.raises(ValueError, match="cannot be negative"): + extension_services.validate_wasm_runtime_limit_overrides( + {"wasm_runtime_max_execution_ms": -1} + ) + + with pytest.raises(ValueError, match="must be an integer"): + extension_services.validate_wasm_runtime_limit_overrides( + {"wasm_runtime_max_execution_ms": True} + ) + + with pytest.raises(ValueError, match="must be an integer"): + extension_services.validate_wasm_runtime_limit_overrides( + {"wasm_runtime_max_execution_ms": 1.5} + ) + + +@pytest.mark.anyio +async def test_update_wasm_extension_runtime_limits_saves_sparse_overrides( + tmp_path, + settings: Settings, + mocker: MockerFixture, +): + ext_id = "wasm_demo" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + try: + settings.lnbits_extensions_path = str(tmp_path) + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + config_dir = settings.wasm_extensions_dir / ext_id + config_dir.mkdir(parents=True) + (config_dir / "config.json").write_text( + '{"extension_type": "wasm"}', + encoding="utf-8", + ) + installed_extension = InstallableExtension( + id=ext_id, + name="WASM Demo", + version="1.0.0", + ) + mocker.patch( + "lnbits.core.services.extensions.get_installed_extension", + mocker.AsyncMock(return_value=installed_extension), + ) + update_mock = mocker.patch( + "lnbits.core.services.extensions." + "update_installed_extension_wasm_runtime_limits", + mocker.AsyncMock(), + ) + + saved_limits = await extension_services.update_wasm_extension_runtime_limits( + ext_id, + { + "wasm_runtime_max_execution_ms": "15000", + "wasm_runtime_max_fuel": 0, + "wasm_runtime_max_memory_bytes": "", + }, + ) + finally: + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + + assert saved_limits == { + "wasm_runtime_max_execution_ms": 15000, + "wasm_runtime_max_fuel": 0, + } + update_mock.assert_awaited_once_with(ext_id=ext_id, limits=saved_limits) + + +@pytest.mark.anyio +async def test_wasm_invocation_concurrency_limits(mocker: MockerFixture): + _reset_wasm_invocation_state() + mocker.patch( + "lnbits.core.services.extensions.create_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.update_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.get_wasm_invocation", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + limits = extension_services.wasm_runtime_limit_defaults() + limits.update( + { + "wasm_runtime_max_concurrent_invocations": 1, + "wasm_runtime_max_concurrent_invocations_per_extension": 1, + "wasm_runtime_max_concurrent_invocations_per_user": 1, + } + ) + + invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + user_id="user-id", + runtime_limits=limits, + ) + + with pytest.raises(ValueError, match="too many active invocations"): + await start_wasm_invocation( + extension_id="demoext", + export_name="render", + user_id="user-id", + runtime_limits=limits, + ) + + await finish_wasm_invocation(invocation.id, status="completed") + + +@pytest.mark.anyio +async def test_wasm_invocation_host_call_limits(mocker: MockerFixture): + _reset_wasm_invocation_state() + mocker.patch( + "lnbits.core.services.extensions.create_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.update_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.get_wasm_invocation", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + limits = extension_services.wasm_runtime_limit_defaults() + limits["wasm_runtime_max_host_calls"] = 1 + + invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + runtime_limits=limits, + ) + record_wasm_invocation_host_call(invocation.id, "http.request") + + with pytest.raises(ValueError, match="host call limit"): + record_wasm_invocation_host_call(invocation.id, "storage.get") + + await finish_wasm_invocation(invocation.id, status="failed") + + +@pytest.mark.anyio +async def test_wasm_invocation_host_call_category_limits_can_be_disabled( + mocker: MockerFixture, +): + _reset_wasm_invocation_state() + mocker.patch( + "lnbits.core.services.extensions.create_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.update_wasm_invocation", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.get_wasm_invocation", + mocker.AsyncMock(return_value=None), + ) + mocker.patch( + "lnbits.core.services.extensions.mark_stale_wasm_invocations", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.services.extensions.delete_old_wasm_invocations", + mocker.AsyncMock(), + ) + limits = extension_services.wasm_runtime_limit_defaults() + limits["wasm_runtime_max_host_calls"] = 10 + limits["wasm_runtime_max_http_calls"] = 1 + + invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + runtime_limits=limits, + ) + record_wasm_invocation_host_call(invocation.id, "http.request") + with pytest.raises(ValueError, match="http host call limit"): + record_wasm_invocation_host_call(invocation.id, "extension.api.request") + await finish_wasm_invocation(invocation.id, status="failed") + + limits["wasm_runtime_max_host_calls"] = 0 + limits["wasm_runtime_max_http_calls"] = 0 + unlimited_invocation = await start_wasm_invocation( + extension_id="demoext", + export_name="render", + runtime_limits=limits, + ) + for _ in range(5): + record_wasm_invocation_host_call(unlimited_invocation.id, "http.request") + + await finish_wasm_invocation(unlimited_invocation.id, status="completed") + + +@pytest.mark.anyio +async def test_start_extension_background_work_handles_missing_and_sync_starts( + mocker: MockerFixture, +): + import_module_mock = mocker.patch( + "lnbits.core.services.extensions.importlib.import_module", + return_value=object(), + ) + + assert await start_extension_background_work("demoext") is False + + called = {"start": False} + + def demoext_start(): + called["start"] = True + + import_module_mock.return_value = SimpleNamespace(demoext_start=demoext_start) + + assert await start_extension_background_work("demoext") is True + assert called["start"] is True + + +@pytest.mark.anyio +async def test_get_valid_extensions_and_single_extension_respect_settings( + tmp_path, settings: Settings +): + ext_id_one = f"ext_{uuid4().hex[:8]}" + ext_id_two = f"ext_{uuid4().hex[:8]}" + ext_one = make_installable_extension(ext_id_one) + ext_two = make_installable_extension(ext_id_two) + original_deactivated = set(settings.lnbits_deactivated_extensions) + original_deactivate_all = settings.lnbits_extensions_deactivate_all + original_data_folder = settings.lnbits_data_folder + original_extensions_path = settings.lnbits_extensions_path + + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_deactivated_extensions = {ext_id_two} + settings.lnbits_extensions_deactivate_all = False + await create_installed_extension(ext_one) + await create_installed_extension(ext_two) + + valid_extensions = await get_valid_extensions(include_deactivated=False) + valid_codes = {ext.code for ext in valid_extensions} + assert ext_id_one in valid_codes + assert ext_id_two not in valid_codes + + assert ( + await get_valid_extension(ext_id_one, include_deactivated=True) is not None + ) + + settings.lnbits_extensions_deactivate_all = True + assert await get_valid_extensions(include_deactivated=False) == [] + assert await get_valid_extension(ext_id_one, include_deactivated=False) is None + finally: + await delete_installed_extension(ext_id=ext_id_one) + await delete_installed_extension(ext_id=ext_id_two) + settings.lnbits_deactivated_extensions = original_deactivated + settings.lnbits_extensions_deactivate_all = original_deactivate_all + settings.lnbits_data_folder = original_data_folder + settings.lnbits_extensions_path = original_extensions_path diff --git a/tests/unit/test_services_extensions_builder.py b/tests/unit/test_services_extensions_builder.py new file mode 100644 index 000000000..d33770f96 --- /dev/null +++ b/tests/unit/test_services_extensions_builder.py @@ -0,0 +1,107 @@ +import hashlib +import zipfile +from pathlib import Path +from types import SimpleNamespace + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.models.extensions import ExtensionRelease +from lnbits.core.services.extensions_builder import ( + build_extension_from_data, + clean_extension_builder_data, + zip_directory, +) +from lnbits.settings import Settings +from tests.helpers import make_extension_data + + +@pytest.mark.anyio +async def test_build_extension_from_data_orchestrates_builder_steps( + tmp_path, mocker: MockerFixture +): + data = make_extension_data() + release = ExtensionRelease( + name="stub", + version="0.1.0", + archive="https://example.com/stub.zip", + source_repo="org/repo", + is_github_release=True, + ) + build_dir = tmp_path / "build" + fetch_mock = mocker.patch( + "lnbits.core.services.extensions_builder._fetch_extension_builder_stub", + mocker.AsyncMock(), + ) + transform_mock = mocker.patch( + "lnbits.core.services.extensions_builder._transform_extension_builder_stub" + ) + export_mock = mocker.patch( + "lnbits.core.services.extensions_builder._export_extension_data_json" + ) + mocker.patch( + "lnbits.core.services.extensions_builder._get_extension_stub_release", + mocker.AsyncMock(return_value=release), + ) + mocker.patch( + "lnbits.core.services.extensions_builder._copy_ext_stub_to_build_dir", + return_value=build_dir, + ) + mocker.patch( + "lnbits.core.services.extensions_builder.uuid4", + return_value=SimpleNamespace(hex="seed"), + ) + + built_release, output_dir = await build_extension_from_data(data, "stub-ext") + + assert output_dir == build_dir + assert built_release == release + assert built_release.hash == hashlib.sha256(b"seed").hexdigest() + assert built_release.icon == "/demoext/static/image/demoext.png" + assert built_release.is_github_release is False + fetch_mock.assert_awaited_once_with("stub-ext", release) + transform_mock.assert_called_once_with(data, build_dir) + export_mock.assert_called_once_with(data, build_dir) + + +def test_clean_extension_builder_data_recreates_working_directory( + settings: Settings, tmp_path +): + original_data_folder = settings.lnbits_data_folder + try: + settings.lnbits_data_folder = str(tmp_path) + working_dir = settings.extension_builder_working_dir_path + working_dir.mkdir(parents=True, exist_ok=True) + Path(working_dir, "stale.txt").write_text("stale") + + clean_extension_builder_data() + + assert working_dir.is_dir() + assert list(working_dir.iterdir()) == [] + finally: + settings.lnbits_data_folder = original_data_folder + + +def test_zip_directory_skips_excluded_directories(tmp_path): + source_dir = tmp_path / "source" + zip_path = tmp_path / "archive.zip" + (source_dir / "nested").mkdir(parents=True) + (source_dir / "node_modules").mkdir() + (source_dir / "__pycache__").mkdir() + (source_dir / "root.txt").write_text("root") + (source_dir / "nested" / "file.txt").write_text("nested") + (source_dir / "node_modules" / "ignored.txt").write_text("ignored") + (source_dir / "__pycache__" / "ignored.pyc").write_text("ignored") + + from_builder = "lnbits.core.services.extensions_builder._is_excluded_dir" + with pytest.MonkeyPatch.context() as monkeypatch: + monkeypatch.setattr( + from_builder, + lambda path: "node_modules" in path or "__pycache__" in path, + ) + zip_directory(source_dir, zip_path) + + with zipfile.ZipFile(zip_path) as archive: + names = sorted(archive.namelist()) + + assert names == ["nested/file.txt", "root.txt"] diff --git a/tests/unit/test_services_funding_source.py b/tests/unit/test_services_funding_source.py new file mode 100644 index 000000000..9c2fa568d --- /dev/null +++ b/tests/unit/test_services_funding_source.py @@ -0,0 +1,171 @@ +from types import SimpleNamespace +from typing import Any, cast +from uuid import uuid4 + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import create_account, create_wallet, get_total_balance +from lnbits.core.models import Account +from lnbits.core.models.misc import BalanceDelta +from lnbits.core.services.funding_source import ( + check_balance_delta_changed, + check_server_balance_against_node, + get_balance_delta, + switch_to_voidwallet, +) +from lnbits.core.services.payments import update_wallet_balance +from lnbits.settings import Settings + + +@pytest.mark.anyio +async def test_switch_to_voidwallet_returns_when_already_using_voidwallet( + settings: Settings, mocker: MockerFixture +): + original_backend_class = settings.lnbits_backend_wallet_class + try: + settings.lnbits_backend_wallet_class = "FakeWallet" + mocker.patch( + "lnbits.core.services.funding_source.get_funding_source", + return_value=type("VoidWallet", (), {})(), + ) + set_funding_source = mocker.patch( + "lnbits.core.services.funding_source.set_funding_source" + ) + + await switch_to_voidwallet() + + set_funding_source.assert_not_called() + assert settings.lnbits_backend_wallet_class == "FakeWallet" + finally: + settings.lnbits_backend_wallet_class = original_backend_class + + +@pytest.mark.anyio +async def test_switch_to_voidwallet_updates_backend_class( + settings: Settings, mocker: MockerFixture +): + original_backend_class = settings.lnbits_backend_wallet_class + try: + settings.lnbits_backend_wallet_class = "FakeWallet" + mocker.patch( + "lnbits.core.services.funding_source.get_funding_source", + return_value=type("FakeWallet", (), {})(), + ) + set_funding_source = mocker.patch( + "lnbits.core.services.funding_source.set_funding_source" + ) + + await switch_to_voidwallet() + + set_funding_source.assert_called_once_with("VoidWallet") + assert settings.lnbits_backend_wallet_class == "VoidWallet" + finally: + settings.lnbits_backend_wallet_class = original_backend_class + + +@pytest.mark.anyio +async def test_get_balance_delta(mocker: MockerFixture): + baseline_balance = await get_total_balance() + await _create_wallet_with_balance(11) + funding_source = SimpleNamespace( + status=mocker.AsyncMock( + return_value=SimpleNamespace(balance_msat=7_000, error_message=None) + ) + ) + mocker.patch( + "lnbits.core.services.funding_source.get_funding_source", + return_value=funding_source, + ) + + delta = await get_balance_delta() + expected_balance_sats = (baseline_balance + 11_000) // 1000 + + assert delta.lnbits_balance_sats == expected_balance_sats + assert delta.node_balance_sats == 7 + assert delta.delta_sats == expected_balance_sats - 7 + + +@pytest.mark.anyio +async def test_check_server_balance_against_node_notifies_and_switches( + settings: Settings, mocker: MockerFixture +): + original_switch = settings.lnbits_watchdog_switch_to_voidwallet + original_notification = settings.lnbits_notification_watchdog + original_delta = settings.lnbits_watchdog_delta + try: + settings.lnbits_watchdog_switch_to_voidwallet = True + settings.lnbits_notification_watchdog = True + settings.lnbits_watchdog_delta = 5 + mocker.patch( + "lnbits.core.services.funding_source.get_funding_source", + return_value=type("FakeWallet", (), {})(), + ) + mocker.patch( + "lnbits.core.services.funding_source.get_balance_delta", + mocker.AsyncMock( + return_value=BalanceDelta( + lnbits_balance_sats=12, + node_balance_sats=1, + ) + ), + ) + enqueue = mocker.patch( + "lnbits.core.services.funding_source.enqueue_admin_notification" + ) + switch = mocker.patch( + "lnbits.core.services.funding_source.switch_to_voidwallet", + mocker.AsyncMock(), + ) + + await check_server_balance_against_node() + + enqueue.assert_called_once() + switch.assert_awaited_once() + finally: + settings.lnbits_watchdog_switch_to_voidwallet = original_switch + settings.lnbits_notification_watchdog = original_notification + settings.lnbits_watchdog_delta = original_delta + + +@pytest.mark.anyio +async def test_check_balance_delta_changed_tracks_and_notifies( + settings: Settings, mocker: MockerFixture +): + settings_any = cast(Any, settings) + original_latest = settings.latest_balance_delta_sats + original_threshold = settings.notification_balance_delta_threshold_sats + try: + settings_any.latest_balance_delta_sats = None + settings.notification_balance_delta_threshold_sats = 3 + mocker.patch( + "lnbits.core.services.funding_source.get_balance_delta", + mocker.AsyncMock( + side_effect=[ + BalanceDelta(lnbits_balance_sats=12, node_balance_sats=10), + BalanceDelta(lnbits_balance_sats=20, node_balance_sats=10), + ] + ), + ) + enqueue = mocker.patch( + "lnbits.core.services.funding_source.enqueue_admin_notification" + ) + + await check_balance_delta_changed() + enqueue.assert_not_called() + assert settings.latest_balance_delta_sats == 2 + + await check_balance_delta_changed() + enqueue.assert_called_once() + assert settings.latest_balance_delta_sats == 10 + finally: + settings_any.latest_balance_delta_sats = original_latest + settings.notification_balance_delta_threshold_sats = original_threshold + + +async def _create_wallet_with_balance(amount: int): + user_id = uuid4().hex + await create_account(Account(id=user_id, username=f"user_{user_id[:8]}")) + wallet = await create_wallet(user_id=user_id, wallet_name="wallet") + await update_wallet_balance(wallet=wallet, amount=amount) + return wallet diff --git a/tests/unit/test_services_lnurl.py b/tests/unit/test_services_lnurl.py new file mode 100644 index 000000000..d07a45a90 --- /dev/null +++ b/tests/unit/test_services_lnurl.py @@ -0,0 +1,185 @@ +from typing import cast +from uuid import uuid4 + +import pytest +from bolt11.types import MilliSatoshi +from lnurl import ( + LnAddress, + LnurlErrorResponse, + LnurlPayActionResponse, + LnurlResponseException, + LnurlSuccessResponse, + LnurlWithdrawResponse, +) +from lnurl.types import CallbackUrl, LightningInvoice +from pydantic import parse_obj_as +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import create_account, create_wallet, get_wallet +from lnbits.core.models import Account +from lnbits.core.models.lnurl import CreateLnurlPayment +from lnbits.core.models.wallets import Wallet +from lnbits.core.services.lnurl import ( + fetch_lnurl_pay_request, + get_pr_from_lnurl, + perform_withdraw, + store_paylink, +) +from tests.helpers import make_lnurl_pay_response + +TEST_BOLT11 = ( + "lnbc1pnsu5z3pp57getmdaxhg5kc9yh2a2qsh7cjf4gnccgkw0qenm8vsqv50w7s" + "ygqdqj0fjhymeqv9kk7atwwscqzzsxqyz5vqsp5e2yyqcp0a3ujeesp24ya0glej" + "srh703md8mrx0g2lyvjxy5w27ss9qxpqysgqyjreasng8a086kpkczv48er5c6l5" + "73aym6ynrdl9nkzqnag49vt3sjjn8qdfq5cr6ha0vrdz5c5r3v4aghndly0hplmv" + "6hjxepwp93cq398l3s" +) + + +@pytest.mark.anyio +async def test_perform_withdraw_success_and_validation(mocker: MockerFixture): + withdraw_response = LnurlWithdrawResponse( + callback=parse_obj_as(CallbackUrl, "https://example.com/callback"), + k1="k1", + minWithdrawable=MilliSatoshi(1), + maxWithdrawable=MilliSatoshi(1000), + defaultDescription="test", + ) + execute_withdraw_mock = mocker.patch( + "lnbits.core.services.lnurl.execute_withdraw", + mocker.AsyncMock(return_value=LnurlSuccessResponse()), + ) + mocker.patch( + "lnbits.core.services.lnurl.handle", + mocker.AsyncMock(return_value=withdraw_response), + ) + + await perform_withdraw("lnurl", "bolt11") + + execute_withdraw_mock.assert_awaited_once() + + mocker.patch( + "lnbits.core.services.lnurl.check_callback_url", + side_effect=ValueError("blocked"), + ) + with pytest.raises(LnurlResponseException, match="Invalid callback URL"): + await perform_withdraw("lnurl", "bolt11") + + +@pytest.mark.anyio +async def test_perform_withdraw_rejects_error_response(mocker: MockerFixture): + mocker.patch( + "lnbits.core.services.lnurl.handle", + mocker.AsyncMock(return_value=LnurlErrorResponse(reason="boom")), + ) + + with pytest.raises(LnurlResponseException, match="boom"): + await perform_withdraw("lnurl", "bolt11") + + +@pytest.mark.anyio +async def test_get_pr_from_lnurl_success_and_error(mocker: MockerFixture): + pay_response = make_lnurl_pay_response(min_sendable_msat=1, text="Test") + mocker.patch( + "lnbits.core.services.lnurl.handle", + mocker.AsyncMock(return_value=pay_response), + ) + mocker.patch( + "lnbits.core.services.lnurl.execute_pay_request", + mocker.AsyncMock( + return_value=LnurlPayActionResponse( + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)) + ) + ), + ) + + assert await get_pr_from_lnurl("lnurl", 1000, comment="hello") == TEST_BOLT11 + + mocker.patch( + "lnbits.core.services.lnurl.handle", + mocker.AsyncMock(return_value=LnurlErrorResponse(reason="nope")), + ) + with pytest.raises(LnurlResponseException, match="nope"): + await get_pr_from_lnurl("lnurl", 1000) + + +@pytest.mark.anyio +async def test_fetch_lnurl_pay_request_converts_currency_and_stores_paylink( + mocker: MockerFixture, +): + pay_response = make_lnurl_pay_response(min_sendable_msat=1, text="Test") + action_response = LnurlPayActionResponse( + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), disposable=False + ) + mocker.patch( + "lnbits.core.services.lnurl.fiat_amount_as_satoshis", + mocker.AsyncMock(return_value=100), + ) + execute_mock = mocker.patch( + "lnbits.core.services.lnurl.execute_pay_request", + mocker.AsyncMock(return_value=action_response), + ) + store_paylink_mock = mocker.patch( + "lnbits.core.services.lnurl.store_paylink", + mocker.AsyncMock(), + ) + wallet = _make_wallet() + + data = CreateLnurlPayment(res=pay_response, amount=2500, unit="USD", comment="hi") + response, action = await fetch_lnurl_pay_request(data, wallet=wallet) + + assert response == pay_response + assert action == action_response + execute_mock.assert_awaited_once() + assert execute_mock.await_args is not None + assert execute_mock.await_args.kwargs["msat"] == 100_000 + store_paylink_mock.assert_awaited_once_with( + pay_response, action_response, wallet, None + ) + + with pytest.raises(LnurlResponseException, match="No LNURL pay request provided."): + await fetch_lnurl_pay_request(CreateLnurlPayment(amount=1)) + + +@pytest.mark.anyio +async def test_store_paylink_appends_and_updates_existing(): + wallet = await _create_wallet() + pay_response = make_lnurl_pay_response(min_sendable_msat=1, text="Test") + action_response = LnurlPayActionResponse( + pr=cast(LightningInvoice, LightningInvoice(TEST_BOLT11)), disposable=False + ) + + await store_paylink( + pay_response, action_response, wallet, LnAddress("alice@example.com") + ) + stored_wallet = await get_wallet(wallet.id) + + assert stored_wallet is not None + assert len(stored_wallet.stored_paylinks.links) == 1 + assert stored_wallet.stored_paylinks.links[0].lnurl == "alice@example.com" + + first_used = stored_wallet.stored_paylinks.links[0].last_used + await store_paylink( + pay_response, action_response, wallet, LnAddress("alice@example.com") + ) + stored_wallet = await get_wallet(wallet.id) + + assert stored_wallet is not None + assert len(stored_wallet.stored_paylinks.links) == 1 + assert stored_wallet.stored_paylinks.links[0].last_used >= first_used + + +def _make_wallet() -> Wallet: + return Wallet( + id="wallet-id", + user="user-id", + name="Wallet", + adminkey="admin-key", + inkey="invoice-key", + ) + + +async def _create_wallet() -> Wallet: + user_id = uuid4().hex + await create_account(Account(id=user_id, username=f"user_{user_id[:8]}")) + return await create_wallet(user_id=user_id, wallet_name="Wallet") diff --git a/tests/unit/test_services_nostr.py b/tests/unit/test_services_nostr.py new file mode 100644 index 000000000..86cded033 --- /dev/null +++ b/tests/unit/test_services_nostr.py @@ -0,0 +1,117 @@ +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.services.nostr import fetch_nip5_details, send_nostr_dm + + +class FakeWebSocket: + def __init__(self): + self.sent: list[str] = [] + self.closed = False + + def send(self, message: str): + self.sent.append(message) + + def close(self): + self.closed = True + + +class MockHTTPClient: + def __init__(self, response): + self.response = response + self.calls: list[str] = [] + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return False + + async def get(self, url: str): + self.calls.append(url) + return self.response + + +class MockHTTPResponse: + def __init__(self, json_data: dict, error: Exception | None = None): + self._json_data = json_data + self._error = error + + def raise_for_status(self): + if self._error: + raise self._error + + def json(self): + return self._json_data + + +@pytest.mark.anyio +async def test_send_nostr_dm_sends_to_available_relays_and_closes_connections( + mocker: MockerFixture, +): + event = mocker.Mock() + event.to_message.return_value = "nostr-message" + event.to_dict.return_value = {"id": "event-id"} + dm = mocker.Mock() + dm.to_event.return_value = event + mocker.patch("lnbits.core.services.nostr.EncryptedDirectMessage", return_value=dm) + + ws_one = FakeWebSocket() + ws_two = FakeWebSocket() + mocker.patch( + "lnbits.core.services.nostr.create_connection", + side_effect=[ws_one, RuntimeError("boom"), ws_two], + ) + mocker.patch("lnbits.core.services.nostr.asyncio.sleep", mocker.AsyncMock()) + + result = await send_nostr_dm( + "privkey", + "pubkey", + "hello", + ["wss://relay-1", "wss://broken", "wss://relay-2"], + ) + + assert ws_one.sent == ["nostr-message"] + assert ws_two.sent == ["nostr-message"] + assert ws_one.closed is True + assert ws_two.closed is True + assert result == {"id": "event-id"} + + +@pytest.mark.anyio +async def test_fetch_nip5_details_returns_pubkey_and_relays(mocker: MockerFixture): + response = MockHTTPResponse( + { + "names": {"alice": "f" * 64}, + "relays": {"f" * 64: ["wss://relay.example.com"]}, + } + ) + client = MockHTTPClient(response) + mocker.patch("lnbits.core.services.nostr.is_valid_url", return_value=True) + validate_identifier = mocker.patch("lnbits.core.services.nostr.validate_identifier") + validate_pub_key = mocker.patch("lnbits.core.services.nostr.validate_pub_key") + mocker.patch("lnbits.core.services.nostr.httpx.AsyncClient", return_value=client) + + pubkey, relays = await fetch_nip5_details("alice@example.com") + + validate_identifier.assert_called_once_with("alice") + validate_pub_key.assert_called_once_with("f" * 64) + assert client.calls == ["https://example.com/.well-known/nostr.json?name=alice"] + assert pubkey == "f" * 64 + assert relays == ["wss://relay.example.com"] + + +@pytest.mark.anyio +async def test_fetch_nip5_details_rejects_invalid_values(mocker: MockerFixture): + with pytest.raises(ValueError, match="not enough values to unpack"): + await fetch_nip5_details("invalid") + + mocker.patch("lnbits.core.services.nostr.is_valid_url", return_value=False) + with pytest.raises(ValueError, match="Invalid NIP5 domain"): + await fetch_nip5_details("alice@example.com") + + mocker.patch("lnbits.core.services.nostr.is_valid_url", return_value=True) + client = MockHTTPClient(MockHTTPResponse({"names": {}})) + mocker.patch("lnbits.core.services.nostr.httpx.AsyncClient", return_value=client) + with pytest.raises(ValueError, match="NIP5 not name found"): + await fetch_nip5_details("alice@example.com") diff --git a/tests/unit/test_services_notifications.py b/tests/unit/test_services_notifications.py new file mode 100644 index 000000000..e3699fb1f --- /dev/null +++ b/tests/unit/test_services_notifications.py @@ -0,0 +1,648 @@ +import asyncio +from http import HTTPStatus +from types import SimpleNamespace +from unittest.mock import MagicMock +from uuid import uuid4 + +import httpx +import pytest +from pytest_mock.plugin import MockerFixture +from pywebpush import WebPushException + +from lnbits.core.crud import ( + create_account, + create_payment, + create_wallet, + create_webpush_subscription, + get_payment, + get_webpush_subscription, + update_payment, + update_wallet, +) +from lnbits.core.models import Account, CreatePayment, Payment, PaymentState, Wallet +from lnbits.core.models.notifications import NotificationType +from lnbits.core.models.users import UserExtra, UserNotifications +from lnbits.core.models.wallets import ( + WalletPermission, + WalletSharePermission, + WalletShareStatus, +) +from lnbits.core.services.notifications import ( + dispatch_webhook, + enqueue_admin_notification, + enqueue_user_notification, + process_next_notification, + send_admin_notification, + send_chat_payment_notification, + send_email, + send_email_notification, + send_nostr_notification, + send_nostr_notifications, + send_notification, + send_notification_in_background, + send_payment_notification, + send_payment_push_notification, + send_push_notification, + send_telegram_message, + send_telegram_notification, + send_user_notification, + send_ws_payment_notification, +) +from lnbits.settings import Settings + + +class MockHTTPClient: + def __init__(self, post_response=None, post_exception=None): + self.post_response = post_response + self.post_exception = post_exception + self.posts: list[tuple[str, dict]] = [] + + async def __aenter__(self): + return self + + async def __aexit__(self, exc_type, exc, tb): + return None + + async def post(self, url, **kwargs): + self.posts.append((url, kwargs)) + if self.post_exception: + raise self.post_exception + return self.post_response + + +@pytest.mark.anyio +async def test_enqueue_and_process_notifications( + settings: Settings, mocker: MockerFixture +): + queue: asyncio.Queue = asyncio.Queue() + admin_mock = mocker.patch( + "lnbits.core.services.notifications.send_admin_notification", + mocker.AsyncMock(), + ) + user_mock = mocker.patch( + "lnbits.core.services.notifications.send_user_notification", + mocker.AsyncMock(), + ) + mocker.patch("lnbits.core.services.notifications.notifications_queue", queue) + mocker.patch( + "lnbits.core.services.notifications._is_message_type_enabled", + return_value=True, + ) + + enqueue_admin_notification(NotificationType.settings_update, {"username": "alice"}) + await process_next_notification() + + assert admin_mock.await_count == 1 + assert admin_mock.await_args is not None + assert admin_mock.await_args.args[0].startswith(f"[{settings.lnbits_site_title}]") + assert "alice" in admin_mock.await_args.args[0] + assert admin_mock.await_args.args[1] == NotificationType.settings_update.value + + user_notifications = UserNotifications(email_address="alice@example.com") + enqueue_user_notification( + NotificationType.text_message, + {"message": "hello"}, + user_notifications, + ) + await process_next_notification() + + assert user_mock.await_count == 1 + assert user_mock.await_args is not None + assert user_mock.await_args.args[0] == user_notifications + assert "hello" in user_mock.await_args.args[1] + assert user_mock.await_args.args[2] == NotificationType.text_message.value + + +@pytest.mark.anyio +async def test_send_admin_and_user_notification_use_expected_targets( + settings: Settings, mocker: MockerFixture +): + send_mock = mocker.patch( + "lnbits.core.services.notifications.send_notification_in_background", + mocker.AsyncMock(), + ) + original_chat_id = settings.lnbits_telegram_notifications_chat_id + original_identifiers = list(settings.lnbits_nostr_notifications_identifiers) + original_emails = list(settings.lnbits_email_notifications_to_emails) + try: + settings.lnbits_telegram_notifications_chat_id = "chat-id" + settings.lnbits_nostr_notifications_identifiers = ["alice@example.com"] + settings.lnbits_email_notifications_to_emails = ["admin@example.com"] + + await send_admin_notification("hello", "settings_update") + await send_user_notification( + UserNotifications( + telegram_chat_id="user-chat", + nostr_identifier="bob@example.com", + email_address="bob@example.com", + ), + "hello user", + "text_message", + ) + finally: + settings.lnbits_telegram_notifications_chat_id = original_chat_id + settings.lnbits_nostr_notifications_identifiers = original_identifiers + settings.lnbits_email_notifications_to_emails = original_emails + + assert send_mock.await_args_list[0].args == ( + "chat-id", + ["alice@example.com"], + ["admin@example.com"], + "hello", + "settings_update", + ) + assert send_mock.await_args_list[1].args == ( + "user-chat", + ["bob@example.com"], + ["bob@example.com"], + "hello user", + "text_message", + ) + + +@pytest.mark.anyio +async def test_send_notification_in_background_schedules_notification( + mocker: MockerFixture, +): + scheduled = [] + + def create_task(coro): + scheduled.append(coro) + coro.close() + return mocker.Mock() + + create_task_mock = mocker.patch( + "lnbits.core.services.notifications.create_task", + side_effect=create_task, + ) + send_mock = mocker.patch( + "lnbits.core.services.notifications.send_notification", + mocker.AsyncMock(), + ) + + await send_notification_in_background( + "chat-id", + ["alice@example.com"], + ["admin@example.com"], + "hello", + "settings_update", + ) + + create_task_mock.assert_called_once() + send_mock.assert_called_once_with( + "chat-id", + ["alice@example.com"], + ["admin@example.com"], + "hello", + "settings_update", + ) + assert len(scheduled) == 1 + + +@pytest.mark.anyio +async def test_send_notification_uses_available_channels_and_swallows_exceptions( + settings: Settings, mocker: MockerFixture +): + original_email_enabled = settings.lnbits_email_notifications_enabled + try: + settings.lnbits_email_notifications_enabled = True + mocker.patch.object( + type(settings), + "is_telegram_notifications_configured", + return_value=True, + ) + mocker.patch.object( + type(settings), + "is_nostr_notifications_configured", + return_value=True, + ) + telegram_mock = mocker.patch( + "lnbits.core.services.notifications.send_telegram_notification", + mocker.AsyncMock(side_effect=Exception("telegram boom")), + ) + nostr_mock = mocker.patch( + "lnbits.core.services.notifications.send_nostr_notifications", + mocker.AsyncMock(return_value=["alice@example.com"]), + ) + email_mock = mocker.patch( + "lnbits.core.services.notifications.send_email_notification", + mocker.AsyncMock(side_effect=Exception("email boom")), + ) + + await send_notification( + "chat-id", + ["alice@example.com"], + ["alice@example.com"], + "hello", + "text_message", + ) + finally: + settings.lnbits_email_notifications_enabled = original_email_enabled + + telegram_mock.assert_awaited_once() + nostr_mock.assert_awaited_once() + email_mock.assert_awaited_once() + + +@pytest.mark.anyio +async def test_send_nostr_notifications_and_single_notification( + mocker: MockerFixture, +): + send_mock = mocker.patch( + "lnbits.core.services.notifications.send_nostr_notification", + mocker.AsyncMock(side_effect=[None, Exception("boom"), None]), + ) + + result = await send_nostr_notifications(["ok-1", "bad", "ok-2"], "hello") + + assert result == ["ok-1", "ok-2"] + assert send_mock.await_count == 3 + + fetch_mock = mocker.patch( + "lnbits.core.services.notifications.fetch_nip5_details", + mocker.AsyncMock(return_value=("pubkey", ["wss://relay"])), + ) + normalize_mock = mocker.patch( + "lnbits.core.services.notifications.normalize_private_key", + return_value="server-private-key", + ) + dm_mock = mocker.patch( + "lnbits.core.services.notifications.send_nostr_dm", + mocker.AsyncMock(), + ) + + await send_nostr_notification("alice@example.com", "hello") + + fetch_mock.assert_awaited_once_with("alice@example.com") + normalize_mock.assert_called_once() + dm_mock.assert_awaited_once_with( + "server-private-key", + "pubkey", + "hello", + ["wss://relay"], + ) + + +@pytest.mark.anyio +async def test_send_telegram_message_and_wrapper( + settings: Settings, mocker: MockerFixture +): + response = httpx.Response( + 200, + request=httpx.Request("POST", "https://api.telegram.org"), + json={"ok": True}, + ) + client = MockHTTPClient(post_response=response) + mocker.patch( + "lnbits.core.services.notifications.httpx.AsyncClient", + return_value=client, + ) + + result = await send_telegram_message("token", "chat-id", "hello") + + assert result == {"ok": True} + assert client.posts[0][0].endswith("/bottoken/sendMessage") + + original_token = settings.lnbits_telegram_notifications_access_token + try: + settings.lnbits_telegram_notifications_access_token = "wrapper-token" + wrapper_mock = mocker.patch( + "lnbits.core.services.notifications.send_telegram_message", + mocker.AsyncMock(return_value={"ok": True}), + ) + + await send_telegram_notification("chat-id", "hello") + finally: + settings.lnbits_telegram_notifications_access_token = original_token + + wrapper_mock.assert_awaited_once_with("wrapper-token", "chat-id", "hello") + + +@pytest.mark.anyio +async def test_send_email_notification_and_send_email( + settings: Settings, mocker: MockerFixture +): + original_email_enabled = settings.lnbits_email_notifications_enabled + try: + settings.lnbits_email_notifications_enabled = False + disabled = await send_email_notification(["alice@example.com"], "hello") + assert disabled["status"] == "error" + + settings.lnbits_email_notifications_enabled = True + send_email_mock = mocker.patch( + "lnbits.core.services.notifications.send_email", + mocker.AsyncMock(return_value=True), + ) + enabled = await send_email_notification(["alice@example.com"], "hello") + assert enabled == {"status": "ok"} + send_email_mock.assert_awaited_once() + finally: + settings.lnbits_email_notifications_enabled = original_email_enabled + + smtp_server = MagicMock() + smtp_context = MagicMock() + smtp_context.__enter__.return_value = smtp_server + smtp_context.__exit__.return_value = None + mocker.patch( + "lnbits.core.services.notifications.smtplib.SMTP", + return_value=smtp_context, + ) + + assert ( + await send_email( + "smtp.example.com", + 587, + "", + "password", + "from@example.com", + ["to@example.com"], + "Subject", + "Body", + ) + is True + ) + smtp_server.starttls.assert_called_once() + smtp_server.login.assert_called_once_with("from@example.com", "password") + smtp_server.sendmail.assert_called_once() + + with pytest.raises(ValueError, match="Invalid from email address"): + await send_email( + "smtp.example.com", + 587, + "user", + "password", + "bad-email", + ["to@example.com"], + "Subject", + "Body", + ) + + with pytest.raises(ValueError, match="No email addresses provided"): + await send_email( + "smtp.example.com", + 587, + "user", + "password", + "from@example.com", + [], + "Subject", + "Body", + ) + + +@pytest.mark.anyio +async def test_dispatch_webhook_marks_missing_invalid_and_failed_requests( + mocker: MockerFixture, +): + wallet = await _create_wallet() + + payment = await _create_payment(wallet, webhook=None) + await dispatch_webhook(payment) + assert (await get_payment(payment.checking_id)).webhook_status == "-1" + + invalid_payment = await _create_payment(wallet, webhook="https://invalid.example") + assert invalid_payment.webhook is not None + invalid_client = MockHTTPClient( + post_response=httpx.Response( + 200, + request=httpx.Request("POST", invalid_payment.webhook), + json={"ok": True}, + ) + ) + mocker.patch( + "lnbits.core.services.notifications.check_callback_url", + side_effect=ValueError("blocked"), + ) + mocker.patch( + "lnbits.core.services.notifications.httpx.AsyncClient", + return_value=invalid_client, + ) + + await dispatch_webhook(invalid_payment) + assert (await get_payment(invalid_payment.checking_id)).webhook_status in { + "-1", + "200", + } + + error_payment = await _create_payment(wallet, webhook="https://error.example") + assert error_payment.webhook is not None + mocker.patch( + "lnbits.core.services.notifications.check_callback_url", + return_value=None, + ) + mocker.patch( + "lnbits.core.services.notifications.httpx.AsyncClient", + return_value=MockHTTPClient( + post_response=httpx.Response( + 500, + request=httpx.Request("POST", error_payment.webhook), + ) + ), + ) + + await dispatch_webhook(error_payment) + assert (await get_payment(error_payment.checking_id)).webhook_status == "500" + + request_payment = await _create_payment(wallet, webhook="https://request.example") + assert request_payment.webhook is not None + mocker.patch( + "lnbits.core.services.notifications.httpx.AsyncClient", + return_value=MockHTTPClient( + post_exception=httpx.RequestError( + "boom", + request=httpx.Request("POST", request_payment.webhook), + ) + ), + ) + + await dispatch_webhook(request_payment) + assert (await get_payment(request_payment.checking_id)).webhook_status == "-1" + + +@pytest.mark.anyio +async def test_send_payment_notification_fans_out_to_shared_wallet_and_webhook( + mocker: MockerFixture, +): + wallet = await _create_wallet(name="Primary Wallet") + shared_wallet = await _create_wallet(name="Shared Wallet") + wallet.extra.shared_with = [ + WalletSharePermission( + request_id="share-1", + username="bob", + shared_with_wallet_id=shared_wallet.id, + permissions=[WalletPermission.VIEW_PAYMENTS], + status=WalletShareStatus.APPROVED, + ) + ] + await update_wallet(wallet) + payment = await _create_payment(wallet, webhook="https://webhook.example") + ws_mock = mocker.patch( + "lnbits.core.services.notifications.send_ws_payment_notification", + mocker.AsyncMock(), + ) + chat_mock = mocker.patch( + "lnbits.core.services.notifications.send_chat_payment_notification", + mocker.AsyncMock(), + ) + push_mock = mocker.patch( + "lnbits.core.services.notifications.send_payment_push_notification", + mocker.AsyncMock(), + ) + dispatch_mock = mocker.patch( + "lnbits.core.services.notifications.dispatch_webhook", + mocker.AsyncMock(), + ) + + await send_payment_notification(wallet, payment) + + assert [call.args[0].id for call in ws_mock.await_args_list] == [ + wallet.id, + shared_wallet.id, + ] + chat_mock.assert_awaited_once_with(wallet, payment) + push_mock.assert_awaited_once_with(wallet, payment) + dispatch_mock.assert_awaited_once_with(payment) + + +@pytest.mark.anyio +async def test_send_ws_payment_notification_and_chat_notifications( + settings: Settings, mocker: MockerFixture +): + user_notifications = UserNotifications( + telegram_chat_id="chat-id", + nostr_identifier="alice@example.com", + email_address="alice@example.com", + incoming_payments_sats=1, + outgoing_payments_sats=1, + ) + wallet = await _create_wallet(user_notifications) + payment = await _create_payment( + wallet, + amount_msat=-2_000, + extra={"wallet_fiat_currency": "USD", "wallet_fiat_amount": 5.25}, + ) + websocket_mock = mocker.patch( + "lnbits.core.services.notifications.websocket_manager.send", + mocker.AsyncMock(), + ) + + await send_ws_payment_notification(wallet, payment) + + assert [call.args[0] for call in websocket_mock.await_args_list] == [ + wallet.inkey, + wallet.adminkey, + payment.payment_hash, + ] + + original_outgoing = settings.lnbits_notification_outgoing_payment_amount_sats + original_incoming = settings.lnbits_notification_incoming_payment_amount_sats + try: + settings.lnbits_notification_outgoing_payment_amount_sats = 1 + settings.lnbits_notification_incoming_payment_amount_sats = 1 + admin_mock = mocker.patch( + "lnbits.core.services.notifications.enqueue_admin_notification" + ) + user_mock = mocker.patch( + "lnbits.core.services.notifications.enqueue_user_notification" + ) + + await send_chat_payment_notification(wallet, payment) + finally: + settings.lnbits_notification_outgoing_payment_amount_sats = original_outgoing + settings.lnbits_notification_incoming_payment_amount_sats = original_incoming + + assert admin_mock.call_args.args[0] == NotificationType.outgoing_payment + assert "`5.25`*USD* / " in admin_mock.call_args.args[1]["fiat_value_fmt"] + assert user_mock.call_args.args[0] == NotificationType.outgoing_payment + + +@pytest.mark.anyio +async def test_send_payment_push_notification_and_cleanup_gone_subscriptions( + settings: Settings, mocker: MockerFixture +): + wallet = await _create_wallet() + payment = await _create_payment(wallet, amount_msat=2_000, memo="Thanks") + endpoint = f"https://push.example/{uuid4().hex}" + subscription = await create_webpush_subscription( + endpoint, + wallet.user, + '{"endpoint":"https://push.example"}', + "push.example", + ) + send_push_mock = mocker.patch( + "lnbits.core.services.notifications.send_push_notification", + mocker.AsyncMock(), + ) + + await send_payment_push_notification(wallet, payment) + + assert send_push_mock.await_args is not None + assert send_push_mock.await_args.args[0].endpoint == subscription.endpoint + assert send_push_mock.await_args.args[1] == f"LNbits: {wallet.name}" + assert "received 2 sats" in send_push_mock.await_args.args[2] + assert send_push_mock.await_args.args[3] == ( + f"https://{subscription.host}/wallet?usr={wallet.user}&wal={wallet.id}" + ) + + original_privkey = settings.lnbits_webpush_privkey + try: + settings.lnbits_webpush_privkey = "" + exc = WebPushException("gone") + exc.response = SimpleNamespace(status_code=HTTPStatus.GONE, text="gone") + mocker.patch( + "lnbits.core.services.notifications.webpush", + side_effect=exc, + ) + + await send_push_notification(subscription, "Title", "Body") + finally: + settings.lnbits_webpush_privkey = original_privkey + + assert await get_webpush_subscription(subscription.endpoint, wallet.user) is None + + +async def _create_wallet( + notifications: UserNotifications | None = None, + *, + name: str | None = None, +) -> Wallet: + account = Account( + id=uuid4().hex, + username=f"user_{uuid4().hex[:8]}", + extra=UserExtra(notifications=notifications or UserNotifications()), + ) + await create_account(account) + return await create_wallet( + user_id=account.id, + wallet_name=name or f"wallet_{account.id[:8]}", + ) + + +async def _create_payment( + wallet: Wallet, + *, + amount_msat: int = 2_000, + status: PaymentState = PaymentState.SUCCESS, + webhook: str | None = None, + webhook_status: str | None = None, + memo: str | None = "memo", + extra: dict | None = None, +) -> Payment: + checking_id = f"checking_{uuid4().hex[:8]}" + payment = await create_payment( + checking_id=checking_id, + data=CreatePayment( + wallet_id=wallet.id, + payment_hash=uuid4().hex, + bolt11=f"bolt11-{checking_id}", + amount_msat=amount_msat, + memo=memo or "", + webhook=webhook, + extra=extra or {}, + ), + status=status, + ) + if webhook_status is not None: + payment.webhook_status = webhook_status + await update_payment(payment) + return await get_payment(checking_id) diff --git a/tests/unit/test_services_payments.py b/tests/unit/test_services_payments.py new file mode 100644 index 000000000..d2bb8d293 --- /dev/null +++ b/tests/unit/test_services_payments.py @@ -0,0 +1,569 @@ +from datetime import datetime, timedelta, timezone +from types import SimpleNamespace +from uuid import uuid4 + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import ( + create_account, + create_payment, + create_wallet, + get_payment, + get_payments, + update_payment, +) +from lnbits.core.models import ( + Account, + CreateInvoice, + CreatePayment, + PaymentState, + Wallet, +) +from lnbits.core.services.payments import ( + calculate_fiat_amounts, + cancel_hold_invoice, + check_payment_status, + check_pending_payments, + check_time_limit_between_transactions, + check_transaction_status, + check_wallet_daily_withdraw_limit, + check_wallet_limits, + create_payment_request, + get_payments_daily_stats, + settle_hold_invoice, + update_pending_payment, + update_pending_payments, + update_wallet_balance, +) +from lnbits.db import Filters +from lnbits.exceptions import InvoiceError, PaymentError +from lnbits.settings import Settings +from lnbits.wallets.base import ( + InvoiceResponse, + PaymentFailedStatus, + PaymentPendingStatus, + PaymentResponse, + PaymentStatus, + PaymentSuccessStatus, +) + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + (True, (True, False, False)), + (None, (False, True, False)), + (False, (False, False, True)), + ], +) +def test_payment_response_states_are_mutually_exclusive(value, expected): + response = PaymentResponse(ok=value) + assert (response.success, response.pending, response.failed) == expected + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + (True, (True, False, False)), + (None, (False, True, False)), + (False, (False, True, True)), + ], +) +def test_payment_status_properties(value, expected): + status = PaymentStatus(paid=value) + assert (status.success, status.pending, status.failed) == expected + + +@pytest.mark.anyio +async def test_create_payment_request_routes_by_invoice_type(mocker: MockerFixture): + wallet_payment = SimpleNamespace(checking_id="wallet") + fiat_payment = SimpleNamespace(checking_id="fiat") + wallet_mock = mocker.patch( + "lnbits.core.services.payments.create_wallet_invoice", + mocker.AsyncMock(return_value=wallet_payment), + ) + fiat_mock = mocker.patch( + "lnbits.core.services.payments.create_fiat_invoice", + mocker.AsyncMock(return_value=fiat_payment), + ) + + assert ( + await create_payment_request("wallet-1", CreateInvoice(amount=1)) + == wallet_payment + ) + assert ( + await create_payment_request( + "wallet-1", + CreateInvoice(amount=1, fiat_provider="stripe"), + ) + == fiat_payment + ) + wallet_mock.assert_awaited_once() + fiat_mock.assert_awaited_once() + + +@pytest.mark.anyio +@pytest.mark.parametrize("fiat_provider", ("stripe", "square", "paypal")) +async def test_create_payment_request_rejects_fiat_subscription( + fiat_provider: str, mocker: MockerFixture +): + fiat_mock = mocker.patch( + "lnbits.core.services.payments.create_fiat_invoice", + mocker.AsyncMock(), + ) + + with pytest.raises( + ValueError, + match="Cannot create direct fiat subscription payments.", + ): + await create_payment_request( + "wallet-1", + CreateInvoice( + unit="USD", + amount=2100, + fiat_provider=fiat_provider, + extra={ + "fiat_method": "subscription", + "subscription": { + "checking_id": "fiat_stripe_cs_paid_session", + "payment_request": "", + }, + }, + ), + ) + + fiat_mock.assert_not_awaited() + + +@pytest.mark.anyio +async def test_update_pending_payment_and_bulk_pending_updates(mocker: MockerFixture): + wallet = await _create_wallet() + failed_id = await _create_payment(wallet) + success_id = await _create_payment(wallet) + failed_payment = await get_payment(failed_id) + success_payment = await get_payment(success_id) + + mocker.patch( + "lnbits.core.services.payments.check_payment_status", + mocker.AsyncMock(side_effect=[PaymentFailedStatus(), PaymentSuccessStatus()]), + ) + + await update_pending_payment(failed_payment) + await update_pending_payment(success_payment) + + assert (await get_payment(failed_id)).status == PaymentState.FAILED + assert (await get_payment(success_id)).status == PaymentState.SUCCESS + + bulk_wallet = await _create_wallet() + bulk_failed_id = await _create_payment(bulk_wallet) + bulk_success_id = await _create_payment(bulk_wallet) + mocker.patch( + "lnbits.core.services.payments.check_payment_status", + mocker.AsyncMock(side_effect=[PaymentFailedStatus(), PaymentSuccessStatus()]), + ) + + await update_pending_payments(bulk_wallet.id) + + bulk_statuses = { + (await get_payment(bulk_failed_id)).status, + (await get_payment(bulk_success_id)).status, + } + assert bulk_statuses == {PaymentState.FAILED, PaymentState.SUCCESS} + + +@pytest.mark.anyio +async def test_update_pending_payment_marks_expired_incoming_invoice_failed( + app, + mocker: MockerFixture, +): + wallet = await _create_wallet() + checking_id = await _create_payment( + wallet, + expiry=datetime.now(timezone.utc) - timedelta(seconds=1), + labels=["test"], + ) + payment = await get_payment(checking_id) + check_status_mock = mocker.patch( + "lnbits.core.services.payments.check_payment_status", + mocker.AsyncMock( + side_effect=AssertionError("expired invoices should not be checked") + ), + ) + + updated_payment = await update_pending_payment(payment) + + assert updated_payment.status == PaymentState.FAILED + assert updated_payment.labels == ["test", "expired"] + check_status_mock.assert_not_awaited() + + stored_payment = await get_payment(checking_id) + assert stored_payment.status == PaymentState.FAILED + assert stored_payment.labels == ["test", "expired"] + + +@pytest.mark.anyio +async def test_check_pending_payments_skips_voidwallet_and_updates_recent_items( + mocker: MockerFixture, +): + class VoidWallet: + pass + + class FakeWalletSource: + pass + + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=VoidWallet(), + ) + sleep_mock = mocker.patch( + "lnbits.core.services.payments.asyncio.sleep", mocker.AsyncMock() + ) + + await check_pending_payments() + sleep_mock.assert_not_awaited() + + existing_pending = await get_payments(pending=True, exclude_uncheckable=True) + wallet = await _create_wallet() + checking_id = await _create_payment(wallet) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=FakeWalletSource(), + ) + mocker.patch( + "lnbits.core.services.payments.check_payment_status", + mocker.AsyncMock(return_value=PaymentSuccessStatus()), + ) + + try: + await check_pending_payments() + finally: + for payment in existing_pending: + payment.status = PaymentState.PENDING + await update_payment(payment) + + assert (await get_payment(checking_id)).status == PaymentState.SUCCESS + assert sleep_mock.await_count >= 1 + + +@pytest.mark.anyio +async def test_update_wallet_balance_validates_credit_and_debit( + settings: Settings, mocker: MockerFixture +): + wallet = await _create_wallet() + wallet.balance_msat = 20_000 + + with pytest.raises(ValueError, match="Amount cannot be 0."): + await update_wallet_balance(wallet, 0) + + with pytest.raises(ValueError, match="can not go into negative balance"): + await update_wallet_balance(wallet, -30) + + payment_secret = (uuid4().hex * 2)[:64] + payment_hash = (uuid4().hex * 2)[:64] + mocker.patch( + "lnbits.core.services.payments.random_secret_and_hash", + return_value=(payment_secret, payment_hash), + ) + mocker.patch( + "lnbits.core.services.payments.fake_privkey", + return_value="privkey", + ) + mocker.patch( + "lnbits.core.services.payments.bolt11_encode", + return_value="encoded-bolt11", + ) + + await update_wallet_balance(wallet, -10) + + debit_payment = await get_payment("internal_" + payment_hash) + assert debit_payment is not None + assert debit_payment.amount == -10_000 + assert debit_payment.status == PaymentState.SUCCESS + + original_max_balance = settings.lnbits_wallet_limit_max_balance + try: + settings.lnbits_wallet_limit_max_balance = 21 + with pytest.raises(ValueError, match="amount exceeds maximum balance"): + await update_wallet_balance(wallet, 5) + + settings.lnbits_wallet_limit_max_balance = 0 + queue_mock = mocker.patch( + "lnbits.task_manager.task_manager.internal_invoice_queue.put_nowait", + ) + + await update_wallet_balance(wallet, 5) + finally: + settings.lnbits_wallet_limit_max_balance = original_max_balance + + credit_payments = [ + payment + for payment in await get_payments(wallet_id=wallet.id, incoming=True) + if payment.memo == "Admin credit" + ] + assert credit_payments + assert credit_payments[0].status == PaymentState.SUCCESS + queue_mock.assert_called_once() + assert queue_mock.call_args[0][0].checking_id == credit_payments[0].checking_id + + +@pytest.mark.anyio +async def test_check_wallet_limits_and_time_limit( + settings: Settings, mocker: MockerFixture +): + time_limit_mock = mocker.patch( + "lnbits.core.services.payments.check_time_limit_between_transactions", + mocker.AsyncMock(), + ) + daily_limit_mock = mocker.patch( + "lnbits.core.services.payments.check_wallet_daily_withdraw_limit", + mocker.AsyncMock(), + ) + + await check_wallet_limits("wallet-1", 1_000) + + time_limit_mock.assert_awaited_once_with("wallet-1", None) + daily_limit_mock.assert_awaited_once_with("wallet-1", 1_000, None) + + wallet = await _create_wallet() + await _create_payment(wallet, amount_msat=-2_000) + original_limit = settings.lnbits_wallet_limit_secs_between_trans + try: + settings.lnbits_wallet_limit_secs_between_trans = 30 + with pytest.raises(PaymentError) as exc_info: + await check_time_limit_between_transactions(wallet.id) + assert "30 seconds between payments" in exc_info.value.message + + other_wallet = await _create_wallet() + assert await check_time_limit_between_transactions(other_wallet.id) is None + finally: + settings.lnbits_wallet_limit_secs_between_trans = original_limit + + +@pytest.mark.anyio +async def test_check_wallet_daily_limit_counts_all_daily_payments(settings: Settings): + wallet = await _create_wallet() + await _create_payment(wallet, amount_msat=-2_000, status=PaymentState.SUCCESS) + await _create_payment(wallet, amount_msat=-3_000, status=PaymentState.SUCCESS) + + original_limit = settings.lnbits_wallet_limit_daily_max_withdraw + try: + settings.lnbits_wallet_limit_daily_max_withdraw = 5 + with pytest.raises( + ValueError, match="Daily withdrawal limit of 5 sats reached." + ): + await check_wallet_daily_withdraw_limit(wallet.id, 1_000) + finally: + settings.lnbits_wallet_limit_daily_max_withdraw = original_limit + + +@pytest.mark.anyio +async def test_calculate_fiat_amounts_handles_conversion_and_errors( + mocker: MockerFixture, +): + wallet = await _create_wallet() + wallet.currency = "EUR" + mocker.patch( + "lnbits.core.services.payments.fiat_amount_as_satoshis", + mocker.AsyncMock(return_value=200), + ) + sat_to_fiat_mock = mocker.patch( + "lnbits.core.services.payments.satoshis_amount_as_fiat", + mocker.AsyncMock(return_value=1.5), + ) + + amount_sat, fiat_amounts = await calculate_fiat_amounts(2.0, wallet, "USD") + + assert amount_sat == 200 + assert fiat_amounts["fiat_currency"] == "USD" + assert fiat_amounts["wallet_fiat_currency"] == "EUR" + assert fiat_amounts["wallet_fiat_amount"] == 1.5 + + sat_to_fiat_mock.side_effect = Exception("boom") + amount_sat, fiat_amounts = await calculate_fiat_amounts(10, wallet, "sat", extra={}) + + assert amount_sat == 10 + assert fiat_amounts == {} + + +@pytest.mark.anyio +async def test_check_transaction_status_and_payment_status(mocker: MockerFixture): + wallet = await _create_wallet() + missing_hash = uuid4().hex + assert (await check_transaction_status(wallet.id, missing_hash)).pending is True + + success_hash = uuid4().hex + success_id = await _create_payment( + wallet, + status=PaymentState.SUCCESS, + payment_hash=success_hash, + fee=-123, + ) + success_status = await check_transaction_status(wallet.id, success_hash) + assert success_status.success is True + assert success_status.fee_msat == -123 + + pending_hash = uuid4().hex + await _create_payment(wallet, payment_hash=pending_hash) + mocker.patch( + "lnbits.core.services.payments.check_payment_status", + mocker.AsyncMock(return_value=PaymentFailedStatus()), + ) + assert (await check_transaction_status(wallet.id, pending_hash)).failed is True + + internal_success = await get_payment(success_id) + internal_success.checking_id = "internal_" + internal_success.payment_hash + internal_success.status = PaymentState.SUCCESS.value + assert (await check_payment_status(internal_success)).success is True + + internal_failed = await get_payment(success_id) + internal_failed.checking_id = "internal_" + internal_failed.payment_hash + internal_failed.status = PaymentState.FAILED.value + assert (await check_payment_status(internal_failed)).failed is True + + internal_fiat = await get_payment(success_id) + internal_fiat.checking_id = "fiat_" + internal_fiat.payment_hash + internal_fiat.status = PaymentState.PENDING.value + internal_fiat.fiat_provider = "stripe" + mocker.patch( + "lnbits.core.services.payments.check_fiat_status", + mocker.AsyncMock(return_value=SimpleNamespace(paid=True)), + ) + assert (await check_payment_status(internal_fiat)).success is True + + outgoing = await get_payment(success_id) + outgoing.checking_id = "external-out" + outgoing.amount = -2_000 + incoming = await get_payment(success_id) + incoming.checking_id = "external-in" + incoming.amount = 2_000 + funding_source = SimpleNamespace( + get_payment_status=mocker.AsyncMock(return_value=PaymentSuccessStatus()), + get_invoice_status=mocker.AsyncMock(return_value=PaymentPendingStatus()), + ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=funding_source, + ) + + assert (await check_payment_status(outgoing)).success is True + assert (await check_payment_status(incoming)).pending is True + + +@pytest.mark.anyio +async def test_get_payments_daily_stats_fills_missing_dates(): + wallet = await _create_wallet() + user_id = wallet.user + now = datetime.now(timezone.utc).replace(hour=12, minute=0, second=0, microsecond=0) + await _create_payment( + wallet, + amount_msat=2_000, + status=PaymentState.SUCCESS, + time=now - timedelta(days=2), + ) + await _create_payment( + wallet, + amount_msat=-500, + status=PaymentState.SUCCESS, + fee=100, + time=now, + ) + + stats = await get_payments_daily_stats(Filters(), user_id=user_id) + + assert [point.date.date() for point in stats[-3:]] == [ + (now - timedelta(days=2)).date(), + (now - timedelta(days=1)).date(), + now.date(), + ] + assert [point.balance for point in stats[-3:]] == [2, 2, 1] + assert stats[-1].fee == 0 + + +@pytest.mark.anyio +async def test_settle_and_cancel_hold_invoice_persist_status(mocker: MockerFixture): + wallet = await _create_wallet() + checking_id = await _create_payment(wallet, payment_hash="33" * 32) + payment = await get_payment(checking_id) + funding_source = SimpleNamespace( + settle_hold_invoice=mocker.AsyncMock( + return_value=InvoiceResponse(ok=True, checking_id="settled") + ), + cancel_hold_invoice=mocker.AsyncMock( + return_value=InvoiceResponse(ok=True, checking_id="cancelled") + ), + ) + mocker.patch( + "lnbits.core.services.payments.get_funding_source", + return_value=funding_source, + ) + mocker.patch( + "lnbits.core.services.payments.verify_preimage", + return_value=False, + ) + + with pytest.raises(InvoiceError, match="Invalid preimage."): + await settle_hold_invoice(payment, "00" * 32) + + mocker.patch( + "lnbits.core.services.payments.verify_preimage", + return_value=True, + ) + + assert (await settle_hold_invoice(payment, "11" * 32)).ok is True + assert (await cancel_hold_invoice(payment)).ok is True + + stored = await get_payment(checking_id) + assert stored.preimage == "11" * 32 + assert stored.extra["hold_invoice_settled"] is True + assert stored.extra["hold_invoice_cancelled"] is True + assert stored.status == PaymentState.FAILED + + +def _account() -> Account: + account_id = uuid4().hex + return Account(id=account_id, username=f"user_{account_id[:8]}") + + +async def _create_wallet() -> Wallet: + account = _account() + await create_account(account) + return await create_wallet( + user_id=account.id, wallet_name=f"wallet_{account.id[:8]}" + ) + + +async def _create_payment( + wallet: Wallet, + *, + amount_msat: int = 2_000, + status: PaymentState = PaymentState.PENDING, + checking_id: str | None = None, + payment_hash: str | None = None, + fee: int = 0, + time: datetime | None = None, + expiry: datetime | None = None, + labels: list[str] | None = None, +) -> str: + checking_id = checking_id or f"checking_{uuid4().hex[:8]}" + payment_hash = payment_hash or uuid4().hex + payment = await create_payment( + checking_id=checking_id, + data=CreatePayment( + wallet_id=wallet.id, + payment_hash=payment_hash, + bolt11=f"bolt11-{checking_id}", + amount_msat=amount_msat, + memo="memo", + expiry=expiry, + fee=fee, + labels=labels, + ), + status=status, + ) + if time: + payment.time = time + payment.created_at = time + payment.updated_at = time + await update_payment(payment) + return checking_id diff --git a/tests/unit/test_services_settings.py b/tests/unit/test_services_settings.py new file mode 100644 index 000000000..af82deaed --- /dev/null +++ b/tests/unit/test_services_settings.py @@ -0,0 +1,155 @@ +import pytest +from pydantic import ValidationError +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import ( + create_admin_settings, + delete_admin_settings, + get_super_settings, +) +from lnbits.core.crud.settings import get_settings_field +from lnbits.core.services.settings import ( + check_webpush_settings, + dict_to_settings, + update_cached_settings, +) +from lnbits.settings import Settings + + +class FakePublicKey: + def public_bytes(self, *_args, **_kwargs): + return b"public-bytes" + + +class FakeVapid: + def __init__(self, has_public_key: bool = True): + self.public_key = FakePublicKey() if has_public_key else None + + def generate_keys(self): + return None + + def private_pem(self): + return b"private-key" + + +def test_dict_to_settings_parses_known_values(): + parsed = dict_to_settings( + { + "lnbits_site_title": "Test Title", + "lnbits_service_fee": 5, + "lnbits_default_burger_menu_background": False, + "ignored_field": "ignored", + } + ) + + assert parsed.lnbits_site_title == "Test Title" + assert parsed.lnbits_service_fee == 5 + assert parsed.lnbits_default_burger_menu_background is False + assert not hasattr(parsed, "ignored_field") + + +def test_dict_to_settings_validates_invalid_values(): + with pytest.raises(ValidationError): + dict_to_settings({"lnbits_service_fee": "not-a-number"}) + + +def test_update_cached_settings_updates_runtime_values(settings: Settings): + original_title = settings.lnbits_site_title + original_host = settings.host + original_super_user = settings.super_user + try: + update_cached_settings( + { + "lnbits_site_title": "Updated", + "host": "forbidden-host", + "super_user": "super-user-id", + "missing_field": "ignored", + } + ) + + assert settings.lnbits_site_title == "Updated" + assert settings.host == original_host + assert settings.super_user == "super-user-id" + finally: + settings.lnbits_site_title = original_title + settings.host = original_host + settings.super_user = original_super_user + + +@pytest.mark.anyio +async def test_check_webpush_settings_generates_and_persists_keys( + settings: Settings, mocker: MockerFixture +): + previous_settings = await get_super_settings() + previous_private = settings.lnbits_webpush_privkey + previous_public = settings.lnbits_webpush_pubkey + previous_admin_ui = settings.lnbits_admin_ui + await delete_admin_settings() + + settings.lnbits_webpush_privkey = "" + settings.lnbits_webpush_pubkey = None + settings.lnbits_admin_ui = True + mocker.patch("lnbits.core.services.settings.Vapid", return_value=FakeVapid()) + mocker.patch( + "lnbits.core.services.settings.b64urlencode", return_value="public-key" + ) + try: + await check_webpush_settings() + + stored_private = await get_settings_field("lnbits_webpush_privkey") + stored_public = await get_settings_field("lnbits_webpush_pubkey") + + assert settings.lnbits_webpush_privkey == "private-key" + assert settings.lnbits_webpush_pubkey == "public-key" + assert stored_private is not None + assert stored_private.value == "private-key" + assert stored_public is not None + assert stored_public.value == "public-key" + finally: + await delete_admin_settings() + if previous_settings: + await create_admin_settings( + previous_settings.super_user, + previous_settings.dict(exclude={"super_user"}), + ) + update_cached_settings(previous_settings.dict()) + settings.lnbits_webpush_privkey = previous_private + settings.lnbits_webpush_pubkey = previous_public + settings.lnbits_admin_ui = previous_admin_ui + + +@pytest.mark.anyio +async def test_check_webpush_settings_requires_public_key( + settings: Settings, mocker: MockerFixture +): + mocker.patch.object(settings, "lnbits_webpush_privkey", "") + mocker.patch.object(settings, "lnbits_admin_ui", False) + mocker.patch( + "lnbits.core.services.settings.Vapid", + return_value=FakeVapid(has_public_key=False), + ) + + with pytest.raises(ValueError, match="VAPID public key does not exist"): + await check_webpush_settings() + + +@pytest.mark.anyio +async def test_check_webpush_settings_skips_generation_when_keys_exist( + settings: Settings, mocker: MockerFixture +): + previous_private = settings.lnbits_webpush_privkey + previous_public = settings.lnbits_webpush_pubkey + previous_private_field = await get_settings_field("lnbits_webpush_privkey") + previous_public_field = await get_settings_field("lnbits_webpush_pubkey") + settings.lnbits_webpush_privkey = "existing-private-key" + settings.lnbits_webpush_pubkey = "existing-public-key" + vapid = mocker.patch("lnbits.core.services.settings.Vapid") + try: + await check_webpush_settings() + finally: + settings.lnbits_webpush_privkey = previous_private + settings.lnbits_webpush_pubkey = previous_public + + assert await get_settings_field("lnbits_webpush_privkey") == previous_private_field + assert await get_settings_field("lnbits_webpush_pubkey") == previous_public_field + vapid.assert_not_called() diff --git a/tests/unit/test_services_users.py b/tests/unit/test_services_users.py new file mode 100644 index 000000000..0e656c5e8 --- /dev/null +++ b/tests/unit/test_services_users.py @@ -0,0 +1,408 @@ +from typing import Any +from uuid import uuid4 + +import pytest + +from lnbits.core.crud import ( + create_account, + create_admin_settings, + create_user_extension, + delete_admin_settings, + get_account, + get_super_settings, + get_user_extensions, + get_wallets, +) +from lnbits.core.crud.settings import get_settings_field, set_settings_field +from lnbits.core.models import Account +from lnbits.core.models.extensions import UserExtension +from lnbits.core.models.users import RegisterUser +from lnbits.core.services.settings import update_cached_settings +from lnbits.core.services.users import ( + check_admin_settings, + check_register_activation_settings, + create_user_account, + create_user_account_no_ckeck, + init_admin_settings, + update_user_account, + update_user_extensions, +) +from lnbits.settings import Settings + + +@pytest.mark.anyio +async def test_create_user_account_rejects_when_registration_disabled( + settings: Settings, +): + settings.lnbits_allow_new_accounts = False + + with pytest.raises(ValueError, match="Account creation is disabled."): + await create_user_account() + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("existing_data", "new_data", "message"), + [ + ( + {"username": f"user_{uuid4().hex[:8]}"}, + {"username": lambda existing: existing.username}, + "Username already exists.", + ), + ( + {"email": f"{uuid4().hex[:8]}@example.com"}, + {"email": lambda existing: existing.email}, + "Email already exists.", + ), + ( + {"pubkey": f"{1:064x}"}, + {"pubkey": lambda existing: existing.pubkey}, + "Pubkey already exists.", + ), + ], +) +async def test_create_user_account_no_check_rejects_duplicate_identity_fields( + existing_data: dict, new_data: dict, message: str +): + existing = _account(**existing_data) + await create_account(existing) + + resolved: dict[str, Any] = { + key: (value(existing) if callable(value) else value) + for key, value in new_data.items() + } + account = _account(**resolved) + + with pytest.raises(ValueError, match=message): + await create_user_account_no_ckeck(account) + + +@pytest.mark.anyio +async def test_create_user_account_no_check_creates_wallet_and_extensions( + settings: Settings, +): + account = _account() + original_default_exts = list(settings.lnbits_user_default_extensions) + try: + settings.lnbits_user_default_extensions = ["default-ext"] + + user = await create_user_account_no_ckeck( + account, + wallet_name="Primary", + default_exts=["extra-ext"], + ) + finally: + settings.lnbits_user_default_extensions = original_default_exts + + wallets = await get_wallets(user.id) + user_extensions = await get_user_extensions(user.id) + + assert len(wallets) == 1 + assert wallets[0].name == "Primary" + assert {ext.extension for ext in user_extensions} == {"default-ext", "extra-ext"} + assert all(ext.active is True for ext in user_extensions) + + +# TDOO: revisit for postgres +# @pytest.mark.anyio +# async def test_create_user_account_no_check_duplicate_extension_insert_behavior( +# settings: Settings, +# ): +# account = _account() +# original_default_exts = list(settings.lnbits_user_default_extensions) +# try: +# settings.lnbits_user_default_extensions = ["dup-ext"] +# if DB_TYPE == POSTGRES: +# with pytest.raises(DBAPIError, match="current transaction is aborted"): +# await create_user_account_no_ckeck(account, default_exts=["dup-ext"]) +# else: +# user = await +# create_user_account_no_ckeck(account, default_exts=["dup-ext"]) +# finally: +# settings.lnbits_user_default_extensions = original_default_exts + +# if DB_TYPE == POSTGRES: +# assert await get_account(account.id) is not None +# else: +# user_extensions = await get_user_extensions(user.id) +# assert [ext.extension for ext in user_extensions] == ["dup-ext"] + + +@pytest.mark.anyio +async def test_update_user_account_requires_existing_user(): + account = _account() + + with pytest.raises(ValueError, match="User does not exist."): + await update_user_account(account) + + +@pytest.mark.anyio +async def test_update_user_account_rejects_conflicting_identity_fields(): + existing = _account(pubkey=_pubkey(2)) + conflict = _account(pubkey=_pubkey(3)) + await create_account(existing) + await create_account(conflict) + + with pytest.raises(ValueError, match="Username already exists."): + await update_user_account( + _account( + id_=existing.id, + username=conflict.username, + email=existing.email, + pubkey=existing.pubkey, + ) + ) + + with pytest.raises(ValueError, match="Email already exists."): + await update_user_account( + _account( + id_=existing.id, + username=existing.username, + email=conflict.email, + pubkey=existing.pubkey, + ) + ) + + with pytest.raises(ValueError, match="Pubkey already exists."): + await update_user_account( + _account( + id_=existing.id, + username=existing.username, + email=existing.email, + pubkey=conflict.pubkey, + ) + ) + + +@pytest.mark.anyio +async def test_update_user_account_updates_persisting_password(): + account = _account(pubkey=_pubkey(4)) + account.hash_password("secret1234") + await create_account(account) + + updated = _account( + id_=account.id, + username=f"updated_{account.id[:8]}", + email=f"{account.id[:8]}+updated@example.com", + pubkey=(uuid4().hex * 2)[:64], + ) + result = await update_user_account(updated) + stored = await get_account(account.id) + + assert result.id == account.id + assert stored is not None + assert stored.username == updated.username + assert stored.email == updated.email + assert stored.pubkey == updated.pubkey + assert stored.password_hash == account.password_hash + + +@pytest.mark.anyio +async def test_update_user_extensions_toggles_existing_and_creates_missing( + settings: Settings, +): + original_default_exts = list(settings.lnbits_user_default_extensions) + try: + settings.lnbits_user_default_extensions = [] + user = await create_user_account(_account()) + finally: + settings.lnbits_user_default_extensions = original_default_exts + + await create_user_extension( + UserExtension(user=user.id, extension="keep", active=True) + ) + await create_user_extension( + UserExtension(user=user.id, extension="enable", active=False) + ) + await create_user_extension( + UserExtension(user=user.id, extension="disable", active=True) + ) + + await update_user_extensions(user.id, ["keep", "enable", "new-ext"]) + + user_extensions = { + ext.extension: ext.active for ext in await get_user_extensions(user.id) + } + assert user_extensions == { + "keep": True, + "enable": True, + "disable": False, + "new-ext": True, + } + + +@pytest.mark.anyio +async def test_check_admin_settings_initializes_cache_and_marks_first_install( + settings: Settings, tmp_path +): + previous_settings = await get_super_settings() + previous_super_user = settings.super_user + previous_data_folder = settings.lnbits_data_folder + previous_admin_ui = settings.lnbits_admin_ui + previous_first_install = settings.first_install + super_user = uuid4().hex + + try: + await delete_admin_settings() + settings.super_user = super_user + settings.lnbits_data_folder = str(tmp_path) + settings.lnbits_admin_ui = True + settings.first_install = False + + await check_admin_settings() + + stored_settings = await get_super_settings() + stored_account = await get_account(super_user) + assert stored_settings is not None + assert stored_settings.super_user == super_user + assert stored_account is not None + assert stored_account.extra.provider == "env" + assert settings.first_install is True + assert (tmp_path / ".super_user").read_text() == super_user + finally: + await delete_admin_settings() + if previous_settings: + await create_admin_settings( + previous_settings.super_user, + previous_settings.dict(exclude={"super_user"}), + ) + update_cached_settings(previous_settings.dict()) + settings.super_user = previous_super_user + settings.lnbits_data_folder = previous_data_folder + settings.lnbits_admin_ui = previous_admin_ui + settings.first_install = previous_first_install + + +@pytest.mark.anyio +async def test_init_admin_settings_creates_account_and_wallet_when_missing(): + super_user = uuid4().hex + + result = await init_admin_settings(super_user) + + wallets = await get_wallets(super_user) + assert result.super_user == super_user + assert await get_account(super_user) is not None + assert len(wallets) == 1 + + +@pytest.mark.anyio +async def test_check_register_activation_settings_handles_invitation_codes( + settings: Settings, +): + reusable = "reusable-code" + one_time = "one-time-code" + original_require_activation = settings.lnbits_require_user_activation + original_by_invite = settings.lnbits_user_activation_by_invitation_code + original_reusable = settings.lnbits_register_reusable_activation_code + original_one_time = list(settings.lnbits_register_one_time_activation_codes) + previous_stored_codes = await get_settings_field( + "lnbits_register_one_time_activation_codes" + ) + + try: + settings.lnbits_require_user_activation = False + assert ( + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + ) + ) + is None + ) + + settings.lnbits_require_user_activation = True + settings.lnbits_user_activation_by_invitation_code = True + settings.lnbits_register_reusable_activation_code = reusable + settings.lnbits_register_one_time_activation_codes = [one_time] + + with pytest.raises(ValueError, match="Invitation code cannot be empty."): + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + invitation_code=" ", + ) + ) + + assert ( + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + invitation_code=reusable, + ) + ) + is None + ) + + assert ( + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + invitation_code=one_time, + ) + ) + is None + ) + assert one_time not in settings.lnbits_register_one_time_activation_codes + stored_codes = await get_settings_field( + "lnbits_register_one_time_activation_codes" + ) + assert stored_codes is not None + assert stored_codes.value == [] + + with pytest.raises(ValueError, match="Invalid invitation code."): + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + invitation_code="bad-code", + ) + ) + + settings.lnbits_user_activation_by_invitation_code = False + with pytest.raises(ValueError, match="No activation method provided."): + await check_register_activation_settings( + RegisterUser( + username=f"user_{uuid4().hex[:8]}", + password="secret1234", + password_repeat="secret1234", + invitation_code=reusable, + ) + ) + finally: + settings.lnbits_require_user_activation = original_require_activation + settings.lnbits_user_activation_by_invitation_code = original_by_invite + settings.lnbits_register_reusable_activation_code = original_reusable + settings.lnbits_register_one_time_activation_codes = original_one_time + await set_settings_field( + "lnbits_register_one_time_activation_codes", + previous_stored_codes.value if previous_stored_codes else original_one_time, + ) + + +def _pubkey(value: int) -> str: + return f"{value:064x}" + + +def _account( + *, + id_: str | None = None, + username: str | None = None, + email: str | None = None, + pubkey: str | None = None, +) -> Account: + account_id = id_ or uuid4().hex + return Account( + id=account_id, + username=username or f"user_{account_id[:8]}", + email=email or f"{account_id[:8]}@example.com", + pubkey=pubkey, + ) diff --git a/tests/unit/test_services_websockets.py b/tests/unit/test_services_websockets.py new file mode 100644 index 000000000..a495fb677 --- /dev/null +++ b/tests/unit/test_services_websockets.py @@ -0,0 +1,76 @@ +from typing import cast + +import pytest +from fastapi import WebSocket, WebSocketDisconnect +from pytest_mock.plugin import MockerFixture + +from lnbits.core.services.websockets import ( + WebsocketConnectionManager, + websocket_updater, +) +from lnbits.settings import Settings + + +class FakeWebSocket: + def __init__(self, received=None): + self.received = list(received or []) + self.accepted = False + self.sent: list[str] = [] + + async def accept(self): + self.accepted = True + + async def receive_text(self): + if self.received: + value = self.received.pop(0) + if isinstance(value, Exception): + raise value + return value + raise WebSocketDisconnect() + + async def send_text(self, data: str): + self.sent.append(data) + + +@pytest.mark.anyio +async def test_websocket_connection_manager_connect_and_send(): + manager = WebsocketConnectionManager() + websocket = FakeWebSocket() + + conn = await manager.connect("item-1", cast(WebSocket, websocket)) + await manager.send("item-1", "payload") + + assert websocket.accepted is True + assert manager.has_connection("item-1") is True + assert manager.get_connections("item-1") == [conn] + assert websocket.sent == ["payload"] + + +@pytest.mark.anyio +async def test_websocket_connection_manager_listen_queues_messages_and_disconnects( + settings: Settings, +): + manager = WebsocketConnectionManager() + websocket = FakeWebSocket(["hello", WebSocketDisconnect()]) + conn = await manager.connect("item-2", cast(WebSocket, websocket)) + original_running = settings.lnbits_running + try: + settings.lnbits_running = True + await manager.listen(conn) + finally: + settings.lnbits_running = original_running + + assert conn.receive_queue.get_nowait() == "hello" + assert manager.has_connection("item-2") is False + + +@pytest.mark.anyio +async def test_websocket_updater_delegates_to_manager(mocker: MockerFixture): + send = mocker.patch( + "lnbits.core.services.websockets.websocket_manager.send", + mocker.AsyncMock(), + ) + + await websocket_updater("item-3", "data") + + send.assert_awaited_once_with("item-3", "data") diff --git a/tests/unit/test_settings.py b/tests/unit/test_settings.py index a300afb0f..521bfb538 100644 --- a/tests/unit/test_settings.py +++ b/tests/unit/test_settings.py @@ -1,29 +1,73 @@ +from pathlib import Path +from typing import Any, Literal + import pytest +from pytest_mock.plugin import MockerFixture -from lnbits.settings import RedirectPath +from lnbits.settings import ( + DEFAULT_WASM_MANIFESTS, + AssetSettings, + ExchangeRateProvider, + InstalledExtensionsSettings, + NotificationsSettings, + PublicSettings, + RedirectPath, + SecuritySettings, + Settings, + UsersSettings, + list_parse_fallback, + set_cli_settings, +) -lnurlp_redirect_path = { +lnurlp_redirect_path: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", } -lnurlp_redirect_path_with_headers = { +lnurlp_redirect_path_with_headers: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", "header_filters": {"accept": "application/nostr+json"}, } -lnaddress_redirect_path = { +lnaddress_redirect_path: dict[str, Any] = { "from_path": "/.well-known/lnurlp", "redirect_to_path": "/api/v1/well-known", } -nostrrelay_redirect_path = { +nostrrelay_redirect_path: dict[str, Any] = { "from_path": "/", "redirect_to_path": "/api/v1/relay-info", "header_filters": {"accept": "application/nostr+json"}, } +@pytest.mark.parametrize( + ("mode", "creation_allowed"), + [ + ("core_first", True), + ("extension_first", True), + ("extension_only", False), + ], +) +def test_ln_address_mode( + mode: Literal["core_first", "extension_first", "extension_only"], + creation_allowed: bool, +): + users_settings = UsersSettings(lnbits_ln_address_mode=mode) + + assert users_settings.lnbits_ln_address_mode == mode + assert users_settings.ln_address_creation_allowed is creation_allowed + + +def test_ln_address_mode_defaults_to_extension_first(): + assert UsersSettings().lnbits_ln_address_mode == "extension_first" + + +def test_ln_address_mode_rejects_invalid_value(): + with pytest.raises(ValueError): + UsersSettings.parse_obj({"lnbits_ln_address_mode": "invalid"}) + + @pytest.fixture() def lnurlp(): return RedirectPath(ext_id="lnurlp", **lnurlp_redirect_path) @@ -166,3 +210,219 @@ def test_redirect_path_new_path_from(lnurlp: RedirectPath): lnurlp.new_path_from("/.well-known/lnurlp/path/more") == "/lnurlp/api/v1/well-known/path/more" ) + + +def test_list_parse_fallback(): + assert list_parse_fallback("a, b, c") == ["a", "b", "c"] + assert list_parse_fallback('["a", "b"]') == ["a", "b"] + assert list_parse_fallback("") == [] + + +def test_settings_keep_wasm_manifests_separate_from_extension_manifests(): + settings = Settings( + lnbits_extensions_manifests=["https://example.com/extensions.json"], + lnbits_wasm_extensions_manifests=[ + *DEFAULT_WASM_MANIFESTS, + "https://example.com/extensions.json", + ], + ) + + assert settings.lnbits_extensions_manifests == [ + "https://example.com/extensions.json" + ] + assert settings.lnbits_wasm_extensions_manifests == [ + *DEFAULT_WASM_MANIFESTS, + "https://example.com/extensions.json", + ] + assert settings.dict()["lnbits_extensions_manifests"] == [ + "https://example.com/extensions.json" + ] + assert settings.dict()["lnbits_wasm_extensions_manifests"] == [ + *DEFAULT_WASM_MANIFESTS, + "https://example.com/extensions.json", + ] + + +def test_wasm_extensions_directory_defaults_to_data_folder_and_is_configurable( + tmp_path: Path, +): + data_folder = tmp_path / "data" + default_settings = Settings( + lnbits_data_folder=str(data_folder), + lnbits_wasm_extensions_path="", + ) + custom_path = tmp_path / "custom-wasm" + custom_settings = Settings( + lnbits_data_folder=str(data_folder), + lnbits_wasm_extensions_path=str(custom_path), + ) + + assert default_settings.wasm_extensions_dir == data_folder / "wasm_extensions" + assert default_settings.lnbits_wasm_extensions_path == str( + data_folder / "wasm_extensions" + ) + assert custom_settings.wasm_extensions_dir == custom_path + + +def test_wasm_extensions_directory_must_not_be_importable(tmp_path: Path): + settings = Settings( + lnbits_data_folder=str(tmp_path / "data"), + lnbits_extensions_path=str(tmp_path / "code"), + lnbits_wasm_extensions_path=str( + tmp_path / "code" / "extensions" / "wasm_extensions" + ), + ) + + with pytest.raises(ValueError, match="outside importable extension directories"): + _ = settings.wasm_extensions_dir + + +def test_exchange_rate_provider_convert_ticker(): + provider = ExchangeRateProvider( + name="Provider", + api_url="https://example.com", + path="$.price", + ticker_conversion=["USD:USDT"], + ) + invalid_provider = ExchangeRateProvider( + name="Invalid", + api_url="https://example.com", + path="$.price", + ticker_conversion=["invalid"], + ) + + assert provider.convert_ticker("USD") == "USDT" + assert provider.convert_ticker("EUR") == "EUR" + assert invalid_provider.convert_ticker("USD") == "USD" + + +def test_installed_extensions_settings_activate_and_deactivate_paths(): + installed = InstalledExtensionsSettings() + redirects = [ + { + "from_path": "/.well-known/lnurlp", + "redirect_to_path": "/api/v1/well-known", + } + ] + + installed.activate_extension_paths("lnurlp", ext_redirects=redirects) + + redirect = installed.find_extension_redirect("/.well-known/lnurlp", []) + assert redirect is not None + assert redirect.ext_id == "lnurlp" + assert "lnurlp" in installed.lnbits_installed_extensions_ids + + installed.deactivate_extension_paths("lnurlp") + + assert "lnurlp" in installed.lnbits_deactivated_extensions + assert installed.find_extension_redirect("/.well-known/lnurlp", []) is None + + +def test_public_settings_include_burger_menu_background(settings: Settings): + settings.lnbits_default_burger_menu_background = False + + public_settings = PublicSettings.from_settings(settings) + + assert public_settings.default_burger_menu_background is False + + +def test_installed_extensions_settings_detects_conflicting_redirects(): + installed = InstalledExtensionsSettings( + lnbits_extensions_redirects=[ + RedirectPath( + ext_id="ext_a", + from_path="/.well-known/lnurlp", + redirect_to_path="/api/v1/well-known", + ) + ] + ) + + with pytest.raises(ValueError, match="Cannot redirect for extension 'ext_b'"): + installed.activate_extension_paths( + "ext_b", + ext_redirects=[ + { + "from_path": "/.well-known/lnurlp", + "redirect_to_path": "/api/v1/well-known", + } + ], + ) + + +def test_settings_helper_methods(settings: Settings, mocker: MockerFixture): + mocker.patch.object(settings, "super_user", "super-user") + mocker.patch.object(settings, "lnbits_admin_users", ["admin-user"]) + mocker.patch.object(settings, "lnbits_allowed_users", ["allowed-user"]) + mocker.patch.object(settings, "lnbits_installed_extensions_ids", {"installed"}) + mocker.patch.object(settings, "lnbits_all_extensions_ids", {"installed", "new"}) + + assert settings.is_user_allowed("allowed-user") is True + assert settings.is_user_allowed("admin-user") is True + assert settings.is_user_allowed("super-user") is True + assert settings.is_user_allowed("random-user") is False + assert settings.is_super_user("super-user") is True + assert settings.is_admin_user("admin-user") is True + assert settings.is_installed_extension_id("installed") is True + assert settings.is_ready_to_install_extension_id("new") is True + assert settings.is_ready_to_install_extension_id("installed") is False + + +def test_asset_security_and_notification_helpers( + settings: Settings, mocker: MockerFixture +): + mocker.patch.object(settings, "super_user", "super-user") + mocker.patch.object(settings, "lnbits_admin_users", ["admin-user"]) + + asset_settings = AssetSettings(lnbits_assets_no_limit_users=["vip-user"]) + security_settings = SecuritySettings(lnbits_wallet_limit_max_balance=100) + notification_settings = NotificationsSettings( + lnbits_nostr_notifications_enabled=True, + lnbits_nostr_notifications_private_key="nostr-key", + lnbits_telegram_notifications_enabled=True, + lnbits_telegram_notifications_access_token="telegram-token", + ) + + assert asset_settings.is_unlimited_assets_user("admin-user") is True + assert asset_settings.is_unlimited_assets_user("vip-user") is True + assert asset_settings.is_unlimited_assets_user("random-user") is False + assert security_settings.is_wallet_max_balance_exceeded(101) is True + assert security_settings.is_wallet_max_balance_exceeded(100) is False + assert notification_settings.is_nostr_notifications_configured() is True + assert notification_settings.is_telegram_notifications_configured() is True + + +def test_public_settings_from_settings(settings: Settings): + original_site_title = settings.lnbits_site_title + original_ad_space = settings.lnbits_ad_space + original_ad_space_enabled = settings.lnbits_ad_space_enabled + original_installed_extensions = settings.lnbits_installed_extensions_ids + original_first_install_token = settings.first_install_token + try: + settings.lnbits_site_title = "Test LNbits" + settings.lnbits_ad_space = "https://example.com;/banner.png;/thumb.png" + settings.lnbits_ad_space_enabled = True + settings.lnbits_installed_extensions_ids = {"ext_a"} + settings.first_install_token = "token" + + public = PublicSettings.from_settings(settings) + + assert public.site_title == "Test LNbits" + assert public.show_ad_space is True + assert public.ad_space == [["https://example.com", "/banner.png", "/thumb.png"]] + assert set(public.extensions) == {"ext_a"} + assert public.has_first_install_token is True + finally: + settings.lnbits_site_title = original_site_title + settings.lnbits_ad_space = original_ad_space + settings.lnbits_ad_space_enabled = original_ad_space_enabled + settings.lnbits_installed_extensions_ids = original_installed_extensions + settings.first_install_token = original_first_install_token + + +def test_set_cli_settings_updates_runtime_settings(settings: Settings): + original_host = settings.host + try: + set_cli_settings(host="0.0.0.0") # noqa S104 + assert settings.host == "0.0.0.0" # noqa S104 + finally: + settings.host = original_host diff --git a/tests/unit/test_wallet_payment_ambiguity.py b/tests/unit/test_wallet_payment_ambiguity.py new file mode 100644 index 000000000..d4c4bc5e9 --- /dev/null +++ b/tests/unit/test_wallet_payment_ambiguity.py @@ -0,0 +1,890 @@ +from types import SimpleNamespace +from typing import Any, cast + +import grpc +import httpx +import pytest +from pyln.client import RpcError +from pytest_mock.plugin import MockerFixture + +import lnbits.wallets.breez as breez_wallet_module +import lnbits.wallets.breez_liquid as breez_liquid_wallet_module +from lnbits.wallets.alby import AlbyWallet +from lnbits.wallets.base import PaymentPendingStatus +from lnbits.wallets.blink import BlinkWallet +from lnbits.wallets.boltz import BoltzWallet +from lnbits.wallets.boltz_grpc_files import boltzrpc_pb2 +from lnbits.wallets.corelightning import CoreLightningWallet +from lnbits.wallets.eclair import EclairWallet +from lnbits.wallets.lnd_grpc_files.lightning_pb2 import Payment as LndPayment +from lnbits.wallets.lndgrpc import LndWallet +from lnbits.wallets.lndrest import LndRestWallet +from lnbits.wallets.lnpay import LNPayWallet +from lnbits.wallets.lntips import LnTipsWallet +from lnbits.wallets.nwc import NWCError, NWCWallet +from lnbits.wallets.opennode import OpenNodeWallet +from lnbits.wallets.phoenixd import PhoenixdWallet +from lnbits.wallets.spark import SparkWallet +from lnbits.wallets.sparkl2 import SparkL2Wallet +from lnbits.wallets.strike import StrikeWallet +from lnbits.wallets.zbd import ZBDWallet + + +def _response(status_code: int, **kwargs) -> httpx.Response: + request = httpx.Request("POST", "https://wallet.test/pay") + return httpx.Response(status_code, request=request, **kwargs) + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("status_code", "expected"), + [ + (400, None), + (401, False), + (403, False), + (404, False), + (405, False), + (408, None), + (409, None), + (422, None), + (429, None), + (500, None), + ], +) +async def test_alby_only_treats_definite_http_rejection_as_failed( + mocker: MockerFixture, status_code: int, expected: bool | None +): + wallet = object.__new__(AlbyWallet) + wallet.endpoint = "https://wallet.test" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response(status_code, json={"message": "error"}) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +async def test_blink_keeps_unconfirmed_payment_pending(mocker: MockerFixture): + wallet = object.__new__(BlinkWallet) + wallet._wallet_id = "wallet-id" + wallet.endpoint = "https://wallet.test" + mocker.patch( + "lnbits.wallets.blink.bolt11_lib.decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + mocker.patch.object( + wallet, + "_graphql_query", + return_value={"data": {"lnInvoicePaymentSend": {"errors": []}}}, + ) + mocker.patch.object( + wallet, "get_payment_status", return_value=PaymentPendingStatus() + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("status_code", "expected"), + [ + (400, False), + (401, False), + (403, False), + (404, False), + (405, False), + (408, None), + (409, None), + (422, None), + (429, None), + (500, None), + ], +) +async def test_eclair_only_treats_request_rejections_as_failed( + mocker: MockerFixture, status_code: int, expected: bool | None +): + wallet = object.__new__(EclairWallet) + wallet.url = "https://wallet.test" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response(status_code, json={"error": "invoice has expired"}) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + assert response.error_message == "invoice has expired" + + +@pytest.mark.anyio +async def test_lndrest_unknown_payment_state_is_pending( + mocker: MockerFixture, settings +): + settings.lnd_rest_allow_self_payment = False + wallet = object.__new__(LndRestWallet) + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response( + 200, + json={ + "result": { + "status": "FUTURE_STATUS", + "payment_hash": "payment-hash", + "payment_preimage": "", + "fee_msat": "0", + } + }, + ) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("error", "expected"), + [ + ( + { + "code": 2, + "message": "invoice not for current active network 'regtest'", + }, + False, + ), + ({"code": 2, "message": "invoice expired"}, False), + ({"code": 3, "message": "invalid payment request"}, False), + ({"code": 2, "message": "payment stream interrupted"}, None), + ({"code": 14, "message": "transport unavailable"}, None), + ], +) +async def test_lndrest_only_pre_dispatch_rpc_errors_are_failed( + mocker: MockerFixture, + settings, + error: dict, + expected: bool | None, +): + settings.lnd_rest_allow_self_payment = False + wallet = object.__new__(LndRestWallet) + wallet.endpoint = "https://wallet.test" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response(500, json={"error": error}), + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + assert response.error_message == error["message"] + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("code", "details", "expected"), + [ + ( + grpc.StatusCode.UNKNOWN, + "invoice not for current active network 'regtest'", + False, + ), + (grpc.StatusCode.UNKNOWN, "invoice expired", False), + (grpc.StatusCode.INVALID_ARGUMENT, "invalid payment request", False), + (grpc.StatusCode.PERMISSION_DENIED, "permission denied", False), + (grpc.StatusCode.UNAUTHENTICATED, "invalid macaroon", False), + (grpc.StatusCode.UNAVAILABLE, "transport is closing", None), + (grpc.StatusCode.DEADLINE_EXCEEDED, "deadline exceeded", None), + (grpc.StatusCode.ALREADY_EXISTS, "payment is in flight", None), + (grpc.StatusCode.UNKNOWN, "payment stream interrupted", None), + ], +) +async def test_lndgrpc_only_pre_dispatch_rpc_errors_are_failed( + mocker: MockerFixture, + settings, + code: grpc.StatusCode, + details: str, + expected: bool | None, +): + settings.lnd_grpc_allow_self_payment = False + metadata = grpc.aio.Metadata() + error = grpc.aio.AioRpcError(code, metadata, metadata, details=details) + wallet = object.__new__(LndWallet) + cast(Any, wallet).router_rpc = SimpleNamespace( + SendPaymentV2=mocker.Mock( + return_value=SimpleNamespace(read=mocker.AsyncMock(side_effect=error)) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +async def test_lndgrpc_in_flight_payment_is_pending(mocker: MockerFixture, settings): + settings.lnd_grpc_allow_self_payment = False + wallet = object.__new__(LndWallet) + cast(Any, wallet).router_rpc = SimpleNamespace( + SendPaymentV2=mocker.Mock( + return_value=SimpleNamespace( + read=mocker.AsyncMock( + return_value=SimpleNamespace( + status=LndPayment.PaymentStatus.IN_FLIGHT, + payment_hash="payment-hash", + ) + ) + ) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("error", "expected"), + [ + ( + { + "code": 0, + "message": "destination is not reachable", + "attempts": [{"status": "failed"}], + }, + False, + ), + ( + { + "code": 0, + "message": "payment is still running", + "attempts": [{"status": "pending"}], + }, + None, + ), + ({"code": 0, "message": "unclassified RPC error"}, None), + ({"code": 205, "message": "unable to find a route"}, False), + ], +) +async def test_corelightning_only_terminal_rpc_errors_are_failed( + mocker: MockerFixture, + error: dict, + expected: bool | None, +): + wallet = object.__new__(CoreLightningWallet) + wallet.pay = "pay" + wallet.pay_failure_error_codes = [-32602, 201, 203, 205, 206, 207, 210] + cast(Any, wallet).ln = SimpleNamespace( + call=mocker.Mock(side_effect=RpcError("pay", {}, cast(Any, error))) + ) + mocker.patch( + "lnbits.wallets.corelightning.bolt11_decode", + return_value=SimpleNamespace( + payment_hash="payment-hash", + amount_msat=1_000, + description="", + ), + ) + mocker.patch.object( + wallet, "get_payment_status", return_value=PaymentPendingStatus() + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("status_code", "expected"), + [ + (400, None), + (401, False), + (403, False), + (404, False), + (405, False), + (408, None), + (409, None), + (422, None), + (429, None), + (500, None), + ], +) +async def test_lnpay_only_treats_client_rejection_as_failed( + mocker: MockerFixture, status_code: int, expected: bool | None +): + wallet = object.__new__(LNPayWallet) + wallet.wallet_key = "wallet-key" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response(status_code, json={"message": "error"}) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +async def test_lnpay_malformed_payment_response_is_pending(mocker: MockerFixture): + wallet = object.__new__(LNPayWallet) + wallet.wallet_key = "wallet-key" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock(return_value=_response(200, content=b"not-json")) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + + +@pytest.mark.anyio +@pytest.mark.parametrize("wallet_class", [LnTipsWallet, OpenNodeWallet, ZBDWallet]) +@pytest.mark.parametrize( + ("status_code", "expected"), + [(400, None), (401, False), (422, None)], +) +async def test_http_wallets_only_fail_definite_request_rejections( + mocker: MockerFixture, + wallet_class: type[LnTipsWallet | OpenNodeWallet | ZBDWallet], + status_code: int, + expected: bool | None, +): + wallet = object.__new__(wallet_class) + wallet.endpoint = "https://wallet.test" + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response(status_code, json={"message": "error"}) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +async def test_breez_immediate_failed_state_is_failed(mocker: MockerFixture, settings): + settings.breez_use_trampoline = False + breez_wallet = cast(Any, breez_wallet_module) + wallet = object.__new__(breez_wallet.BreezSdkWallet) + mocker.patch( + "lnbits.wallets.breez.bolt11_decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + cast(Any, wallet).sdk_services = SimpleNamespace( + send_payment=mocker.Mock( + return_value=SimpleNamespace( + payment=SimpleNamespace(status=breez_wallet.BreezPaymentStatus.FAILED) + ) + ) + ) + + response = await cast(Any, wallet).pay_invoice("bolt11", 1_000) + + assert response.ok is False + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +async def test_breez_liquid_timed_out_outgoing_payment_is_failed( + mocker: MockerFixture, +): + breez_liquid_wallet = cast(Any, breez_liquid_wallet_module) + wallet = object.__new__(breez_liquid_wallet.BreezLiquidSdkWallet) + cast(Any, wallet).sdk_services = SimpleNamespace( + get_payment=mocker.Mock( + return_value=SimpleNamespace( + payment_type=breez_liquid_wallet.PaymentType.SEND, + status=breez_liquid_wallet.PaymentState.TIMED_OUT, + ) + ) + ) + + status = await cast(Any, wallet).get_payment_status("payment-hash") + + assert status.paid is False + + +@pytest.mark.anyio +async def test_breez_liquid_prepare_error_is_failed(mocker: MockerFixture): + breez_liquid_wallet = cast(Any, breez_liquid_wallet_module) + wallet = object.__new__(breez_liquid_wallet.BreezLiquidSdkWallet) + mocker.patch( + "lnbits.wallets.breez_liquid.bolt11_decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + cast(Any, wallet).sdk_services = SimpleNamespace( + prepare_send_payment=mocker.Mock(side_effect=RuntimeError("cannot prepare")) + ) + + response = await cast(Any, wallet).pay_invoice("bolt11", 1_000) + + assert response.ok is False + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("code", "expected"), + [("PAYMENT_FAILED", False), ("INTERNAL", None), ("OTHER", None)], +) +async def test_nwc_only_explicit_payment_failure_is_failed( + mocker: MockerFixture, code: str, expected: bool | None +): + wallet = object.__new__(NWCWallet) + cast(Any, wallet).conn = SimpleNamespace( + call=mocker.AsyncMock(side_effect=NWCError(code, "error")) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + + +@pytest.mark.anyio +async def test_phoenix_request_error_is_pending(mocker: MockerFixture): + wallet = object.__new__(PhoenixdWallet) + wallet.endpoint = "https://wallet.test" + request = httpx.Request("POST", "https://wallet.test/payinvoice") + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + side_effect=httpx.ReadError("read failed", request=request) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + + +@pytest.mark.anyio +async def test_spark_sidecar_missing_checking_id_is_pending(mocker: MockerFixture): + wallet = object.__new__(SparkL2Wallet) + mocker.patch.object(wallet, "_request", return_value={"status": "PENDING"}) + + response = await wallet.pay_invoice("not-a-bolt11", 1_000) + + assert response.ok is None + assert response.checking_id is None + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("provider_status", "expected"), + [("unpaid", None), ("expired", False), ("paid", True)], +) +async def test_spark_invoice_uses_exact_terminal_status( + mocker: MockerFixture, + provider_status: str, + expected: bool | None, +): + wallet = object.__new__(SparkWallet) + mocker.patch.object( + wallet, + "listinvoices", + return_value={"invoices": [{"status": provider_status}]}, + ) + + status = await wallet.get_invoice_status("invoice-id") + + assert status.paid is expected + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("state", "expected"), + [ + (boltzrpc_pb2.SwapState.ERROR, False), + (999, None), + ], +) +async def test_boltz_only_known_terminal_swap_state_is_failed( + mocker: MockerFixture, state: int, expected: bool | None +): + wallet = object.__new__(BoltzWallet) + wallet.metadata = None + cast(Any, wallet).rpc = SimpleNamespace( + GetSwapInfo=mocker.AsyncMock( + return_value=SimpleNamespace(swap=SimpleNamespace(state=state)) + ) + ) + + status = await wallet.get_payment_status("00" * 32) + + assert status.paid is expected + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("code", "details", "expected"), + [ + ( + grpc.StatusCode.INVALID_ARGUMENT, + "invalid invoice or lnurl: invalid HRP", + False, + ), + ( + grpc.StatusCode.UNKNOWN, + "boltz error: could not find route to pay invoice", + False, + ), + (grpc.StatusCode.UNKNOWN, "payment response interrupted", None), + (grpc.StatusCode.ALREADY_EXISTS, "swap already exists", None), + ], +) +async def test_boltz_only_pre_dispatch_create_swap_errors_are_failed( + mocker: MockerFixture, + code: grpc.StatusCode, + details: str, + expected: bool | None, +): + metadata = grpc.aio.Metadata() + error = grpc.aio.AioRpcError(code, metadata, metadata, details=details) + wallet = object.__new__(BoltzWallet) + wallet.metadata = None + wallet.wallet_id = 1 + cast(Any, wallet).rpc = SimpleNamespace( + GetPairInfo=mocker.AsyncMock( + return_value=SimpleNamespace( + fees=SimpleNamespace(percentage=0, miner_fees=0) + ) + ), + CreateSwap=mocker.AsyncMock(side_effect=error), + ) + mocker.patch( + "lnbits.wallets.boltz.decode", + return_value=SimpleNamespace( + amount_msat=1_000, + payment_hash="payment-hash", + ), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("state", "expected"), + [ + (boltzrpc_pb2.ERROR, False), + (boltzrpc_pb2.PENDING, None), + (boltzrpc_pb2.SUCCESSFUL, True), + ], +) +async def test_boltz_resolves_ambiguous_create_swap_error_from_backend_state( + mocker: MockerFixture, + state: int, + expected: bool | None, +): + metadata = grpc.aio.Metadata() + error = grpc.aio.AioRpcError( + grpc.StatusCode.UNKNOWN, + metadata, + metadata, + details='sendrawtransaction RPC error: {"message":"txn-mempool-conflict"}', + ) + payment_hash = "00" * 32 + wallet = object.__new__(BoltzWallet) + wallet.metadata = None + wallet.wallet_id = 1 + cast(Any, wallet).rpc = SimpleNamespace( + GetPairInfo=mocker.AsyncMock( + return_value=SimpleNamespace( + fees=SimpleNamespace(percentage=0, miner_fees=0) + ) + ), + CreateSwap=mocker.AsyncMock(side_effect=error), + GetSwapInfo=mocker.AsyncMock( + return_value=SimpleNamespace( + swap=SimpleNamespace( + state=state, + service_fee=1, + onchain_fee=2, + status="swap status", + preimage="preimage", + ) + ) + ), + ) + mocker.patch( + "lnbits.wallets.boltz.decode", + return_value=SimpleNamespace( + amount_msat=1_000, + payment_hash=payment_hash, + ), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + assert response.checking_id == payment_hash + assert response.fee_msat == (3_000 if expected is True else None) + assert response.preimage == ("preimage" if expected is True else None) + + +@pytest.mark.anyio +async def test_boltz_error_text_without_terminal_state_is_pending( + mocker: MockerFixture, +): + async def swap_updates(): + yield SimpleNamespace( + swap=SimpleNamespace(state=999, error="unrecognized transient error") + ) + + wallet = object.__new__(BoltzWallet) + wallet.metadata = None + wallet.wallet_id = 1 + cast(Any, wallet).rpc = SimpleNamespace( + GetPairInfo=mocker.AsyncMock( + return_value=SimpleNamespace( + fees=SimpleNamespace(percentage=0, miner_fees=0) + ) + ), + CreateSwap=mocker.AsyncMock(return_value=SimpleNamespace(id="swap-id")), + GetSwapInfoStream=mocker.Mock(return_value=swap_updates()), + ) + mocker.patch( + "lnbits.wallets.boltz.decode", + return_value=SimpleNamespace( + amount_msat=1_000, + payment_hash="payment-hash", + ), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + + +@pytest.mark.anyio +async def test_opennode_terminal_error_status_is_failed(mocker: MockerFixture): + wallet = object.__new__(OpenNodeWallet) + cast(Any, wallet).client = SimpleNamespace( + get=mocker.AsyncMock( + return_value=_response( + 200, + json={"data": {"status": "error", "fee": 1}}, + ) + ) + ) + + status = await wallet.get_payment_status("withdrawal-id") + + assert status.paid is False + + +@pytest.mark.anyio +async def test_opennode_terminal_status_does_not_require_provider_id( + mocker: MockerFixture, +): + wallet = object.__new__(OpenNodeWallet) + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response( + 200, + json={"data": {"status": "failed"}}, + ) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is False + assert response.checking_id is None + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("provider_status", "expected"), + [("processing", None), ("completed", True), ("failed", False)], +) +async def test_zbd_preserves_provider_id_and_exact_status( + mocker: MockerFixture, + provider_status: str, + expected: bool | None, +): + wallet = object.__new__(ZBDWallet) + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response( + 200, + json={ + "data": { + "id": "zbd-payment-id", + "status": provider_status, + "fee": "10", + "preimage": "preimage", + } + }, + ) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is expected + assert response.checking_id == "zbd-payment-id" + + +@pytest.mark.anyio +async def test_zbd_terminal_status_does_not_require_provider_id( + mocker: MockerFixture, +): + wallet = object.__new__(ZBDWallet) + cast(Any, wallet).client = SimpleNamespace( + post=mocker.AsyncMock( + return_value=_response( + 200, + json={"data": {"status": "failed"}}, + ) + ) + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is False + assert response.checking_id is None + + +@pytest.mark.anyio +async def test_strike_invalid_fallback_identifier_is_pending(mocker: MockerFixture): + wallet = object.__new__(StrikeWallet) + wallet.pending_payments = {} + cast(Any, wallet)._get = mocker.AsyncMock( + return_value=_response( + 400, + json={ + "data": { + "code": "INVALID_DATA", + "validationErrors": { + "paymentId": [ + { + "code": "INVALID_DATA", + "message": "paymentId is not valid.", + } + ] + }, + } + }, + ) + ) + + status = await wallet._get_payment_status_by_checking_id("payment-hash") + + assert status.paid is None + + +@pytest.mark.anyio +async def test_strike_ambiguous_execution_uses_payment_hash_fallback( + mocker: MockerFixture, +): + wallet = object.__new__(StrikeWallet) + wallet.pending_payments = {} + mocker.patch( + "lnbits.wallets.strike.bolt11_decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + mocker.patch.object( + wallet, + "_create_payment_quote", + return_value=("quote-id", None), + ) + mocker.patch.object( + wallet, + "_execute_payment_quote", + return_value=(None, "request timed out"), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + assert response.checking_id is None + + +@pytest.mark.anyio +async def test_strike_terminal_state_does_not_require_payment_id( + mocker: MockerFixture, +): + wallet = object.__new__(StrikeWallet) + wallet.pending_payments = {} + mocker.patch( + "lnbits.wallets.strike.bolt11_decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + mocker.patch.object( + wallet, + "_create_payment_quote", + return_value=("quote-id", None), + ) + mocker.patch.object( + wallet, + "_execute_payment_quote", + return_value=({"state": "FAILED"}, None), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is False + assert response.checking_id == "payment-hash" + + +@pytest.mark.anyio +@pytest.mark.parametrize("state", ["CANCELED", "TIMED_OUT", "UNKNOWN"]) +async def test_strike_undocumented_payment_state_is_pending( + mocker: MockerFixture, state: str +): + wallet = object.__new__(StrikeWallet) + wallet.pending_payments = {} + mocker.patch( + "lnbits.wallets.strike.bolt11_decode", + return_value=SimpleNamespace(payment_hash="payment-hash"), + ) + mocker.patch.object( + wallet, + "_create_payment_quote", + return_value=("quote-id", None), + ) + mocker.patch.object( + wallet, + "_execute_payment_quote", + return_value=({"state": state, "paymentId": "payment-id"}, None), + ) + + response = await wallet.pay_invoice("bolt11", 1_000) + + assert response.ok is None + assert response.checking_id == "payment-id" + + +@pytest.mark.anyio +async def test_strike_persisted_payment_hash_not_found_stays_pending( + mocker: MockerFixture, +): + wallet = object.__new__(StrikeWallet) + wallet.pending_payments = {} + cast(Any, wallet)._get = mocker.AsyncMock( + return_value=_response(404, text="Not Found") + ) + + payment_hash = "ab" * 32 + status = await wallet.get_payment_status(payment_hash) + + assert status.paid is None + cast(Any, wallet)._get.assert_awaited_once_with(f"/payments/{payment_hash}") diff --git a/tests/unit/test_wasm_extension_api_client.py b/tests/unit/test_wasm_extension_api_client.py new file mode 100644 index 000000000..5441d712b --- /dev/null +++ b/tests/unit/test_wasm_extension_api_client.py @@ -0,0 +1,301 @@ +from types import SimpleNamespace +from typing import cast + +import httpx +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.wasm_ext.api.models import ExtensionApiRequest +from lnbits.core.wasm_ext.client import extensions as extension_client +from lnbits.settings import Settings + + +def test_wasm_extension_api_path_validation(): + assert ( + extension_client._extension_api_path("/api/v1/payments?limit=1") + == "/api/v1/payments?limit=1" + ) + + for path, message in [ + ("https://example.com/api/v1/payments", "relative"), + ("/wallet", "start with '/api/'"), + ("/api/v1/payments#frag", "fragment"), + ("/api/v1/../admin", "traverse"), + ("/api/v1/%2e%2e/admin", "traverse"), + ("/api//v1/payments", "invalid"), + ]: + with pytest.raises(PermissionError, match=message): + extension_client._extension_api_path(path) + + +def test_wasm_extension_api_target_and_access_validation(): + assert extension_client._target_extension_id(" target_ext ") == "target_ext" + for extension_id in ["", "../admin", "bad.ext"]: + with pytest.raises(PermissionError, match="invalid target"): + extension_client._target_extension_id(extension_id) + + assert extension_client._target_extension_access(["target"], "target") == {"read"} + assert extension_client._target_extension_access( + [{"id": "target", "access": ["read", "write", "ignored"]}], + "target", + ) == {"read", "write"} + + read_request = ExtensionApiRequest( + extension_id="target", + method="GET", + path="/api/v1/demo", + body=None, + ) + write_request = ExtensionApiRequest( + extension_id="target", + method="POST", + path="/api/v1/demo", + body="{}", + ) + extension_client._require_method_access( + "caller", + "target", + {"read"}, + read_request, + ) + with pytest.raises(PermissionError, match="cannot write"): + extension_client._require_method_access( + "caller", + "target", + {"read"}, + write_request, + ) + + +@pytest.mark.anyio +async def test_wasm_extension_api_request_enforces_auth_policy_and_user_enablement( + settings: Settings, + mocker: MockerFixture, +): + settings.host = "127.0.0.1" + settings.port = 5000 + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_installed_extension", + mocker.AsyncMock(return_value=SimpleNamespace(active=True)), + ) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_user_active_extensions_ids", + mocker.AsyncMock(return_value=["target"]), + ) + client = _FakeAsyncClient( + _FakeStreamResponse( + status_code=202, + headers={"set-cookie": "secret", "x-result": "ok"}, + chunks=[b'{"accepted":true}'], + ) + ) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.httpx.AsyncClient", + client.factory, + ) + + response = await extension_client.send_extension_api_request( + "caller", + [{"id": "target", "access": ["write"]}], + "user-id", + "access-token", + ExtensionApiRequest( + extension_id="target", + method="POST", + path="/api/v1/run?value=1", + body="{}", + ), + timeout_ms=750, + max_response_bytes=100, + ) + + assert response.status_code == 202 + assert response.body == '{"accepted":true}' + assert response.headers == {"x-result": "ok"} + assert client.kwargs["follow_redirects"] is False + assert client.kwargs["trust_env"] is False + assert client.kwargs["timeout"] == 0.75 + assert ( + client.stream_kwargs["url"] == "http://127.0.0.1:5000/target/api/v1/run?value=1" + ) + assert client.stream_kwargs["headers"] == {"Authorization": "Bearer access-token"} + + +@pytest.mark.anyio +async def test_wasm_extension_api_request_rejects_missing_auth_and_disabled_targets( + mocker: MockerFixture, +): + request = ExtensionApiRequest( + extension_id="target", + method="GET", + path="/api/v1/run", + body=None, + ) + with pytest.raises(PermissionError, match="authentication"): + await extension_client.send_extension_api_request( + "caller", + ["target"], + None, + "access-token", + request, + ) + with pytest.raises(PermissionError, match="access token"): + await extension_client.send_extension_api_request( + "caller", + ["target"], + "user-id", + None, + request, + ) + + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_installed_extension", + mocker.AsyncMock(return_value=SimpleNamespace(active=False)), + ) + with pytest.raises(PermissionError, match="not installed or enabled"): + await extension_client.send_extension_api_request( + "caller", + ["target"], + "user-id", + "access-token", + request, + ) + + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_installed_extension", + mocker.AsyncMock(return_value=SimpleNamespace(active=True)), + ) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_user_active_extensions_ids", + mocker.AsyncMock(return_value=[]), + ) + with pytest.raises(PermissionError, match="not active for this user"): + await extension_client.send_extension_api_request( + "caller", + ["target"], + "user-id", + "access-token", + request, + ) + + +@pytest.mark.anyio +async def test_wasm_extension_api_request_rejects_oversized_body_and_response( + mocker: MockerFixture, +): + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_installed_extension", + mocker.AsyncMock(return_value=SimpleNamespace(active=True)), + ) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_user_active_extensions_ids", + mocker.AsyncMock(return_value=["target"]), + ) + with pytest.raises(ValueError, match="body is too large"): + await extension_client.send_extension_api_request( + "caller", + [{"id": "target", "access": ["write"]}], + "user-id", + "access-token", + ExtensionApiRequest.construct( + extension_id="target", + method="POST", + path="/api/v1/run", + body="x" * 65_537, + ), + ) + + with pytest.raises(ValueError, match="response is too large"): + await extension_client._read_limited_response( + cast(httpx.Response, _FakeStreamResponse(chunks=[b"12345", b"67890"])), + max_response_bytes=8, + ) + + +@pytest.mark.anyio +async def test_wasm_extension_api_request_hides_transport_errors( + mocker: MockerFixture, +): + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_installed_extension", + mocker.AsyncMock(return_value=SimpleNamespace(active=True)), + ) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.get_user_active_extensions_ids", + mocker.AsyncMock(return_value=["target"]), + ) + client = _FakeAsyncClient(_FakeStreamError()) + mocker.patch( + "lnbits.core.wasm_ext.client.extensions.httpx.AsyncClient", + client.factory, + ) + + with pytest.raises(ValueError, match="Extension API request failed"): + await extension_client.send_extension_api_request( + "caller", + ["target"], + "user-id", + "access-token", + ExtensionApiRequest( + extension_id="target", + method="GET", + path="/api/v1/run", + body=None, + ), + ) + + +class _FakeAsyncClient: + def __init__(self, response): + self.response = response + self.kwargs = {} + self.stream_kwargs = {} + + def factory(self, **kwargs): + self.kwargs = kwargs + return self + + async def __aenter__(self): + return self + + async def __aexit__(self, *_args): + return False + + def stream(self, method, url, **kwargs): + self.stream_kwargs = {"method": method, "url": url, **kwargs} + return self.response + + +class _FakeStreamResponse: + def __init__( + self, + *, + status_code: int = 200, + headers: dict[str, str] | None = None, + chunks: list[bytes] | None = None, + ): + self.status_code = status_code + self.headers = headers or {} + self.encoding = "utf-8" + self._chunks = chunks or [] + + async def __aenter__(self): + return self + + async def __aexit__(self, *_args): + return False + + async def aiter_bytes(self): + for chunk in self._chunks: + yield chunk + + +class _FakeStreamError: + async def __aenter__(self): + raise httpx.RequestError( + "network failed", + request=httpx.Request("GET", "http://127.0.0.1"), + ) + + async def __aexit__(self, *_args): + return False diff --git a/tests/unit/test_wasm_extension_events.py b/tests/unit/test_wasm_extension_events.py new file mode 100644 index 000000000..08f2354cf --- /dev/null +++ b/tests/unit/test_wasm_extension_events.py @@ -0,0 +1,295 @@ +import json +from pathlib import Path +from types import SimpleNamespace + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.db import core_app_extra +from lnbits.core.models.extensions import ExtensionPermission +from lnbits.core.wasm_ext.wasm.config import parse_wasm_extension_config +from lnbits.core.wasm_ext.wasm.events import ( + _payment_extension_id, + _payment_source_id, + _wasm_public_invoice_source_tables_from_permissions, + dispatch_wasm_invoice_paid, +) +from lnbits.core.wasm_ext.wasm.loader import WasmExtension +from lnbits.helpers import sha256s + + +def test_wasm_invoice_paid_helpers_extract_extension_and_source_tables(): + payment = SimpleNamespace( + extension="", + extra={"tag": "demoext", "source_id": "row-1"}, + tag="fallback", + ) + permissions = [ + ExtensionPermission( + id="wallet.create_invoice_public", + policies=[ + {"table": "tip_jars", "wallet_field": "wallet_id"}, + {"table": "", "wallet_field": "wallet_id"}, + ], + ), + ExtensionPermission(id="http.request"), + ] + + assert _payment_extension_id(payment) == "demoext" + assert _payment_source_id(payment) == "row-1" + assert _wasm_public_invoice_source_tables_from_permissions(permissions) == [ + "tip_jars" + ] + + +@pytest.mark.anyio +async def test_dispatch_wasm_invoice_paid_invokes_registered_event_export_with_owner( + mocker: MockerFixture, +): + ext_id = "demo_event_ext" + extension = _wasm_extension(ext_id) + registry = core_app_extra.wasm_extension_registry + registry.register(extension) + installed_extension = SimpleNamespace( + permissions=[ + ExtensionPermission( + id="wallet.create_invoice_public", + policies=[{"table": "tip_jars", "wallet_field": "wallet_id"}], + ) + ] + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_installed_extension", + mocker.AsyncMock(return_value=installed_extension), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_wallet", + mocker.AsyncMock(return_value=None), + ) + storage_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.storage_get_row_owner_id", + mocker.AsyncMock(return_value="owner-1"), + ) + invoke_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.invoke_wasm_extension_export", + mocker.AsyncMock(), + ) + payment = _payment(ext_id) + + try: + await dispatch_wasm_invoice_paid(payment) + finally: + registry._extensions.pop(ext_id, None) + + storage_mock.assert_awaited_once_with(ext_id, "tip_jars", "row-1") + invoke_mock.assert_awaited_once() + assert invoke_mock.await_args is not None + args = invoke_mock.await_args.args + kwargs = invoke_mock.await_args.kwargs + assert args[0] == ext_id + assert args[1] == "on_invoice_paid" + assert args[2]["paymentHash"] == "payment-hash" + assert args[2]["payment"] == {"id": "payment-row"} + assert kwargs["context"] == "event" + assert kwargs["owner_id"] == "owner-1" + assert kwargs["trigger_type"] == "event" + assert kwargs["event_type"] == "invoice_paid" + assert kwargs["wallet_id"] == "wallet-1" + assert kwargs["payment_hash"] == "payment-hash" + assert kwargs["checking_id"] == "checking-id" + + +@pytest.mark.anyio +async def test_dispatch_wasm_invoice_paid_skips_invalid_event_export_visibility( + mocker: MockerFixture, +): + ext_id = "demo_public_event_ext" + extension = _wasm_extension(ext_id, visibility="public") + registry = core_app_extra.wasm_extension_registry + registry.register(extension) + invoke_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.invoke_wasm_extension_export", + mocker.AsyncMock(), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_wallet", + mocker.AsyncMock(return_value=None), + ) + + try: + await dispatch_wasm_invoice_paid(_payment(ext_id)) + finally: + registry._extensions.pop(ext_id, None) + + invoke_mock.assert_not_awaited() + + +@pytest.mark.anyio +async def test_dispatch_wasm_invoice_paid_invokes_wallet_watch_grant( + mocker: MockerFixture, +): + ext_id = "demo_wallet_watch_ext" + extension = _wasm_extension(ext_id) + registry = core_app_extra.wasm_extension_registry + registry.register(extension) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_wallet", + mocker.AsyncMock(return_value=SimpleNamespace(id="wallet-1", user="user-1")), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_user_extensions", + mocker.AsyncMock( + return_value=[ + SimpleNamespace( + active=True, + extension=ext_id, + permissions={ + "wallet.payments.watch": [ + { + "id": "grant-1", + "wallet_id": "wallet-1", + "enabled": True, + } + ] + }, + ) + ] + ), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_installed_extension", + mocker.AsyncMock( + return_value=SimpleNamespace( + active=True, + permissions=[ExtensionPermission(id="wallet.payments.watch")], + ) + ), + ) + invoke_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.invoke_wasm_extension_export", + mocker.AsyncMock(), + ) + + try: + await dispatch_wasm_invoice_paid(_payment("")) + finally: + registry._extensions.pop(ext_id, None) + + invoke_mock.assert_awaited_once() + assert invoke_mock.await_args is not None + args = invoke_mock.await_args.args + kwargs = invoke_mock.await_args.kwargs + assert args[0] == ext_id + assert args[1] == "on_invoice_paid" + assert args[2]["paymentHash"] == "payment-hash" + assert kwargs["context"] == "event" + assert kwargs["owner_id"] == sha256s("user-1") + + +@pytest.mark.anyio +async def test_dispatch_wasm_invoice_paid_dedupes_tagged_wallet_watch_grant( + mocker: MockerFixture, +): + ext_id = "demo_dedupe_event_ext" + extension = _wasm_extension(ext_id) + registry = core_app_extra.wasm_extension_registry + registry.register(extension) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_wallet", + mocker.AsyncMock(return_value=SimpleNamespace(id="wallet-1", user="user-1")), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_user_extensions", + mocker.AsyncMock( + return_value=[ + SimpleNamespace( + active=True, + extension=ext_id, + permissions={ + "wallet.payments.watch": [ + { + "id": "grant-1", + "wallet_id": "wallet-1", + "enabled": True, + } + ] + }, + ) + ] + ), + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_installed_extension", + mocker.AsyncMock( + return_value=SimpleNamespace( + active=True, + permissions=[ExtensionPermission(id="wallet.payments.watch")], + ) + ), + ) + invoke_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.invoke_wasm_extension_export", + mocker.AsyncMock(), + ) + + try: + await dispatch_wasm_invoice_paid(_payment(ext_id, extra={})) + finally: + registry._extensions.pop(ext_id, None) + + invoke_mock.assert_awaited_once() + assert invoke_mock.await_args is not None + assert invoke_mock.await_args.kwargs["owner_id"] == sha256s("user-1") + + +def _wasm_extension(ext_id: str, *, visibility: str = "event") -> WasmExtension: + config = parse_wasm_extension_config( + ext_id, + { + "id": ext_id, + "name": "Demo event extension", + "short_description": "Demo", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": { + "module": "extension.wasm", + "exports": [ + { + "name": "on_invoice_paid", + "visibility": visibility, + } + ], + }, + "events": {"onInvoicePaid": "on_invoice_paid"}, + }, + ) + root_path = Path(__file__).resolve().parent / ext_id + return WasmExtension( + id=ext_id, + name=config.name, + version=config.version, + root_path=root_path, + module_path=root_path / "extension.wasm", + wit_path=None, + world=config.wasm.world, + exports=config.wasm.exports, + config=config, + ) + + +def _payment(ext_id: str, *, extra: dict | None = None) -> SimpleNamespace: + return SimpleNamespace( + extension=ext_id, + extra={"source_id": "row-1"} if extra is None else extra, + tag=None, + wallet_id="wallet-1", + payment_hash="payment-hash", + checking_id="checking-id", + amount=1000, + fee=0, + bolt11="lnbc1", + memo="memo", + pending=False, + status="success", + json=lambda: json.dumps({"id": "payment-row"}), + ) diff --git a/tests/unit/test_wasm_extension_frontend.py b/tests/unit/test_wasm_extension_frontend.py new file mode 100644 index 000000000..0626089af --- /dev/null +++ b/tests/unit/test_wasm_extension_frontend.py @@ -0,0 +1,144 @@ +import json +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] + + +def test_wasm_frontend_assets_are_registered_in_component_bundle(): + package_json = json.loads((ROOT / "package.json").read_text(encoding="utf-8")) + components = package_json["bundle"]["components"] + + assert "js/wasm-extension-component.js" in components + assert "js/components/lnbits-extension-permissions.js" in components + assert "js/components/admin/lnbits-admin-wasm-runtime.js" in components + assert "js/components/admin/lnbits-admin-wasm-limit-config.js" in components + + +def test_wasm_extension_routes_keep_global_wallet_dialog_mounted(): + base_template = (ROOT / "lnbits/templates/base.html").read_text(encoding="utf-8") + wallet_dialog_start = base_template.index("", wallet_dialog_start + ) + wallet_dialog = base_template[wallet_dialog_start:wallet_dialog_end] + + assert 'v-if="g.user && !g.isPublicPage"' in wallet_dialog + assert "!$route.path.startsWith('/ext/')" not in wallet_dialog + + +def test_wasm_frontend_bridge_restricts_api_routes_and_realtime_actions(): + bridge = (ROOT / "lnbits/static/js/wasm-extension-component.js").read_text( + encoding="utf-8" + ) + + assert "allowedApiRoute(method, path)" in bridge + assert "url.origin !== window.location.origin" in bridge + assert "Extension API route is not allowed." in bridge + assert "extensionRoute(path)" in bridge + assert "Extension route must stay inside this extension." in bridge + assert "message.action === 'payment.subscribe'" in bridge + assert "message.action === 'payment.unsubscribe'" in bridge + assert "message.action === 'websocket.subscribe'" in bridge + assert "message.action === 'websocket.unsubscribe'" in bridge + assert "message.action === 'websocket.send'" in bridge + assert "sendWebsocket(message)" in bridge + assert "Unknown websocket subscription." not in bridge + assert "if (!subscription) {\n return\n }" in bridge + assert "message.action === 'navigation.replace'" in bridge + assert "message.action === 'navigation.open_new_tab'" in bridge + assert "openNewTab(message)" in bridge + assert "newTabUrl(rawUrl)" in bridge + assert "copyNewTabLink()" in bridge + assert "navigator.clipboard.writeText(prompt.url)" in bridge + assert 'label="Copy Link"' in bridge + assert "window.open(prompt.url, '_blank', 'noopener,noreferrer')" in bridge + assert "Only HTTP and HTTPS links can be opened." in bridge + assert "This link is not on the same domain as this LNbits page." in bridge + assert "message.action === 'storage.session.get'" in bridge + assert "message.action === 'storage.session.set'" in bridge + assert "bridgeSessionStorageKey(rawKey)" in bridge + assert "lnbits.ext.session.${this.bridge.extensionId}.${key}" in bridge + assert "hasBridgePermission('websocket.subscribe')" in bridge + assert "/api/v1/ext/ws/${encodeURIComponent(" in bridge + assert "/api/v1/ws/${encodeURIComponent(paymentHash)}" in bridge + assert "message.action === 'ui.scan_qr'" in bridge + + +def test_wasm_extension_install_ui_requests_permissions_before_install_paths(): + extensions_page = (ROOT / "lnbits/static/js/pages/extensions.js").read_text( + encoding="utf-8" + ) + permissions_template = ( + ROOT / "lnbits/templates/components/lnbits-extension-permissions.vue" + ).read_text(encoding="utf-8") + wasm_bulk_update_skip_message = ( + "Skipping ${ext.id}; this extension update requires permission approval." + ) + + assert "await this.resolveExtensionPermissionGrant(release)" in extensions_page + assert "permissions: grantedPermissions" in extensions_page + assert "release.extension_type === 'wasm'" in extensions_page + assert "this.selectedExtension?.isWasm === true" in extensions_page + assert "saveManagedExtensionPermissions()" in extensions_page + assert ( + "`/api/v1/extension/${this.selectedExtension.id}/permissions`" + in extensions_page + ) + assert "editableAppendPublicLimits" in permissions_template + assert "max_rows_per_source" in permissions_template + assert "editableWebsocketPublishLimits" in permissions_template + assert "max_messages_per_second" in permissions_template + assert wasm_bulk_update_skip_message in extensions_page + + +def test_extension_install_ui_warns_only_for_python_releases(): + extensions_template = (ROOT / "lnbits/templates/pages/extensions.vue").read_text( + encoding="utf-8" + ) + + assert "release.extension_type !== 'wasm'" in extensions_template + assert ( + "'Python extensions have full server access. Trust the source.'" + in extensions_template + ) + assert ' None: + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + ext_dir = settings.wasm_extensions_dir / ext_id + ext_dir.mkdir(parents=True) + (ext_dir / "extension.wasm").write_bytes(b"\0asm") + config = { + "name": "Demo", + "short_description": "Demo extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + } + if config_id is not None: + config["id"] = config_id + (ext_dir / "config.json").write_text(json.dumps(config), encoding="utf-8") + + +def _wasm_extension(ext_id: str, root_path: Path) -> WasmExtension: + config = parse_wasm_extension_config(ext_id, _wasm_config(ext_id)) + return WasmExtension( + id=ext_id, + name=ext_id, + version="1.0.0", + root_path=root_path, + module_path=root_path / "extension.wasm", + wit_path=None, + world="", + exports=[], + config=config, + ) + + +def _wasm_config(ext_id: str) -> dict[str, Any]: + return { + "id": ext_id, + "name": ext_id, + "short_description": "Demo extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + } diff --git a/tests/unit/test_wasm_extension_permissions.py b/tests/unit/test_wasm_extension_permissions.py new file mode 100644 index 000000000..2e4c675b3 --- /dev/null +++ b/tests/unit/test_wasm_extension_permissions.py @@ -0,0 +1,815 @@ +from types import SimpleNamespace +from typing import Any, cast + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.models.extensions import ( + ExtensionBackgroundPaymentDestinationPolicy, + ExtensionPermission, +) +from lnbits.core.views.extension_api import ( + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, + WALLET_PAYMENTS_WATCH_PERMISSION, + _background_destination_policy_covers, + _check_background_payment_permission, + _check_wallet_payments_watch_permission, + _find_background_payment_grant, + _find_wallet_payments_watch_grant, + _remove_user_permission_grant, + _safe_user_extension_permissions, + _user_permission_grant_id_for_wallet, +) +from lnbits.core.wasm_ext.api.permissions import ( + PUBLIC_APPEND_MAX_ROWS_PER_SOURCE_LIMIT, + validate_wasm_extension_permissions, +) +from lnbits.core.wasm_ext.api.websockets import ( + WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT, +) +from lnbits.core.wasm_ext.wasm.events import _wasm_invoice_paid_owner_id +from lnbits.core.wasm_ext.wasm.invoke import _active_installed_extension +from tests.helpers import make_installable_extension + + +def test_validate_wasm_permissions_rejects_broader_policy_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "http.request", + "policies": [{"host": "https://api.example.com"}], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="http.request", + policies=[ + {"host": "https://api.example.com"}, + {"host": "https://evil.example.com"}, + ], + ) + ], + extension_config, + ) + + +def test_validate_wasm_permissions_stores_narrower_policy_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.read_public", + "description": "Read public storage.", + "policies": [ + { + "table_name": "tip_jars", + "source_id_field": "wallet_id", + "public_fields": ["id", "title", "description"], + } + ], + } + ], + ) + + permissions = validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.read_public", + policies=[ + { + "table_name": "tip_jars", + "source_id_field": "wallet_id", + "public_fields": ["id", "title"], + } + ], + ) + ], + extension_config, + ) + + assert permissions == [ + ExtensionPermission( + id="ext.storage.read_public", + description="Read public storage.", + policies=[ + { + "table_name": "tip_jars", + "source_id_field": "wallet_id", + "public_fields": ["id", "title"], + } + ], + ) + ] + + +def test_validate_wasm_permissions_rejects_public_read_source_field_omission(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.read_public", + "policies": [ + { + "table_name": "messages", + "source_id_field": "conversation_id", + "public_fields": ["id", "body"], + } + ], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.read_public", + policies=[ + { + "table_name": "messages", + "public_fields": ["id", "body"], + } + ], + ) + ], + extension_config, + ) + + +def test_validate_wasm_permissions_allows_narrower_public_append_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.append_public", + "description": "Append public messages.", + "policies": [ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["name", "message"], + "max_rows_per_source": 100, + } + ], + } + ], + ) + + permissions = validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 50, + } + ], + ) + ], + extension_config, + ) + + assert permissions == [ + ExtensionPermission( + id="ext.storage.append_public", + description="Append public messages.", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 50, + } + ], + ) + ] + + +def test_validate_wasm_permissions_rejects_broader_public_append_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.append_public", + "policies": [ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 100, + } + ], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message", "admin"], + "max_rows_per_source": 101, + } + ], + ) + ], + extension_config, + ) + + +def test_validate_wasm_permissions_admin_can_raise_public_append_row_limit(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.append_public", + "description": "Append public messages.", + "policies": [ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 100, + } + ], + } + ], + ) + + permissions = validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 500, + } + ], + ) + ], + extension_config, + allow_admin_policy_overrides=True, + ) + + assert permissions == [ + ExtensionPermission( + id="ext.storage.append_public", + description="Append public messages.", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 500, + } + ], + ) + ] + + +def test_validate_wasm_permissions_admin_cannot_raise_public_append_fields_or_cap(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "ext.storage.append_public", + "policies": [ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": 100, + } + ], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message", "admin"], + "max_rows_per_source": 500, + } + ], + ) + ], + extension_config, + allow_admin_policy_overrides=True, + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="ext.storage.append_public", + policies=[ + { + "table": "messages", + "source_table": "threads", + "source_id_field": "thread_id", + "allowed_fields": ["message"], + "max_rows_per_source": ( + PUBLIC_APPEND_MAX_ROWS_PER_SOURCE_LIMIT + 1 + ), + } + ], + ) + ], + extension_config, + allow_admin_policy_overrides=True, + ) + + +def test_validate_wasm_permissions_rejects_broader_extension_api_access(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "extension.api.request", + "policies": [{"id": "targetext", "access": ["read"]}], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="extension.api.request", + policies=[{"id": "targetext", "access": ["read", "write"]}], + ) + ], + extension_config, + ) + + +def test_validate_wasm_permissions_allows_empty_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "wallet.create_invoice_public", + "policies": [{"table": "tip_jars", "wallet_field": "wallet_id"}], + } + ], + ) + + assert validate_wasm_extension_permissions(ext_info, [], extension_config) == [] + + +def test_validate_wasm_permissions_rejects_unrequested_permission_grant(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config("demoext", [{"id": "utils.basic"}]) + + with pytest.raises(ValueError, match="unrequested permissions"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission(id="utils.basic"), + ExtensionPermission(id="wallet.list"), + ], + extension_config, + ) + + +def test_validate_wasm_permissions_allows_wallet_payments_watch_permission(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [{"id": "wallet.payments.watch"}], + ) + + assert validate_wasm_extension_permissions( + ext_info, + [ExtensionPermission(id="wallet.payments.watch")], + extension_config, + ) == [ExtensionPermission(id="wallet.payments.watch")] + + +def test_validate_wasm_permissions_allows_websocket_permissions(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "websocket.publish", + "policies": [{"max_messages_per_second": 10}], + }, + {"id": "websocket.subscribe"}, + ], + ) + + assert validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="websocket.publish", + policies=[{"max_messages_per_second": 5}], + ), + ExtensionPermission(id="websocket.subscribe"), + ], + extension_config, + ) == [ + ExtensionPermission( + id="websocket.publish", + policies=[{"max_messages_per_second": 5}], + ), + ExtensionPermission(id="websocket.subscribe"), + ] + + +def test_validate_wasm_permissions_rejects_websocket_publish_without_policy(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [{"id": "websocket.publish"}], + ) + + with pytest.raises(ValueError, match="invalid policies"): + validate_wasm_extension_permissions( + ext_info, + [ExtensionPermission(id="websocket.publish")], + extension_config, + ) + + +def test_validate_wasm_permissions_rejects_broader_websocket_publish_limit(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "websocket.publish", + "policies": [{"max_messages_per_second": 10}], + } + ], + ) + + with pytest.raises(ValueError, match="broader policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="websocket.publish", + policies=[{"max_messages_per_second": 11}], + ) + ], + extension_config, + ) + + +def test_validate_wasm_permissions_admin_can_raise_websocket_publish_limit(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "websocket.publish", + "policies": [{"max_messages_per_second": 10}], + } + ], + ) + + assert validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="websocket.publish", + policies=[{"max_messages_per_second": 20}], + ) + ], + extension_config, + allow_admin_policy_overrides=True, + ) == [ + ExtensionPermission( + id="websocket.publish", + policies=[{"max_messages_per_second": 20}], + ) + ] + + +def test_validate_wasm_permissions_rejects_websocket_publish_limit_over_cap(): + ext_info = make_installable_extension("demoext") + extension_config = _wasm_config( + "demoext", + [ + { + "id": "websocket.publish", + "policies": [ + { + "max_messages_per_second": ( + WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT + 1 + ) + } + ], + } + ], + ) + + with pytest.raises(ValueError, match="invalid policies"): + validate_wasm_extension_permissions( + ext_info, + [ + ExtensionPermission( + id="websocket.publish", + policies=[ + { + "max_messages_per_second": ( + WEBSOCKET_PUBLISH_MAX_MESSAGES_PER_SECOND_LIMIT + 1 + ) + } + ], + ) + ], + extension_config, + allow_admin_policy_overrides=True, + ) + + +def test_background_payment_grant_lookup_and_policy_coverage(): + permissions = { + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: [ + { + "id": "grant-1", + "wallet_id": "wallet-1", + "enabled": True, + "max_amount": 5000, + "destination_policy": "external_allowed", + } + ] + } + + grant = _find_background_payment_grant(permissions, "wallet-1") + + assert grant + assert grant.max_amount == 5000 + assert _background_destination_policy_covers( + grant.destination_policy, + ExtensionBackgroundPaymentDestinationPolicy.OWN_WALLETS_ONLY, + ) + assert _background_destination_policy_covers( + grant.destination_policy, + ExtensionBackgroundPaymentDestinationPolicy.EXTERNAL_ALLOWED, + ) + assert not _background_destination_policy_covers( + ExtensionBackgroundPaymentDestinationPolicy.OWN_WALLETS_ONLY, + ExtensionBackgroundPaymentDestinationPolicy.EXTERNAL_ALLOWED, + ) + + +def test_wallet_payments_watch_grant_lookup_ignores_disabled_grant(): + permissions = { + WALLET_PAYMENTS_WATCH_PERMISSION: [ + {"id": "grant-1", "wallet_id": "wallet-1", "enabled": False} + ] + } + + grant = _find_wallet_payments_watch_grant(permissions, "wallet-1") + + assert grant + assert grant.enabled is False + + +def test_safe_user_extension_permissions_keeps_only_grants_with_ids(): + permissions = { + WALLET_PAYMENTS_WATCH_PERMISSION: [ + {"id": "grant-1", "wallet_id": "wallet-1", "enabled": True}, + {"wallet_id": "wallet-2", "enabled": True}, + "broken", + ], + "broken": "not-a-list", + } + + safe_permissions = _safe_user_extension_permissions(permissions) + + assert safe_permissions == { + WALLET_PAYMENTS_WATCH_PERMISSION: [ + {"id": "grant-1", "wallet_id": "wallet-1", "enabled": True} + ] + } + + +def test_user_permission_grant_id_for_wallet_returns_existing_grant_id(): + permissions = { + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: [ + {"id": "grant-1", "wallet_id": "wallet-1", "enabled": True} + ] + } + + grant_id = _user_permission_grant_id_for_wallet( + permissions, WALLET_PAY_INVOICE_BACKGROUND_PERMISSION, "wallet-1" + ) + + assert grant_id == "grant-1" + + +def test_remove_user_permission_grant_removes_only_matching_grant_id(): + permissions = { + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: [ + {"id": "grant-1", "wallet_id": "wallet-1", "enabled": True}, + {"id": "grant-2", "wallet_id": "wallet-2", "enabled": True}, + ], + WALLET_PAYMENTS_WATCH_PERMISSION: [{"id": "grant-3", "wallet_id": "wallet-1"}], + } + + updated_permissions = _remove_user_permission_grant(permissions, "grant-1") + + assert updated_permissions == { + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: [ + {"id": "grant-2", "wallet_id": "wallet-2", "enabled": True} + ], + WALLET_PAYMENTS_WATCH_PERMISSION: [{"id": "grant-3", "wallet_id": "wallet-1"}], + } + + +def test_remove_user_permission_grant_drops_empty_permission(): + permissions = { + WALLET_PAYMENTS_WATCH_PERMISSION: [{"id": "grant-1", "wallet_id": "wallet-1"}] + } + + updated_permissions = _remove_user_permission_grant(permissions, "grant-1") + + assert updated_permissions == {} + + +@pytest.mark.anyio +async def test_background_payment_check_reports_approved_grant( + mocker: MockerFixture, +): + permissions = { + WALLET_PAY_INVOICE_BACKGROUND_PERMISSION: [ + { + "id": "grant-1", + "wallet_id": "wallet-1", + "enabled": True, + "max_amount": 5000, + "destination_policy": "external_allowed", + } + ] + } + mocker.patch( + "lnbits.core.views.extension_api.get_wallet", + mocker.AsyncMock( + return_value=SimpleNamespace( + user="user-1", + is_lightning_shared_wallet=False, + can_send_payments=True, + ) + ), + ) + + result = await _check_background_payment_permission( + "user-1", + permissions, + { + "wallet_id": "wallet-1", + "max_amount": 1000, + "destination_policy": "own_wallets_only", + }, + ) + + assert result.id == WALLET_PAY_INVOICE_BACKGROUND_PERMISSION + assert result.approved is True + assert result.grant["id"] == "grant-1" + assert result.grant["max_amount"] == 5000 + + +@pytest.mark.anyio +async def test_wallet_payment_watch_check_returns_requested_unapproved_grant( + mocker: MockerFixture, +): + mocker.patch( + "lnbits.core.views.extension_api.get_wallet", + mocker.AsyncMock(return_value=SimpleNamespace(user="user-1")), + ) + + result = await _check_wallet_payments_watch_permission( + "user-1", + {}, + {"wallet_id": "wallet-1"}, + ) + + assert result.id == WALLET_PAYMENTS_WATCH_PERMISSION + assert result.approved is False + assert result.grant["wallet_id"] == "wallet-1" + assert result.grant["enabled"] is True + assert isinstance(result.grant["id"], str) + + +@pytest.mark.anyio +async def test_invoice_paid_owner_lookup_uses_stored_granted_policies( + mocker: MockerFixture, +): + extension = SimpleNamespace( + id="demoext", + config=_wasm_config( + "demoext", + [ + { + "id": "wallet.create_invoice_public", + "policies": [ + {"table": "requested_table", "wallet_field": "wallet_id"} + ], + } + ], + ), + ) + payment = SimpleNamespace(extra={"source_id": "source-1"}) + installed_extension = SimpleNamespace( + permissions=[ + ExtensionPermission( + id="wallet.create_invoice_public", + policies=[{"table": "granted_table", "wallet_field": "wallet_id"}], + ) + ] + ) + mocker.patch( + "lnbits.core.wasm_ext.wasm.events.get_installed_extension", + mocker.AsyncMock(return_value=installed_extension), + ) + storage_mock = mocker.patch( + "lnbits.core.wasm_ext.wasm.events.storage_get_row_owner_id", + mocker.AsyncMock(return_value="owner-1"), + ) + + owner_id = await _wasm_invoice_paid_owner_id(extension, payment) + + assert owner_id == "owner-1" + storage_mock.assert_awaited_once_with("demoext", "granted_table", "source-1") + + +@pytest.mark.anyio +async def test_wasm_invocation_requires_installed_active_extension( + mocker: MockerFixture, +): + extension = SimpleNamespace(id="demoext") + mocker.patch( + "lnbits.core.wasm_ext.wasm.invoke.get_installed_extension", + mocker.AsyncMock(return_value=None), + ) + + with pytest.raises(PermissionError, match="deactivated"): + await _active_installed_extension(cast(Any, extension)) + + +def _wasm_config(ext_id: str, permissions: list[dict]) -> dict: + return { + "id": ext_id, + "name": ext_id, + "short_description": "Demo extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": {"module": "extension.wasm"}, + "permissions": permissions, + } diff --git a/tests/unit/test_wasm_extension_routes.py b/tests/unit/test_wasm_extension_routes.py new file mode 100644 index 000000000..9b0cf39ca --- /dev/null +++ b/tests/unit/test_wasm_extension_routes.py @@ -0,0 +1,697 @@ +from __future__ import annotations + +import json +from collections.abc import AsyncIterator +from pathlib import Path +from typing import cast + +import pytest +from fastapi import FastAPI, HTTPException, Request + +from lnbits.core.wasm_ext.routes.api import ( + WasmRequestBodyTooLargeError, + WasmRoutePayload, + _read_api_payload, + _read_json_object_with_size, + _wasm_extension_api_export, + _wasm_route_owner_id, + register_wasm_extension_api_routes, + unregister_wasm_extension_api_routes, +) +from lnbits.core.wasm_ext.routes.assets import ( + WASM_EXTENSION_STATIC_MIME_TYPES, + _reject_html_like_wasm_static_asset, + _wasm_extension_core_asset_response, +) +from lnbits.core.wasm_ext.routes.register import _format_wasm_extension_size +from lnbits.core.wasm_ext.routes.security import ( + consume_wasm_extension_frame_token, + wasm_extension_frame_csp, + wasm_extension_frame_url, +) +from lnbits.core.wasm_ext.routes.ui import ( + _match_wasm_extension_ui_route, + _wasm_extension_bridge_api_routes, + _wasm_extension_entrypoint, + register_wasm_extension_ui_routes, +) +from lnbits.core.wasm_ext.wasm.config import parse_wasm_extension_config +from lnbits.core.wasm_ext.wasm.loader import WasmExtension + + +@pytest.mark.parametrize( + ("size_bytes", "formatted_size"), + [ + (128_235, "128.24 KB"), + (1_000_000, "1.00 MB"), + (12_823_598, "12.82 MB"), + ], +) +def test_format_wasm_extension_size(size_bytes: int, formatted_size: str): + assert _format_wasm_extension_size(size_bytes) == formatted_size + + +@pytest.mark.anyio +async def test_wasm_json_reader_rejects_large_content_length_without_reading(): + request = _FakeRequest([b"{}"], content_length="11") + + with pytest.raises(WasmRequestBodyTooLargeError, match="11 bytes"): + await _read_json_object_with_size(cast(Request, request), max_body_bytes=10) + + assert request.stream_started is False + + +@pytest.mark.anyio +async def test_wasm_json_reader_rejects_large_stream_without_content_length(): + request = _FakeRequest([b'{"value":"', b"x" * 20, b'"}']) + + with pytest.raises(WasmRequestBodyTooLargeError): + await _read_json_object_with_size(cast(Request, request), max_body_bytes=16) + + assert request.stream_started is True + + +@pytest.mark.anyio +async def test_wasm_api_payload_records_actual_body_bytes(): + body = b'{"amount":21}' + request = _FakeRequest( + [body], + path_params={"invoice_id": "abc"}, + query_params={"include_paid": "true"}, + ) + + payload = await _read_api_payload( + cast(Request, request), + {"invoice_id": "invoiceId"}, + max_body_bytes=100, + ) + + assert payload.data == { + "invoiceId": "abc", + "includePaid": "true", + "amount": 21, + } + assert payload.request_bytes == len(body) + + +def test_wasm_api_export_visibility_is_enforced(tmp_path: Path): + extension = _wasm_extension(tmp_path) + + assert _wasm_extension_api_export(extension, "render") == "render" + assert _wasm_extension_api_export(extension, "private_render") == "private_render" + with pytest.raises(PermissionError, match="not callable over HTTP"): + _wasm_extension_api_export(extension, "on_invoice_paid") + with pytest.raises(KeyError, match="has no export"): + _wasm_extension_api_export(extension, "missing") + + +def test_wasm_ui_entrypoint_rejects_escape_static_and_non_html(tmp_path: Path): + extension = _wasm_extension(tmp_path) + (tmp_path / "index.html").write_text("", encoding="utf-8") + (tmp_path / "index.txt").write_text("text", encoding="utf-8") + (tmp_path / "static").mkdir() + (tmp_path / "static" / "index.html").write_text("", encoding="utf-8") + + assert ( + _wasm_extension_entrypoint(extension, "index.html") + == (tmp_path / "index.html").resolve() + ) + with pytest.raises(ValueError, match="escapes extension root"): + _wasm_extension_entrypoint(extension, "../outside.html") + with pytest.raises(ValueError, match="must not be inside the static"): + _wasm_extension_entrypoint(extension, "static/index.html") + with pytest.raises(ValueError, match="must be an HTML file"): + _wasm_extension_entrypoint(extension, "index.txt") + + +def test_wasm_frame_token_is_one_time_and_user_bound(tmp_path: Path): + extension = _wasm_extension(tmp_path) + frame_path = "/ext-frame/demoext/0" + frame_url = wasm_extension_frame_url(extension, frame_path, "user-1") + token = frame_url.split("frame_token=", 1)[1] + + with pytest.raises(HTTPException) as wrong_user: + consume_wasm_extension_frame_token( + _request_with_query(token), + extension, + frame_path, + "user-2", + ) + assert wrong_user.value.status_code == 404 + + consume_wasm_extension_frame_token( + _request_with_query(token), + extension, + frame_path, + "user-1", + ) + with pytest.raises(HTTPException) as reused: + consume_wasm_extension_frame_token( + _request_with_query(token), + extension, + frame_path, + "user-1", + ) + assert reused.value.status_code == 404 + + +def test_wasm_frame_csp_is_locked_to_extension_assets(tmp_path: Path): + csp = wasm_extension_frame_csp( + _request_with_query("token"), + _wasm_extension(tmp_path), + ) + + assert "sandbox allow-scripts" in csp + assert "default-src 'none'" in csp + assert "connect-src 'none'" in csp + assert "frame-ancestors 'self'" in csp + assert "http://testserver/ext-assets/demoext/" in csp + + +def test_wasm_ui_route_matching_and_bridge_public_api_filtering(tmp_path: Path): + extension = _wasm_extension(tmp_path) + + matched = _match_wasm_extension_ui_route(extension, "/ext/demo/abc") + public_routes = _wasm_extension_bridge_api_routes(extension, public=True) + private_routes = _wasm_extension_bridge_api_routes(extension, public=False) + + assert matched["auth"] == "user" + assert matched["route_params"] == {"item_id": "abc"} + assert public_routes == [ + { + "method": "GET", + "path": "/api/v1/ext/demoext/public/{item_id}", + "pattern": "^/api/v1/ext/demoext/public/[^/]+$", + } + ] + assert {route["path"] for route in private_routes} == { + "/api/v1/ext/demoext/public/{item_id}", + "/api/v1/ext/demoext/private/{item_id}", + } + + +def test_wasm_api_routes_are_included_in_openapi(tmp_path: Path): + app = FastAPI() + app.openapi_schema = {"stale": True} + + register_wasm_extension_api_routes(app, _wasm_extension(tmp_path)) + + assert app.openapi_schema is None + schema = app.openapi() + assert "/api/v1/ext/demoext/public/{item_id}" in schema["paths"] + assert "/api/v1/ext/demoext/private/{item_id}" in schema["paths"] + assert schema["paths"]["/api/v1/ext/demoext/public/{item_id}"]["get"]["tags"] == [ + "Demo" + ] + assert schema["paths"]["/api/v1/ext/demoext/private/{item_id}"]["post"]["tags"] == [ + "Demo" + ] + + +def test_wasm_api_routes_load_openapi_operation_fragment(tmp_path: Path): + app = FastAPI() + openapi_dir = tmp_path / "wasm" + openapi_dir.mkdir() + (openapi_dir / "openapi.json").write_text( + json.dumps( + { + "schemas": { + "DemoItem": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": {"type": "string"}, + "name": {"type": "string"}, + }, + } + }, + "routes": { + "list_demo_items": { + "summary": "List demo items", + "description": "Returns demo items.", + "operationId": "demoext_list_demo_items", + "tags": ["Ignored"], + "responses": { + "200": { + "description": "Demo item list", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/schemas/DemoItem" + }, + } + }, + } + } + }, + } + }, + } + }, + } + ), + encoding="utf-8", + ) + + register_wasm_extension_api_routes( + app, + _wasm_extension( + tmp_path, + openapi="wasm/openapi.json", + extra_exports=[{"name": "list-demo-items", "visibility": "public"}], + api_routes=[ + { + "method": "GET", + "path": "/public/{item_id}", + "export": "list-demo-items", + "auth": "public", + } + ], + ), + ) + + operation = app.openapi()["paths"]["/api/v1/ext/demoext/public/{item_id}"]["get"] + item_schema = operation["responses"]["200"]["content"]["application/json"][ + "schema" + ]["properties"]["items"]["items"] + assert operation["summary"] == "List demo items" + assert operation["description"] == "Returns demo items." + assert operation["operationId"] == "demoext_list_demo_items" + assert operation["tags"] == ["Demo"] + assert item_schema["properties"]["name"] == {"type": "string"} + + +def test_wasm_api_routes_allow_route_openapi_fragment_override(tmp_path: Path): + app = FastAPI() + openapi_dir = tmp_path / "wasm" + openapi_dir.mkdir() + (openapi_dir / "openapi.json").write_text( + json.dumps( + { + "routes": { + "render": { + "summary": "Default render docs", + "operationId": "demoext_render", + }, + "custom-render": { + "summary": "Custom render docs", + "operationId": "demoext_custom_render", + }, + } + } + ), + encoding="utf-8", + ) + + register_wasm_extension_api_routes( + app, + _wasm_extension( + tmp_path, + openapi="wasm/openapi.json", + api_routes=[ + { + "method": "GET", + "path": "/public/{item_id}", + "export": "render", + "auth": "public", + "openapi": "#/routes/custom-render", + } + ], + ), + ) + + operation = app.openapi()["paths"]["/api/v1/ext/demoext/public/{item_id}"]["get"] + assert operation["summary"] == "Custom render docs" + assert operation["operationId"] == "demoext_custom_render" + + +def test_wasm_api_routes_add_success_response_example_for_redoc(tmp_path: Path): + app = FastAPI() + openapi_dir = tmp_path / "wasm" + openapi_dir.mkdir() + (openapi_dir / "openapi.json").write_text( + json.dumps( + { + "schemas": { + "DemoItem": { + "type": "object", + "properties": { + "id": {"type": "string"}, + "count": {"type": "integer"}, + }, + }, + "DemoResponse": { + "type": "object", + "required": ["ok", "data"], + "properties": { + "ok": {"type": "boolean", "enum": [True]}, + "data": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": {"$ref": "#/schemas/DemoItem"}, + } + }, + }, + }, + }, + "ErrorResponse": { + "type": "object", + "required": ["ok", "error"], + "properties": { + "ok": {"type": "boolean", "enum": [False]}, + "error": {"type": "string"}, + }, + }, + }, + "routes": { + "render": { + "summary": "Render", + "responses": { + "200": { + "description": "Success or extension-level error.", + "content": { + "application/json": { + "schema": { + "oneOf": [ + {"$ref": "#/schemas/DemoResponse"}, + {"$ref": "#/schemas/ErrorResponse"}, + ] + } + } + }, + } + }, + } + }, + } + ), + encoding="utf-8", + ) + + register_wasm_extension_api_routes( + app, + _wasm_extension( + tmp_path, + openapi="wasm/openapi.json", + api_routes=[ + { + "method": "GET", + "path": "/public/{item_id}", + "export": "render", + "auth": "public", + } + ], + ), + ) + + json_content = app.openapi()["paths"]["/api/v1/ext/demoext/public/{item_id}"][ + "get" + ]["responses"]["200"]["content"]["application/json"] + assert json_content["example"] == { + "ok": True, + "data": {"items": [{"id": "string", "count": 0}]}, + } + + +def test_wasm_api_routes_ignore_missing_openapi_fragment(tmp_path: Path): + app = FastAPI() + + register_wasm_extension_api_routes( + app, + _wasm_extension( + tmp_path, + api_routes=[ + { + "method": "GET", + "path": "/public/{item_id}", + "export": "render", + "auth": "public", + "openapi": "wasm/missing.json#/routes/list_demo_items", + } + ], + ), + ) + + operation = app.openapi()["paths"]["/api/v1/ext/demoext/public/{item_id}"]["get"] + assert operation["summary"] == "GET /public/{item_id}" + assert operation["operationId"] == "demoext_get_public_item_id" + + +def test_wasm_api_routes_replace_same_extension_routes_on_upgrade(tmp_path: Path): + app = FastAPI() + route_path = "/api/v1/ext/demoext/public/{item_id}" + + async def legacy_handler() -> dict[str, bool]: + return {"legacy": True} + + app.add_api_route( + route_path, + legacy_handler, + methods=["GET"], + name=f"demoext:GET:{route_path}", + include_in_schema=False, + ) + app.openapi_schema = {"stale": True} + + register_wasm_extension_api_routes(app, _wasm_extension(tmp_path)) + + routes = _matching_routes(app, route_path, "GET") + assert len(routes) == 1 + assert routes[0].endpoint != legacy_handler + assert routes[0].include_in_schema is True + assert app.openapi_schema is None + assert route_path in app.openapi()["paths"] + + +def test_wasm_api_routes_remove_obsolete_routes_on_upgrade(tmp_path: Path): + app = FastAPI() + route_path = "/api/v1/ext/demoext/removed" + + async def removed_handler() -> dict[str, bool]: + return {"removed": True} + + app.add_api_route( + route_path, + removed_handler, + methods=["GET"], + name=f"demoext:GET:{route_path}", + ) + app.openapi_schema = {"stale": True} + + register_wasm_extension_api_routes(app, _wasm_extension(tmp_path)) + + assert _matching_routes(app, route_path, "GET") == [] + assert app.openapi_schema is None + assert route_path not in app.openapi()["paths"] + + +def test_wasm_api_route_cleanup_preserves_ui_frame_config_route(tmp_path: Path): + app = FastAPI() + (tmp_path / "index.html").write_text("", encoding="utf-8") + extension = _wasm_extension(tmp_path) + frame_config_path = "/api/v1/ext/demoext/_ui/frame" + api_route_path = "/api/v1/ext/demoext/public/{item_id}" + + register_wasm_extension_ui_routes(app, extension) + assert _matching_routes(app, frame_config_path, "POST") != [] + + register_wasm_extension_api_routes(app, extension) + + assert _matching_routes(app, frame_config_path, "POST") != [] + assert _matching_routes(app, api_route_path, "GET") != [] + + assert unregister_wasm_extension_api_routes(app, "demoext") is True + assert _matching_routes(app, api_route_path, "GET") == [] + assert _matching_routes(app, frame_config_path, "POST") != [] + + +def test_wasm_api_routes_are_removed_from_openapi_on_uninstall(tmp_path: Path): + app = FastAPI() + route_path = "/api/v1/ext/demoext/public/{item_id}" + + register_wasm_extension_api_routes(app, _wasm_extension(tmp_path)) + assert route_path in app.openapi()["paths"] + + assert unregister_wasm_extension_api_routes(app, "demoext") is True + + assert app.openapi_schema is None + assert _matching_routes(app, route_path, "GET") == [] + assert route_path not in app.openapi()["paths"] + + +@pytest.mark.anyio +async def test_wasm_api_route_owner_context_uses_configured_storage_row( + tmp_path: Path, mocker +): + extension = _wasm_extension(tmp_path) + route_config = parse_wasm_extension_config( + "demoext", + { + "id": "demoext", + "name": "Demo", + "short_description": "Demo extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": { + "module": "extension.wasm", + "exports": [{"name": "finish", "visibility": "public"}], + }, + "api_routes": [ + { + "method": "POST", + "path": "/games/{game_id}/finish", + "export": "finish", + "auth": "public", + "path_params": {"game_id": "gameId"}, + "ownerContext": {"table": "games", "idParam": "gameId"}, + } + ], + }, + ).api_routes[0] + owner_lookup = mocker.patch( + "lnbits.core.wasm_ext.routes.api.storage_get_row_owner_id", + mocker.AsyncMock(return_value="owner-1"), + ) + + owner_id = await _wasm_route_owner_id( + extension, + route_config, + WasmRoutePayload({"gameId": "game-1"}, request_bytes=10), + ) + + assert owner_id == "owner-1" + owner_lookup.assert_awaited_once_with("demoext", "games", "game-1") + + +def test_wasm_static_core_assets_and_html_like_text_assets_are_guarded(tmp_path: Path): + response = _wasm_extension_core_asset_response("_lnbits/material-icons.css") + assert response.headers["X-Content-Type-Options"] == "nosniff" + assert response.headers["Cache-Control"] == "no-store" + assert WASM_EXTENSION_STATIC_MIME_TYPES[".ogg"] == "audio/ogg" + + for path in ["_lnbits/../bundle.min.css", "_lnbits/missing.css"]: + with pytest.raises(HTTPException) as exc_info: + _wasm_extension_core_asset_response(path) + assert exc_info.value.status_code == 404 + + script_path = tmp_path / "app.js" + script_path.write_text("", encoding="utf-8") + with pytest.raises(HTTPException) as html_like: + _reject_html_like_wasm_static_asset(script_path) + assert html_like.value.status_code == 404 + + +class _FakeRequest: + method = "POST" + + def __init__( + self, + chunks: list[bytes], + *, + content_length: str | None = None, + path_params: dict[str, str] | None = None, + query_params: dict[str, str] | None = None, + ) -> None: + self._chunks = chunks + self.headers: dict[str, str] = {} + if content_length is not None: + self.headers["content-length"] = content_length + self.path_params = path_params or {} + self.query_params = query_params or {} + self.stream_started = False + + async def stream(self) -> AsyncIterator[bytes]: + self.stream_started = True + for chunk in self._chunks: + yield chunk + + +def _wasm_extension( + root_path: Path, + *, + api_routes: list[dict] | None = None, + openapi: str | None = None, + extra_exports: list[dict] | None = None, +) -> WasmExtension: + extension_config = { + "id": "demoext", + "name": "Demo", + "short_description": "Demo extension", + "version": "1.0.0", + "extension_type": "wasm", + "wasm": { + "module": "extension.wasm", + "exports": [ + {"name": "render", "visibility": "public"}, + {"name": "private_render", "visibility": "authenticated"}, + {"name": "on_invoice_paid", "visibility": "event"}, + *(extra_exports or []), + ], + }, + "ui_routes": [ + { + "path": "/demo/{item_id}", + "entrypoint": "index.html", + "auth": "user", + } + ], + "api_routes": api_routes + or [ + { + "method": "GET", + "path": "/public/{item_id}", + "export": "render", + "auth": "public", + }, + { + "method": "POST", + "path": "/private/{item_id}", + "export": "private_render", + "auth": "user", + }, + ], + } + if openapi: + extension_config["openapi"] = openapi + config = parse_wasm_extension_config("demoext", extension_config) + return WasmExtension( + id="demoext", + name="Demo", + version="1.0.0", + root_path=root_path, + module_path=root_path / "extension.wasm", + wit_path=None, + world="", + exports=config.wasm.exports, + config=config, + ) + + +def _request_with_query(token: str) -> Request: + return Request( + { + "type": "http", + "method": "GET", + "scheme": "http", + "server": ("testserver", 80), + "path": "/ext-frame/demoext/0", + "query_string": f"frame_token={token}".encode(), + "headers": [], + } + ) + + +def _matching_routes(app: FastAPI, route_path: str, method: str) -> list: + return [ + route + for route in app.router.routes + if getattr(route, "path", None) == route_path + and method in (getattr(route, "methods", set()) or set()) + ] diff --git a/tests/unit/test_wasm_extension_storage.py b/tests/unit/test_wasm_extension_storage.py new file mode 100644 index 000000000..572c33149 --- /dev/null +++ b/tests/unit/test_wasm_extension_storage.py @@ -0,0 +1,490 @@ +import json +from datetime import datetime, timedelta, timezone +from pathlib import Path +from types import SimpleNamespace +from typing import Any, cast +from uuid import uuid4 + +import pytest +from pytest_mock.plugin import MockerFixture + +from lnbits.core.crud import extensions as extension_crud +from lnbits.core.crud import update_migration_version +from lnbits.core.db import db as core_db +from lnbits.core.migrations import ( + m010_create_installed_extensions_table, + m046_add_permissions_to_installed_extensions, + m047_create_wasm_invocations_table, + m048_add_wasm_runtime_limits_to_installed_extensions, +) +from lnbits.core.models.extensions import ExtensionPermission, WasmInvocation +from lnbits.core.wasm_ext.storage import crud as storage_crud +from lnbits.core.wasm_ext.storage.crud import ( + OWNER_ID_FIELD, + migrate_wasm_extension_database, + storage_append_public_row, + storage_count_rows, + storage_delete_row, + storage_get_paginated_rows, + storage_get_public_row, + storage_get_row, + storage_set_row, +) +from lnbits.db import DB_TYPE, SQLITE, Compat, Connection, Database +from lnbits.settings import Settings +from tests.helpers import make_installable_extension + + +@pytest.mark.anyio +async def test_core_wasm_migrations_create_persistent_columns( + tmp_path: Path, settings: Settings +): + if DB_TYPE != SQLITE: + pytest.skip("temporary core databases are SQLite-only") + + db = _temporary_database(tmp_path, settings, "wasm_core_migrations") + + async with db.connect() as conn: + await m010_create_installed_extensions_table(conn) + await m046_add_permissions_to_installed_extensions(conn) + await m047_create_wasm_invocations_table(conn) + await m048_add_wasm_runtime_limits_to_installed_extensions(conn) + + installed_columns = { + row["name"] + for row in await conn.fetchall("PRAGMA table_info(installed_extensions)") + } + invocation_columns = { + row["name"] + for row in await conn.fetchall("PRAGMA table_info(wasm_invocations)") + } + + assert {"permissions", "wasm_runtime_limits"}.issubset(installed_columns) + assert { + "extension_id", + "status", + "request_bytes", + "response_bytes", + "host_call_count", + "http_call_count", + "storage_call_count", + "wallet_call_count", + "context", + }.issubset(invocation_columns) + + +@pytest.mark.anyio +async def test_installed_extension_permissions_and_wasm_limits_round_trip( + app, + tmp_path: Path, + settings: Settings, + mocker: MockerFixture, +): + db = await _temporary_core_crud_database(tmp_path, settings) + mocker.patch.object(extension_crud, "db", db) + + ext_id = f"wasmlimits_{uuid4().hex[:8]}" + extension = make_installable_extension(ext_id) + extension.permissions = [ExtensionPermission(id="utils.basic")] + extension.wasm_runtime_limits = {"wasm_runtime_max_execution_ms": 1234} + + await extension_crud.create_installed_extension(extension) + stored = await extension_crud.get_installed_extension(ext_id) + + assert stored is not None + assert stored.permissions == [ExtensionPermission(id="utils.basic")] + assert stored.wasm_runtime_limits == {"wasm_runtime_max_execution_ms": 1234} + + stored.wasm_runtime_limits = {"wasm_runtime_max_fuel": 0} + await extension_crud.update_installed_extension(stored) + updated = await extension_crud.get_installed_extension(ext_id) + + assert updated is not None + assert updated.wasm_runtime_limits == {"wasm_runtime_max_fuel": 0} + + +@pytest.mark.anyio +async def test_wasm_invocation_crud_stats_and_cleanup_are_isolated( + app, + tmp_path: Path, + settings: Settings, + mocker: MockerFixture, +): + db = await _temporary_core_crud_database(tmp_path, settings) + mocker.patch.object(extension_crud, "db", db) + + now = datetime.now(timezone.utc) + old = now - timedelta(days=10) + ext_id = f"wasminv_{uuid4().hex[:8]}" + other_ext_id = f"wasminv_{uuid4().hex[:8]}" + invocations = [ + WasmInvocation( + id=f"inv_{uuid4().hex}", + extension_id=ext_id, + export_name="render", + status="completed", + started_at=old, + finished_at=old + timedelta(milliseconds=20), + duration_ms=20, + host_call_count=2, + http_call_count=1, + ), + WasmInvocation( + id=f"inv_{uuid4().hex}", + extension_id=ext_id, + export_name="render", + status="failed", + started_at=now, + finished_at=now, + duration_ms=40, + host_call_count=3, + storage_call_count=2, + ), + WasmInvocation( + id=f"inv_{uuid4().hex}", + extension_id=ext_id, + export_name="render", + status="running", + started_at=old, + ), + WasmInvocation( + id=f"inv_{uuid4().hex}", + extension_id=other_ext_id, + export_name="render", + status="completed", + started_at=now, + duration_ms=100, + ), + ] + for invocation in invocations: + await extension_crud.create_wasm_invocation(invocation) + + failed = await extension_crud.get_wasm_invocations( + extension_id=ext_id, + status="failed", + ) + stats = await extension_crud.get_wasm_invocation_stats( + extension_id=ext_id, + since=now - timedelta(days=30), + ) + deleted = await extension_crud.delete_old_wasm_invocations(retention_days=7) + remaining_running = await extension_crud.get_wasm_invocations( + extension_id=ext_id, + status="running", + ) + + assert [invocation.id for invocation in failed] == [invocations[1].id] + assert stats.total == 3 + assert stats.completed == 1 + assert stats.failed == 1 + assert stats.running == 1 + assert stats.host_call_count == 5 + assert stats.http_call_count == 1 + assert stats.storage_call_count == 2 + assert deleted == 1 + assert [invocation.id for invocation in remaining_running] == [invocations[2].id] + + +@pytest.mark.anyio +async def test_wasm_datetime_queries_use_postgres_placeholders( + mocker: MockerFixture, +): + db = mocker.Mock() + db.timestamp_placeholder.side_effect = lambda key: f"to_timestamp(:{key})" + db.fetchone = mocker.AsyncMock(return_value=None) + db.execute = mocker.AsyncMock(return_value=SimpleNamespace(rowcount=0)) + + field = {"name": "created_at", "type": "datetime"} + assert ( + storage_crud._value_placeholder(cast(Compat, db), field, "created_at") + == "to_timestamp(:created_at)" + ) + where_sql, _ = storage_crud._where_sql( + cast(Compat, db), {"fields": [field]}, {"created_at": 0}, None, [] + ) + assert "created_at = to_timestamp(:filter_created_at)" in where_sql + + conn = cast(Connection, db) + await extension_crud.get_wasm_invocation_stats( + since=datetime.now(timezone.utc), conn=conn + ) + await extension_crud.delete_old_wasm_invocations(1, conn=conn) + await extension_crud.mark_stale_wasm_invocations(conn=conn) + + queries = [ + db.fetchone.call_args.args[0], + *[c.args[0] for c in db.execute.call_args_list], + ] + assert all("to_timestamp(:" in query for query in queries) + + +@pytest.mark.anyio +async def test_wasm_storage_migration_and_owner_scoped_crud( + tmp_path: Path, + settings: Settings, +): + ext_id = f"wasmstore_{uuid4().hex[:8]}" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + original_data_folder = settings.lnbits_data_folder + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + Path(settings.lnbits_data_folder).mkdir(parents=True) + ext_dir = _write_storage_extension(settings, ext_id) + + await migrate_wasm_extension_database(make_installable_extension(ext_id)) + await storage_set_row( + ext_id, + "notes", + { + "id": "note-1", + "title": "First", + "count": 1, + "published": True, + "tags": ["alpha", "beta"], + "created_at": 1_700_000_000, + }, + "owner-1", + ) + await storage_set_row( + ext_id, + "notes", + { + "id": "note-1", + "title": "Other owner attempt", + "count": 2, + "published": False, + "tags": ["gamma"], + "created_at": 1_700_000_001, + }, + "owner-2", + ) + + owner_row = await storage_get_row(ext_id, "notes", "note-1", "owner-1") + other_owner_row = await storage_get_row(ext_id, "notes", "note-1", "owner-2") + public_row = await storage_get_public_row(ext_id, "notes", "note-1") + page = await storage_get_paginated_rows( + ext_id, + "notes", + {"published": True}, + owner_id="owner-1", + search="fir", + search_fields=["title"], + sort_by="count", + descending=True, + limit=50, + offset=0, + ) + await storage_delete_row(ext_id, "notes", "note-1", "owner-2") + still_owned = await storage_get_row(ext_id, "notes", "note-1", "owner-1") + await storage_delete_row(ext_id, "notes", "note-1", "owner-1") + deleted = await storage_get_row(ext_id, "notes", "note-1", "owner-1") + finally: + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + settings.lnbits_data_folder = original_data_folder + + assert ext_dir.is_dir() + assert owner_row is not None + assert owner_row["title"] == "First" + assert owner_row["tags"] == ["alpha", "beta"] + assert owner_row["created_at"] == 1_700_000_000 + assert other_owner_row is None + assert public_row is not None + assert public_row["title"] == "First" + assert page["total"] == 1 + assert page["data"][0]["id"] == "note-1" + assert still_owned is not None + assert deleted is None + + +@pytest.mark.anyio +async def test_wasm_storage_public_append_generates_id_and_counts_by_owner( + tmp_path: Path, + settings: Settings, +): + ext_id = f"wasmstore_{uuid4().hex[:8]}" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + original_data_folder = settings.lnbits_data_folder + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + Path(settings.lnbits_data_folder).mkdir(parents=True) + _write_storage_extension(settings, ext_id) + + await migrate_wasm_extension_database(make_installable_extension(ext_id)) + await storage_set_row( + ext_id, + "threads", + {"id": "thread-1", "title": "Support"}, + "owner-1", + ) + message_id = await storage_append_public_row( + ext_id, + "messages", + {"thread_id": "thread-1", "message": "Hello"}, + "owner-1", + ) + owner_count = await storage_count_rows( + ext_id, + "messages", + {"thread_id": "thread-1"}, + owner_id="owner-1", + ) + other_owner_count = await storage_count_rows( + ext_id, + "messages", + {"thread_id": "thread-1"}, + owner_id="owner-2", + ) + message = await storage_get_row(ext_id, "messages", message_id, "owner-1") + finally: + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + settings.lnbits_data_folder = original_data_folder + + assert message_id + assert owner_count == 1 + assert other_owner_count == 0 + assert message is not None + assert message["id"] == message_id + assert message["thread_id"] == "thread-1" + assert message["message"] == "Hello" + + +@pytest.mark.anyio +async def test_wasm_storage_rejects_reserved_fields_and_invalid_identifiers( + tmp_path: Path, + settings: Settings, +): + ext_id = f"wasmstore_{uuid4().hex[:8]}" + original_extensions_path = settings.lnbits_extensions_path + original_wasm_extensions_path = settings.lnbits_wasm_extensions_path + original_data_folder = settings.lnbits_data_folder + try: + settings.lnbits_data_folder = str(tmp_path / "data") + settings.lnbits_extensions_path = str(tmp_path / "code") + settings.lnbits_wasm_extensions_path = str(tmp_path / "wasm_extensions") + Path(settings.lnbits_data_folder).mkdir(parents=True) + _write_storage_extension(settings, ext_id) + + with pytest.raises(ValueError, match="Invalid WASM storage SQL identifier"): + await storage_get_row(ext_id, "notes;DROP", "note-1", "owner-1") + + with pytest.raises(ValueError, match="reserved owner field"): + await storage_set_row( + ext_id, + "notes", + {"id": "note-1", OWNER_ID_FIELD: "owner-2"}, + "owner-1", + ) + + schema_path = settings.wasm_extensions_dir / ext_id / "storage" / "schema.json" + schema = json.loads(schema_path.read_text(encoding="utf-8")) + schema["tables"]["notes"]["fields"].append( + {"name": OWNER_ID_FIELD, "type": "string"} + ) + schema_path.write_text(json.dumps(schema), encoding="utf-8") + + with pytest.raises(ValueError, match="reserved field"): + await storage_get_row(ext_id, "notes", "note-1", "owner-1") + finally: + settings.lnbits_extensions_path = original_extensions_path + settings.lnbits_wasm_extensions_path = original_wasm_extensions_path + settings.lnbits_data_folder = original_data_folder + + +def _temporary_database( + tmp_path: Path, + settings: Settings, + name: str, +) -> Database: + settings.lnbits_data_folder = str(tmp_path / "data") + Path(settings.lnbits_data_folder).mkdir(parents=True, exist_ok=True) + return Database(name) + + +async def _temporary_core_crud_database( + tmp_path: Path, + settings: Settings, +) -> Database: + if DB_TYPE != SQLITE: + return core_db + + db = _temporary_database(tmp_path, settings, f"core_{uuid4().hex[:8]}") + async with db.connect() as conn: + await conn.execute(""" + CREATE TABLE dbversions ( + db TEXT PRIMARY KEY, + version INT NOT NULL + ) + """) + await update_migration_version(conn, "core", 48) + await m010_create_installed_extensions_table(conn) + await m046_add_permissions_to_installed_extensions(conn) + await m047_create_wasm_invocations_table(conn) + await m048_add_wasm_runtime_limits_to_installed_extensions(conn) + return db + + +def _write_storage_extension(settings: Settings, ext_id: str) -> Path: + ext_dir = settings.wasm_extensions_dir / ext_id + storage_dir = ext_dir / "storage" + migrations_dir = storage_dir / "migrations" + migrations_dir.mkdir(parents=True) + schema: dict[str, Any] = { + "tables": { + "notes": { + "fields": [ + {"name": "id", "type": "string"}, + {"name": "title", "type": "string"}, + {"name": "count", "type": "integer", "default": 0}, + {"name": "published", "type": "boolean", "default": False}, + {"name": "tags", "type": "string", "list": True}, + {"name": "created_at", "type": "datetime"}, + ] + }, + "threads": { + "fields": [ + {"name": "id", "type": "string"}, + {"name": "title", "type": "string"}, + ] + }, + "messages": { + "fields": [ + {"name": "id", "type": "string"}, + {"name": "thread_id", "type": "string"}, + {"name": "message", "type": "string"}, + ] + }, + } + } + migration = { + "operations": [ + { + "op": "create_table", + "table": "notes", + "fields": schema["tables"]["notes"]["fields"], + }, + { + "op": "create_table", + "table": "threads", + "fields": schema["tables"]["threads"]["fields"], + }, + { + "op": "create_table", + "table": "messages", + "fields": schema["tables"]["messages"]["fields"], + }, + ] + } + (storage_dir / "schema.json").write_text(json.dumps(schema), encoding="utf-8") + (migrations_dir / "001_init.json").write_text( + json.dumps(migration), + encoding="utf-8", + ) + return ext_dir diff --git a/tests/unit/test_wasm_extension_websocket_api.py b/tests/unit/test_wasm_extension_websocket_api.py new file mode 100644 index 000000000..781762265 --- /dev/null +++ b/tests/unit/test_wasm_extension_websocket_api.py @@ -0,0 +1,50 @@ +from types import SimpleNamespace +from unittest.mock import AsyncMock + +import pytest + +from lnbits.core.models.extensions import ExtensionPermission +from lnbits.core.views.websocket_api import extension_websocket_connect + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_delegates_installed_wasm_subscription(mocker): + websocket = AsyncMock() + conn = SimpleNamespace() + installed_ext = SimpleNamespace( + active=True, + is_wasm=True, + permissions=[ExtensionPermission(id="websocket.subscribe")], + ) + mocker.patch( + "lnbits.core.views.websocket_api.get_installed_extension", + AsyncMock(return_value=installed_ext), + ) + connect = mocker.patch( + "lnbits.core.views.websocket_api.wasm_extension_websocket_hub.connect", + AsyncMock(return_value=conn), + ) + listen = mocker.patch( + "lnbits.core.views.websocket_api.wasm_extension_websocket_hub.listen", + AsyncMock(), + ) + + await extension_websocket_connect(websocket, "demoext", "room-1") + + websocket.close.assert_not_awaited() + connect.assert_awaited_once_with("demoext", "room-1", websocket) + listen.assert_awaited_once_with(conn) + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_rejects_missing_subscribe_permission(mocker): + websocket = AsyncMock() + installed_ext = SimpleNamespace(active=True, is_wasm=True, permissions=[]) + mocker.patch( + "lnbits.core.views.websocket_api.get_installed_extension", + AsyncMock(return_value=installed_ext), + ) + + await extension_websocket_connect(websocket, "demoext", "room-1") + + websocket.close.assert_awaited_once() diff --git a/tests/unit/test_wasm_extension_websockets.py b/tests/unit/test_wasm_extension_websockets.py new file mode 100644 index 000000000..94449839a --- /dev/null +++ b/tests/unit/test_wasm_extension_websockets.py @@ -0,0 +1,131 @@ +from typing import cast + +import pytest +from fastapi import WebSocket, WebSocketDisconnect + +from lnbits.core.wasm_ext.api.websockets import ( + WasmExtensionWebsocketHub, + WasmExtensionWebsocketRateLimitError, +) + + +class FakeWebSocket: + def __init__( + self, + received: list[str] | None = None, + send_error: Exception | None = None, + ): + self.accepted = False + self.sent: list[str] = [] + self.closed: int | None = None + self.received = list(received or []) + self.send_error = send_error + + async def accept(self): + self.accepted = True + + async def send_text(self, data: str): + if self.send_error: + raise self.send_error + self.sent.append(data) + + async def receive_text(self): + if self.received: + return self.received.pop(0) + raise WebSocketDisconnect() + + async def close(self, code: int = 1000): + self.closed = code + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_hub_publishes_to_matching_channel(): + hub = WasmExtensionWebsocketHub() + matching = FakeWebSocket() + other_item = FakeWebSocket() + other_extension = FakeWebSocket() + + await hub.connect("demoext", "room-1", cast(WebSocket, matching)) + await hub.connect("demoext", "room-2", cast(WebSocket, other_item)) + await hub.connect("otherext", "room-1", cast(WebSocket, other_extension)) + + await hub.publish( + "demoext", + "room-1", + '{"message":"Hello"}', + max_messages_per_second=10, + ) + + assert matching.accepted is True + assert matching.sent == ['{"message":"Hello"}'] + assert other_item.sent == [] + assert other_extension.sent == [] + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_hub_prunes_stale_publish_connections(): + hub = WasmExtensionWebsocketHub() + stale = FakeWebSocket(send_error=RuntimeError("websocket closed")) + active = FakeWebSocket() + + await hub.connect("demoext", "room-1", cast(WebSocket, stale)) + await hub.connect("demoext", "room-1", cast(WebSocket, active)) + + await hub.publish( + "demoext", + "room-1", + '{"message":"Hello"}', + max_messages_per_second=10, + ) + + assert active.sent == ['{"message":"Hello"}'] + assert hub.get_connections("demoext", "room-1")[0].websocket == active + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_hub_rate_limits_per_channel(): + hub = WasmExtensionWebsocketHub() + websocket = FakeWebSocket() + other_websocket = FakeWebSocket() + + await hub.connect("demoext", "room-1", cast(WebSocket, websocket)) + await hub.connect("demoext", "room-2", cast(WebSocket, other_websocket)) + + await hub.publish( + "demoext", + "room-1", + '{"message":1}', + max_messages_per_second=1, + ) + with pytest.raises(WasmExtensionWebsocketRateLimitError): + await hub.publish( + "demoext", + "room-1", + '{"message":2}', + max_messages_per_second=1, + ) + + await hub.publish( + "demoext", + "room-2", + '{"message":3}', + max_messages_per_second=1, + ) + + assert websocket.sent == ['{"message":1}'] + assert other_websocket.sent == ['{"message":3}'] + + +@pytest.mark.anyio +async def test_wasm_extension_websocket_hub_rebroadcasts_client_messages_to_peers(): + hub = WasmExtensionWebsocketHub() + sender = FakeWebSocket(received=['{"type":"input","paddle":0.5}']) + peer = FakeWebSocket() + + conn = await hub.connect("demoext", "game-1", cast(WebSocket, sender)) + await hub.connect("demoext", "game-1", cast(WebSocket, peer)) + + await hub.listen(conn) + + assert sender.sent == [] + assert peer.sent == ['{"type":"input","paddle":0.5}'] diff --git a/tests/wallets/fixtures/json/fixtures_rest.json b/tests/wallets/fixtures/json/fixtures_rest.json index 3206b0e5b..54a1e0f43 100644 --- a/tests/wallets/fixtures/json/fixtures_rest.json +++ b/tests/wallets/fixtures/json/fixtures_rest.json @@ -38,7 +38,9 @@ "wallet_class": "LNbitsWallet", "settings": { "lnbits_endpoint": "http://127.0.0.1:8555", + "lnbits_key": null, "lnbits_admin_key": "f171ba022a764e679eef950b21fb1c04", + "lnbits_invoice_key": null, "user_agent": "LNbits/Tests" } }, @@ -1831,6 +1833,26 @@ "fee_msat": null, "preimage": null }, + "expect_by_funding_source": { + "alby": { + "error_message": "Not Found", + "success": false, + "pending": false, + "failed": true, + "checking_id": null, + "fee_msat": null, + "preimage": null + }, + "eclair": { + "error_message": "Unable to connect to http://127.0.0.1:8555.", + "success": false, + "pending": false, + "failed": true, + "checking_id": null, + "fee_msat": null, + "preimage": null + } + }, "mocks": { "corelightningrest": { "pay_invoice_endpoint": [ @@ -2073,7 +2095,7 @@ { "response_type": "json", "response": { - "settled": true + "state": "SETTLED" } } ] @@ -2155,8 +2177,15 @@ ] }, "lndrest": { - "description": "lndrest.py doesn't handle the 'failed' status for `get_invoice_status`", - "get_invoice_status_endpoint": [] + "get_invoice_status_endpoint": [ + { + "description": "error status", + "response_type": "json", + "response": { + "state": "CANCELED" + } + } + ] }, "alby": { "description": "alby.py doesn't handle the 'failed' status for `get_invoice_status`", @@ -2243,13 +2272,6 @@ "response_type": "json", "response": {} }, - { - "description": "error status", - "response_type": "json", - "response": { - "seetled": false - } - }, { "description": "bad json", "response_type": "data", diff --git a/tests/wallets/fixtures/models.py b/tests/wallets/fixtures/models.py index 7f5ecf5b1..023a2bb3c 100644 --- a/tests/wallets/fixtures/models.py +++ b/tests/wallets/fixtures/models.py @@ -46,6 +46,7 @@ class FunctionTest(BaseModel): description: str call_params: dict expect: dict + expect_by_funding_source: dict[str, dict] = {} mocks: dict[str, list[dict[str, TestMock]]] @@ -76,11 +77,20 @@ class WalletTest(BaseModel): fn, test, ) -> list["WalletTest"]: + test_data = { + key: value + for key, value in test.items() + if key != "expect_by_funding_source" + } + expect_by_funding_source = test.get("expect_by_funding_source", {}) + if fs.name in expect_by_funding_source: + test_data["expect"] = expect_by_funding_source[fs.name] + t = WalletTest( **{ "funding_source": fs, "function": fn_name, - **test, + **test_data, "mocks": [], "skip": fs.skip, } diff --git a/tests/wallets/index.html b/tests/wallets/index.html new file mode 100644 index 000000000..bb22ca0b9 --- /dev/null +++ b/tests/wallets/index.html @@ -0,0 +1,6396 @@ + + + + + + Wallet Fixture Studio + + + + +
+
+
+
+
+
Wallet Fixture Studio
+

Test matrix for wallet funding sources

+

{{ currentLoadedFileName }}

+
+ +
+ + + + +
+
+ +
+
+
Funding Sources
+
+
+ {{ currentDataset.analysis.summary.fundingSources }} +
+ +
+
+
+
Functions
+
+ {{ currentDataset.analysis.summary.functions }} +
+
+
+
Raw Test Cases
+
+ {{ currentDataset.analysis.summary.rawTests }} +
+
+
+
Expanded Wallet Tests
+
+ {{ currentDataset.analysis.summary.expandedTests }} +
+
+
+ + + {{ currentDataset.loadError }} + +
+ +
+ + + + +
+
{{ fn.name }}
+
{{ fn.tests.length }} tests
+
+
+
+ +
+
+
+ + +
{{ group.label }}
+
+
+ + + +
+
+
+
+

+ {{ `${group.label} ${entryIndex + 1}` }} +

+
+ Raw test {{ testEntry.index + 1 }} +
+
+
+ +
+ {{ testEntry.note }} +
+ +
+
+ + +
+ {{ testEntry.callParamsError }} +
+
+
+ + +
+ {{ testEntry.expectedError }} +
+
+
+ +
+ +
+ + + + + +
+
+ +
+
+
+ + +
+ +
+
+
+ + + + +
+
+ +
+
+ + + + +
+ {{ item.error }} +
+
+
+ +
+ No objects are defined in this mock array + yet. +
+ +
+ +
+
+ +
+ {{ mockSet.error }} +
+
+
+ +
+ No wallet-specific mock entry is defined for + {{ currentTestFundingSource.name }} + in this test. +
+
+
+
+
+
+ +
+ No tests are defined for this function. +
+
+
+ +
+ No functions are defined for this fixture file. +
+
+
+
+
+ + + + +
+

Funding Source Settings

+
+ Edit the settings for the selected funding source. Changes + update the active fixture JSON immediately. +
+
+ +
+ + {{ currentFundingSourceSettingRows.length }} rows + +
+ + +
+ + + + +
+ + + + + +
+ +
+
+ +
+
+
+
+
Key
+
Type
+
Value
+
Actions
+
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ + +
+ +
+ +
+
+ +
+ {{ row.error }} +
+
+
+
+ +
+ No settings are defined yet for this funding source. +
+ +
+ +
+
+ +
+ No funding sources are defined for this fixture file. +
+
+ + + + + + +
+
+ + + + +
+

Function Mocks

+
+ Reusable mocks for the selected function and funding source. +
+
+ Changes update + {{ currentFunctionBaseMockPath }} + immediately. +
+
+ +
+ + {{ currentFunctionMockRows.length }} mocks + +
+ + +
+ + + + +
+
+
+
+
+
Mock Name
+
Method
+ + +
+ +
+
+
+ +
+ Mock Name: Stable mock identifier used inside this + function's fixture map. +
+
+ +
+
+ +
+
+ + + +
+ Request Type: Choose REST for HTTP + mocks or RPC for Python patch mocks. +
+
+ +
+ +
+ {{ functionMockMethodHint(mockRow) }} +
+
+ +
+ +
+ Path: Request path or URI matcher for REST mocks. +
+
+
+ + + + +
+ +
+ {{ mockRow.error }} +
+
+ Leave unused fields blank. JSON columns must contain + valid JSON objects or values. +
+
+
+
+
+ +
+ No function-level mocks are defined yet for + {{ currentTestFundingSource.name }} + in + {{ currentFunction.name }}. +
+ +
+ +
+
+ +
+ Select a funding source and function first. +
+
+ + + + + + +
+
+ + + + +
+

Raw JSON Editor

+
+ Edit the current fixture file directly, then apply, save, or + download the changes. +
+
+ + +
+ + + + +
+
+ + {{ editorDirty ? 'Unsaved editor changes' : 'Editor synced' }} + + + {{ currentDataset.parseError ? 'JSON error' : 'Valid JSON' }} + +
+ +
+ + + + + +
+
+ + + {{ currentDataset.parseError }} + + + +
+ + + + + + +
+
+ + +
+ + + + + + diff --git a/tests/wallets/test_bark.py b/tests/wallets/test_bark.py new file mode 100644 index 000000000..38a2d4f4c --- /dev/null +++ b/tests/wallets/test_bark.py @@ -0,0 +1,301 @@ +import asyncio +import json + +import httpx +import pytest +from bolt11 import decode as bolt11_decode + +from lnbits.wallets.bark import BarkWallet +from lnbits.wallets.base import PaymentResponse + +BOLT11 = ( + "lnbc1u1pjl0uhypp5yxvdqq923atm9ywkpgtu3yxv9w2n44ensrkwfyagvmzqhml2x9gq" + "dpv2phhwetjv4jzqcneypqyc6t8dp6xu6twva2xjuzzda6qcqzzsxqrrsssp5h3qlnnlfq" + "ekquacwwj9yu7fhujyzxhzqegpxenscw45pgv6xakfq9qyyssqqjruygw0jrcg3365jksxn" + "6yhsxx7c5pdjrjdlyvuhs7xh8r409h4e3kucc54kgh34pscaq3mg7hn55l8a0qszgzex80" + "amwrp4gkdgqcpkse88y" +) + + +class FakeWebSocket: + def __init__(self, messages: list[dict]): + self.messages = messages + + async def recv(self): + return json.dumps(self.messages.pop(0)) + + +class FakeConnection: + def __init__(self, websocket: FakeWebSocket): + self.websocket = websocket + + async def __aenter__(self): + return self.websocket + + async def __aexit__(self, *_): + return None + + +@pytest.fixture +def bark_wallet(settings): + settings.bark_api_endpoint = "http://localhost:3000" + settings.bark_api_token = "test-token" + return BarkWallet() + + +def payment_response(status_code: int, **kwargs) -> httpx.Response: + request = httpx.Request("POST", "http://localhost:3000/api/v1/lightning/pay") + return httpx.Response(status_code, request=request, **kwargs) + + +@pytest.mark.anyio +async def test_paid_invoices_stream_yields_successful_receive( + bark_wallet: BarkWallet, mocker +): + checking_id = bolt11_decode(BOLT11).payment_hash + notification = { + "type": "movement-updated", + "movement": { + "status": "successful", + "received_on": [ + { + "destination": {"type": "invoice", "value": BOLT11}, + "amount_sat": 100, + } + ], + }, + } + websocket = FakeWebSocket([notification]) + connect = mocker.patch( + "lnbits.wallets.bark.connect", return_value=FakeConnection(websocket) + ) + request = mocker.patch.object( + bark_wallet, + "_request_json", + side_effect=[ + "websocket-ticket", + {"state": "preimage-revealed", "payment_preimage": "preimage"}, + ], + ) + + stream = bark_wallet.paid_invoices_stream() + try: + assert await anext(stream) == checking_id + status = await bark_wallet.get_invoice_status(checking_id) + assert status.success + assert status.preimage == "preimage" + finally: + await stream.aclose() + await bark_wallet.cleanup() + + assert request.await_args_list == [ + mocker.call("GET", "/api/v1/notifications/ws/ticket", timeout=10), + mocker.call("GET", f"/api/v1/lightning/receives/{checking_id}"), + ] + connect.assert_called_once_with( + "ws://localhost:3000/api/v1/notifications/ws?ticket=websocket-ticket" + ) + + +def test_incoming_payment_hash_ignores_non_receive_movements(bark_wallet: BarkWallet): + notification = { + "type": "movement-updated", + "movement": { + "status": "successful", + "received_on": [], + "sent_to": [{"destination": {"type": "invoice", "value": BOLT11}}], + }, + } + + assert bark_wallet._incoming_payment_hash(notification) is None + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("data", "expected_paid"), + [ + ( + { + "state": "settled", + "settled_at": "2026-07-16T12:00:00Z", + "payment_preimage": "preimage", + }, + True, + ), + ( + { + "finished_at": "2026-07-16T12:00:00Z", + "preimage_revealed_at": "2026-07-16T12:00:00Z", + "payment_preimage": "preimage", + }, + True, + ), + ({"state": "awaiting-payment"}, None), + ({"finished_at": "2026-07-16T12:00:00Z"}, False), + ], + ids=["settled", "legacy-settled", "pending", "failed"], +) +async def test_get_invoice_status_maps_receive_state( + bark_wallet: BarkWallet, mocker, data: dict, expected_paid: bool | None +): + checking_id = bolt11_decode(BOLT11).payment_hash + request = mocker.patch.object(bark_wallet, "_request_json", return_value=data) + + status = await bark_wallet.get_invoice_status(checking_id) + + assert status.paid is expected_paid + assert status.preimage == ("preimage" if expected_paid else None) + request.assert_awaited_once_with("GET", f"/api/v1/lightning/receives/{checking_id}") + + +@pytest.mark.anyio +@pytest.mark.parametrize("ok", [True, None], ids=["settled", "pending"]) +async def test_send_payment_checks_status_after_payment_is_initiated( + bark_wallet: BarkWallet, mocker, settings, ok: bool | None +): + settings.lnbits_funding_source_pay_invoice_wait_seconds = 0 + checking_id = bolt11_decode(BOLT11).payment_hash + expected = PaymentResponse(ok=ok, checking_id=checking_id) + mocker.patch.object( + bark_wallet.client, + "post", + return_value=payment_response( + 200, json={"message": "Payment initiated successfully"} + ), + ) + get_status = mocker.patch.object( + bark_wallet, "_payment_response_from_status", return_value=expected + ) + + response = await bark_wallet._send_payment(BOLT11, checking_id) + + assert response == expected + assert bark_wallet.pending_payments[checking_id] == BOLT11 + get_status.assert_awaited_once_with(checking_id) + + +@pytest.mark.anyio +async def test_send_payment_waits_for_successful_movement_notification( + bark_wallet: BarkWallet, mocker, settings +): + settings.lnbits_funding_source_pay_invoice_wait_seconds = 5 + checking_id = bolt11_decode(BOLT11).payment_hash + mocker.patch.object( + bark_wallet.client, + "post", + return_value=payment_response( + 200, json={"message": "Payment initiated successfully"} + ), + ) + mocker.patch.object( + bark_wallet, + "_payment_response_from_status", + return_value=PaymentResponse(ok=None, checking_id=checking_id), + ) + + payment_task = asyncio.create_task(bark_wallet._send_payment(BOLT11, checking_id)) + await asyncio.sleep(0) + bark_wallet._notify_outgoing_payment( + { + "type": "movement-updated", + "movement": { + "status": "successful", + "offchain_fee_sat": 2, + "metadata": {"payment_preimage": "preimage"}, + "sent_to": [ + { + "destination": {"type": "invoice", "value": BOLT11}, + "amount_sat": 100, + } + ], + }, + } + ) + + response = await payment_task + + assert response.ok is True + assert response.checking_id == checking_id + assert response.fee_msat == 2000 + assert response.preimage == "preimage" + assert checking_id not in bark_wallet.outgoing_payment_waiters + + +@pytest.mark.anyio +@pytest.mark.parametrize( + "error", + [ + httpx.TimeoutException("timeout"), + httpx.ReadError("connection lost"), + ], + ids=["timeout", "read-error"], +) +async def test_send_payment_keeps_transport_errors_pending( + bark_wallet: BarkWallet, mocker, error: httpx.RequestError +): + checking_id = bolt11_decode(BOLT11).payment_hash + mocker.patch.object(bark_wallet.client, "post", side_effect=error) + + response = await bark_wallet._send_payment(BOLT11, checking_id) + + assert response.pending + assert response.checking_id == checking_id + assert bark_wallet.pending_payments[checking_id] == BOLT11 + + +@pytest.mark.anyio +@pytest.mark.parametrize( + ("status_code", "expected_ok"), + [ + (400, None), + (401, False), + (403, False), + (404, False), + (405, False), + (408, None), + (409, None), + (422, None), + (429, None), + (500, None), + ], +) +async def test_send_payment_maps_http_errors( + bark_wallet: BarkWallet, + mocker, + status_code: int, + expected_ok: bool | None, +): + checking_id = bolt11_decode(BOLT11).payment_hash + mocker.patch.object( + bark_wallet.client, + "post", + return_value=payment_response(status_code, json={"message": "payment error"}), + ) + + response = await bark_wallet._send_payment(BOLT11, checking_id) + + assert response.ok is expected_ok + assert response.checking_id == checking_id + assert (checking_id in bark_wallet.pending_payments) is (expected_ok is None) + + +@pytest.mark.anyio +@pytest.mark.parametrize( + "response", + [ + payment_response(200, content=b"not json"), + payment_response(200, json={"unexpected": "response"}), + ], + ids=["invalid-json", "missing-message"], +) +async def test_send_payment_keeps_invalid_responses_pending( + bark_wallet: BarkWallet, mocker, response: httpx.Response +): + checking_id = bolt11_decode(BOLT11).payment_hash + mocker.patch.object(bark_wallet.client, "post", return_value=response) + + payment = await bark_wallet._send_payment(BOLT11, checking_id) + + assert payment.pending + assert payment.checking_id == checking_id + assert bark_wallet.pending_payments[checking_id] == BOLT11 diff --git a/tests/wallets/test_blink.py b/tests/wallets/test_blink.py index b07271a7d..f9ba016e5 100644 --- a/tests/wallets/test_blink.py +++ b/tests/wallets/test_blink.py @@ -1,10 +1,13 @@ import os +from typing import cast +from unittest.mock import AsyncMock import pytest from loguru import logger from lnbits.settings import settings from lnbits.wallets import BlinkWallet, get_funding_source, set_funding_source +from lnbits.wallets.base import PaymentStatus settings.lnbits_backend_wallet_class = "BlinkWallet" settings.blink_token = "mock" @@ -29,7 +32,7 @@ logger.info(f"settings.blink_api_endpoint: {settings.blink_api_endpoint}") logger.info(f"settings.blink_token: {settings.blink_token}") set_funding_source() -funding_source = get_funding_source() +funding_source = cast(BlinkWallet, get_funding_source()) assert isinstance(funding_source, BlinkWallet) @@ -146,3 +149,153 @@ async def test_get_payment_status(payhash): logger.info(f"test_get_payment_status: payment_status: {payment_status.paid}") else: assert True, "BLINK_TOKEN is not set. Skipping test using mock api" + + +# Reproducible bolt11 invoices (fixed timestamp, long expiry) used to test the +# fee probing logic in pay_invoice without hitting the live Blink API. +# amount invoice: 1000 sat (1_000_000 msat) +AMOUNT_BOLT11 = ( + "lnbc10u1pj48ugqpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5" + "zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq8w3jhxaqxq8zals8squ" + "qsakyemlpj9guae3a9havssjcjewgr24hedxkq6t978jk99srrxx9azy6k0cs66a757cfdc43" + "vkfhmlexyzdqtytzzteh2n4qngapgpesavte" +) +# zero-amount (amountless) invoice +ZERO_BOLT11 = ( + "lnbc1pj48ugqpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg" + "3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq8w3jhxaqxq8zals8sq3c00" + "hc6end9u8pafqge29y690e2x0kztq0l9z4dfd2yg8au9xuwxz9a2hy2hn2jqzq2mpy43tx9td" + "wxcy6yuc9ghuqkzj3kruh4tpcgp7n84qu" +) + + +def _make_blink_wallet_with_mock(graphql_side_effect): + """Build a BlinkWallet with a mocked GraphQL layer for pay_invoice tests.""" + settings.blink_api_endpoint = "https://api.blink.sv/graphql" + settings.blink_ws_endpoint = "wss://ws.blink.sv/graphql" + settings.blink_token = settings.blink_token or "mock" + wallet = BlinkWallet() + wallet._wallet_id = "mock_wallet_id" + wallet._graphql_query = graphql_side_effect # type: ignore[method-assign] + wallet.get_payment_status = AsyncMock( # type: ignore[method-assign] + return_value=PaymentStatus(paid=True, fee_msat=1000, preimage="preimage") + ) + return wallet + + +@pytest.mark.anyio +async def test_pay_invoice_amount_invoice_probes_and_sends(): + """Amount invoices are probed via lnInvoiceFeeProbe then sent.""" + calls = {"probe": 0, "send": 0} + + async def graphql(payload): + query = payload["query"] + if "lnInvoiceFeeProbe" in query: + calls["probe"] += 1 + return {"data": {"lnInvoiceFeeProbe": {"amount": 1, "errors": []}}} + if "lnNoAmountInvoiceFeeProbe" in query: + raise AssertionError("must not probe amount invoice as no-amount") + if "lnInvoicePaymentSend" in query: + calls["send"] += 1 + return { + "data": {"lnInvoicePaymentSend": {"status": "SUCCESS", "errors": []}} + } + return {"data": {}} + + wallet = _make_blink_wallet_with_mock(graphql) + response = await wallet.pay_invoice(AMOUNT_BOLT11, fee_limit_msat=5000) + + assert calls["probe"] == 1 + assert calls["send"] == 1 + assert response.ok is True + assert response.fee_msat == 1000 + + +@pytest.mark.anyio +async def test_pay_invoice_rejects_when_probed_fee_exceeds_limit(): + """A probed fee above the fee limit rejects the payment before sending.""" + calls = {"send": 0} + + async def graphql(payload): + query = payload["query"] + if "lnInvoiceFeeProbe" in query: + # 1 sat = 1000 msat, above the 500 msat limit below + return {"data": {"lnInvoiceFeeProbe": {"amount": 1, "errors": []}}} + if "lnInvoicePaymentSend" in query: + calls["send"] += 1 + return { + "data": {"lnInvoicePaymentSend": {"status": "SUCCESS", "errors": []}} + } + return {"data": {}} + + wallet = _make_blink_wallet_with_mock(graphql) + response = await wallet.pay_invoice(AMOUNT_BOLT11, fee_limit_msat=500) + + assert calls["send"] == 0 + assert response.ok is False + assert response.error_message is not None + assert "exceeds" in response.error_message + + +@pytest.mark.parametrize( + ("probe_response", "expected_error"), + [ + ({"errors": [{"message": "probe unavailable"}]}, "probe unavailable"), + ( + {"data": {"lnInvoiceFeeProbe": {"errors": []}}}, + "missing fee probe amount", + ), + ], +) +@pytest.mark.anyio +async def test_pay_invoice_strict_probe_failure_rejects_without_sending( + probe_response, expected_error +): + """Strict mode rejects malformed probe responses before sending.""" + settings.blink_send_without_probe = False + calls = {"send": 0} + + async def graphql(payload): + query = payload["query"] + if "lnInvoiceFeeProbe" in query: + return probe_response + if "lnInvoicePaymentSend" in query: + calls["send"] += 1 + return { + "data": {"lnInvoicePaymentSend": {"status": "SUCCESS", "errors": []}} + } + return {"data": {}} + + wallet = _make_blink_wallet_with_mock(graphql) + response = await wallet.pay_invoice(AMOUNT_BOLT11, fee_limit_msat=5000) + + assert calls["send"] == 0 + assert response.ok is False + assert response.error_message is not None + assert expected_error in response.error_message + + +@pytest.mark.anyio +async def test_pay_invoice_zero_amount_skips_probe_and_sends(): + """Zero-amount invoices cannot be probed and fall back to sending.""" + settings.blink_send_without_probe = True + calls = {"probe": 0, "send": 0} + + async def graphql(payload): + query = payload["query"] + if "FeeProbe" in query: + calls["probe"] += 1 + raise AssertionError("zero-amount invoices must not be probed") + if "lnInvoicePaymentSend" in query: + calls["send"] += 1 + return { + "data": {"lnInvoicePaymentSend": {"status": "SUCCESS", "errors": []}} + } + return {"data": {}} + + wallet = _make_blink_wallet_with_mock(graphql) + response = await wallet.pay_invoice(ZERO_BOLT11, fee_limit_msat=5000) + + assert calls["probe"] == 0 + assert calls["send"] == 1 + assert response.ok is True diff --git a/tests/wallets/test_nwc_wallets.py b/tests/wallets/test_nwc_wallets.py index f43105403..35fc36bba 100644 --- a/tests/wallets/test_nwc_wallets.py +++ b/tests/wallets/test_nwc_wallets.py @@ -1,3 +1,4 @@ +import asyncio import base64 import hashlib import json @@ -12,7 +13,7 @@ from Cryptodome.Util.Padding import pad, unpad from websockets import ServerConnection from websockets import serve as ws_serve -from lnbits.wallets.nwc import NWCWallet +from lnbits.wallets.nwc import NWCConnection, NWCWallet from tests.wallets.helpers import ( WalletTest, build_test_id, @@ -40,7 +41,7 @@ def encrypt_content(priv_key, dest_pub_key, content): def decrypt_content(priv_key, source_pub_key, content): p = PublicKey(bytes.fromhex("02" + source_pub_key)) shared = p.multiply(bytes.fromhex(priv_key)).format()[1:] - (encrypted_content_b64, iv_b64) = content.split("?iv=") + encrypted_content_b64, iv_b64 = content.split("?iv=") encrypted_content = base64.b64decode(encrypted_content_b64.encode("ascii")) iv = base64.b64decode(iv_b64.encode("ascii")) aes = AES.new(shared, AES.MODE_CBC, iv) @@ -99,6 +100,8 @@ async def handle( # noqa: C901 event, ) await websocket.send(json.dumps(["EVENT", sub_id, event])) + elif 23195 in kinds: + assert sub_filter["authors"] == [mock_settings["service_public_key"]] elif msg[0] == "EVENT": event = msg[1] decrypted_content = decrypt_content( @@ -177,6 +180,129 @@ async def run(data: WalletTest): await nwcwallet.cleanup() +@pytest.mark.anyio +async def test_nwc_rejects_event_from_unexpected_pubkey(mocker): + async def _noop(*args, **kwargs): + return None + + mocker.patch("lnbits.wallets.nwc.NWCConnection._connect_to_relay", new=_noop) + mocker.patch("lnbits.wallets.nwc.NWCConnection._handle_timeouts", new=_noop) + + service_private_key = PrivateKey() + service_public_key = service_private_key.public_key.format().hex()[2:] + attacker_private_key = PrivateKey() + attacker_public_key = attacker_private_key.public_key.format().hex()[2:] + account_private_key = PrivateKey() + + conn = NWCConnection( + service_public_key, + account_private_key.secret.hex(), + "ws://127.0.0.1:8555", + ) + try: + event = { + "kind": 23195, + "content": "{}", + "created_at": int(time.time()), + "tags": [["e", "request-event-id"]], + } + sign_event(attacker_public_key, attacker_private_key.secret.hex(), event) + + with pytest.raises(Exception, match="Invalid event signature"): + await conn._on_event_message(["EVENT", "subid", event]) + finally: + await conn.close() + + +@pytest.mark.anyio +async def test_nwc_marks_pending_invoice_settled_only_once(): + wallet = NWCWallet.__new__(NWCWallet) + wallet.pending_invoice_details = {"checking-id": {"checking_id": "checking-id"}} + wallet.pending_invoices = ["checking-id"] + wallet.paid_invoices_queue = asyncio.Queue(0) + + wallet._mark_invoice_settled("checking-id", source="notification") + wallet._mark_invoice_settled("checking-id", source="notification") + + assert wallet.paid_invoices_queue.qsize() == 1 + assert await wallet.paid_invoices_queue.get() == "checking-id" + + +@pytest.mark.anyio +async def test_nwc_registers_notification_subscriptions(mocker): + async def _noop(*args, **kwargs): + return None + + mocker.patch("lnbits.wallets.nwc.NWCConnection._connect_to_relay", new=_noop) + mocker.patch("lnbits.wallets.nwc.NWCConnection._handle_timeouts", new=_noop) + + service_private_key = PrivateKey() + service_public_key = service_private_key.public_key.format().hex()[2:] + account_private_key = PrivateKey() + + conn = NWCConnection( + service_public_key, + account_private_key.secret.hex(), + "ws://127.0.0.1:8555", + ) + send_mock = mocker.patch.object(conn, "_send", mocker.AsyncMock()) + + try: + await conn._subscribe_to_notifications() + + assert len(conn.notification_subscription_ids) == 2 + assert len(conn.subscriptions) == 2 + assert set(conn.subscriptions.keys()) == conn.notification_subscription_ids + assert all( + subscription["method"] == "notification_sub" + and subscription["event_id"] == subscription["sub_id"] + for subscription in conn.subscriptions.values() + ) + assert send_mock.await_count == 2 + finally: + await conn.close() + + +@pytest.mark.anyio +async def test_nwc_spreads_fallback_lookups_with_cooldown(mocker): + def _schedule_next_lookup( + invoice: dict[str, object], now: float | None = None + ) -> None: + assert now is not None + invoice["next_lookup_at"] = now + 1 + + wallet = NWCWallet.__new__(NWCWallet) + wallet.shutdown = False + wallet.pending_invoices = ["checking-1", "checking-2"] + wallet.pending_invoice_details = { + "checking-1": { + "checking_id": "checking-1", + "next_lookup_at": 0.0, + "lookup_attempts": 0, + }, + "checking-2": { + "checking_id": "checking-2", + "next_lookup_at": 0.0, + "lookup_attempts": 0, + }, + } + wallet.pending_invoices_lookup_cooldown = 1.0 + wallet._is_shutting_down = lambda: False + wallet._payment_data_is_settled = lambda payment_data: False + wallet._cache_payment_data = lambda *args, **kwargs: None + wallet._schedule_next_lookup = _schedule_next_lookup + wallet.conn = mocker.Mock() + wallet.conn.get_info = mocker.AsyncMock() + wallet.conn.supports_method = mocker.Mock(return_value=True) + wallet.conn.call = mocker.AsyncMock(return_value={"settled_at": None}) + sleep_mock = mocker.patch("lnbits.wallets.nwc.asyncio.sleep", mocker.AsyncMock()) + + await wallet._run_fallback_lookups(100.0) + + assert wallet.conn.call.await_count == 2 + sleep_mock.assert_awaited_once_with(1.0) + + @pytest.mark.anyio @pytest.mark.parametrize( "test_data", diff --git a/tests/wallets/test_rpc_wallets.py b/tests/wallets/test_rpc_wallets.py index e76c82cd9..51c3810c7 100644 --- a/tests/wallets/test_rpc_wallets.py +++ b/tests/wallets/test_rpc_wallets.py @@ -1,4 +1,5 @@ import importlib +from typing import Any from unittest.mock import AsyncMock, Mock import pytest @@ -80,7 +81,9 @@ def _check_calls(expected_calls): for func_call in func_calls: req = func_call["request_data"] args = req["args"] if "args" in req else {} - kwargs = _eval_dict(req["kwargs"]) if "kwargs" in req else {} + kwargs: dict[str, Any] = ( + _eval_dict(req["kwargs"]) or {} if "kwargs" in req else {} + ) if "klass" in req: *rest, cls = req["klass"].split(".") @@ -166,7 +169,7 @@ def _mock_field(field): return response -def _eval_dict(data: dict | None) -> dict | None: +def _eval_dict(data: dict | None) -> dict[str, Any] | None: fn_prefix = "__eval__:" if not data: return data @@ -215,9 +218,9 @@ def _data_mock(data: dict) -> Mock: def _raise(error: dict | None): if not error: return Exception() - data = error["data"] if "data" in error else None + data: dict[str, Any] = error["data"] if "data" in error else {} if "module" not in error or "class" not in error: - return Exception(data) + return Exception(data or None) error_module = importlib.import_module(error["module"]) error_class = getattr(error_module, error["class"]) diff --git a/tools/codegen/extension_sdk_typescript.py b/tools/codegen/extension_sdk_typescript.py new file mode 100644 index 000000000..b1dfac0f9 --- /dev/null +++ b/tools/codegen/extension_sdk_typescript.py @@ -0,0 +1,368 @@ +from __future__ import annotations + +import argparse +import re +from collections import defaultdict +from collections.abc import Sequence +from pathlib import Path +from types import UnionType +from typing import Any, Literal, Union, get_args, get_origin + +from pydantic import BaseModel + +from lnbits.core.wasm_ext import ( + ExtensionAPIMethod, + ExtensionHostAPI, + get_extension_api_method, + list_extension_api_methods, +) + + +def generate_typescript_sdk( + api_cls: type[ExtensionHostAPI] | None = None, + method_ids: Sequence[str] | None = None, +) -> str: + api_cls = api_cls or ExtensionHostAPI + methods = _select_methods(api_cls, method_ids) + models = _collect_models(methods) + + lines = [ + "/* Generated by LNbits ExtensionHostAPI codegen. */", + "/* Do not edit by hand. */", + "", + "export type MaybePromise = T | Promise", + "", + ] + + for model in models: + lines.extend(_render_model_type(model)) + lines.append("") + + lines.extend(_render_method_metadata(methods)) + lines.append("") + lines.extend(_render_host_type(methods)) + lines.append("") + lines.extend(_render_sdk_type(methods)) + lines.append("") + + lines.extend(_render_create_sdk(methods)) + + return "\n".join(lines).rstrip() + "\n" + + +def write_typescript_sdk( + path: str | Path, + api_cls: type[ExtensionHostAPI] | None = None, + method_ids: Sequence[str] | None = None, +) -> None: + Path(path).write_text( + generate_typescript_sdk(api_cls, method_ids), encoding="utf-8" + ) + + +def _select_methods( + api_cls: type[ExtensionHostAPI], method_ids: Sequence[str] | None +) -> list[ExtensionAPIMethod]: + if not method_ids: + return list_extension_api_methods(api_cls) + return [get_extension_api_method(method_id, api_cls) for method_id in method_ids] + + +def _collect_models(methods: Sequence[ExtensionAPIMethod]) -> list[type[BaseModel]]: + models: dict[str, type[BaseModel]] = {} + pending = [ + model + for method in methods + for model in (method.request_model, method.response_model) + ] + + while pending: + model = pending.pop() + if model.__name__ in models: + continue + models[model.__name__] = model + for field in model.__fields__.values(): + pending.extend(_nested_model_types(field.outer_type_)) + return [models[name] for name in sorted(models)] + + +def _nested_model_types(type_: Any) -> list[type[BaseModel]]: + models: list[type[BaseModel]] = [] + if _is_model_type(type_): + models.append(type_) + for arg in get_args(type_): + models.extend(_nested_model_types(arg)) + return models + + +def _render_model_type(model: type[BaseModel]) -> list[str]: + name = _model_name(model) + fields = model.__fields__ + if not fields: + return [f"export type {name} = Record"] + + lines = [f"export type {name} = {{"] + for field_name, field in fields.items(): + optional = "?" if not field.required else "" + ts_type = _python_type_to_ts(field.outer_type_, field.allow_none) + lines.append(f" {_camel(field_name)}{optional}: {ts_type}") + lines.append("}") + return lines + + +def _python_type_to_ts(type_: Any, allow_none: bool = False) -> str: + origin = get_origin(type_) + args = get_args(type_) + + if origin in (UnionType, Union): + ts = " | ".join( + _python_type_to_ts(arg) for arg in args if arg is not type(None) + ) + if type(None) in args: + ts = f"{ts} | null" + return ts + + if origin is Literal: + return " | ".join(_literal_to_ts(arg) for arg in args) + + if _is_model_type(type_): + ts = _model_name(type_) + elif origin in (list, Sequence): + item_type = _python_type_to_ts(args[0]) if args else "unknown" + ts = f"{item_type}[]" + elif origin is dict: + key_type = _python_type_to_ts(args[0]) if args else "string" + value_type = _python_type_to_ts(args[1]) if len(args) > 1 else "unknown" + ts = ( + f"Record<{key_type}, {value_type}>" + if key_type == "string" + else f"{{ [key: string]: {value_type} }}" + ) + elif _is_subclass(type_, str): + ts = "string" + elif _is_subclass(type_, bool): + ts = "boolean" + elif _is_subclass(type_, int) or _is_subclass(type_, float): + ts = "number" + else: + ts = "unknown" + + return f"{ts} | null" if allow_none else ts + + +def _literal_to_ts(value: Any) -> str: + if isinstance(value, str): + return f'"{value}"' + if isinstance(value, bool): + return "true" if value else "false" + if value is None: + return "null" + return str(value) + + +def _is_subclass(type_: Any, class_: type) -> bool: + try: + return isinstance(type_, type) and issubclass(type_, class_) + except TypeError: + return False + + +def _is_model_type(type_: Any) -> bool: + return _is_subclass(type_, BaseModel) + + +def _render_method_metadata( + methods: Sequence[ExtensionAPIMethod], +) -> list[str]: + lines = ["export const extensionApiMethods = ["] + for method in methods: + permission = ( + f'"{method.required_permission}"' if method.required_permission else "null" + ) + lines.extend( + [ + " {", + f' id: "{method.method_id}",', + f' namespace: "{method.namespace}",', + f' sdkName: "{method.sdk_name}",', + f' pythonName: "{method.python_name}",', + f' hostInterface: "{method.host_interface}",', + f' hostName: "{method.host_name}",', + f' hostJsName: "{_camel(method.host_name)}",', + f" requiredPermission: {permission},", + " },", + ] + ) + lines.append("] as const") + return lines + + +def _render_host_type(methods: Sequence[ExtensionAPIMethod]) -> list[str]: + lines = ["export type ExtensionHost = {"] + for host_interface, interface_methods in _methods_by_host_interface( + methods + ).items(): + lines.append(f" {_ts_property(host_interface)}: {{") + for method in sorted(interface_methods, key=lambda item: item.host_name): + request = _model_name(method.request_model) + response = _model_name(method.response_model) + if _is_empty_model(method.request_model): + lines.append( + f" {_camel(method.host_name)}(): MaybePromise<{response}>" + ) + else: + lines.append( + f" {_camel(method.host_name)}" + f"(input: {request}): MaybePromise<{response}>" + ) + lines.append(" }") + lines.append("}") + return lines + + +def _render_sdk_type(methods: Sequence[ExtensionAPIMethod]) -> list[str]: + lines = ["export type ExtensionSdk = {"] + _render_sdk_type_node(lines, _namespace_tree(methods), 1) + lines.append("}") + return lines + + +def _render_create_sdk(methods: Sequence[ExtensionAPIMethod]) -> list[str]: + lines = [ + "export function createExtensionSdk(", + " host: ExtensionHost", + "): ExtensionSdk {", + " return {", + ] + _render_create_sdk_node(lines, _namespace_tree(methods), 2) + lines.extend([" }", "}"]) + return lines + + +def _render_sdk_type_node(lines: list[str], node: dict[str, Any], level: int) -> None: + indent = " " * level + for namespace, child in _iter_child_namespaces(node): + lines.append(f"{indent}{namespace}: {{") + _render_sdk_type_node(lines, child, level + 1) + lines.append(f"{indent}}}") + + for method in node.get("__methods__", []): + request = _model_name(method.request_model) + response = _model_name(method.response_model) + if _is_empty_model(method.request_model): + lines.append(f"{indent}{method.sdk_name}(): Promise<{response}>") + else: + lines.append( + f"{indent}{method.sdk_name}(input: {request}): Promise<{response}>" + ) + + +def _render_create_sdk_node(lines: list[str], node: dict[str, Any], level: int) -> None: + indent = " " * level + for namespace, child in _iter_child_namespaces(node): + lines.append(f"{indent}{namespace}: {{") + _render_create_sdk_node(lines, child, level + 1) + lines.append(f"{indent}}},") + + for method in node.get("__methods__", []): + host_call_target = ( + f"host{_ts_access(method.host_interface)}" + f"{_ts_access(_camel(method.host_name))}" + ) + if _is_empty_model(method.request_model): + signature = f"{method.sdk_name}()" + host_call = f"{host_call_target}()" + else: + signature = f"{method.sdk_name}(input)" + host_call = f"{host_call_target}(input)" + lines.extend( + [ + f"{indent}async {signature} {{", + f"{indent} return {host_call}", + f"{indent}}},", + ] + ) + + +def _methods_by_host_interface( + methods: Sequence[ExtensionAPIMethod], +) -> dict[str, list[ExtensionAPIMethod]]: + interfaces: dict[str, list[ExtensionAPIMethod]] = defaultdict(list) + for method in sorted( + methods, key=lambda item: (item.host_interface, item.host_name) + ): + interfaces[method.host_interface].append(method) + return dict(sorted(interfaces.items())) + + +def _namespace_tree(methods: Sequence[ExtensionAPIMethod]) -> dict[str, Any]: + tree: dict[str, Any] = {} + for method in sorted(methods, key=lambda item: (item.namespace, item.sdk_name)): + node = tree + for part in method.namespace.split("."): + node = node.setdefault(part, {}) + node.setdefault("__methods__", []).append(method) + return tree + + +def _iter_child_namespaces( + node: dict[str, Any], +) -> list[tuple[str, dict[str, Any]]]: + return [ + (key, value) + for key, value in sorted(node.items()) + if key != "__methods__" and isinstance(value, dict) + ] + + +def _model_name(model: type[BaseModel]) -> str: + return model.__name__ + + +def _camel(value: str) -> str: + head, *tail = value.split("_") + return head + "".join(part.capitalize() for part in tail) + + +def _ts_property(value: str) -> str: + if re.match(r"^[A-Za-z_$][A-Za-z0-9_$]*$", value): + return value + return f'"{value}"' + + +def _ts_access(value: str) -> str: + if re.match(r"^[A-Za-z_$][A-Za-z0-9_$]*$", value): + return f".{value}" + return f'["{value}"]' + + +def _is_empty_model(model: type[BaseModel]) -> bool: + return not model.__fields__ + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="Generate a TypeScript SDK from the LNbits ExtensionHostAPI." + ) + parser.add_argument( + "--method", + action="append", + dest="method_ids", + help="ExtensionHostAPI method id to include. Can be passed multiple times.", + ) + parser.add_argument( + "--out", + help="Output file. If omitted, the generated SDK is printed to stdout.", + ) + args = parser.parse_args(argv) + + sdk = generate_typescript_sdk(method_ids=args.method_ids) + if args.out: + Path(args.out).write_text(sdk, encoding="utf-8") + else: + print(sdk, end="") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/conv.py b/tools/conv.py index a05954458..b0d3e5190 100644 --- a/tools/conv.py +++ b/tools/conv.py @@ -136,12 +136,10 @@ def migrate_db(file: str, schema: str, exclude_tables: list[str] | None = None): assert os.path.isfile(file), f"{file} does not exist!" sqlite_cursor = get_sqlite_cursor(file) - tables = sqlite_cursor.execute( - """ + tables = sqlite_cursor.execute(""" SELECT name FROM sqlite_master WHERE type='table' AND name not like 'sqlite?_%' escape '?' - """ - ).fetchall() + """).fetchall() for table in tables: table_name = table[0] @@ -184,11 +182,9 @@ def build_table_columns(file: str, schema: str, table_name: str): sqlite_columns = sqlite_cursor.execute( f"PRAGMA table_info({table_name})" ).fetchall() - pg_cursor.execute( - f""" + pg_cursor.execute(f""" SELECT table_name, column_name, udt_name FROM information_schema.columns - WHERE table_schema = '{schema}'AND table_name = '{table_name}';""" - ) + WHERE table_schema = '{schema}'AND table_name = '{table_name}';""") pg_columns = pg_cursor.fetchall() columns = [] diff --git a/uv.lock b/uv.lock index d71506f94..87ecf55c7 100644 --- a/uv.lock +++ b/uv.lock @@ -2,18 +2,22 @@ version = 1 revision = 3 requires-python = ">=3.10, <3.13" +[options] +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. +exclude-newer-span = "P1W" + [[package]] name = "aiohappyeyeballs" -version = "2.6.1" +version = "2.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +sdist = { url = "https://files.pythonhosted.org/packages/33/c6/61a2d7b7572279226bb2e7f61d7a19ca7c90da0329c93fa0d560cbf288d8/aiohappyeyeballs-2.6.2.tar.gz", hash = "sha256:e202810ee718bd01fc6ef49e8ea53d023d5cb6b581076d7925aa499fa55dbe64", size = 22591, upload-time = "2026-05-20T15:12:24.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, + { url = "https://files.pythonhosted.org/packages/5f/fc/a7bf5b6e4e617b45f90f2d9d2a68519c249c81dd4fc2658c7a2a61c4f4b7/aiohappyeyeballs-2.6.2-py3-none-any.whl", hash = "sha256:4708045e2d7a6c6bdf8aafa8ed39649eaf926a4543b54560659129e3365953c4", size = 15062, upload-time = "2026-05-20T15:12:23.328Z" }, ] [[package]] name = "aiohttp" -version = "3.13.3" +version = "3.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -23,61 +27,65 @@ dependencies = [ { name = "frozenlist" }, { name = "multidict" }, { name = "propcache" }, + { name = "typing-extensions" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, - { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, - { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, - { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, - { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, - { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, - { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, - { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, - { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, - { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, - { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, - { url = "https://files.pythonhosted.org/packages/f1/4c/a164164834f03924d9a29dc3acd9e7ee58f95857e0b467f6d04298594ebb/aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b", size = 746051, upload-time = "2026-01-03T17:29:43.287Z" }, - { url = "https://files.pythonhosted.org/packages/82/71/d5c31390d18d4f58115037c432b7e0348c60f6f53b727cad33172144a112/aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64", size = 499234, upload-time = "2026-01-03T17:29:44.822Z" }, - { url = "https://files.pythonhosted.org/packages/0e/c9/741f8ac91e14b1d2e7100690425a5b2b919a87a5075406582991fb7de920/aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea", size = 494979, upload-time = "2026-01-03T17:29:46.405Z" }, - { url = "https://files.pythonhosted.org/packages/75/b5/31d4d2e802dfd59f74ed47eba48869c1c21552c586d5e81a9d0d5c2ad640/aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a", size = 1748297, upload-time = "2026-01-03T17:29:48.083Z" }, - { url = "https://files.pythonhosted.org/packages/1a/3e/eefad0ad42959f226bb79664826883f2687d602a9ae2941a18e0484a74d3/aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540", size = 1707172, upload-time = "2026-01-03T17:29:49.648Z" }, - { url = "https://files.pythonhosted.org/packages/c5/3a/54a64299fac2891c346cdcf2aa6803f994a2e4beeaf2e5a09dcc54acc842/aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b", size = 1805405, upload-time = "2026-01-03T17:29:51.244Z" }, - { url = "https://files.pythonhosted.org/packages/6c/70/ddc1b7169cf64075e864f64595a14b147a895a868394a48f6a8031979038/aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3", size = 1899449, upload-time = "2026-01-03T17:29:53.938Z" }, - { url = "https://files.pythonhosted.org/packages/a1/7e/6815aab7d3a56610891c76ef79095677b8b5be6646aaf00f69b221765021/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1", size = 1748444, upload-time = "2026-01-03T17:29:55.484Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f2/073b145c4100da5511f457dc0f7558e99b2987cf72600d42b559db856fbc/aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3", size = 1606038, upload-time = "2026-01-03T17:29:57.179Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c1/778d011920cae03ae01424ec202c513dc69243cf2db303965615b81deeea/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440", size = 1724156, upload-time = "2026-01-03T17:29:58.914Z" }, - { url = "https://files.pythonhosted.org/packages/0e/cb/3419eabf4ec1e9ec6f242c32b689248365a1cf621891f6f0386632525494/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7", size = 1722340, upload-time = "2026-01-03T17:30:01.962Z" }, - { url = "https://files.pythonhosted.org/packages/7a/e5/76cf77bdbc435bf233c1f114edad39ed4177ccbfab7c329482b179cff4f4/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c", size = 1783041, upload-time = "2026-01-03T17:30:03.609Z" }, - { url = "https://files.pythonhosted.org/packages/9d/d4/dd1ca234c794fd29c057ce8c0566b8ef7fd6a51069de5f06fa84b9a1971c/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51", size = 1596024, upload-time = "2026-01-03T17:30:05.132Z" }, - { url = "https://files.pythonhosted.org/packages/55/58/4345b5f26661a6180afa686c473620c30a66afdf120ed3dd545bbc809e85/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4", size = 1804590, upload-time = "2026-01-03T17:30:07.135Z" }, - { url = "https://files.pythonhosted.org/packages/7b/06/05950619af6c2df7e0a431d889ba2813c9f0129cec76f663e547a5ad56f2/aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29", size = 1740355, upload-time = "2026-01-03T17:30:09.083Z" }, - { url = "https://files.pythonhosted.org/packages/3e/80/958f16de79ba0422d7c1e284b2abd0c84bc03394fbe631d0a39ffa10e1eb/aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239", size = 433701, upload-time = "2026-01-03T17:30:10.869Z" }, - { url = "https://files.pythonhosted.org/packages/dc/f2/27cdf04c9851712d6c1b99df6821a6623c3c9e55956d4b1e318c337b5a48/aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f", size = 457678, upload-time = "2026-01-03T17:30:12.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" }, - { url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" }, - { url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" }, - { url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" }, - { url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" }, - { url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" }, - { url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" }, - { url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" }, - { url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" }, - { url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" }, - { url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" }, - { url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" }, - { url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4d/4a99fb425c5e0cad715eea7bd190aff46f38b959a0a2dadb993705d34b26/aiohttp-3.14.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:eb0495d778817619273c108784292be161a924b9f5ae5cbbc70a2caa6838250b", size = 765848, upload-time = "2026-07-23T01:52:08.217Z" }, + { url = "https://files.pythonhosted.org/packages/74/e8/43b85dc55b8e950dc644babe762add781319ea881b57b33d2cce12017d12/aiohttp-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c3c200cf9757edd785051dc699c7ecbec22110dbfcb3fefc7a9f9695eda8ea7a", size = 517476, upload-time = "2026-07-23T01:52:10.846Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9e/73b582c4dbbc3c12ef4473822475effaabf1f934b56f14f5b03fe5d3a2af/aiohttp-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd51ebf9d3a00c074df4ede271023f4d2dba289bcc740b88191872716014e3c5", size = 515334, upload-time = "2026-07-23T01:52:12.636Z" }, + { url = "https://files.pythonhosted.org/packages/79/03/e98c3c9e05a5bdf97defe5ff9169baba4f0ec9a901f2d60e0f060c2f051e/aiohttp-3.14.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:134ac5ddcf61c6fad984b9a5727d83492ada43d63471db20fb73042c13fca62f", size = 1708830, upload-time = "2026-07-23T01:52:14.538Z" }, + { url = "https://files.pythonhosted.org/packages/d7/2c/26e60b694844dfd2176c57f913a22d0cd6a16f9ff202cbda7580d0328b98/aiohttp-3.14.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:70c987b27534f9ae1a723f47ae921571d616da21d3208282bf4c52af5164ac43", size = 1674012, upload-time = "2026-07-23T01:52:16.486Z" }, + { url = "https://files.pythonhosted.org/packages/38/65/672df92e3172cd876aacfa97a952ac560877eb169384b2991ac5b273de4c/aiohttp-3.14.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1b59533861b70a2185c8f4f350f791f39d64358ef6944ce71c5240c9ec0982c9", size = 1767015, upload-time = "2026-07-23T01:52:18.28Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c5/228dec7bfec1c373cc2217cdeb47d6456dcd7a13a4c55144930a75ae3851/aiohttp-3.14.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1c5281acc88b92396f88c7e1e2748f8466689df22b80170e4f51efa712fb47a8", size = 1858700, upload-time = "2026-07-23T01:52:20.08Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ff/cb36724e8c8d17f90ada567a9ff3efe1d6e9b549fba697a242aece180f21/aiohttp-3.14.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:48d67b87db6279c044760787eb01f6413032c2e6f3ba1cafaa492b1c8e578479", size = 1714075, upload-time = "2026-07-23T01:52:22.071Z" }, + { url = "https://files.pythonhosted.org/packages/9f/3a/296a4135c6366376263aeef54b15caca1f07676c2ae0c525d7832f2f808a/aiohttp-3.14.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f53bcd52f585e1ac3e590d61434eb61f9a88c38df041b4ea126d97144344a77b", size = 1588234, upload-time = "2026-07-23T01:52:23.757Z" }, + { url = "https://files.pythonhosted.org/packages/7d/81/9d5d853ef892dc066d1eb6db0e87a47348b920c1c879aa554612fdbd9d79/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fdea2281997af69da84c77ffa6f5938a0285f21fb3887c249d67419ca865b3d", size = 1677300, upload-time = "2026-07-23T01:52:25.861Z" }, + { url = "https://files.pythonhosted.org/packages/68/96/021d386ae32d9b26d4b88df2e794546232ff56bb6be952bf6be227c0bbc7/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cda5fd5c95ad7a125a2e8464acc78b98b94c475a3780d6aa0aa157c93f470f4d", size = 1691501, upload-time = "2026-07-23T01:52:28Z" }, + { url = "https://files.pythonhosted.org/packages/29/9f/af66adce26a14af135c003cbd0f44ccaa68cebd30ff8ac99ca47fb4958f7/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6debfa7312ff9d4c124dc71d72e9a0a4b9e0879e48ba6fcb42bef5c3300289e2", size = 1735113, upload-time = "2026-07-23T01:52:29.995Z" }, + { url = "https://files.pythonhosted.org/packages/2f/90/28c390d4c9851effe52ac25b5a2e1d92246acd00728b4fc7975dafb67484/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:f4e05329faa0ea1a404b37de4f034fd2c2defcca06a68dc6745e4e56c88e8a48", size = 1577486, upload-time = "2026-07-23T01:52:31.937Z" }, + { url = "https://files.pythonhosted.org/packages/db/c2/00e23a1bf2abb70dd353f6987db7e7f2491d0261f7363997738c71c98f95/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a3a8296e7ab5c295f53f1041487cb088e1480775aafbf7fe545d93b770a0f96f", size = 1751353, upload-time = "2026-07-23T01:52:33.688Z" }, + { url = "https://files.pythonhosted.org/packages/6e/7d/d51a706a8cbfa57f0611127daf61ab3ae02ab8420b0407412079227d1c65/aiohttp-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5373dc80ad1aa2fb9ad95c83f24eef418bbda3a61375f128e5b0192e4f3f9b32", size = 1698681, upload-time = "2026-07-23T01:52:38.167Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b0/90bd5cd9fdd9787cb4211d284d1fb8401339a933cb0227a15b71e789232f/aiohttp-3.14.3-cp310-cp310-win32.whl", hash = "sha256:a3e22975f905b89a55a488c2a08f2fdb2186175349e917d48985cc468a3d4c6e", size = 456733, upload-time = "2026-07-23T01:52:41.823Z" }, + { url = "https://files.pythonhosted.org/packages/d8/15/fe5b8f6a71ae112bc677163d0b0701bda5dc15005249582258ede0eb88c7/aiohttp-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdd0e2834dce1a26c1bbe26464861e16bbe217042cbff619247c11594472518c", size = 480460, upload-time = "2026-07-23T01:52:43.905Z" }, + { url = "https://files.pythonhosted.org/packages/54/00/45e98b6645cd7f00a4b78b749ebd309094b0eaeb2d2e96157eadbc0d0050/aiohttp-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:eac645b09bcfdf73df7536331f0678c1086ea250981118ddb5199e17ccef72bb", size = 453479, upload-time = "2026-07-23T01:52:46.075Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5c/b3e4ff8ad43a8afef9602c5e90285936da1beaea8b029016b793891f03c3/aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e568e14940c09955aa51f4e645b6daa18a581c5dcfcd73744dcc86a856e3ced3", size = 764250, upload-time = "2026-07-23T01:52:48.525Z" }, + { url = "https://files.pythonhosted.org/packages/0e/da/f1b384465e51449d844056b75070461da03a9a23e6c1747003695bf4172a/aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54cfcdee2770dac994417cbb0ee1f3eb0e7cb6b30c79bf44f2c02ff79ec5124a", size = 516281, upload-time = "2026-07-23T01:52:51.047Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:21c016079415ed3fd676963e9793700a566d85dbbd6bfc564b9b2d209147dcc8", size = 514742, upload-time = "2026-07-23T01:52:53.779Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8d/a71c6f2db52ac1ed142b133f7feddaa6b70539c3f4de24d7e226c95b794c/aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6088ec9894113802bddb3c09e974929aed2c7b3a8c456219b8aab4481f1a239", size = 1780613, upload-time = "2026-07-23T01:52:56.948Z" }, + { url = "https://files.pythonhosted.org/packages/a5/11/3dd9b3fb3a170f6ec9011b5291d876a6fab4086714c9e158600edf01b4fd/aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:16ea7e24c309fb7c0bbd505d149abe4fe4dccfb8db911db7dbec0921bc889a6f", size = 1737688, upload-time = "2026-07-23T01:52:59.294Z" }, + { url = "https://files.pythonhosted.org/packages/6d/3e/834c26918be7d88068822b40e0db30fca50b5f4fe79104aa16a93f1d74e6/aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56f355e79f71aef2a85c80305cc915f894b170dba76de5fe84f6351939b83c06", size = 1845742, upload-time = "2026-07-23T01:53:01.641Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c9/49ab8572df7d66bc13d11e31f781292badb04180dd87ba98733066c6aed7/aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18c441d0a8fca6de8d1f546849b9f0ab20d435993e2c5b59562b2fae6be2f929", size = 1928412, upload-time = "2026-07-23T01:53:04.018Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b9/2b8f0c0ce09c87a1daf80fd483431b56b1435d3f62789bc86f572e1245de/aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53e7b4ce82b54a8bcc71b3b67a5cbd177ca1d7f592cbc92cd38b7349f73482db", size = 1786220, upload-time = "2026-07-23T01:53:06.481Z" }, + { url = "https://files.pythonhosted.org/packages/85/00/9c45f81de11710460edfa1dc81317b6e882703b160926c879a9d20da9fcc/aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f55119f7bf25f49ed210f6096090715da24f2943c62102448915fde3c62877ce", size = 1637231, upload-time = "2026-07-23T01:53:10.258Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/967d628e910756f3539c6107cb7844a1b69440dcb3029a5ee7871b09ab63/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9aa6e61fdf20105c4144e755bd586008ff450791d67b1c8146fdc15959c4d51c", size = 1753161, upload-time = "2026-07-23T01:53:13.817Z" }, + { url = "https://files.pythonhosted.org/packages/11/b2/0c3d4114f0aee4f580f5b3b4eb71b24d7a23b834ea506a4dfebe76513f35/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ccd4893707b3e2a13e39c90d43cf80edf2e4d0457935bcc103bf2346214c3f15", size = 1756356, upload-time = "2026-07-23T01:53:16.211Z" }, + { url = "https://files.pythonhosted.org/packages/63/5d/99e7d91c82f1399d1ae2a854e080bd1493fbc31e5e959dbc4ec33dac3bec/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2466434105a4e03113c36ec775cc2ebe6676b62eae326fa670bb607ef788c1c", size = 1819846, upload-time = "2026-07-23T01:53:18.289Z" }, + { url = "https://files.pythonhosted.org/packages/ad/05/d5e1cb6480eeffd3f901d40a2c5e2d1e7effdc797837da3b490272699f13/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ba59d59aba08ac02fc03b0c8983ccd5ee39a199d0552ce9e6d2b4845b34d59ae", size = 1628531, upload-time = "2026-07-23T01:53:23.86Z" }, + { url = "https://files.pythonhosted.org/packages/c9/90/b934682bcaefae18a9e04f3dff5b68522ba810906358ae5029b68110ea3b/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ed099d105449c4f9e84f24af203cd131349d4761d8813fa7e02c32e7128cd910", size = 1832712, upload-time = "2026-07-23T01:53:27.551Z" }, + { url = "https://files.pythonhosted.org/packages/21/df/6061679faaf81fac746e7307c7adb71e858071a5d34c27583afefc64f543/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:152516815ef926786a0b6ae2b8f1fd2e0c71582dee0b435636865316fd4891b7", size = 1775014, upload-time = "2026-07-23T01:53:30.223Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1d/f854878bbc69b88faefe924b619a34a6f59ec05fd387c77690667eaa75eb/aiohttp-3.14.3-cp311-cp311-win32.whl", hash = "sha256:a4af35c443e0b1a1bd6a8af3f3485d7fda15c142751a00f3ff8090f0b93346fa", size = 456006, upload-time = "2026-07-23T01:53:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/73/0c/2af9d1674baccd1dbd47282a93d660a22e57ef6167c856deb24b4214fbab/aiohttp-3.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1e74298bab6ee0d6e749ed4fd1901c7e604bdda32c03d787a2cc71c46d0433d", size = 481069, upload-time = "2026-07-23T01:53:39.673Z" }, + { url = "https://files.pythonhosted.org/packages/8e/76/88401ff3fc95e85c5fc38d588f36f55e61ecb64343b2bc8d69326f453cc0/aiohttp-3.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:03cd2bde3d7f085b64e549c985f4bb928cad7e8ecf5323bfca320db548d81b39", size = 453021, upload-time = "2026-07-23T01:53:43.749Z" }, + { url = "https://files.pythonhosted.org/packages/18/d4/eb96299230e20acf2efae207cb8d69051f1f68e357e5ea5e479bf6fb097a/aiohttp-3.14.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:39aded8c7f3b935b54aab1d8d73c70ec0ee2d3ec3b943e0e86611bc150ba47f5", size = 754690, upload-time = "2026-07-23T01:53:47.332Z" }, + { url = "https://files.pythonhosted.org/packages/88/11/e7a70a209eb9a067c0d3212b518a0134e3484f5178c7533878b6b514d469/aiohttp-3.14.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5bcb6ff3fdab1258a192679ff1a05d44f59626430aa05cd1a9d2447423599228", size = 509484, upload-time = "2026-07-23T01:53:51.159Z" }, + { url = "https://files.pythonhosted.org/packages/30/07/4bbc222cc8dbe31d4c3e8a5baad2286e4d42026ac0c570027b89afce6344/aiohttp-3.14.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:617105e2c3018ee38d0c8ce5ee3c84f621a6d8b9f723202aacaff28449ca91ee", size = 511949, upload-time = "2026-07-23T01:53:55.083Z" }, + { url = "https://files.pythonhosted.org/packages/54/b9/42e74c46b7b7c794b995bbc1f573fb48950c38b19d8600c62a6804ee2d67/aiohttp-3.14.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f631fe87a6f30df5fbe6d79640b25e4cffb38c31c7fb6f10871517b84b0f8c1a", size = 1765282, upload-time = "2026-07-23T01:53:59.662Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ed/62bc4d74363ad346d518e0720363a949f63e2e23439a79eb5813d4d29bb3/aiohttp-3.14.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a94dbaae5ae27bd849c93570669bff91e0510f33a80805738e3de72a7be0447b", size = 1741511, upload-time = "2026-07-23T01:54:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9f/181e8a8bc79e47d13c7fc4540bd7a3b729d9505609c61f392a8dd2fbfe55/aiohttp-3.14.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8f2f1c4c032c7cedd7d8da6f54c97b70266c6570c3108d3fdffee7188bb70529", size = 1810680, upload-time = "2026-07-23T01:54:09.882Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9a/dec94d6ad694552fe3424e3f1928d7a606a5d9d9433a04e7ecdd9d38ae7f/aiohttp-3.14.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea05e1f97ceea523942d9b2a7d7c0359d781d683d6b043f5943a602b14da4787", size = 1905646, upload-time = "2026-07-23T01:54:13.475Z" }, + { url = "https://files.pythonhosted.org/packages/52/b7/7cd31f29d6055bd711ae6e669367fba6f5ae9de463910a793e30556a8db7/aiohttp-3.14.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:543906c127fb1d929b95076db19b83fa2d46751006ff1e23b093aa5ac4d8db42", size = 1792122, upload-time = "2026-07-23T01:54:15.752Z" }, + { url = "https://files.pythonhosted.org/packages/66/73/10b1ef93afa61f4963c746257b70ced619cf31a4798671de5fdb2608501d/aiohttp-3.14.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0a5ff2dfbb9ce645fa5b8ef3e02c6c0b9cc3f6030ff863d0c51fffc50cb5541b", size = 1591127, upload-time = "2026-07-23T01:54:19.489Z" }, + { url = "https://files.pythonhosted.org/packages/49/ed/3b203fa6de1b338c14acdc06bf6ca9b043b7944f005966958c2ced932cde/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:041badb8f84396357c4d3ad26de6afd7a32b112f43d3c63045c0c8278cfd2043", size = 1725210, upload-time = "2026-07-23T01:54:24.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/b7/1c2aab8c706436dcc28598452488ac9cd7c409da815237c28c27d58993e6/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:530125ee1163c4219af35dc3aa1206e541e7b31b6efc1a3f93b70a136f65d427", size = 1764848, upload-time = "2026-07-23T01:54:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/54/50/94c28f08b131c4bf10984ea2c7a536c9920608bb2d6e7f95642c30cc87b7/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8653fd547c93a61aadc612007790f5555cdd18946fa48cf45e26d8ea4ea473d", size = 1777102, upload-time = "2026-07-23T01:54:31.775Z" }, + { url = "https://files.pythonhosted.org/packages/13/d4/e7d09ba7d345fb2d74440fd2fa033c5e079fac05552927705986f41a364f/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:89176250f686cb9853c0fb7ead90e639e915b84a6f43eedc2a4e7ec21f1037f0", size = 1580205, upload-time = "2026-07-23T01:54:34.518Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/072a91d68e1e1eb587985b54baab94221277f877e8ef274fc213a0ceae28/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3a26434dafe408229ff3403458ca58de24fb51936504decac49ce6755f77e59d", size = 1797219, upload-time = "2026-07-23T01:54:36.995Z" }, + { url = "https://files.pythonhosted.org/packages/e0/eb/aad34e897e668424d6e995da5dff8a4a09af93363d3392488772957a63aa/aiohttp-3.14.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d1558173930a5a8d3069cee5c92fc91c87c4dbcb099debbb3622053717145a19", size = 1768629, upload-time = "2026-07-23T01:54:40.103Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2b/6bb88ddba0fecd9122aa3ebcad25996cf6c083a4a7040dbb3a4f97972af6/aiohttp-3.14.3-cp312-cp312-win32.whl", hash = "sha256:16100ad3ab8d649fdfbee87602d9d2dcdca9df0b9eda8a1b5fdc0d41f96da559", size = 451481, upload-time = "2026-07-23T01:54:42.547Z" }, + { url = "https://files.pythonhosted.org/packages/76/9b/f2f8f108da17ecef2cc3efc424e8b7ad3782b1a8360f7b8eae8ced84f6ea/aiohttp-3.14.3-cp312-cp312-win_amd64.whl", hash = "sha256:33a2d7c28d33797a2e99923dffa63f83d908a19b6bf26cfe80fa790aa5e1a75a", size = 476845, upload-time = "2026-07-23T01:54:44.853Z" }, + { url = "https://files.pythonhosted.org/packages/3e/44/28dac80a8941b604f4da10ce21097614ca1bf905ce93dca28d8d7de9c1e7/aiohttp-3.14.3-cp312-cp312-win_arm64.whl", hash = "sha256:362a3fd481769cac1a824514bcd86fda51c65e8fe6e051099e008fddde6db17c", size = 448050, upload-time = "2026-07-23T01:54:47.087Z" }, ] [[package]] @@ -102,6 +110,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" }, ] +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + [[package]] name = "anyio" version = "4.12.1" @@ -183,11 +200,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.3.0" +version = "26.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, ] [[package]] @@ -252,87 +269,79 @@ wheels = [ [[package]] name = "bip32" -version = "4.0" +version = "5.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coincurve" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/37/b69968b1b6eaea1fedb8efdb1862d86e92b6f68e182f39c764f894984db5/bip32-4.0.tar.gz", hash = "sha256:8035588f252f569bb414bc60df151ae431fc1c6789a19488a32890532ef3a2fc", size = 21662, upload-time = "2024-09-07T12:40:26.388Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/ad/857ffe66a4bbe8f8f2e9c0e792e19944d7cd0909546e2ac47249857f82c3/bip32-5.0.0.tar.gz", hash = "sha256:4caa1f74eed9f2cd4624b55f34a4094f52542552fe3d0cc52e1179b8d6e9f21e", size = 21668, upload-time = "2025-11-13T18:36:25.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/bd/dcf1650776a241c10a2bc6826b6e23ff63bf55373bb053b716c69c463758/bip32-4.0-py3-none-any.whl", hash = "sha256:9728b38336129c00e1f870bbb3e328c9632d51c1bddeef4011fd3115cb3aeff9", size = 12898, upload-time = "2024-09-07T12:40:25.358Z" }, + { url = "https://files.pythonhosted.org/packages/d8/b7/f971ff16f791a65a19f75ca0fe341d1ed7e56c99deae1bc7652c687dfa38/bip32-5.0.0-py3-none-any.whl", hash = "sha256:b20872795ae2bb4e5fac351f53ccdf2b998f82e927413922a2c5473a004bd6d0", size = 13007, upload-time = "2025-11-13T18:36:23.62Z" }, ] [[package]] name = "bitarray" -version = "3.6.1" +version = "3.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/76/b08705dbfabc4169eab93bba4a10b0ad60940f48cc8a62ff16e2a05f0452/bitarray-3.6.1.tar.gz", hash = "sha256:4255bff37b01562b8e6adcf9db256029765985b0790c5ff76bbe1837edcd53ea", size = 148620, upload-time = "2025-08-12T09:52:35.677Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/47/b5da717e7bbe97a6dc4c986f053ca55fd3276078d78f68f9e8b417d1425a/bitarray-3.8.1.tar.gz", hash = "sha256:f90bb3c680804ec9630bcf8c0965e54b4de84d33b17d7da57c87c30f0c64c6f5", size = 152471, upload-time = "2026-04-02T16:29:01.712Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/73/3c07ddcd195a049f52770f4377cb7e1c9545826b01e6d911560ce6501904/bitarray-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716ec396af5292275f7f572850596990ff84bf1a8552428ee982fe54f773aeb9", size = 146082, upload-time = "2025-08-12T09:49:17.109Z" }, - { url = "https://files.pythonhosted.org/packages/29/4a/6507ef7d019ab647f5b32cf45e16ef4bdb1544225b667663398751cc6921/bitarray-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c1d916d36c03c2100af0accc3698091c0bc2e94470cac88462d9f6b56758f37", size = 142509, upload-time = "2025-08-12T09:49:19.732Z" }, - { url = "https://files.pythonhosted.org/packages/95/89/9117c269f9391b0b5f5d7d3a4ef47a56144f3a1221462fce3bcd77dc0e60/bitarray-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:028e95a4792ddef067a5c6151d223089665d5c566cb88f3fe68155e251d8f522", size = 318028, upload-time = "2025-08-12T09:49:20.977Z" }, - { url = "https://files.pythonhosted.org/packages/e5/97/94501124d897a509651530cafea84beb84fa14ed2df0bcb610427620e60d/bitarray-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66db701a1c3ea69919a2eb415fb0fce83d55179fd65390399eb40579b102f0a4", size = 336148, upload-time = "2025-08-12T09:49:22.397Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e5/713709923a357141b62f1fdeba063b4294fa11cf434d8fd4124fd89b7063/bitarray-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cff53ab9cf8d088e88402174ed53529c6ec3897a5146c2a18625253b3b2f6d21", size = 328291, upload-time = "2025-08-12T09:49:23.503Z" }, - { url = "https://files.pythonhosted.org/packages/1a/ff/7b0dc217cae6c66aa0bae235471910487e87abed6e15360223057a7f1e56/bitarray-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bb5c678d3957104a33e093427bd514d3b08673e47b358242be6a53d33613ce", size = 320464, upload-time = "2025-08-12T09:49:24.606Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d4/e378ba68ce48c74ab0d5c28fe59eed277a679c60dc3a5a8a57c1b329ccf5/bitarray-3.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3916c63580d9ca9c3264744ce1162e500a6b99c841f25b9657bca2595d2d438", size = 309323, upload-time = "2025-08-12T09:49:25.95Z" }, - { url = "https://files.pythonhosted.org/packages/fe/d8/94728264965b295fef03e9494572fff42dffba3bec3211d63714472f1e65/bitarray-3.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7134fa2d0d253ce1fcd6a5d646f4024ede4a3bf845420bc799dccb430c254ecc", size = 310995, upload-time = "2025-08-12T09:49:26.984Z" }, - { url = "https://files.pythonhosted.org/packages/71/8c/1e9cb6ddbf41f62774dc0616460f24212cb1ede542f409e97802a765d2d6/bitarray-3.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed3009c2ecb7c01b4da8fd0a5e47e0e86a45af746700a6386f247fd922cd3cc2", size = 307465, upload-time = "2025-08-12T09:49:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/61/e8/fa9c1b832f7eaeeaa519052a7f13f73dc1484908ba08709a0b66ece05d3d/bitarray-3.6.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:73cee88d7af7a881447ea593cbaae207be4a472a8c0a9f2da54bcb17512fd75f", size = 335270, upload-time = "2025-08-12T09:49:29.065Z" }, - { url = "https://files.pythonhosted.org/packages/7e/3a/76e4bc3734f0ff35bfd6ea2b21f2af0e3a76c78d38c58fa46d326f5577e7/bitarray-3.6.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:3abea085790b12c12b3f8ceefae4a7953e14518d88c4b0547187805b999e4158", size = 335315, upload-time = "2025-08-12T09:49:30.498Z" }, - { url = "https://files.pythonhosted.org/packages/83/41/6a0fd72de58a2b9be5af78c5f9809d7840ab02e10aee911359fb705d8136/bitarray-3.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8aa92c400c813961ff868801ef71a6fa161c6f546433bfb396ee3f596d807a20", size = 315993, upload-time = "2025-08-12T09:49:31.757Z" }, - { url = "https://files.pythonhosted.org/packages/25/50/90102a8426198ef88fc323b8c142c15eefe7d2a43bce51444c7e7ac6b4d7/bitarray-3.6.1-cp310-cp310-win32.whl", hash = "sha256:32dc6efc7c87badd7c7941df5ca40346a29532d37bd97a52b67ed563d324b6c7", size = 138612, upload-time = "2025-08-12T09:49:33.785Z" }, - { url = "https://files.pythonhosted.org/packages/7f/4c/04f79fa7c49fbe093d15abcf46c4d187228f5aa4d56b9b3778b9195f6779/bitarray-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ad4e07524372225302e17cb92e7f682baa38fe323e2647dc4f6202304dd8d1a", size = 145207, upload-time = "2025-08-12T09:49:35.121Z" }, - { url = "https://files.pythonhosted.org/packages/e8/a4/89fad7089373383b4fa2f1446b441131a42d15679a87bdfc36a068d59b1c/bitarray-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:52320d72dca8022b4c61bfb5d059743f44421488c0502df623ff87b6d6f48166", size = 146080, upload-time = "2025-08-12T09:49:36.19Z" }, - { url = "https://files.pythonhosted.org/packages/66/ec/9faa8b52d7648c6bc2362bf193cdef4da317652148da2309ecf219fa97cd/bitarray-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bc717849ea0693b6b93480e499f0da3ea7501f52aaea2b144aa28ac5eecbe62", size = 142511, upload-time = "2025-08-12T09:49:37.32Z" }, - { url = "https://files.pythonhosted.org/packages/cb/f1/f5434b6e3fa9f947f98c9c79fab7d57af64caa77afd0ad01ae523c6773cf/bitarray-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00a129b2d790e772fbfb26e31c65f54d5451636654e7f0600af03086aba6461a", size = 325454, upload-time = "2025-08-12T09:49:39.138Z" }, - { url = "https://files.pythonhosted.org/packages/3c/4d/499c541b5b53eb382a7a9051958b3170d46c89a640c93a0ae63b19c266bd/bitarray-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9016c534c64342cf3d8c6fda8df681b9771e9fa15a1697423a3766e986d2f958", size = 344318, upload-time = "2025-08-12T09:49:40.268Z" }, - { url = "https://files.pythonhosted.org/packages/b3/63/76d32982fe00225ba3f55c17e9f08952b67f59369780aaab0205fdeba311/bitarray-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8404a2c126abdc6cb236347565d4ea622712734fa0987f13c6505b550963b651", size = 337089, upload-time = "2025-08-12T09:49:41.398Z" }, - { url = "https://files.pythonhosted.org/packages/18/f6/db7b3f0610b7a50d7161650bb7ebd05d1b5f5db706c13ed0f7d211b7439a/bitarray-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:966478685f59bd429e2425f6a8172a6d8f54fd7d6df48fcae98fd24ff03163d1", size = 328377, upload-time = "2025-08-12T09:49:42.484Z" }, - { url = "https://files.pythonhosted.org/packages/15/87/7058ff8e7f618042846bfc3c6c62cd279b7aba1783d44c061ba16a6a84d8/bitarray-3.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41248ab4781a68d5f7ad492d1546b98c2f190c99941de6c92445b693d79123b4", size = 317355, upload-time = "2025-08-12T09:49:43.947Z" }, - { url = "https://files.pythonhosted.org/packages/ff/c5/240ed912f508a93adc1d5d44e52ffa8918ffdc220b9a09415dfc5b9e34be/bitarray-3.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:285a4a39b8d4715bc5165ee3e0bc81bc7f27ef92483bae478dc3d430c0734e82", size = 319043, upload-time = "2025-08-12T09:49:45.461Z" }, - { url = "https://files.pythonhosted.org/packages/36/7c/4aaa750b263d1694563da4ade62a196a171b158355a60861cfaf824fa600/bitarray-3.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c9d578179a618b8176fd625dcc3f756f9dc46647c35250798c318e5d4689d096", size = 315163, upload-time = "2025-08-12T09:49:46.978Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f9/740821848a9040faf54787d58d96d423e7f937cc4664b3a971e8ba8deb77/bitarray-3.6.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a2581ad5f45eba60bb8d5be324d26052620bb72fd3f76cb6d54d3d0f74859b2", size = 343174, upload-time = "2025-08-12T09:49:48.431Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d2/f44917e607b8c68c5fa221fdb9fb95d45296cf0815b10da9e3f88f60b532/bitarray-3.6.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:be8f2fd4798539f9b49db517ec9a2e9d1e9132ec92562220f67f80f176900c21", size = 343668, upload-time = "2025-08-12T09:49:49.486Z" }, - { url = "https://files.pythonhosted.org/packages/56/8b/87e501afdc5ee806459de1b77ac88a35841894cc159a3c723439678d9980/bitarray-3.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4af03ea3ed535f0c50ed1b871b1c7985188310b26fc5455241a66efb7ac0139f", size = 324096, upload-time = "2025-08-12T09:49:50.918Z" }, - { url = "https://files.pythonhosted.org/packages/1f/5f/7e0feb35442b68f1bb6738461f62b7ee3824929d25d169e4f3e84f493d6f/bitarray-3.6.1-cp311-cp311-win32.whl", hash = "sha256:1e04d1176f0657fc250ad022c3adc86b52ac7c5352d3d00262b0fc53c376005a", size = 138765, upload-time = "2025-08-12T09:49:52.319Z" }, - { url = "https://files.pythonhosted.org/packages/f7/00/814fea8b1b7521cd8433ce678a267d41bd8c29aaa39b500216bc32938952/bitarray-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:eb6ba70e7cf5128ec43787dbc0b5cd661118bf32b756078ff5cb143c9c825d11", size = 145434, upload-time = "2025-08-12T09:49:53.369Z" }, - { url = "https://files.pythonhosted.org/packages/e6/80/2a8514df92257d54cded7733aebeade6b594d551c0fb16746d4564fb1303/bitarray-3.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a236fc1e87a70adb588b37b09b18add71224279d28140d9ee847778e1f3f5a1a", size = 145778, upload-time = "2025-08-12T09:49:54.401Z" }, - { url = "https://files.pythonhosted.org/packages/c0/f8/a14a3deecb3580da1ae208ea32567a6581ebf6944c93c6c7f381fda08060/bitarray-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d5cf59d8f1ee8332f60e7352464209db1de909ae960d3b1f9d76897e484aa4ed", size = 142496, upload-time = "2025-08-12T09:49:55.772Z" }, - { url = "https://files.pythonhosted.org/packages/21/50/ae0e1cb8c1633372ad493b9a11bc0c66108c219e6bea5519d5119e28ec3e/bitarray-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38ce28427eea22bafcef073768d7e14d14233ced3eea8505ee13b92fb3723bce", size = 328326, upload-time = "2025-08-12T09:49:56.848Z" }, - { url = "https://files.pythonhosted.org/packages/f7/8b/4e196ea39ef05affc1591d09097c14d750b6a5b226973bdf4bfe761b08b3/bitarray-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e92011003d87e224e101533a98ede388bb40de0ec65978c6d0bb0d98f949f1b8", size = 346514, upload-time = "2025-08-12T09:49:57.977Z" }, - { url = "https://files.pythonhosted.org/packages/31/78/23c7c3fead7e7de36c4c7ed1ed3db105d6e293775cda6943b43e24e54fe3/bitarray-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f378316f45ffcec4ed429cf2ef446c8a3d7afe29e5020eb51ed789e443f4359f", size = 339657, upload-time = "2025-08-12T09:49:59.276Z" }, - { url = "https://files.pythonhosted.org/packages/24/44/f811e87fc5d937955502b5e5124e2a81315d577e9ff200ab568c8cd0bde6/bitarray-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b12c11894d991dfaa415229329452e8be2b230e06fba2aff27110158e2f0dafd", size = 331357, upload-time = "2025-08-12T09:50:00.464Z" }, - { url = "https://files.pythonhosted.org/packages/b4/08/e8250cba930c59c37786795b5cad2bef9772f7d9b6f68d21a474500b7e22/bitarray-3.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f53d6a0ac86d67b6760530196963ea0598588c1a9b155f7e137d9b6a1befd27", size = 319921, upload-time = "2025-08-12T09:50:01.65Z" }, - { url = "https://files.pythonhosted.org/packages/38/1f/bfedc526e3c512663062402ab2dcc4993eb73292aadac8c2cdaf06425135/bitarray-3.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4b17029647fd990ce6fd3f1fb253ff47bfc27df8255bea99b5e381b2030b6d54", size = 321237, upload-time = "2025-08-12T09:50:02.866Z" }, - { url = "https://files.pythonhosted.org/packages/15/bb/e813631a61d54c6d6662e6adfc2ab42596413b46c05d607ad66f2cd0c7e3/bitarray-3.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:36cd656877eb3d215ecbb575743d05c521911514985b2a0999a23bb504a8ae64", size = 317839, upload-time = "2025-08-12T09:50:04.138Z" }, - { url = "https://files.pythonhosted.org/packages/64/5d/548a375c81d3b366cc76ee611cbebb267ef6e5e33cc58461628e68ff65d8/bitarray-3.6.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ac29a0cda5ea50c78ff20d06d8c5b8402147448a9dde2b118ecea2b4cec490ec", size = 345106, upload-time = "2025-08-12T09:50:05.744Z" }, - { url = "https://files.pythonhosted.org/packages/6d/7d/7ffeab0566d798a6a4652b0fe16126611446863ede12873309e23b3e1978/bitarray-3.6.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8dceb8d43fe51b8643766152736ec0f32f0a6a5b6e2e6742f1165cbe5799102e", size = 346469, upload-time = "2025-08-12T09:50:07.248Z" }, - { url = "https://files.pythonhosted.org/packages/92/47/f5fb907c9c8ea9c0376792152e7c511ae95a0140f54562f6a49c66a30094/bitarray-3.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:137bfb9c00c172c16ddabe8615a4746e745789cfedb0e7c5b25236a20ccf051c", size = 327378, upload-time = "2025-08-12T09:50:08.512Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fb/3203d199f9cba9595227afefc614c5390b1babb9d73df0df78d50b88f053/bitarray-3.6.1-cp312-cp312-win32.whl", hash = "sha256:aba6043eb44b68055145c5ae2062f976c02ec0b04ff688ee5b43deda8185b708", size = 138827, upload-time = "2025-08-12T09:50:09.745Z" }, - { url = "https://files.pythonhosted.org/packages/60/95/cd3e4a4e783ff8d0f54ae3bc8fc26e077333d2eebe917f6ee7886c9004e8/bitarray-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:64a3a8c79468bd5283907f2e60651c857f0dab3dc671943bcf5ec2d15e2f8177", size = 145639, upload-time = "2025-08-12T09:50:10.857Z" }, - { url = "https://files.pythonhosted.org/packages/38/f8/2d01a469adee4c5b475fcedecd431234ba38fff90c428f0628cf7b691d28/bitarray-3.6.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a15055d392a921093d3c583e7978acc63fd3f76068a10f8e2deaa078b58a0ac9", size = 140944, upload-time = "2025-08-12T09:51:56.495Z" }, - { url = "https://files.pythonhosted.org/packages/62/b0/c05c0efe241abed2c4e31d68483bf80aeb2225f03510f98501b3dd44fbd8/bitarray-3.6.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b6b68a6f7b7b872ea4838d438547ee69a1b020078893f087b35152dd6c3550e", size = 137711, upload-time = "2025-08-12T09:51:58.095Z" }, - { url = "https://files.pythonhosted.org/packages/0c/33/55c45cd23c4132d582a19b1efcc3e7016e6b6944f682d44a8ed71fb14d34/bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26180314ad363dcefa03fff9b7008d8cc2dcc7b080bb38e5bfde545d08e0a7cb", size = 146028, upload-time = "2025-08-12T09:52:00.005Z" }, - { url = "https://files.pythonhosted.org/packages/e5/1f/e63cfea10b55f80b6edddc0ca3b195f4f18b4f03407b63e9f8baefde1edf/bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cae78167bceb3991652dab9d5e66c94e09860005753b51ba608a803a8c2504fb", size = 146828, upload-time = "2025-08-12T09:52:01.428Z" }, - { url = "https://files.pythonhosted.org/packages/bf/34/64c1b1760369b432d532e6ab0a4726fdcea6a243c9cc2c6e7b228d304d4c/bitarray-3.6.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b04a4884e52958d2a5c5e17389fdcc99cb01acbf311a7aa81871a28a2756f89", size = 148624, upload-time = "2025-08-12T09:52:03.142Z" }, - { url = "https://files.pythonhosted.org/packages/09/69/75fa43cfc2079220514c2f25aed0c9dbf388a7042b46ba3b3baabbe6d526/bitarray-3.6.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:78a3c6fe40206a3d550a1d10249732152a849d1817fced3e7af5b19f5e832615", size = 143976, upload-time = "2025-08-12T09:52:04.628Z" }, + { url = "https://files.pythonhosted.org/packages/ff/fc/4352b1dd55a50c85f7b502c011d40279a66a05eb0c6a5d3d44160838d9a4/bitarray-3.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30d42c34da2974a5e2e0b51c57ecf89892c1e83ed67e1084d1e27eefc27add91", size = 149074, upload-time = "2026-04-02T16:26:16.319Z" }, + { url = "https://files.pythonhosted.org/packages/34/06/104c9ff50e5230f6581056d6f4b0d1e0db14aba41549cae4b0541be0369c/bitarray-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0793c51d3b1c7410bde1f7254fff71fabff1bc0cdeba1fa51319ac4e7931df3d", size = 146031, upload-time = "2026-04-02T16:26:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/65/0b/99d65fa6ceb3616c4b96ab9fef2dcd4994ad05fa48f595706ba001f13ba7/bitarray-3.8.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133648c3405564e7fef9103f1768cb018de1b4976f3d8beff09cd4acea73bfe4", size = 325129, upload-time = "2026-04-02T16:26:19.77Z" }, + { url = "https://files.pythonhosted.org/packages/18/d4/e0913c6b15fbd1e6b4d60a541a6784eb5d8f1fddcbcbb8c076240f665f2e/bitarray-3.8.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4fd3399eaf6f1c77ea3132611efbc3d7a8c0eb899793387b3266be221dc75fd", size = 353126, upload-time = "2026-04-02T16:26:21.274Z" }, + { url = "https://files.pythonhosted.org/packages/49/1b/0fd86dece4eca8078a99e54ca01183d5b660195dea8f2c8ad5740b190e9f/bitarray-3.8.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3b9790ae107fc8648155f120e80a58ef8e94424efefff5b355de84061de6a18b", size = 363588, upload-time = "2026-04-02T16:26:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/ec/2d/e62ddf9e52a0124a19f2cd83be5dfa256c6c1f20722fb0bb4b0aed51bb0b/bitarray-3.8.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af01133e78e5528ee282ceb1cf4bc54aecb937c2001913e751452ad7dffbbeb1", size = 331725, upload-time = "2026-04-02T16:26:24.296Z" }, + { url = "https://files.pythonhosted.org/packages/cd/fc/ea1c532169d56747c128f4e0256a3ad1f0c91ed00ca83cdf93964a60fec3/bitarray-3.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2da2ca9495668ab77132a911f6bd530d2bfe686d10467584894efc3b66e9ffb5", size = 322939, upload-time = "2026-04-02T16:26:25.904Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/8fe68993779f077c713fc4c21c0d9ba2719beeea596bcdc37f9660b6f181/bitarray-3.8.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:72a0e87b2196120523fc6194ca6b580fcffa12d7daa4d57a16d7838e60f82d0e", size = 351084, upload-time = "2026-04-02T16:26:27.396Z" }, + { url = "https://files.pythonhosted.org/packages/96/c5/f5cb62b60e0da428ef9457e7e1d9a3d3d8874b4f0f925adfff4b9ab3a319/bitarray-3.8.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:defa3c12cb06b2fd2066a9e21bf00aab96465be84d9585c8c05195f080510506", size = 347489, upload-time = "2026-04-02T16:26:28.935Z" }, + { url = "https://files.pythonhosted.org/packages/88/71/bb9baadbdd305f80def4220ce38266f53404433661492fc2c3d894129bfb/bitarray-3.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7eae9e763fbd32f19f2a66dfc2e37906f8422e0c4ad4a6c9dcf9d3246740812e", size = 328394, upload-time = "2026-04-02T16:26:30.585Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/c4d487b029488bebef38a4c04df34294d27f313b5ab3491aa3a051394f24/bitarray-3.8.1-cp310-cp310-win32.whl", hash = "sha256:3b9358f6437a5fa0c765ffae5810c9830547baf4bcf469438b82845c3f33f998", size = 143245, upload-time = "2026-04-02T16:26:32.414Z" }, + { url = "https://files.pythonhosted.org/packages/98/ae/adadedf7cdd49fb8d81b8013d3471c193d6208035a0748205c808b1709cd/bitarray-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:6f92d12a46b2a67d56194bb5d226dabf586b386d1f1a5e25be5b745a3080dbba", size = 149976, upload-time = "2026-04-02T16:26:33.868Z" }, + { url = "https://files.pythonhosted.org/packages/26/de/2a7a8c2868d85e671a6cdb5282bbb299d98cdc0b4c4ade0cfa9a2a21d91d/bitarray-3.8.1-cp310-cp310-win_arm64.whl", hash = "sha256:8e12d50d4d65c74bd877e15c276992263b878456a7cfcf72521e7205a553557f", size = 146729, upload-time = "2026-04-02T16:26:35.216Z" }, + { url = "https://files.pythonhosted.org/packages/05/5c/32ace44d0313b4a9986d2abc3a1349744920dafcfb6a4e454a10ed09ef5a/bitarray-3.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:660e11b9932f58f10151d0febd11f77d3b0d48d6fa4dd4686d8983f40187101e", size = 149069, upload-time = "2026-04-02T16:26:36.671Z" }, + { url = "https://files.pythonhosted.org/packages/6d/85/7bd0a218478f0a226ddfb756dd64286f8ee3c61a17991a1a50aae8d89dca/bitarray-3.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fb1df55f5700187c6db4b47dbdaf8a0653a111341ac7fccc596b397aa3399e65", size = 146036, upload-time = "2026-04-02T16:26:38.179Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e9/e4e6aec6874efac185959f4627b6a61a88c0dad3ec92eee433fd395daa78/bitarray-3.8.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:838fd67b3d00c5a64181073282a2c0bf8f76465da4844d5e79d2dbbc64c987dc", size = 333036, upload-time = "2026-04-02T16:26:39.723Z" }, + { url = "https://files.pythonhosted.org/packages/50/5f/d493eb77f79b58eaa489e9e032aa1c91f6af844287b341c6be681df11b0d/bitarray-3.8.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5743f532e408cfd716fa16776b5a6447b83ff2cf39021fb5f8d052aa0f331508", size = 361247, upload-time = "2026-04-02T16:26:41.023Z" }, + { url = "https://files.pythonhosted.org/packages/24/a3/2e3f33c66f61754b5bb4724d54c9c1122699facc580bcb416d44f1164ffc/bitarray-3.8.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0c8c66f5d8055cb84ad0ea14af57b3579cb0b6db589f2086f5e33f0922cf2354", size = 371922, upload-time = "2026-04-02T16:26:42.373Z" }, + { url = "https://files.pythonhosted.org/packages/05/03/4dfca9a69dfa69cde6fdbcfafbc039e069e105ea2443688177f6873d8444/bitarray-3.8.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8c3fe25871f1758519a3ad8dcafb1bd95c5d1aaeb122e6492ac739ab11fa5907", size = 339203, upload-time = "2026-04-02T16:26:43.915Z" }, + { url = "https://files.pythonhosted.org/packages/14/5d/a2275da6c935893f275624c88afab6cdd5b6aa916d0b45c50dd400cafb20/bitarray-3.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e9ff57452fcadfd1a379314234657b8f4e9967ae64480ddf7c2fd82139bc8cf8", size = 330956, upload-time = "2026-04-02T16:26:45.675Z" }, + { url = "https://files.pythonhosted.org/packages/2d/fd/7f4041c7a7e94ef3e7de86fdb4102d3fe366998b507de77ba0fe5dff6c44/bitarray-3.8.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4e34f1cb6cdb036c5f4a839a2b74419f75fa36177a70c4bab2867f48973cbe44", size = 358882, upload-time = "2026-04-02T16:26:47.327Z" }, + { url = "https://files.pythonhosted.org/packages/29/4e/2d0c381327c0f5bc49681b799bbe7d80d5e629079f9609a79d39da6e8b8f/bitarray-3.8.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:698c37fca3761af69a09a1d39cc0492f7e8cb9e263af39a288dce8f3b8a9e2bc", size = 355761, upload-time = "2026-04-02T16:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/e8/d9/66644d45d9f844d1c78b80f3517c8717ac4b4d9853ec61bd02b3cabc06e6/bitarray-3.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:81ede1f094f26eeaff62e029ff1bc4e84e9d568f20d4669f64dcf7c7b18a28fc", size = 336422, upload-time = "2026-04-02T16:26:49.988Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7d/4ea3fd2424535630d4d236bc0c721621260b39878eed669dbc1deb5c6b22/bitarray-3.8.1-cp311-cp311-win32.whl", hash = "sha256:8a345b5dc8ab8cafdf338e08530d48fe3f73df27f4ff569be793c7a7e7bb6b6b", size = 143391, upload-time = "2026-04-02T16:26:51.69Z" }, + { url = "https://files.pythonhosted.org/packages/d0/4f/46309fcf9e1793c7184e3fc1aa73d7daf2b6a2b0fa1efbcf8d497101690e/bitarray-3.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:ddcd25a1f72b2b545fb27e17882046a6c161f3f24514b2e028c00c58ed73a2dd", size = 150143, upload-time = "2026-04-02T16:26:52.9Z" }, + { url = "https://files.pythonhosted.org/packages/0e/1e/10289fb8e44fdd2d01adcc24d64b5c45ead709fbec76ee973f42e22b3059/bitarray-3.8.1-cp311-cp311-win_arm64.whl", hash = "sha256:dc2cab92c42991b711132bc52405680e075d1505d4356c4468bc6e9c93d49137", size = 147024, upload-time = "2026-04-02T16:26:54.151Z" }, + { url = "https://files.pythonhosted.org/packages/5d/4f/6ab3767b6642a6cbee4353f10a71fe25ade9899d539fae47c3d50686ebe2/bitarray-3.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4494c599effa16064f2b600f6eb28115182d6826847d795a55691339788d8a4d", size = 149202, upload-time = "2026-04-02T16:26:55.635Z" }, + { url = "https://files.pythonhosted.org/packages/eb/53/22bfffd13dd0a266f90011338b24eec45f25c91d37155bb2aa330351e17d/bitarray-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ff2ca039a161d49a8c713f5380def315c6f793df5fe348b94782b1dbee37a644", size = 145999, upload-time = "2026-04-02T16:26:56.849Z" }, + { url = "https://files.pythonhosted.org/packages/5d/dc/60aff29c88b648e18248921001cf9d7169abeda4d8db96f2dc1a24ed98ca/bitarray-3.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df3ffa6ef88166bb36f5d1492e71e664868b9b8b6afd55821e0ac0cb96625441", size = 335945, upload-time = "2026-04-02T16:26:58.403Z" }, + { url = "https://files.pythonhosted.org/packages/83/c8/225380610a01ae0d8f2f5256e531bae7135b2ade6f4607156424718ec43a/bitarray-3.8.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:478b9f0ea86f957624dd2b159066855716f78db94666e9b04babe85fc013e01b", size = 364213, upload-time = "2026-04-02T16:26:59.742Z" }, + { url = "https://files.pythonhosted.org/packages/6c/df/83899be9a74ec5878972e8b636f645ef1771e146c6425a161fdafdd74aaa/bitarray-3.8.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e127b2e7fc533728295196f9265d12834530f475bc6cd6f74619df415d04b8b1", size = 375409, upload-time = "2026-04-02T16:27:01.081Z" }, + { url = "https://files.pythonhosted.org/packages/6c/93/38bc15cb097107d220a942eb66dc50882496d7da54f41e5eea6c31b1c443/bitarray-3.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ef49462a615de062dcac8281944d0b036fe1e9c96a6c690bf6cf5e4b5488f0e", size = 343645, upload-time = "2026-04-02T16:27:02.577Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c3/75fae6991946f8bf643ec50233432ea81b5b65bfdb2918b09d7e37605380/bitarray-3.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4da256fc567a57ded2a4aa962fc9e9d430ab740e5c67be9e98a63ef4eb467f2f", size = 333844, upload-time = "2026-04-02T16:27:03.963Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7e/649e7c3bb12ba938c387bcad6a6c0b84312663c9807ec1457888936690d8/bitarray-3.8.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b46b7aec9272fd81c984e723e599957629a91204120b3e7f0933f138e0792fdf", size = 361267, upload-time = "2026-04-02T16:27:05.361Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5f/db0fb71a7c6c3ef047b84256157e96fa35e10ed8b79b80e892d354ab37f6/bitarray-3.8.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2dc07dab252c63c4f6600e200b26fa05207db6b650d41ae88ab0cec4d6c59459", size = 359373, upload-time = "2026-04-02T16:27:07.106Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b6/a082d84cba7ba509b48d160034f6a2d31df6bf4fff0471801e888bba96c9/bitarray-3.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:29c8c10a49d6a9586f592116618b99c3dabcb24d881b7a649e0691ef87f314c4", size = 340633, upload-time = "2026-04-02T16:27:08.794Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b7/1ba7ec1f3aa62933dfef505b09de0b75778a3cb05984ee8bb798539381db/bitarray-3.8.1-cp312-cp312-win32.whl", hash = "sha256:67125404d12547443d74113862a80c10310cf875aff8dbfc5548fee1d9737123", size = 143521, upload-time = "2026-04-02T16:27:10.423Z" }, + { url = "https://files.pythonhosted.org/packages/82/30/5ff9d30a1121810f336517e51b1cbdea0fa92e92b142efe0741e335dc14e/bitarray-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ba0339d6aa80615a17f47fabc5700485e9469121d658458f95cdd2003288c28b", size = 150451, upload-time = "2026-04-02T16:27:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/a6/08/51e49eb09ca45ecda4a5f05b70a10977a5f0ac39967c79479e9d3e41cb29/bitarray-3.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:c0b367a00e8c88a714b2384c97dedcc85340547b3a54b6037a42fca5554d0576", size = 147218, upload-time = "2026-04-02T16:27:13.566Z" }, ] [[package]] name = "bitstring" -version = "4.3.1" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bitarray" }, + { name = "tibs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/15/a8/a80c890db75d5bdd5314b5de02c4144c7de94fd0cefcae51acaeb14c6a3f/bitstring-4.3.1.tar.gz", hash = "sha256:a08bc09d3857216d4c0f412a1611056f1cc2b64fd254fb1e8a0afba7cfa1a95a", size = 251426, upload-time = "2025-03-22T09:39:06.978Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/d3/de6fe4e7065df8c2f1ac1766f5fdccbe75bc18af2cf2dbeecd34d68e1518/bitstring-4.4.0.tar.gz", hash = "sha256:e682ac522bb63e041d16cbc9d0ca86a4f00194db16d0847c7efe066f836b2e37", size = 255209, upload-time = "2026-03-10T20:29:14.824Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/2d/174566b533755ddf8efb32a5503af61c756a983de379f8ad3aed6a982d38/bitstring-4.3.1-py3-none-any.whl", hash = "sha256:69d1587f0ac18dc7d93fc7e80d5f447161a33e57027e726dc18a0a8bacf1711a", size = 71930, upload-time = "2025-03-22T09:39:05.163Z" }, + { url = "https://files.pythonhosted.org/packages/bf/02/1a870bab76f2896d827aa4963be95e56675ffa1453e53525d13c43036edf/bitstring-4.4.0-py3-none-any.whl", hash = "sha256:feac49524fcf3ef27e6081e86f02b10d2adf6c3773bf22fbe0e7eea9534bc737", size = 76846, upload-time = "2026-03-10T20:29:12.832Z" }, ] [[package]] name = "black" -version = "25.12.0" +version = "26.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -344,24 +353,24 @@ dependencies = [ { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/d9/07b458a3f1c525ac392b5edc6b191ff140b596f9d77092429417a54e249d/black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7", size = 659264, upload-time = "2025-12-08T01:40:52.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/c5/61175d618685d42b005847464b8fb4743a67b1b8fdb75e50e5a96c31a27a/black-26.3.1.tar.gz", hash = "sha256:2c50f5063a9641c7eed7795014ba37b0f5fa227f3d408b968936e24bc0566b07", size = 666155, upload-time = "2026-03-12T03:36:03.593Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/d5/8d3145999d380e5d09bb00b0f7024bf0a8ccb5c07b5648e9295f02ec1d98/black-25.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f85ba1ad15d446756b4ab5f3044731bf68b777f8f9ac9cdabd2425b97cd9c4e8", size = 1895720, upload-time = "2025-12-08T01:46:58.197Z" }, - { url = "https://files.pythonhosted.org/packages/06/97/7acc85c4add41098f4f076b21e3e4e383ad6ed0a3da26b2c89627241fc11/black-25.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546eecfe9a3a6b46f9d69d8a642585a6eaf348bcbbc4d87a19635570e02d9f4a", size = 1727193, upload-time = "2025-12-08T01:52:26.674Z" }, - { url = "https://files.pythonhosted.org/packages/24/f0/fdf0eb8ba907ddeb62255227d29d349e8256ef03558fbcadfbc26ecfe3b2/black-25.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17dcc893da8d73d8f74a596f64b7c98ef5239c2cd2b053c0f25912c4494bf9ea", size = 1774506, upload-time = "2025-12-08T01:46:25.721Z" }, - { url = "https://files.pythonhosted.org/packages/e4/f5/9203a78efe00d13336786b133c6180a9303d46908a9aa72d1104ca214222/black-25.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:09524b0e6af8ba7a3ffabdfc7a9922fb9adef60fed008c7cd2fc01f3048e6e6f", size = 1416085, upload-time = "2025-12-08T01:46:06.073Z" }, - { url = "https://files.pythonhosted.org/packages/ba/cc/7a6090e6b081c3316282c05c546e76affdce7bf7a3b7d2c3a2a69438bd01/black-25.12.0-cp310-cp310-win_arm64.whl", hash = "sha256:b162653ed89eb942758efeb29d5e333ca5bb90e5130216f8369857db5955a7da", size = 1226038, upload-time = "2025-12-08T01:45:29.388Z" }, - { url = "https://files.pythonhosted.org/packages/60/ad/7ac0d0e1e0612788dbc48e62aef8a8e8feffac7eb3d787db4e43b8462fa8/black-25.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0cfa263e85caea2cff57d8f917f9f51adae8e20b610e2b23de35b5b11ce691a", size = 1877003, upload-time = "2025-12-08T01:43:29.967Z" }, - { url = "https://files.pythonhosted.org/packages/e8/dd/a237e9f565f3617a88b49284b59cbca2a4f56ebe68676c1aad0ce36a54a7/black-25.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a2f578ae20c19c50a382286ba78bfbeafdf788579b053d8e4980afb079ab9be", size = 1712639, upload-time = "2025-12-08T01:52:46.756Z" }, - { url = "https://files.pythonhosted.org/packages/12/80/e187079df1ea4c12a0c63282ddd8b81d5107db6d642f7d7b75a6bcd6fc21/black-25.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e1b65634b0e471d07ff86ec338819e2ef860689859ef4501ab7ac290431f9b", size = 1758143, upload-time = "2025-12-08T01:45:29.137Z" }, - { url = "https://files.pythonhosted.org/packages/93/b5/3096ccee4f29dc2c3aac57274326c4d2d929a77e629f695f544e159bfae4/black-25.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3fa71e3b8dd9f7c6ac4d818345237dfb4175ed3bf37cd5a581dbc4c034f1ec5", size = 1420698, upload-time = "2025-12-08T01:45:53.379Z" }, - { url = "https://files.pythonhosted.org/packages/7e/39/f81c0ffbc25ffbe61c7d0385bf277e62ffc3e52f5ee668d7369d9854fadf/black-25.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:51e267458f7e650afed8445dc7edb3187143003d52a1b710c7321aef22aa9655", size = 1229317, upload-time = "2025-12-08T01:46:35.606Z" }, - { url = "https://files.pythonhosted.org/packages/d1/bd/26083f805115db17fda9877b3c7321d08c647df39d0df4c4ca8f8450593e/black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a", size = 1924178, upload-time = "2025-12-08T01:49:51.048Z" }, - { url = "https://files.pythonhosted.org/packages/89/6b/ea00d6651561e2bdd9231c4177f4f2ae19cc13a0b0574f47602a7519b6ca/black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783", size = 1742643, upload-time = "2025-12-08T01:49:59.09Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f3/360fa4182e36e9875fabcf3a9717db9d27a8d11870f21cff97725c54f35b/black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59", size = 1800158, upload-time = "2025-12-08T01:44:27.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/08/2c64830cb6616278067e040acca21d4f79727b23077633953081c9445d61/black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892", size = 1426197, upload-time = "2025-12-08T01:45:51.198Z" }, - { url = "https://files.pythonhosted.org/packages/d4/60/a93f55fd9b9816b7432cf6842f0e3000fdd5b7869492a04b9011a133ee37/black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43", size = 1237266, upload-time = "2025-12-08T01:45:10.556Z" }, - { url = "https://files.pythonhosted.org/packages/68/11/21331aed19145a952ad28fca2756a1433ee9308079bd03bd898e903a2e53/black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828", size = 206191, upload-time = "2025-12-08T01:40:50.963Z" }, + { url = "https://files.pythonhosted.org/packages/32/a8/11170031095655d36ebc6664fe0897866f6023892396900eec0e8fdc4299/black-26.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:86a8b5035fce64f5dcd1b794cf8ec4d31fe458cf6ce3986a30deb434df82a1d2", size = 1866562, upload-time = "2026-03-12T03:39:58.639Z" }, + { url = "https://files.pythonhosted.org/packages/69/ce/9e7548d719c3248c6c2abfd555d11169457cbd584d98d179111338423790/black-26.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5602bdb96d52d2d0672f24f6ffe5218795736dd34807fd0fd55ccd6bf206168b", size = 1703623, upload-time = "2026-03-12T03:40:00.347Z" }, + { url = "https://files.pythonhosted.org/packages/7f/0a/8d17d1a9c06f88d3d030d0b1d4373c1551146e252afe4547ed601c0e697f/black-26.3.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c54a4a82e291a1fee5137371ab488866b7c86a3305af4026bdd4dc78642e1ac", size = 1768388, upload-time = "2026-03-12T03:40:01.765Z" }, + { url = "https://files.pythonhosted.org/packages/52/79/c1ee726e221c863cde5164f925bacf183dfdf0397d4e3f94889439b947b4/black-26.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:6e131579c243c98f35bce64a7e08e87fb2d610544754675d4a0e73a070a5aa3a", size = 1412969, upload-time = "2026-03-12T03:40:03.252Z" }, + { url = "https://files.pythonhosted.org/packages/73/a5/15c01d613f5756f68ed8f6d4ec0a1e24b82b18889fa71affd3d1f7fad058/black-26.3.1-cp310-cp310-win_arm64.whl", hash = "sha256:5ed0ca58586c8d9a487352a96b15272b7fa55d139fc8496b519e78023a8dab0a", size = 1220345, upload-time = "2026-03-12T03:40:04.892Z" }, + { url = "https://files.pythonhosted.org/packages/17/57/5f11c92861f9c92eb9dddf515530bc2d06db843e44bdcf1c83c1427824bc/black-26.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:28ef38aee69e4b12fda8dba75e21f9b4f979b490c8ac0baa7cb505369ac9e1ff", size = 1851987, upload-time = "2026-03-12T03:40:06.248Z" }, + { url = "https://files.pythonhosted.org/packages/54/aa/340a1463660bf6831f9e39646bf774086dbd8ca7fc3cded9d59bbdf4ad0a/black-26.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bf162ed91a26f1adba8efda0b573bc6924ec1408a52cc6f82cb73ec2b142c", size = 1689499, upload-time = "2026-03-12T03:40:07.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/01/b726c93d717d72733da031d2de10b92c9fa4c8d0c67e8a8a372076579279/black-26.3.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:474c27574d6d7037c1bc875a81d9be0a9a4f9ee95e62800dab3cfaadbf75acd5", size = 1754369, upload-time = "2026-03-12T03:40:09.279Z" }, + { url = "https://files.pythonhosted.org/packages/e3/09/61e91881ca291f150cfc9eb7ba19473c2e59df28859a11a88248b5cbbc4d/black-26.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:5e9d0d86df21f2e1677cc4bd090cd0e446278bcbbe49bf3659c308c3e402843e", size = 1413613, upload-time = "2026-03-12T03:40:10.943Z" }, + { url = "https://files.pythonhosted.org/packages/16/73/544f23891b22e7efe4d8f812371ab85b57f6a01b2fc45e3ba2e52ba985b8/black-26.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:9a5e9f45e5d5e1c5b5c29b3bd4265dcc90e8b92cf4534520896ed77f791f4da5", size = 1219719, upload-time = "2026-03-12T03:40:12.597Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f8/da5eae4fc75e78e6dceb60624e1b9662ab00d6b452996046dfa9b8a6025b/black-26.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e6f89631eb88a7302d416594a32faeee9fb8fb848290da9d0a5f2903519fc1", size = 1895920, upload-time = "2026-03-12T03:40:13.921Z" }, + { url = "https://files.pythonhosted.org/packages/2c/9f/04e6f26534da2e1629b2b48255c264cabf5eedc5141d04516d9d68a24111/black-26.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cd2012d35b47d589cb8a16faf8a32ef7a336f56356babd9fcf70939ad1897f", size = 1718499, upload-time = "2026-03-12T03:40:15.239Z" }, + { url = "https://files.pythonhosted.org/packages/04/91/a5935b2a63e31b331060c4a9fdb5a6c725840858c599032a6f3aac94055f/black-26.3.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f76ff19ec5297dd8e66eb64deda23631e642c9393ab592826fd4bdc97a4bce7", size = 1794994, upload-time = "2026-03-12T03:40:17.124Z" }, + { url = "https://files.pythonhosted.org/packages/e7/0a/86e462cdd311a3c2a8ece708d22aba17d0b2a0d5348ca34b40cdcbea512e/black-26.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ddb113db38838eb9f043623ba274cfaf7d51d5b0c22ecb30afe58b1bb8322983", size = 1420867, upload-time = "2026-03-12T03:40:18.83Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e5/22515a19cb7eaee3440325a6b0d95d2c0e88dd180cb011b12ae488e031d1/black-26.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:dfdd51fc3e64ea4f35873d1b3fb25326773d55d2329ff8449139ebaad7357efb", size = 1230124, upload-time = "2026-03-12T03:40:20.425Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/52d98722666d6fc6c3dd4c76df339501d6efd40e0ff95e6186a7b7f0befd/black-26.3.1-py3-none-any.whl", hash = "sha256:2bd5aa94fc267d38bb21a70d7410a89f1a1d318841855f698746f8e7f51acd1b", size = 207542, upload-time = "2026-03-12T03:36:01.668Z" }, ] [[package]] @@ -380,6 +389,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/9e/78e59887cbf94116bdc890af7726ae264d55df14f1c777724c656e8a35fe/bolt11-2.1.1-py3-none-any.whl", hash = "sha256:fd4edb9e73e27bf5e017f47c97f7c6827b523fcf9cab152b123961ca78323e2d", size = 17102, upload-time = "2025-03-12T13:33:08.142Z" }, ] +[[package]] +name = "boltz-client" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/97/c0d3d0cb5a6f70511fc22549d661406fa41859971b3d8e807c9122525d8c/boltz_client-0.4.0.tar.gz", hash = "sha256:a3f5a6b637350267856e3ab680cd92158de720fa2d5805fc075e4583d020cb2a", size = 5305287, upload-time = "2026-05-18T11:29:50.38Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/2a/c99448f0e9789a6d4b6d25392c0eb17b1dedef7c16bafae9a91b2a92e592/boltz_client-0.4.0-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:ed0b520209cf1b05a8523002f5d8f26fa29c04d2faecc9cbde3621b4ddc417e6", size = 5310491, upload-time = "2026-05-18T11:29:48.187Z" }, +] + [[package]] name = "breez-sdk" version = "0.8.0" @@ -404,142 +422,159 @@ wheels = [ [[package]] name = "breez-sdk-liquid" -version = "0.11.11" +version = "0.11.13" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/ba/38408250e136343c5e7ee063f187df29a391c233fac32f8bf924f0d00c85/breez_sdk_liquid-0.11.11-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0c1da93d69112cee65c07f1bf3efbcfbb9182c5e3d8933ca27adc659eae064e0", size = 24855120, upload-time = "2025-12-01T16:16:31.212Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0a/73a0f2ce7550c04bb78939709d7f0c4c0d8222821457d8ec0791f0c0dd3d/breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:c2b2d9a04022e05eb56699b6e8a628e7b53676d6f90b1c461c0b1b38b781d952", size = 16045266, upload-time = "2025-12-01T16:16:33.679Z" }, - { url = "https://files.pythonhosted.org/packages/75/e9/ddc34c2ebd2a2181c61669bebc5f40853ff7a72aad0bea8162d8c6329b65/breez_sdk_liquid-0.11.11-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:6fb44fb16bd55a53fcbd22c7a1982bc8b83de655d0b3e677fe6debd366b41890", size = 15214330, upload-time = "2025-12-01T16:16:35.994Z" }, - { url = "https://files.pythonhosted.org/packages/f7/19/84f59b425683a1be127b0fe203d3040ee21fbd7f773dbe6e6153b288372d/breez_sdk_liquid-0.11.11-cp310-cp310-win32.whl", hash = "sha256:04719223f8b5a44401c02aef6202076e0e557f28476b7cbe787ed9e7947e641a", size = 10214705, upload-time = "2025-12-01T16:16:39.137Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d0/2d94e9afa5a7900a3c75b8a428386c3ba48de8a383eecd2b5403ad4d2b1d/breez_sdk_liquid-0.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0d36272277e8d5b0287b45cacce5444934579ae9f6726de377c9de7d4535dc6f", size = 10743378, upload-time = "2025-12-01T16:16:40.884Z" }, - { url = "https://files.pythonhosted.org/packages/a7/c8/324891a06997e7c8a9713891484b4350613754db663067fac89fd5d0025f/breez_sdk_liquid-0.11.11-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:4ab4029773e5d2f946872ced5b3c76c5686e00cf6786b9515b707e16691e40dd", size = 24855121, upload-time = "2025-12-01T16:16:43.094Z" }, - { url = "https://files.pythonhosted.org/packages/82/04/93adc12245f6e53fb036f4f51eb59b463e629f372543c6a72a31a3903a82/breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:b3ab95f85f7454710c312443d4c0bc96fd1f06a4d3453305eb2fc9c510e9441e", size = 16045269, upload-time = "2025-12-01T16:16:45.194Z" }, - { url = "https://files.pythonhosted.org/packages/04/51/e831d1c0d2639a33b4123e991acbc594838c4a22ac356b9f027e09ac1d32/breez_sdk_liquid-0.11.11-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:bf85cecaad3d433ee9af75814a921d5ae582a74c9f4009c8bc865c820b9f8cd9", size = 15214332, upload-time = "2025-12-01T16:16:48.287Z" }, - { url = "https://files.pythonhosted.org/packages/81/ad/c46ae0bcbf3479f41a4c4f1d11e9d6d7152bfcea84e85de2fe53077c0093/breez_sdk_liquid-0.11.11-cp311-cp311-win32.whl", hash = "sha256:f9b0c5393111f7de3511c061f680f94cfd867f6f2e114904c3f5e31fe1fa2824", size = 10214707, upload-time = "2025-12-01T16:16:50.345Z" }, - { url = "https://files.pythonhosted.org/packages/cc/2b/262bd6dbba9a9ce021290b8fa724eabed7dd562dd1a419147ef92fd3e6b2/breez_sdk_liquid-0.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:7d2862108da64e2b73de46f61ff7d2df5607cbb6bb78a1bc437d19d06caa9f93", size = 10743377, upload-time = "2025-12-01T16:16:52.028Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ad/1733513975b1363844fb341194f67f53b78ce0fe942b5cc9650b93630974/breez_sdk_liquid-0.11.11-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:93faa55da3b4c850b1655b66b8822bd36b40a0491990d31d5d6f9000e0e61521", size = 24855161, upload-time = "2025-12-01T16:16:54.455Z" }, - { url = "https://files.pythonhosted.org/packages/e0/40/400ac6ce7f3c1cdf58558d6d4cc42dbee6a4a8fd46dde362a0c979aac400/breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:337be3e6c59bba6890629fc82e7b8f342bbf19fdb0f9c4a2f0d2aa5e93dfa690", size = 16045270, upload-time = "2025-12-01T16:16:56.668Z" }, - { url = "https://files.pythonhosted.org/packages/1c/6a/5428ba3ce098ee4c62d4da9212d08a9017a83614df796e8224aee791745b/breez_sdk_liquid-0.11.11-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:129baf243381bf5ce4d2927f52dabc68f61f9e173d498ee53d9aef55f4e44fb2", size = 15214331, upload-time = "2025-12-01T16:16:58.766Z" }, - { url = "https://files.pythonhosted.org/packages/ca/0c/e8f64c8ca1e8468abc7a17efa5a248029b724417cdb9181125178cffe83b/breez_sdk_liquid-0.11.11-cp312-cp312-win32.whl", hash = "sha256:9acd3eea87c861ed5cde91e188d38e893090d5de925c9ed3c9b21f9be15abe0d", size = 10214706, upload-time = "2025-12-01T16:17:00.776Z" }, - { url = "https://files.pythonhosted.org/packages/5c/8f/d7aa56c865ac060a540eb6fb214d6ea597c7f3408980ef5d0b1555c5984b/breez_sdk_liquid-0.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:466824ad3124ef22262ccc5ce76f5cedefd4a2540bb0cd0408e9b2f4e67ac58a", size = 10743378, upload-time = "2025-12-01T16:17:02.784Z" }, + { url = "https://files.pythonhosted.org/packages/90/6d/41eb4a4e9acfe924695151ffd863d84e5045b1de95858cadf5e66e8090f8/breez_sdk_liquid-0.11.13-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:b690f2a1aa7ac4ab2cfd043888f1c31c5c3002e868416b5b589f9206175f7944", size = 24586256, upload-time = "2026-01-30T11:43:20.14Z" }, + { url = "https://files.pythonhosted.org/packages/dd/49/5851d590d74f774146bc7e26b24a206515e5ad90744dd56c87d6a7039c6c/breez_sdk_liquid-0.11.13-cp310-cp310-manylinux_2_31_aarch64.whl", hash = "sha256:147c4d3c78417dc73afca419e2edc2a32cd8d849de1861932c391591485a349d", size = 16469712, upload-time = "2026-01-30T11:43:23.105Z" }, + { url = "https://files.pythonhosted.org/packages/53/56/e41ec173649176f05baff3454e855763fcc97852006daa36ca2dfdeca520/breez_sdk_liquid-0.11.13-cp310-cp310-manylinux_2_31_x86_64.whl", hash = "sha256:3b2cebfeb31ffa32772d43976dfb613167cfcf989efb0af9f62ddec6a6766ea5", size = 15640924, upload-time = "2026-01-30T11:43:25.794Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/582553a246484566408d3a0fcff8fb7574325666c7892b4a0738cccc4fff/breez_sdk_liquid-0.11.13-cp310-cp310-win32.whl", hash = "sha256:fb6dca31b259b13bcfd03c22600bc2d9496e40d55711a0261c67550f6931ade5", size = 10082789, upload-time = "2026-01-30T11:43:27.698Z" }, + { url = "https://files.pythonhosted.org/packages/39/42/f145bfcab6405334832833e1a9406c4ed9ec3965cd191a644738428333c0/breez_sdk_liquid-0.11.13-cp310-cp310-win_amd64.whl", hash = "sha256:155f24800e9b393b77f9db74d9ba4772e318765d82c844ce99267b31ec2752b6", size = 10603898, upload-time = "2026-01-30T11:43:30.045Z" }, + { url = "https://files.pythonhosted.org/packages/df/40/9ac9c71fce5465f38d1e773d0833817ef1346cfb3b1e44d35c9e3f212053/breez_sdk_liquid-0.11.13-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:bf6cb7121218fdd04d7ff5e6038b4b3a3dcd444ee5bfe089c05b7211fd3d8fb1", size = 24586256, upload-time = "2026-01-30T11:43:31.925Z" }, + { url = "https://files.pythonhosted.org/packages/66/b3/445b139db0ea08753eda4e9a33c4b4e1f2ce2c9b64a4ff8b51bfb0429b14/breez_sdk_liquid-0.11.13-cp311-cp311-manylinux_2_31_aarch64.whl", hash = "sha256:892e07b6c1bfcc4e4e64e13d71699d5bd22ea2214502eef35c5ec4efa8cc67d2", size = 16469712, upload-time = "2026-01-30T11:43:34.462Z" }, + { url = "https://files.pythonhosted.org/packages/a4/f9/14e833807b10820dce5fc02b6e1599192ff9f6cd29d0dae7e653cd689254/breez_sdk_liquid-0.11.13-cp311-cp311-manylinux_2_31_x86_64.whl", hash = "sha256:727b7f00b5626d2373e81463b51accce5b81e64d6a6fff4fc2ce98a18ba80d0d", size = 15640924, upload-time = "2026-01-30T11:43:36.769Z" }, + { url = "https://files.pythonhosted.org/packages/19/bf/44620f8bcb72ce5b5e0b9494580491c41b684187726bdc8988452b4217f4/breez_sdk_liquid-0.11.13-cp311-cp311-win32.whl", hash = "sha256:7f3956e2e54514c52ec43d60c9212a0045805c172d1fc2898e9cc7529aa8b391", size = 10082791, upload-time = "2026-01-30T11:43:38.525Z" }, + { url = "https://files.pythonhosted.org/packages/41/12/aaa236fae0428803bc4468f632622f745f4255821bd278129d8a134b0e54/breez_sdk_liquid-0.11.13-cp311-cp311-win_amd64.whl", hash = "sha256:c8cc01ccb67e6946033c1fcb59d4eeef7fe5255471abae42923dc13a8cc2b64a", size = 10603898, upload-time = "2026-01-30T11:43:41.712Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e7/306d92e98178b82fc854db45cda0e73f61b4163c38b19aa79af173d05a7c/breez_sdk_liquid-0.11.13-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:71d7ef6a1f968afe11097f4ac3cf6e36f0aa5f808305141140b2aa6ab9002eb3", size = 24586295, upload-time = "2026-01-30T11:43:43.932Z" }, + { url = "https://files.pythonhosted.org/packages/9d/16/684643336df5abbce1e0ae78f9d056799222bc19840d55667ecff0e86a69/breez_sdk_liquid-0.11.13-cp312-cp312-manylinux_2_31_aarch64.whl", hash = "sha256:dee2f7ef481ee4989676e4833886f4d893bc5095f96bca0ef58d9954d5a28ce5", size = 16469714, upload-time = "2026-01-30T11:43:45.97Z" }, + { url = "https://files.pythonhosted.org/packages/ed/90/50cf5868a9d311a2fca31f4866b2c95ca1e8dce14f006687efc3f1c8eee5/breez_sdk_liquid-0.11.13-cp312-cp312-manylinux_2_31_x86_64.whl", hash = "sha256:633c34e2dd4135a9ca029486da3670796c7011818bde8e0c996fcfb37ab42512", size = 15640926, upload-time = "2026-01-30T11:43:48.201Z" }, + { url = "https://files.pythonhosted.org/packages/74/15/65f52eee520b930fec072509a288e0c0b5e915691ee7c2da8cf62b46077e/breez_sdk_liquid-0.11.13-cp312-cp312-win32.whl", hash = "sha256:d48e0597b8e20f0c2d33715929ee782a8de7b0ffbccb7820137d7d0d30159be0", size = 10082791, upload-time = "2026-01-30T11:43:50.251Z" }, + { url = "https://files.pythonhosted.org/packages/83/69/acc6af159b34e4e308ce33c5593ff2e995fdc8e1f32ebb83e5c5603185ff/breez_sdk_liquid-0.11.13-cp312-cp312-win_amd64.whl", hash = "sha256:452e0dbc495797d9bbbd4b002816c4ad55eb22d6b6a5a296fdf371238aeb3157", size = 10603899, upload-time = "2026-01-30T11:43:52.49Z" }, ] [[package]] name = "certifi" -version = "2025.8.3" +version = "2026.5.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, ] [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser" }, + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +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/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, ] [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.3" +version = "3.4.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", size = 207695, upload-time = "2025-08-09T07:55:36.452Z" }, - { url = "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", size = 147153, upload-time = "2025-08-09T07:55:38.467Z" }, - { url = "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", size = 160428, upload-time = "2025-08-09T07:55:40.072Z" }, - { url = "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", size = 157627, upload-time = "2025-08-09T07:55:41.706Z" }, - { url = "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", size = 152388, upload-time = "2025-08-09T07:55:43.262Z" }, - { url = "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", size = 150077, upload-time = "2025-08-09T07:55:44.903Z" }, - { url = "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", size = 161631, upload-time = "2025-08-09T07:55:46.346Z" }, - { url = "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", size = 159210, upload-time = "2025-08-09T07:55:47.539Z" }, - { url = "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", size = 153739, upload-time = "2025-08-09T07:55:48.744Z" }, - { url = "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", size = 99825, upload-time = "2025-08-09T07:55:50.305Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", size = 107452, upload-time = "2025-08-09T07:55:51.461Z" }, - { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, - { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, - { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, - { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, - { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, - { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, - { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, - { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, - { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, - { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, - { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, - { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, - { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, - { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, - { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, - { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, - { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, - { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, - { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, + { url = "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d", size = 315182, upload-time = "2026-04-02T09:25:40.673Z" }, + { url = "https://files.pythonhosted.org/packages/24/47/b192933e94b546f1b1fe4df9cc1f84fcdbf2359f8d1081d46dd029b50207/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8", size = 209329, upload-time = "2026-04-02T09:25:42.354Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b4/01fa81c5ca6141024d89a8fc15968002b71da7f825dd14113207113fabbd/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790", size = 231230, upload-time = "2026-04-02T09:25:44.281Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/7b991776844dfa058017e600e6e55ff01984a063290ca5622c0b63162f68/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc", size = 225890, upload-time = "2026-04-02T09:25:45.475Z" }, + { url = "https://files.pythonhosted.org/packages/20/e7/bed0024a0f4ab0c8a9c64d4445f39b30c99bd1acd228291959e3de664247/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393", size = 216930, upload-time = "2026-04-02T09:25:46.58Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ab/b18f0ab31cdd7b3ddb8bb76c4a414aeb8160c9810fdf1bc62f269a539d87/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153", size = 202109, upload-time = "2026-04-02T09:25:48.031Z" }, + { url = "https://files.pythonhosted.org/packages/82/e5/7e9440768a06dfb3075936490cb82dbf0ee20a133bf0dd8551fa096914ec/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af", size = 214684, upload-time = "2026-04-02T09:25:49.245Z" }, + { url = "https://files.pythonhosted.org/packages/71/94/8c61d8da9f062fdf457c80acfa25060ec22bf1d34bbeaca4350f13bcfd07/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34", size = 212785, upload-time = "2026-04-02T09:25:50.671Z" }, + { url = "https://files.pythonhosted.org/packages/66/cd/6e9889c648e72c0ab2e5967528bb83508f354d706637bc7097190c874e13/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1", size = 203055, upload-time = "2026-04-02T09:25:51.802Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/7a951d6a08aefb7eb8e1b54cdfb580b1365afdd9dd484dc4bee9e5d8f258/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752", size = 232502, upload-time = "2026-04-02T09:25:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/58/d5/abcf2d83bf8e0a1286df55cd0dc1d49af0da4282aa77e986df343e7de124/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53", size = 214295, upload-time = "2026-04-02T09:25:54.765Z" }, + { url = "https://files.pythonhosted.org/packages/47/3a/7d4cd7ed54be99973a0dc176032cba5cb1f258082c31fa6df35cff46acfc/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616", size = 227145, upload-time = "2026-04-02T09:25:55.904Z" }, + { url = "https://files.pythonhosted.org/packages/1d/98/3a45bf8247889cf28262ebd3d0872edff11565b2a1e3064ccb132db3fbb0/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a", size = 218884, upload-time = "2026-04-02T09:25:57.074Z" }, + { url = "https://files.pythonhosted.org/packages/ad/80/2e8b7f8915ed5c9ef13aa828d82738e33888c485b65ebf744d615040c7ea/charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374", size = 148343, upload-time = "2026-04-02T09:25:58.199Z" }, + { url = "https://files.pythonhosted.org/packages/35/1b/3b8c8c77184af465ee9ad88b5aea46ea6b2e1f7b9dc9502891e37af21e30/charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943", size = 159174, upload-time = "2026-04-02T09:25:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/feb40dca40dbb21e0a908801782d9288c64fc8d8e562c2098e9994c8c21b/charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008", size = 147805, upload-time = "2026-04-02T09:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] name = "click" -version = "8.3.1" +version = "8.3.3" 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" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/63/f9e1ea081ce35720d8b92acde70daaedace594dc93b693c869e0d5910718/click-8.3.3.tar.gz", hash = "sha256:398329ad4837b2ff7cbe1dd166a4c0f8900c3ca3a218de04466f38f6497f18a2", size = 328061, upload-time = "2026-04-22T15:11:27.506Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl", hash = "sha256:a2bf429bb3033c89fa4936ffb35d5cb471e3719e1f3c8a7c3fff0b8314305613", size = 110502, upload-time = "2026-04-22T15:11:25.044Z" }, ] [[package]] @@ -595,49 +630,55 @@ wheels = [ [[package]] name = "coverage" -version = "7.11.0" +version = "7.14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/38/ee22495420457259d2f3390309505ea98f98a5eed40901cf62196abad006/coverage-7.11.0.tar.gz", hash = "sha256:167bd504ac1ca2af7ff3b81d245dfea0292c5032ebef9d66cc08a7d28c1b8050", size = 811905, upload-time = "2025-10-15T15:15:08.542Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/fd/0ab2772530e946e1be1abd0bc09e647ec9b02e88f0867857601fefca8953/coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be", size = 920132, upload-time = "2026-05-26T20:41:36.783Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/95/c49df0aceb5507a80b9fe5172d3d39bf23f05be40c23c8d77d556df96cec/coverage-7.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eb53f1e8adeeb2e78962bade0c08bfdc461853c7969706ed901821e009b35e31", size = 215800, upload-time = "2025-10-15T15:12:19.824Z" }, - { url = "https://files.pythonhosted.org/packages/dc/c6/7bb46ce01ed634fff1d7bb53a54049f539971862cc388b304ff3c51b4f66/coverage-7.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9a03ec6cb9f40a5c360f138b88266fd8f58408d71e89f536b4f91d85721d075", size = 216198, upload-time = "2025-10-15T15:12:22.549Z" }, - { url = "https://files.pythonhosted.org/packages/94/b2/75d9d8fbf2900268aca5de29cd0a0fe671b0f69ef88be16767cc3c828b85/coverage-7.11.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0d7f0616c557cbc3d1c2090334eddcbb70e1ae3a40b07222d62b3aa47f608fab", size = 242953, upload-time = "2025-10-15T15:12:24.139Z" }, - { url = "https://files.pythonhosted.org/packages/65/ac/acaa984c18f440170525a8743eb4b6c960ace2dbad80dc22056a437fc3c6/coverage-7.11.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e44a86a47bbdf83b0a3ea4d7df5410d6b1a0de984fbd805fa5101f3624b9abe0", size = 244766, upload-time = "2025-10-15T15:12:25.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/0d/938d0bff76dfa4a6b228c3fc4b3e1c0e2ad4aa6200c141fcda2bd1170227/coverage-7.11.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:596763d2f9a0ee7eec6e643e29660def2eef297e1de0d334c78c08706f1cb785", size = 246625, upload-time = "2025-10-15T15:12:27.387Z" }, - { url = "https://files.pythonhosted.org/packages/38/54/8f5f5e84bfa268df98f46b2cb396b1009734cfb1e5d6adb663d284893b32/coverage-7.11.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef55537ff511b5e0a43edb4c50a7bf7ba1c3eea20b4f49b1490f1e8e0e42c591", size = 243568, upload-time = "2025-10-15T15:12:28.799Z" }, - { url = "https://files.pythonhosted.org/packages/68/30/8ba337c2877fe3f2e1af0ed7ff4be0c0c4aca44d6f4007040f3ca2255e99/coverage-7.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cbabd8f4d0d3dc571d77ae5bdbfa6afe5061e679a9d74b6797c48d143307088", size = 244665, upload-time = "2025-10-15T15:12:30.297Z" }, - { url = "https://files.pythonhosted.org/packages/cc/fb/c6f1d6d9a665536b7dde2333346f0cc41dc6a60bd1ffc10cd5c33e7eb000/coverage-7.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e24045453384e0ae2a587d562df2a04d852672eb63051d16096d3f08aa4c7c2f", size = 242681, upload-time = "2025-10-15T15:12:32.326Z" }, - { url = "https://files.pythonhosted.org/packages/be/38/1b532319af5f991fa153c20373291dc65c2bf532af7dbcffdeef745c8f79/coverage-7.11.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:7161edd3426c8d19bdccde7d49e6f27f748f3c31cc350c5de7c633fea445d866", size = 242912, upload-time = "2025-10-15T15:12:34.079Z" }, - { url = "https://files.pythonhosted.org/packages/67/3d/f39331c60ef6050d2a861dc1b514fa78f85f792820b68e8c04196ad733d6/coverage-7.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d4ed4de17e692ba6415b0587bc7f12bc80915031fc9db46a23ce70fc88c9841", size = 243559, upload-time = "2025-10-15T15:12:35.809Z" }, - { url = "https://files.pythonhosted.org/packages/4b/55/cb7c9df9d0495036ce582a8a2958d50c23cd73f84a23284bc23bd4711a6f/coverage-7.11.0-cp310-cp310-win32.whl", hash = "sha256:765c0bc8fe46f48e341ef737c91c715bd2a53a12792592296a095f0c237e09cf", size = 218266, upload-time = "2025-10-15T15:12:37.429Z" }, - { url = "https://files.pythonhosted.org/packages/68/a8/b79cb275fa7bd0208767f89d57a1b5f6ba830813875738599741b97c2e04/coverage-7.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:24d6f3128f1b2d20d84b24f4074475457faedc3d4613a7e66b5e769939c7d969", size = 219169, upload-time = "2025-10-15T15:12:39.25Z" }, - { url = "https://files.pythonhosted.org/packages/49/3a/ee1074c15c408ddddddb1db7dd904f6b81bc524e01f5a1c5920e13dbde23/coverage-7.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d58ecaa865c5b9fa56e35efc51d1014d4c0d22838815b9fce57a27dd9576847", size = 215912, upload-time = "2025-10-15T15:12:40.665Z" }, - { url = "https://files.pythonhosted.org/packages/70/c4/9f44bebe5cb15f31608597b037d78799cc5f450044465bcd1ae8cb222fe1/coverage-7.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b679e171f1c104a5668550ada700e3c4937110dbdd153b7ef9055c4f1a1ee3cc", size = 216310, upload-time = "2025-10-15T15:12:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/42/01/5e06077cfef92d8af926bdd86b84fb28bf9bc6ad27343d68be9b501d89f2/coverage-7.11.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca61691ba8c5b6797deb221a0d09d7470364733ea9c69425a640f1f01b7c5bf0", size = 246706, upload-time = "2025-10-15T15:12:44.001Z" }, - { url = "https://files.pythonhosted.org/packages/40/b8/7a3f1f33b35cc4a6c37e759137533119560d06c0cc14753d1a803be0cd4a/coverage-7.11.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aef1747ede4bd8ca9cfc04cc3011516500c6891f1b33a94add3253f6f876b7b7", size = 248634, upload-time = "2025-10-15T15:12:45.768Z" }, - { url = "https://files.pythonhosted.org/packages/7a/41/7f987eb33de386bc4c665ab0bf98d15fcf203369d6aacae74f5dd8ec489a/coverage-7.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1839d08406e4cba2953dcc0ffb312252f14d7c4c96919f70167611f4dee2623", size = 250741, upload-time = "2025-10-15T15:12:47.222Z" }, - { url = "https://files.pythonhosted.org/packages/23/c1/a4e0ca6a4e83069fb8216b49b30a7352061ca0cb38654bd2dc96b7b3b7da/coverage-7.11.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e0eb0a2dcc62478eb5b4cbb80b97bdee852d7e280b90e81f11b407d0b81c4287", size = 246837, upload-time = "2025-10-15T15:12:48.904Z" }, - { url = "https://files.pythonhosted.org/packages/5d/03/ced062a17f7c38b4728ff76c3acb40d8465634b20b4833cdb3cc3a74e115/coverage-7.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fbea96343b53f65d5351d8fd3b34fd415a2670d7c300b06d3e14a5af4f552", size = 248429, upload-time = "2025-10-15T15:12:50.73Z" }, - { url = "https://files.pythonhosted.org/packages/97/af/a7c6f194bb8c5a2705ae019036b8fe7f49ea818d638eedb15fdb7bed227c/coverage-7.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:214b622259dd0cf435f10241f1333d32caa64dbc27f8790ab693428a141723de", size = 246490, upload-time = "2025-10-15T15:12:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/ab/c3/aab4df02b04a8fde79068c3c41ad7a622b0ef2b12e1ed154da986a727c3f/coverage-7.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:258d9967520cca899695d4eb7ea38be03f06951d6ca2f21fb48b1235f791e601", size = 246208, upload-time = "2025-10-15T15:12:54.586Z" }, - { url = "https://files.pythonhosted.org/packages/30/d8/e282ec19cd658238d60ed404f99ef2e45eed52e81b866ab1518c0d4163cf/coverage-7.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cf9e6ff4ca908ca15c157c409d608da77a56a09877b97c889b98fb2c32b6465e", size = 247126, upload-time = "2025-10-15T15:12:56.485Z" }, - { url = "https://files.pythonhosted.org/packages/d1/17/a635fa07fac23adb1a5451ec756216768c2767efaed2e4331710342a3399/coverage-7.11.0-cp311-cp311-win32.whl", hash = "sha256:fcc15fc462707b0680cff6242c48625da7f9a16a28a41bb8fd7a4280920e676c", size = 218314, upload-time = "2025-10-15T15:12:58.365Z" }, - { url = "https://files.pythonhosted.org/packages/2a/29/2ac1dfcdd4ab9a70026edc8d715ece9b4be9a1653075c658ee6f271f394d/coverage-7.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:865965bf955d92790f1facd64fe7ff73551bd2c1e7e6b26443934e9701ba30b9", size = 219203, upload-time = "2025-10-15T15:12:59.902Z" }, - { url = "https://files.pythonhosted.org/packages/03/21/5ce8b3a0133179115af4c041abf2ee652395837cb896614beb8ce8ddcfd9/coverage-7.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:5693e57a065760dcbeb292d60cc4d0231a6d4b6b6f6a3191561e1d5e8820b745", size = 217879, upload-time = "2025-10-15T15:13:01.35Z" }, - { url = "https://files.pythonhosted.org/packages/c4/db/86f6906a7c7edc1a52b2c6682d6dd9be775d73c0dfe2b84f8923dfea5784/coverage-7.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9c49e77811cf9d024b95faf86c3f059b11c0c9be0b0d61bc598f453703bd6fd1", size = 216098, upload-time = "2025-10-15T15:13:02.916Z" }, - { url = "https://files.pythonhosted.org/packages/21/54/e7b26157048c7ba555596aad8569ff903d6cd67867d41b75287323678ede/coverage-7.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a61e37a403a778e2cda2a6a39abcc895f1d984071942a41074b5c7ee31642007", size = 216331, upload-time = "2025-10-15T15:13:04.403Z" }, - { url = "https://files.pythonhosted.org/packages/b9/19/1ce6bf444f858b83a733171306134a0544eaddf1ca8851ede6540a55b2ad/coverage-7.11.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c79cae102bb3b1801e2ef1511fb50e91ec83a1ce466b2c7c25010d884336de46", size = 247825, upload-time = "2025-10-15T15:13:05.92Z" }, - { url = "https://files.pythonhosted.org/packages/71/0b/d3bcbbc259fcced5fb67c5d78f6e7ee965f49760c14afd931e9e663a83b2/coverage-7.11.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:16ce17ceb5d211f320b62df002fa7016b7442ea0fd260c11cec8ce7730954893", size = 250573, upload-time = "2025-10-15T15:13:07.471Z" }, - { url = "https://files.pythonhosted.org/packages/58/8d/b0ff3641a320abb047258d36ed1c21d16be33beed4152628331a1baf3365/coverage-7.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80027673e9d0bd6aef86134b0771845e2da85755cf686e7c7c59566cf5a89115", size = 251706, upload-time = "2025-10-15T15:13:09.4Z" }, - { url = "https://files.pythonhosted.org/packages/59/c8/5a586fe8c7b0458053d9c687f5cff515a74b66c85931f7fe17a1c958b4ac/coverage-7.11.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d3ffa07a08657306cd2215b0da53761c4d73cb54d9143b9303a6481ec0cd415", size = 248221, upload-time = "2025-10-15T15:13:10.964Z" }, - { url = "https://files.pythonhosted.org/packages/d0/ff/3a25e3132804ba44cfa9a778cdf2b73dbbe63ef4b0945e39602fc896ba52/coverage-7.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a3b6a5f8b2524fd6c1066bc85bfd97e78709bb5e37b5b94911a6506b65f47186", size = 249624, upload-time = "2025-10-15T15:13:12.5Z" }, - { url = "https://files.pythonhosted.org/packages/c5/12/ff10c8ce3895e1b17a73485ea79ebc1896a9e466a9d0f4aef63e0d17b718/coverage-7.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fcc0a4aa589de34bc56e1a80a740ee0f8c47611bdfb28cd1849de60660f3799d", size = 247744, upload-time = "2025-10-15T15:13:14.554Z" }, - { url = "https://files.pythonhosted.org/packages/16/02/d500b91f5471b2975947e0629b8980e5e90786fe316b6d7299852c1d793d/coverage-7.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dba82204769d78c3fd31b35c3d5f46e06511936c5019c39f98320e05b08f794d", size = 247325, upload-time = "2025-10-15T15:13:16.438Z" }, - { url = "https://files.pythonhosted.org/packages/77/11/dee0284fbbd9cd64cfce806b827452c6df3f100d9e66188e82dfe771d4af/coverage-7.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:81b335f03ba67309a95210caf3eb43bd6fe75a4e22ba653ef97b4696c56c7ec2", size = 249180, upload-time = "2025-10-15T15:13:17.959Z" }, - { url = "https://files.pythonhosted.org/packages/59/1b/cdf1def928f0a150a057cab03286774e73e29c2395f0d30ce3d9e9f8e697/coverage-7.11.0-cp312-cp312-win32.whl", hash = "sha256:037b2d064c2f8cc8716fe4d39cb705779af3fbf1ba318dc96a1af858888c7bb5", size = 218479, upload-time = "2025-10-15T15:13:19.608Z" }, - { url = "https://files.pythonhosted.org/packages/ff/55/e5884d55e031da9c15b94b90a23beccc9d6beee65e9835cd6da0a79e4f3a/coverage-7.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:d66c0104aec3b75e5fd897e7940188ea1892ca1d0235316bf89286d6a22568c0", size = 219290, upload-time = "2025-10-15T15:13:21.593Z" }, - { url = "https://files.pythonhosted.org/packages/23/a8/faa930cfc71c1d16bc78f9a19bb73700464f9c331d9e547bfbc1dbd3a108/coverage-7.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:d91ebeac603812a09cf6a886ba6e464f3bbb367411904ae3790dfe28311b15ad", size = 217924, upload-time = "2025-10-15T15:13:23.39Z" }, - { url = "https://files.pythonhosted.org/packages/5f/04/642c1d8a448ae5ea1369eac8495740a79eb4e581a9fb0cbdce56bbf56da1/coverage-7.11.0-py3-none-any.whl", hash = "sha256:4b7589765348d78fb4e5fb6ea35d07564e387da2fc5efff62e0222971f155f68", size = 207761, upload-time = "2025-10-15T15:15:06.439Z" }, + { url = "https://files.pythonhosted.org/packages/92/69/0d2ef01ff4b8fcecd4cba920d11e92fa4f96ae412441d3b56a90a258e69b/coverage-7.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e3680291c4a1d0dadfa84a2c459576a4af5133abb617905714339a0c73138cf", size = 219722, upload-time = "2026-05-26T20:38:14.002Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ae/9afdeaa31b9d9ce98124b6abf8bb49119bf71aecae04f8567c189d91299f/coverage-7.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5274669f37f2343635a347b91a60777621341ab3378e9c6ac9335eee704bddf", size = 220240, upload-time = "2026-05-26T20:38:17.424Z" }, + { url = "https://files.pythonhosted.org/packages/51/69/c998589871df7ea7dba865cc5ee32b5a3e1d47ba6c68ef91104c7c46fa5e/coverage-7.14.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfe5a5fec635799ef33428f1e5e61bafa45a92a96190ba731561ba558ccc214d", size = 246981, upload-time = "2026-05-26T20:38:19.266Z" }, + { url = "https://files.pythonhosted.org/packages/fc/10/1c7d04c13040dac531d21b712bbe08f902e6dd9b58f5d77875c4d030f8f2/coverage-7.14.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:62a9f70b52e0b5a95cfef4a5c5641b06983cadc5e538a3feeb5c00211f523ac2", size = 248812, upload-time = "2026-05-26T20:38:20.75Z" }, + { url = "https://files.pythonhosted.org/packages/c1/65/2a38a4607ef27cadcfbcee034dba5830ae2569f90144a0f4c7dbf47d30b0/coverage-7.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c18ebc343e15be53049b3a2dce38fe82d58f37e20ab9094b3a39c0aa4f6bb47", size = 250675, upload-time = "2026-05-26T20:38:22.159Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a2/a446ed9752a4a59b79e0fb6cbb319f6facb2183045c0725462625e66f87e/coverage-7.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b84ffdf877644e7096aa936991efeed873f7f3df57b9cd001312b7668ab08550", size = 252590, upload-time = "2026-05-26T20:38:23.63Z" }, + { url = "https://files.pythonhosted.org/packages/9e/fd/e81fbd7ba752365546e9842b1cbdaad3d6919d2a522c590aef16a281ec5e/coverage-7.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e854312c4103f2ad4c0dc023b69b77ebfd2c89db5f86c4c94dc2353f9a92167e", size = 247691, upload-time = "2026-05-26T20:38:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/53/35/f3c26fdaae9ea937d154ca4d372e5ea0a4167ff70d36c6074ac2eacb2f83/coverage-7.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c643734307300234fafa36bf2a040a7235f8f177ea1fd6ec1423aea6fb7b929f", size = 248716, upload-time = "2026-05-26T20:38:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/2e/14/940b6c49551fd343e8507ee2b0ba7af5d0aa04ed5bf768285cb7c72a9884/coverage-7.14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84ac9499e48700399a5dd0ea7085b5091961fec52c68d66b4ec0d3cf7f4441b1", size = 246721, upload-time = "2026-05-26T20:38:28.282Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2c/40fc0634186c28292a662dff578866b3913983d6c375a3c2a74020938719/coverage-7.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7f02d09f70776579b926d889a4c9c235070a1f47c40458aeaca563fae5acfdb5", size = 250533, upload-time = "2026-05-26T20:38:29.753Z" }, + { url = "https://files.pythonhosted.org/packages/de/e3/2c26bf1e811f9df991ff2a9bdddebdd13ee0665d564df7d05979f9146297/coverage-7.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ce66d8e46da2bb5ee313a745cbd2e391d319176c1f7a9451bfcd3a2fb920859b", size = 246990, upload-time = "2026-05-26T20:38:31.516Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b0/060260ef56bd92363ebdce0c7095ce422b06e69aae71828efeca473ab1ca/coverage-7.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c912c259304cfb5ee584481cfb7ce1ff932b4d61e6c9140b8f19cb7b5ed82332", size = 247593, upload-time = "2026-05-26T20:38:33.065Z" }, + { url = "https://files.pythonhosted.org/packages/63/f3/501502046efeb0d6d94b5ca54941d95f1184183dd6bdb7f283985783bb4a/coverage-7.14.1-cp310-cp310-win32.whl", hash = "sha256:1238cb94638e610e972c60dac68e813f868dc7d6e982535270558443058d9d59", size = 222330, upload-time = "2026-05-26T20:38:35.36Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5d/1bf99f2c558f128faf7906817ccbdb576ba815d3b41ce2ac1719b70a3663/coverage-7.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:fc459e5d73be2d6332fcfe8dbf3d8994671fe33c700f4565988ecfa511547253", size = 223261, upload-time = "2026-05-26T20:38:37.196Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d7/477ad149490e6cb849f28abea1dabb9c823cea72e7500c81b4240ce619c0/coverage-7.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:478b5bcd63c2e1357c5c7e16c070690df7b07f676b1c114d7b93e533c664309f", size = 219848, upload-time = "2026-05-26T20:38:38.715Z" }, + { url = "https://files.pythonhosted.org/packages/91/82/a5eb47257c50601bb7b9a9d2857c67b7a3a85ad74180eb2c98bb1fbe0ce5/coverage-7.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a24a81f9715ee42ef59a316cc11611c98fe23920f7c81861315c9f3ff4a230f4", size = 220354, upload-time = "2026-05-26T20:38:40.232Z" }, + { url = "https://files.pythonhosted.org/packages/43/8b/78419b5391a5cb706b6544390507e469d83ffc9a8248b02c4011aceb9365/coverage-7.14.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:196a13319ad88d6d8ef5ab489ec4f44ddde2143c0c7d5b27786f6c3ffd56a7e1", size = 250771, upload-time = "2026-05-26T20:38:41.782Z" }, + { url = "https://files.pythonhosted.org/packages/77/63/e77aaacd491182210d639636b7a8bba23ffffa9b82aa3762da9431855fa9/coverage-7.14.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d452fd08b5c72c5167c93e6867b5c08500bd40f2a21e1e854a500550b6cc36f", size = 252683, upload-time = "2026-05-26T20:38:43.305Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/a022e3cfbec2ac241640003cb3a817e161d9c7f5aa9b49173756cdc03204/coverage-7.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23bf7fa51ac02e07fc7c96849b82946da47ae862dc8f86d183b2a4864fc38129", size = 254791, upload-time = "2026-05-26T20:38:45.361Z" }, + { url = "https://files.pythonhosted.org/packages/61/d6/967e408aca4c1ceb88cb0cc677169110ae7f5995fb5eaf5fb1f5a1bb8f5d/coverage-7.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcaa50684dcaadfa599ac48f81103c756d791cfd85c97203d2217c593d48b860", size = 256748, upload-time = "2026-05-26T20:38:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/b8/be/869188f7fe28638078ec479331ace6dc5f7b40b7153eb616f47ab79404d8/coverage-7.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ea1c034f95c9b056e856b794630b17f9fa3d57e4800ff1e503d3be0f9c9078c", size = 250907, upload-time = "2026-05-26T20:38:48.493Z" }, + { url = "https://files.pythonhosted.org/packages/07/aa/adb7d3b4278d690e68703abcd76ab1b948242e3668d921711551b78f9ddb/coverage-7.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e057326434e441306226fbeb5d1aaf14a2637efe97ba668306635835f32ad7", size = 252483, upload-time = "2026-05-26T20:38:50.074Z" }, + { url = "https://files.pythonhosted.org/packages/43/61/331c74103c62dcb0c4b9b3a0de9a61aca016208b0a90f109592a9f9ecc28/coverage-7.14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59baf88468dbc8d63b1887afd92bda52e40bb1561696e5819670601403810cec", size = 250545, upload-time = "2026-05-26T20:38:51.613Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b6/c5dae3c104d89be04828f61810e6b3473825482e4c288cc4ed04553e08ae/coverage-7.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d75f892b3ab73ba11cab5442cce7b3e168fd64162b16f0e1e0d09c508edef", size = 254310, upload-time = "2026-05-26T20:38:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a1/2b9d5863e3b83c01ad8199e3c597802fbb3a9dc90b058885804c20296d31/coverage-7.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3a56abc20a472baf0304c455721bc601477440d28ecfde8a03dde79ede07e0df", size = 250266, upload-time = "2026-05-26T20:38:55.414Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5e/0e511fbdb269359be26fe678a1c3fa1f2aa2a01573cc3f54268c8d6d4797/coverage-7.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6a3cb83d1552c0cd1b4906655b6a33fd4a8473229633a901c6b73bf86914dee9", size = 251174, upload-time = "2026-05-26T20:38:57.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/10/e55307b622b3dd9671cb321824502dc10f93e72f2802b9946159a8edadeb/coverage-7.14.1-cp311-cp311-win32.whl", hash = "sha256:10274a1fbeb8ec5d72966e17bb198a3104257aca4ac09d98667c5f8aca8c8548", size = 222354, upload-time = "2026-05-26T20:38:58.727Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/107421693cfb71e4f1ca5bf70443f64d4161878068d07a3e51c7ad21d17b/coverage-7.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:87ebdf787d4888e3f3f2d523eadc6e18c6d18c6d0eb173801a189641627fb37e", size = 223290, upload-time = "2026-05-26T20:39:00.413Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1d/3e3644585eb29e9dafefb19555078529a4d7cce12bd21929664eea989277/coverage-7.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:dd34767fa19848d35659ffc0a75314f58c7af3f1cd87ec521e8292a1238398a3", size = 221953, upload-time = "2026-05-26T20:39:02.159Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b7/bdbb725ba02c5b42825b200c940f38b7a54fcad24627b7192f78f8110d76/coverage-7.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a06c76364a9360e33d6d23769aefdf7f66f38e2ffb60ceb1baaa4989d83b695c", size = 220022, upload-time = "2026-05-26T20:39:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/72/81/fdc0898a55c6219223291ec1a1fe89966ef212ce82276aa0899df84b5de0/coverage-7.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fad54e871165f6ec2f536063ac74c3104508a12963e64072ba44bd822de52b0c", size = 220379, upload-time = "2026-05-26T20:39:05.381Z" }, + { url = "https://files.pythonhosted.org/packages/de/72/de048c4a25e13bce59ac6a339351c10bdf2515e07459afcdaf04dc3143a2/coverage-7.14.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:84b535f00655ecafe1d929d1fb00ed5d6fa3051ea643ab2c161a3887b86f294b", size = 251888, upload-time = "2026-05-26T20:39:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/28/30/300c343f68beb9d4cbb64ec81e58c5b6b80b56927f72d2b38654ac26e013/coverage-7.14.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b6b0853b895fe0e98cbfc580d1ec3393d9302b4b1e96a77b3f5c91fdab899e6", size = 254624, upload-time = "2026-05-26T20:39:09.037Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ed/7b25642496e8170b6bac14adce00537c6e5fa2d586159401a4de3e8b49e6/coverage-7.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:442cc9c952b2df400cda54bb04ab87330cf2cd08a8692cbbea36773531eb6f37", size = 255739, upload-time = "2026-05-26T20:39:10.889Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a2/abd210b8c4e29c24e4624916db97bb519097a91034aaeb767f937e7da794/coverage-7.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8270544c361ed405a27a060dbc9ed2c124b084d96dfdc2d9a2510482aef981ad", size = 257998, upload-time = "2026-05-26T20:39:12.722Z" }, + { url = "https://files.pythonhosted.org/packages/7f/24/7c50beed3792fe62f6ce0545c6686ce83379719e2c0276179333d97eae92/coverage-7.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:48b283b1dd6372e8de2a7a9a4c4d5dc06f4d4fd209b876f3c88a7a205a0c8f84", size = 252296, upload-time = "2026-05-26T20:39:14.259Z" }, + { url = "https://files.pythonhosted.org/packages/15/05/0f874628ebcbfc77ead559ff210281ef06a97db08481832e7dd39274a135/coverage-7.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0c99ba93a07d56f6df340bb79be53202a082b2fdb81bfe6190b741a3470d54", size = 253658, upload-time = "2026-05-26T20:39:15.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/6f/ca6ad067364b337ef997802115e7ecad2abd2248b05471464b0dea02b4d4/coverage-7.14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e471bc5769ff073b058cfadb0d736b56ce067c8560eabeb0da88462df98c23e7", size = 251803, upload-time = "2026-05-26T20:39:17.537Z" }, + { url = "https://files.pythonhosted.org/packages/c0/30/b9b4d377cd9f40baf228068f5a81faf8450c6228503011bd499708483a50/coverage-7.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f497a1ea81d4cd7c10ddcaa685135b9aabd291af3d55775a9ddf3cb7a364cdd9", size = 255873, upload-time = "2026-05-26T20:39:19.414Z" }, + { url = "https://files.pythonhosted.org/packages/3c/21/7c721a9e5e6bb88547d30a787aefb97512d3f54c1324c7488d9b3743f7f9/coverage-7.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2222be86d0b54f5dd5a38f45f17f315f737245e857bf0bdedc70734f84a13c02", size = 251372, upload-time = "2026-05-26T20:39:21.169Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f8ae5a2200130e1503cd7661a6cd3b2b7bacef98277fbf3571fb13f8b766/coverage-7.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85e85586565842f6932abebd4c18bcb1074223dc0b3576e7d173ca710622813a", size = 253245, upload-time = "2026-05-26T20:39:23.097Z" }, + { url = "https://files.pythonhosted.org/packages/34/62/70a9024672a5f6910517d9628c52c9afbdd3cf8f46426af52bb148a56fff/coverage-7.14.1-cp312-cp312-win32.whl", hash = "sha256:4a28fd227808366b196a75476dced2eb35b351d6766ba9c858dc93319e87f4f1", size = 222567, upload-time = "2026-05-26T20:39:24.868Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/8b7cd386839b039ebe1855733b9f9449a8dec5d79564018234f185a7fa70/coverage-7.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:54acdb6674a4661768d7bf7db32dfb9f46ab1d764f8aba6df75ce1a6a088724e", size = 223372, upload-time = "2026-05-26T20:39:26.603Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ba/b44d472022f620d289d95fa830143235c0c36461c6f2437ea8d51e5481ed/coverage-7.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:99cd41ff91afd94896fea3bc002706b6ae4ce95727d06e4a0f39c0a8d8bd8b1a", size = 221989, upload-time = "2026-05-26T20:39:28.242Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3c/1a983b9a745d7f83d53f057bcc5bf79ba6a2bbc08266b3f0c7d6fe630c9b/coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2", size = 211815, upload-time = "2026-05-26T20:41:34.078Z" }, ] [package.optional-dependencies] @@ -647,55 +688,60 @@ toml = [ [[package]] name = "cryptography" -version = "44.0.1" +version = "48.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/67/545c79fe50f7af51dbad56d16b23fe33f63ee6a5d956b3cb68ea110cbe64/cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", size = 710819, upload-time = "2025-02-11T15:50:58.39Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/27/5e3524053b4c8889da65cf7814a9d0d8514a05194a25e1e34f46852ee6eb/cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009", size = 6642022, upload-time = "2025-02-11T15:49:32.752Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/4d1fa8d73ae6ec350012f89c3abfbff19fc95fe5420cf972e12a8d182986/cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", size = 3943865, upload-time = "2025-02-11T15:49:36.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/371a9f3f3a4500807b5fcd29fec77f418ba27ffc629d88597d0d1049696e/cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", size = 4162562, upload-time = "2025-02-11T15:49:39.541Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1d/5b77815e7d9cf1e3166988647f336f87d5634a5ccecec2ffbe08ef8dd481/cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", size = 3951923, upload-time = "2025-02-11T15:49:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/28/01/604508cd34a4024467cd4105887cf27da128cba3edd435b54e2395064bfb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", size = 3685194, upload-time = "2025-02-11T15:49:45.226Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3d/d3c55d4f1d24580a236a6753902ef6d8aafd04da942a1ee9efb9dc8fd0cb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", size = 4187790, upload-time = "2025-02-11T15:49:48.215Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a6/44d63950c8588bfa8594fd234d3d46e93c3841b8e84a066649c566afb972/cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", size = 3951343, upload-time = "2025-02-11T15:49:50.313Z" }, - { url = "https://files.pythonhosted.org/packages/c1/17/f5282661b57301204cbf188254c1a0267dbd8b18f76337f0a7ce1038888c/cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", size = 4187127, upload-time = "2025-02-11T15:49:52.051Z" }, - { url = "https://files.pythonhosted.org/packages/f3/68/abbae29ed4f9d96596687f3ceea8e233f65c9645fbbec68adb7c756bb85a/cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", size = 4070666, upload-time = "2025-02-11T15:49:56.56Z" }, - { url = "https://files.pythonhosted.org/packages/0f/10/cf91691064a9e0a88ae27e31779200b1505d3aee877dbe1e4e0d73b4f155/cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", size = 4288811, upload-time = "2025-02-11T15:49:59.248Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/74ea9eb547d13c34e984e07ec8a473eb55b19c1451fe7fc8077c6a4b0548/cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a", size = 2771882, upload-time = "2025-02-11T15:50:01.478Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/3907271ee485679e15c9f5e93eac6aa318f859b0aed8d369afd636fafa87/cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00", size = 3206989, upload-time = "2025-02-11T15:50:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f1/676e69c56a9be9fd1bffa9bc3492366901f6e1f8f4079428b05f1414e65c/cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008", size = 6643714, upload-time = "2025-02-11T15:50:05.555Z" }, - { url = "https://files.pythonhosted.org/packages/ba/9f/1775600eb69e72d8f9931a104120f2667107a0ee478f6ad4fe4001559345/cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", size = 3943269, upload-time = "2025-02-11T15:50:08.54Z" }, - { url = "https://files.pythonhosted.org/packages/25/ba/e00d5ad6b58183829615be7f11f55a7b6baa5a06910faabdc9961527ba44/cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", size = 4166461, upload-time = "2025-02-11T15:50:11.419Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/690a02c748d719a95ab08b6e4decb9d81e0ec1bac510358f61624c86e8a3/cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", size = 3950314, upload-time = "2025-02-11T15:50:14.181Z" }, - { url = "https://files.pythonhosted.org/packages/e6/50/bf8d090911347f9b75adc20f6f6569ed6ca9b9bff552e6e390f53c2a1233/cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", size = 3686675, upload-time = "2025-02-11T15:50:16.3Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e7/cfb18011821cc5f9b21efb3f94f3241e3a658d267a3bf3a0f45543858ed8/cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", size = 4190429, upload-time = "2025-02-11T15:50:19.302Z" }, - { url = "https://files.pythonhosted.org/packages/07/ef/77c74d94a8bfc1a8a47b3cafe54af3db537f081742ee7a8a9bd982b62774/cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", size = 3950039, upload-time = "2025-02-11T15:50:22.257Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b9/8be0ff57c4592382b77406269b1e15650c9f1a167f9e34941b8515b97159/cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", size = 4189713, upload-time = "2025-02-11T15:50:24.261Z" }, - { url = "https://files.pythonhosted.org/packages/78/e1/4b6ac5f4100545513b0847a4d276fe3c7ce0eacfa73e3b5ebd31776816ee/cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", size = 4071193, upload-time = "2025-02-11T15:50:26.18Z" }, - { url = "https://files.pythonhosted.org/packages/3d/cb/afff48ceaed15531eab70445abe500f07f8f96af2bb35d98af6bfa89ebd4/cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", size = 4289566, upload-time = "2025-02-11T15:50:28.221Z" }, - { url = "https://files.pythonhosted.org/packages/30/6f/4eca9e2e0f13ae459acd1ca7d9f0257ab86e68f44304847610afcb813dc9/cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9", size = 2772371, upload-time = "2025-02-11T15:50:29.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/05/5533d30f53f10239616a357f080892026db2d550a40c393d0a8a7af834a9/cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f", size = 3207303, upload-time = "2025-02-11T15:50:32.258Z" }, - { url = "https://files.pythonhosted.org/packages/15/06/507bfb5c7e048114a0185dd65f7814677a2ba285d15705c3d69e660c21d7/cryptography-44.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1f9a92144fa0c877117e9748c74501bea842f93d21ee00b0cf922846d9d0b183", size = 3380782, upload-time = "2025-02-11T15:50:33.94Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f1/7fb4982d59aa86e1a116c812b545e7fc045352be07738ae3fb278835a9a4/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12", size = 3888155, upload-time = "2025-02-11T15:50:36.584Z" }, - { url = "https://files.pythonhosted.org/packages/60/7b/cbc203838d3092203493d18b923fbbb1de64e0530b332a713ba376905b0b/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83", size = 4106417, upload-time = "2025-02-11T15:50:38.714Z" }, - { url = "https://files.pythonhosted.org/packages/12/c7/2fe59fb085ab418acc82e91e040a6acaa7b1696fcc1c1055317537fbf0d3/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420", size = 3887540, upload-time = "2025-02-11T15:50:40.546Z" }, - { url = "https://files.pythonhosted.org/packages/48/89/09fc7b115f60f5bd970b80e32244f8e9aeeb9244bf870b63420cec3b5cd5/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4", size = 4106040, upload-time = "2025-02-11T15:50:43.364Z" }, - { url = "https://files.pythonhosted.org/packages/2e/38/3fd83c4690dc7d753a442a284b3826ea5e5c380a411443c66421cd823898/cryptography-44.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d9c5b9f698a83c8bd71e0f4d3f9f839ef244798e5ffe96febfa9714717db7af7", size = 3134657, upload-time = "2025-02-11T15:50:47.6Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" }, + { url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" }, + { url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" }, + { url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" }, + { url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" }, + { url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" }, + { url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" }, + { url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" }, + { url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" }, + { url = "https://files.pythonhosted.org/packages/a9/d3/eb4e394e587341fdad09a09101fa76478ead3a78b0ad63e55c22f0d75c02/cryptography-48.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:08a597acce1ff37f347400087776599e2348a3a8bc53b44120e463cd274efe4a", size = 3951747, upload-time = "2026-06-09T22:31:23.871Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4a/3f43451b4f858bfceaaaffc649e6e787e8d4fb332a1d443af39ab02cc8f1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:735824ec41b7f74a7c45fb1591349333e4c696cb6c044e5f46356e560143e4cd", size = 4641226, upload-time = "2026-06-09T22:31:02.532Z" }, + { url = "https://files.pythonhosted.org/packages/73/4e/855584c2c23b09e4ce2d3b9c30e983e679cd60b068c513c6bbdb91e11782/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:92a46e1d638daa264ba2971c0b0489c9409787943efae4d60ffda3d091ef832c", size = 4668958, upload-time = "2026-06-09T22:32:06.213Z" }, + { url = "https://files.pythonhosted.org/packages/42/3b/d35750e41d803d1e516fd6d6011f065424924da7af1748cef4cc9cb3ede1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:7e234ac052af99f2700826a5c29ea99d9c1b1f80341cde62d11c8154dc8e0bd9", size = 4640793, upload-time = "2026-06-09T22:32:26.331Z" }, + { url = "https://files.pythonhosted.org/packages/ca/aa/cdb7181fe865285e87e96825aaab239400f1de0c3bfba9bd9769b79f1a92/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:33842cf0888951cef5bc7ac724ab844a42044c1727b967b7f8997289a0464f92", size = 4668505, upload-time = "2026-06-09T22:31:27.534Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8c/ce3823c06c2804f194f9e64f0d67fa3f4094a39f2bb1a990cd03603af8fc/cryptography-48.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6184ca7b174f28d7c703f1290d4b297217c45355f77a98f67e9b7f14549ac54a", size = 3742204, upload-time = "2026-06-09T22:31:34.773Z" }, ] [[package]] name = "deprecated" -version = "1.2.18" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744, upload-time = "2025-01-27T10:46:25.7Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998, upload-time = "2025-01-27T10:46:09.186Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] @@ -718,36 +764,24 @@ wheels = [ [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } +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/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "ecdsa" -version = "0.19.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/1f/924e3caae75f471eae4b26bd13b698f6af2c44279f67af317439c2f4c46a/ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61", size = 201793, upload-time = "2025-03-13T11:52:43.25Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a3/460c57f094a4a165c84a1341c373b0a4f5ec6ac244b998d5021aade89b77/ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", size = 150607, upload-time = "2025-03-13T11:52:41.757Z" }, + { 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 = "email-validator" -version = "2.2.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] [[package]] @@ -758,28 +792,28 @@ sdist = { url = "https://files.pythonhosted.org/packages/83/88/b054b00ade6d2a417 [[package]] name = "exceptiongroup" -version = "1.3.0" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +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/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, + { 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 = "fastapi" -version = "0.116.1" +version = "0.116.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/64/1296f46d6b9e3b23fb22e5d01af3f104ef411425531376212f1eefa2794d/fastapi-0.116.2.tar.gz", hash = "sha256:231a6af2fe21cfa2c32730170ad8514985fc250bec16c9b242d3b94c835ef529", size = 298595, upload-time = "2025-09-16T18:29:23.058Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, + { url = "https://files.pythonhosted.org/packages/32/e4/c543271a8018874b7f682bf6156863c416e1334b8ed3e51a69495c5d4360/fastapi-0.116.2-py3-none-any.whl", hash = "sha256:c3a7a8fb830b05f7e087d920e0d786ca1fc9892eb4e9a84b227be4c1bc7569db", size = 95670, upload-time = "2025-09-16T18:29:21.329Z" }, ] [[package]] @@ -800,11 +834,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.3" +version = "3.29.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, + { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, ] [[package]] @@ -818,94 +852,93 @@ wheels = [ [[package]] name = "frozenlist" -version = "1.7.0" +version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] [[package]] name = "greenlet" -version = "3.3.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" }, - { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" }, - { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" }, - { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" }, - { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" }, - { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" }, - { url = "https://files.pythonhosted.org/packages/1f/cb/48e964c452ca2b92175a9b2dca037a553036cb053ba69e284650ce755f13/greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e", size = 274908, upload-time = "2025-12-04T14:23:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/28/da/38d7bff4d0277b594ec557f479d65272a893f1f2a716cad91efeb8680953/greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62", size = 577113, upload-time = "2025-12-04T14:50:05.493Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f2/89c5eb0faddc3ff014f1c04467d67dee0d1d334ab81fadbf3744847f8a8a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32", size = 590338, upload-time = "2025-12-04T14:57:41.136Z" }, - { url = "https://files.pythonhosted.org/packages/80/d7/db0a5085035d05134f8c089643da2b44cc9b80647c39e93129c5ef170d8f/greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45", size = 601098, upload-time = "2025-12-04T15:07:11.898Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/e959a127b630a58e23529972dbc868c107f9d583b5a9f878fb858c46bc1a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948", size = 590206, upload-time = "2025-12-04T14:26:01.254Z" }, - { url = "https://files.pythonhosted.org/packages/48/60/29035719feb91798693023608447283b266b12efc576ed013dd9442364bb/greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794", size = 1550668, upload-time = "2025-12-04T15:04:22.439Z" }, - { url = "https://files.pythonhosted.org/packages/0a/5f/783a23754b691bfa86bd72c3033aa107490deac9b2ef190837b860996c9f/greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5", size = 1615483, upload-time = "2025-12-04T14:27:28.083Z" }, - { url = "https://files.pythonhosted.org/packages/1d/d5/c339b3b4bc8198b7caa4f2bd9fd685ac9f29795816d8db112da3d04175bb/greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71", size = 301164, upload-time = "2025-12-04T14:42:51.577Z" }, - { url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" }, - { url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" }, - { url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" }, - { url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" }, - { url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" }, - { url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" }, - { url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" }, - { url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" }, + { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747, upload-time = "2026-02-20T20:16:21.325Z" }, + { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202, upload-time = "2026-02-20T20:47:28.955Z" }, + { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620, upload-time = "2026-02-20T20:55:55.581Z" }, + { url = "https://files.pythonhosted.org/packages/03/5f/6e2a7d80c353587751ef3d44bb947f0565ec008a2e0927821c007e96d3a7/greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7", size = 602132, upload-time = "2026-02-20T21:02:43.261Z" }, + { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729, upload-time = "2026-02-20T20:20:58.395Z" }, + { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946, upload-time = "2026-02-20T20:49:31.102Z" }, + { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494, upload-time = "2026-02-20T20:21:06.541Z" }, + { url = "https://files.pythonhosted.org/packages/ac/78/f93e840cbaef8becaf6adafbaf1319682a6c2d8c1c20224267a5c6c8c891/greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f", size = 230092, upload-time = "2026-02-20T20:17:09.379Z" }, + { url = "https://files.pythonhosted.org/packages/f3/47/16400cb42d18d7a6bb46f0626852c1718612e35dcb0dffa16bbaffdf5dd2/greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86", size = 278890, upload-time = "2026-02-20T20:19:39.263Z" }, + { url = "https://files.pythonhosted.org/packages/a3/90/42762b77a5b6aa96cd8c0e80612663d39211e8ae8a6cd47c7f1249a66262/greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f", size = 581120, upload-time = "2026-02-20T20:47:30.161Z" }, + { url = "https://files.pythonhosted.org/packages/bf/6f/f3d64f4fa0a9c7b5c5b3c810ff1df614540d5aa7d519261b53fba55d4df9/greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55", size = 594363, upload-time = "2026-02-20T20:55:56.965Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8b/1430a04657735a3f23116c2e0d5eb10220928846e4537a938a41b350bed6/greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2", size = 605046, upload-time = "2026-02-20T21:02:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/72/83/3e06a52aca8128bdd4dcd67e932b809e76a96ab8c232a8b025b2850264c5/greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358", size = 594156, upload-time = "2026-02-20T20:20:59.955Z" }, + { url = "https://files.pythonhosted.org/packages/70/79/0de5e62b873e08fe3cef7dbe84e5c4bc0e8ed0c7ff131bccb8405cd107c8/greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99", size = 1554649, upload-time = "2026-02-20T20:49:32.293Z" }, + { url = "https://files.pythonhosted.org/packages/5a/00/32d30dee8389dc36d42170a9c66217757289e2afb0de59a3565260f38373/greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be", size = 1619472, upload-time = "2026-02-20T20:21:07.966Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3a/efb2cf697fbccdf75b24e2c18025e7dfa54c4f31fab75c51d0fe79942cef/greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5", size = 230389, upload-time = "2026-02-20T20:17:18.772Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a1/65bbc059a43a7e2143ec4fc1f9e3f673e04f9c7b371a494a101422ac4fd5/greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd", size = 229645, upload-time = "2026-02-20T20:18:18.695Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, + { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, + { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c5/cc09412a29e43406eba18d61c70baa936e299bc27e074e2be3806ed29098/greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb", size = 626250, upload-time = "2026-02-20T21:02:46.596Z" }, + { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, + { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, + { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/cc802e067d02af8b60b6771cea7d57e21ef5e6659912814babb42b864713/greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f", size = 231081, upload-time = "2026-02-20T20:17:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/58/2e/fe7f36ff1982d6b10a60d5e0740c759259a7d6d2e1dc41da6d96de32fff6/greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643", size = 230331, upload-time = "2026-02-20T20:17:23.34Z" }, ] [[package]] @@ -1039,22 +1072,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" }, ] +[package.optional-dependencies] +socks = [ + { name = "socksio" }, +] + [[package]] name = "identify" -version = "2.6.15" +version = "2.6.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, ] [[package]] name = "idna" -version = "3.10" +version = "3.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/88/bcf9709822fe69d02c2a6a77956c98ce6ea8ca8767a9aadcedc7eb6a2390/idna-3.16.tar.gz", hash = "sha256:d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d", size = 203770, upload-time = "2026-05-22T00:16:18.781Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, + { url = "https://files.pythonhosted.org/packages/94/16/70255075a9859a0e3adb789b68ceb0e210dec03934245fd98d248226572f/idna-3.16-py3-none-any.whl", hash = "sha256:cc246e3a3f89580c3a951b5ad298ca4638078b2cdd4f115654332b5c26daded5", size = 74165, upload-time = "2026-05-22T00:16:16.698Z" }, ] [[package]] @@ -1089,56 +1127,59 @@ wheels = [ [[package]] name = "jiter" -version = "0.11.1" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/68/0357982493a7b20925aece061f7fb7a2678e3b232f8d73a6edb7e5304443/jiter-0.11.1.tar.gz", hash = "sha256:849dcfc76481c0ea0099391235b7ca97d7279e0fa4c86005457ac7c88e8b76dc", size = 168385, upload-time = "2025-10-17T11:31:15.186Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/b5/55f06bb281d92fb3cc86d14e1def2bd908bb77693183e7cb1f5a3c388b0c/jiter-0.15.0.tar.gz", hash = "sha256:4251acc80e2b7c9b7b8823456ea0fceeb0734dac2df7636d3c711b38476b5a76", size = 166640, upload-time = "2026-05-19T10:09:48.361Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/10/d099def5716452c8d5ffa527405373a44ddaf8e3c9d4f6de1e1344cffd90/jiter-0.11.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ed58841a491bbbf3f7c55a6b68fff568439ab73b2cce27ace0e169057b5851df", size = 310078, upload-time = "2025-10-17T11:28:36.186Z" }, - { url = "https://files.pythonhosted.org/packages/fe/56/b81d010b0031ffa96dfb590628562ac5f513ce56aa2ab451d29fb3fedeb9/jiter-0.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:499beb9b2d7e51d61095a8de39ebcab1d1778f2a74085f8305a969f6cee9f3e4", size = 317138, upload-time = "2025-10-17T11:28:38.294Z" }, - { url = "https://files.pythonhosted.org/packages/89/12/31ea12af9d79671cc7bd893bf0ccaf3467624c0fc7146a0cbfe7b549bcfa/jiter-0.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b87b2821795e28cc990939b68ce7a038edea680a24910bd68a79d54ff3f03c02", size = 348964, upload-time = "2025-10-17T11:28:40.103Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d2/95cb6dc5ff962410667a29708c7a6c0691cc3c4866a0bfa79d085b56ebd6/jiter-0.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83f6fa494d8bba14ab100417c80e70d32d737e805cb85be2052d771c76fcd1f8", size = 363289, upload-time = "2025-10-17T11:28:41.49Z" }, - { url = "https://files.pythonhosted.org/packages/b8/3e/37006ad5843a0bc3a3ec3a6c44710d7a154113befaf5f26d2fe190668b63/jiter-0.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fbc6aea1daa2ec6f5ed465f0c5e7b0607175062ceebbea5ca70dd5ddab58083", size = 487243, upload-time = "2025-10-17T11:28:43.209Z" }, - { url = "https://files.pythonhosted.org/packages/80/5c/d38c8c801a322a0c0de47b9618c16fd766366f087ce37c4e55ae8e3c8b03/jiter-0.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302288e2edc43174bb2db838e94688d724f9aad26c5fb9a74f7a5fb427452a6a", size = 376139, upload-time = "2025-10-17T11:28:44.821Z" }, - { url = "https://files.pythonhosted.org/packages/b0/cd/442ad2389a5570b0ee673f93e14bbe8cdecd3e08a9ba7756081d84065e4c/jiter-0.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85db563fe3b367bb568af5d29dea4d4066d923b8e01f3417d25ebecd958de815", size = 359279, upload-time = "2025-10-17T11:28:46.152Z" }, - { url = "https://files.pythonhosted.org/packages/9a/35/8f5810d0e7d00bc395889085dbc1ccc36d454b56f28b2a5359dfd1bab48d/jiter-0.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1c1ba2b6b22f775444ef53bc2d5778396d3520abc7b2e1da8eb0c27cb3ffb10", size = 384911, upload-time = "2025-10-17T11:28:48.03Z" }, - { url = "https://files.pythonhosted.org/packages/3c/bd/8c069ceb0bafcf6b4aa5de0c27f02faf50468df39564a02e1a12389ad6c2/jiter-0.11.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:523be464b14f8fd0cc78da6964b87b5515a056427a2579f9085ce30197a1b54a", size = 517879, upload-time = "2025-10-17T11:28:49.902Z" }, - { url = "https://files.pythonhosted.org/packages/bc/3c/9163efcf762f79f47433078b4f0a1bddc56096082c02c6cae2f47f07f56f/jiter-0.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25b99b3f04cd2a38fefb22e822e35eb203a2cd37d680dbbc0c0ba966918af336", size = 508739, upload-time = "2025-10-17T11:28:51.785Z" }, - { url = "https://files.pythonhosted.org/packages/44/07/50690f257935845d3114b95b5dd03749eeaab5e395cbb522f9e957da4551/jiter-0.11.1-cp310-cp310-win32.whl", hash = "sha256:47a79e90545a596bb9104109777894033347b11180d4751a216afef14072dbe7", size = 203948, upload-time = "2025-10-17T11:28:54.368Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3a/5964a944bf2e98ffd566153fdc2a6a368fcb11b58cc46832ca8c75808dba/jiter-0.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:cace75621ae9bd66878bf69fbd4dfc1a28ef8661e0c2d0eb72d3d6f1268eddf5", size = 207522, upload-time = "2025-10-17T11:28:56.79Z" }, - { url = "https://files.pythonhosted.org/packages/8b/34/c9e6cfe876f9a24f43ed53fe29f052ce02bd8d5f5a387dbf46ad3764bef0/jiter-0.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b0088ff3c374ce8ce0168523ec8e97122ebb788f950cf7bb8e39c7dc6a876a2", size = 310160, upload-time = "2025-10-17T11:28:59.174Z" }, - { url = "https://files.pythonhosted.org/packages/bc/9f/b06ec8181d7165858faf2ac5287c54fe52b2287760b7fe1ba9c06890255f/jiter-0.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74433962dd3c3090655e02e461267095d6c84f0741c7827de11022ef8d7ff661", size = 316573, upload-time = "2025-10-17T11:29:00.905Z" }, - { url = "https://files.pythonhosted.org/packages/66/49/3179d93090f2ed0c6b091a9c210f266d2d020d82c96f753260af536371d0/jiter-0.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d98030e345e6546df2cc2c08309c502466c66c4747b043f1a0d415fada862b8", size = 348998, upload-time = "2025-10-17T11:29:02.321Z" }, - { url = "https://files.pythonhosted.org/packages/ae/9d/63db2c8eabda7a9cad65a2e808ca34aaa8689d98d498f5a2357d7a2e2cec/jiter-0.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d6db0b2e788db46bec2cf729a88b6dd36959af2abd9fa2312dfba5acdd96dcb", size = 363413, upload-time = "2025-10-17T11:29:03.787Z" }, - { url = "https://files.pythonhosted.org/packages/25/ff/3e6b3170c5053053c7baddb8d44e2bf11ff44cd71024a280a8438ae6ba32/jiter-0.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55678fbbda261eafe7289165dd2ddd0e922df5f9a1ae46d7c79a5a15242bd7d1", size = 487144, upload-time = "2025-10-17T11:29:05.37Z" }, - { url = "https://files.pythonhosted.org/packages/b0/50/b63fcadf699893269b997f4c2e88400bc68f085c6db698c6e5e69d63b2c1/jiter-0.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a6b74fae8e40497653b52ce6ca0f1b13457af769af6fb9c1113efc8b5b4d9be", size = 376215, upload-time = "2025-10-17T11:29:07.123Z" }, - { url = "https://files.pythonhosted.org/packages/39/8c/57a8a89401134167e87e73471b9cca321cf651c1fd78c45f3a0f16932213/jiter-0.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a55a453f8b035eb4f7852a79a065d616b7971a17f5e37a9296b4b38d3b619e4", size = 359163, upload-time = "2025-10-17T11:29:09.047Z" }, - { url = "https://files.pythonhosted.org/packages/4b/96/30b0cdbffbb6f753e25339d3dbbe26890c9ef119928314578201c758aace/jiter-0.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2638148099022e6bdb3f42904289cd2e403609356fb06eb36ddec2d50958bc29", size = 385344, upload-time = "2025-10-17T11:29:10.69Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d5/31dae27c1cc9410ad52bb514f11bfa4f286f7d6ef9d287b98b8831e156ec/jiter-0.11.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:252490567a5d990986f83b95a5f1ca1bf205ebd27b3e9e93bb7c2592380e29b9", size = 517972, upload-time = "2025-10-17T11:29:12.174Z" }, - { url = "https://files.pythonhosted.org/packages/61/1e/5905a7a3aceab80de13ab226fd690471a5e1ee7e554dc1015e55f1a6b896/jiter-0.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d431d52b0ca2436eea6195f0f48528202100c7deda354cb7aac0a302167594d5", size = 508408, upload-time = "2025-10-17T11:29:13.597Z" }, - { url = "https://files.pythonhosted.org/packages/91/12/1c49b97aa49077e136e8591cef7162f0d3e2860ae457a2d35868fd1521ef/jiter-0.11.1-cp311-cp311-win32.whl", hash = "sha256:db6f41e40f8bae20c86cb574b48c4fd9f28ee1c71cb044e9ec12e78ab757ba3a", size = 203937, upload-time = "2025-10-17T11:29:14.894Z" }, - { url = "https://files.pythonhosted.org/packages/6d/9d/2255f7c17134ee9892c7e013c32d5bcf4bce64eb115402c9fe5e727a67eb/jiter-0.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0cc407b8e6cdff01b06bb80f61225c8b090c3df108ebade5e0c3c10993735b19", size = 207589, upload-time = "2025-10-17T11:29:16.166Z" }, - { url = "https://files.pythonhosted.org/packages/3c/28/6307fc8f95afef84cae6caf5429fee58ef16a582c2ff4db317ceb3e352fa/jiter-0.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:fe04ea475392a91896d1936367854d346724a1045a247e5d1c196410473b8869", size = 188391, upload-time = "2025-10-17T11:29:17.488Z" }, - { url = "https://files.pythonhosted.org/packages/15/8b/318e8af2c904a9d29af91f78c1e18f0592e189bbdb8a462902d31fe20682/jiter-0.11.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c92148eec91052538ce6823dfca9525f5cfc8b622d7f07e9891a280f61b8c96c", size = 305655, upload-time = "2025-10-17T11:29:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/f7/29/6c7de6b5d6e511d9e736312c0c9bfcee8f9b6bef68182a08b1d78767e627/jiter-0.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ecd4da91b5415f183a6be8f7158d127bdd9e6a3174138293c0d48d6ea2f2009d", size = 315645, upload-time = "2025-10-17T11:29:20.889Z" }, - { url = "https://files.pythonhosted.org/packages/ac/5f/ef9e5675511ee0eb7f98dd8c90509e1f7743dbb7c350071acae87b0145f3/jiter-0.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e3ac25c00b9275684d47aa42febaa90a9958e19fd1726c4ecf755fbe5e553b", size = 348003, upload-time = "2025-10-17T11:29:22.712Z" }, - { url = "https://files.pythonhosted.org/packages/56/1b/abe8c4021010b0a320d3c62682769b700fb66f92c6db02d1a1381b3db025/jiter-0.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57d7305c0a841858f866cd459cd9303f73883fb5e097257f3d4a3920722c69d4", size = 365122, upload-time = "2025-10-17T11:29:24.408Z" }, - { url = "https://files.pythonhosted.org/packages/2a/2d/4a18013939a4f24432f805fbd5a19893e64650b933edb057cd405275a538/jiter-0.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e86fa10e117dce22c547f31dd6d2a9a222707d54853d8de4e9a2279d2c97f239", size = 488360, upload-time = "2025-10-17T11:29:25.724Z" }, - { url = "https://files.pythonhosted.org/packages/f0/77/38124f5d02ac4131f0dfbcfd1a19a0fac305fa2c005bc4f9f0736914a1a4/jiter-0.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae5ef1d48aec7e01ee8420155d901bb1d192998fa811a65ebb82c043ee186711", size = 376884, upload-time = "2025-10-17T11:29:27.056Z" }, - { url = "https://files.pythonhosted.org/packages/7b/43/59fdc2f6267959b71dd23ce0bd8d4aeaf55566aa435a5d00f53d53c7eb24/jiter-0.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb68e7bf65c990531ad8715e57d50195daf7c8e6f1509e617b4e692af1108939", size = 358827, upload-time = "2025-10-17T11:29:28.698Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d0/b3cc20ff5340775ea3bbaa0d665518eddecd4266ba7244c9cb480c0c82ec/jiter-0.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43b30c8154ded5845fa454ef954ee67bfccce629b2dea7d01f795b42bc2bda54", size = 385171, upload-time = "2025-10-17T11:29:30.078Z" }, - { url = "https://files.pythonhosted.org/packages/d2/bc/94dd1f3a61f4dc236f787a097360ec061ceeebebf4ea120b924d91391b10/jiter-0.11.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:586cafbd9dd1f3ce6a22b4a085eaa6be578e47ba9b18e198d4333e598a91db2d", size = 518359, upload-time = "2025-10-17T11:29:31.464Z" }, - { url = "https://files.pythonhosted.org/packages/7e/8c/12ee132bd67e25c75f542c227f5762491b9a316b0dad8e929c95076f773c/jiter-0.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:677cc2517d437a83bb30019fd4cf7cad74b465914c56ecac3440d597ac135250", size = 509205, upload-time = "2025-10-17T11:29:32.895Z" }, - { url = "https://files.pythonhosted.org/packages/39/d5/9de848928ce341d463c7e7273fce90ea6d0ea4343cd761f451860fa16b59/jiter-0.11.1-cp312-cp312-win32.whl", hash = "sha256:fa992af648fcee2b850a3286a35f62bbbaeddbb6dbda19a00d8fbc846a947b6e", size = 205448, upload-time = "2025-10-17T11:29:34.217Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/8002d78637e05009f5e3fb5288f9d57d65715c33b5d6aa20fd57670feef5/jiter-0.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88b5cae9fa51efeb3d4bd4e52bfd4c85ccc9cac44282e2a9640893a042ba4d87", size = 204285, upload-time = "2025-10-17T11:29:35.446Z" }, - { url = "https://files.pythonhosted.org/packages/9f/a2/bb24d5587e4dff17ff796716542f663deee337358006a80c8af43ddc11e5/jiter-0.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:9a6cae1ab335551917f882f2c3c1efe7617b71b4c02381e4382a8fc80a02588c", size = 188712, upload-time = "2025-10-17T11:29:37.027Z" }, - { url = "https://files.pythonhosted.org/packages/9d/51/bd41562dd284e2a18b6dc0a99d195fd4a3560d52ab192c42e56fe0316643/jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:e642b5270e61dd02265866398707f90e365b5db2eb65a4f30c789d826682e1f6", size = 306871, upload-time = "2025-10-17T11:31:03.616Z" }, - { url = "https://files.pythonhosted.org/packages/ba/cb/64e7f21dd357e8cd6b3c919c26fac7fc198385bbd1d85bb3b5355600d787/jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:464ba6d000585e4e2fd1e891f31f1231f497273414f5019e27c00a4b8f7a24ad", size = 301454, upload-time = "2025-10-17T11:31:05.338Z" }, - { url = "https://files.pythonhosted.org/packages/55/b0/54bdc00da4ef39801b1419a01035bd8857983de984fd3776b0be6b94add7/jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:055568693ab35e0bf3a171b03bb40b2dcb10352359e0ab9b5ed0da2bf1eb6f6f", size = 336801, upload-time = "2025-10-17T11:31:06.893Z" }, - { url = "https://files.pythonhosted.org/packages/de/8f/87176ed071d42e9db415ed8be787ef4ef31a4fa27f52e6a4fbf34387bd28/jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c69ea798d08a915ba4478113efa9e694971e410056392f4526d796f136d3fa", size = 343452, upload-time = "2025-10-17T11:31:08.259Z" }, - { url = "https://files.pythonhosted.org/packages/a6/bc/950dd7f170c6394b6fdd73f989d9e729bd98907bcc4430ef080a72d06b77/jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:0d4d6993edc83cf75e8c6828a8d6ce40a09ee87e38c7bfba6924f39e1337e21d", size = 302626, upload-time = "2025-10-17T11:31:09.645Z" }, - { url = "https://files.pythonhosted.org/packages/3a/65/43d7971ca82ee100b7b9b520573eeef7eabc0a45d490168ebb9a9b5bb8b2/jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f78d151c83a87a6cf5461d5ee55bc730dd9ae227377ac6f115b922989b95f838", size = 297034, upload-time = "2025-10-17T11:31:10.975Z" }, - { url = "https://files.pythonhosted.org/packages/19/4c/000e1e0c0c67e96557a279f8969487ea2732d6c7311698819f977abae837/jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9022974781155cd5521d5cb10997a03ee5e31e8454c9d999dcdccd253f2353f", size = 337328, upload-time = "2025-10-17T11:31:12.399Z" }, - { url = "https://files.pythonhosted.org/packages/d9/71/71408b02c6133153336d29fa3ba53000f1e1a3f78bb2fc2d1a1865d2e743/jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18c77aaa9117510d5bdc6a946baf21b1f0cfa58ef04d31c8d016f206f2118960", size = 343697, upload-time = "2025-10-17T11:31:13.773Z" }, + { url = "https://files.pythonhosted.org/packages/1d/da/76a2c7e510ba15fe323d9509c223ab272da79ea59f54488f4a78da6426db/jiter-0.15.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:edebcf7d1f601199084bb6e844d7dc67e03e04f6ac786b0332d616635c4ff7a4", size = 310849, upload-time = "2026-05-19T10:06:51.944Z" }, + { url = "https://files.pythonhosted.org/packages/5d/8e/827be942883a4dc0862c48626ff41af3320b1902d136a0bf4b9041f2c567/jiter-0.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f924585cdacf631cd382b657966847bb537bf9ed0a6f9b991da5f05a631480f", size = 314991, upload-time = "2026-05-19T10:06:53.522Z" }, + { url = "https://files.pythonhosted.org/packages/6d/38/be2832be361ba1b9517c76f46d30b64e985be1dd43c974f4c3a4b1844436/jiter-0.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abbf258599526ad0326fe51e252e24f2bd6f24f1852681b4b78feda3808f1d18", size = 340843, upload-time = "2026-05-19T10:06:55.071Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d8/90f01fb83c0c7ba509303ec93e32a308fbfa167d264860b01c0fd0dbbd06/jiter-0.15.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c468136b8bd6bb18c8786e4236a1fa27362f24cb23450ba0cb204ab379b8e6f", size = 365116, upload-time = "2026-05-19T10:06:56.893Z" }, + { url = "https://files.pythonhosted.org/packages/91/38/94593d34f8c67a0b6f6cbc027f016ffa9780b3a858a7a86f6fd7a15bcc1e/jiter-0.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05906b93d72f03339e6bb7cf8dc10ebda64a0266126eed6beba79e20abcf5fd4", size = 457970, upload-time = "2026-05-19T10:06:58.707Z" }, + { url = "https://files.pythonhosted.org/packages/df/04/d79962dd49d00c97e2a9b4cacea1947904d02135936960351f9a96d4c1a6/jiter-0.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30ce785d2adb8e32c3f7741442370a74834ec4c01f3c48f0750227a0b4ef27d6", size = 375744, upload-time = "2026-05-19T10:07:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/c3/2e/5d37abe2be0e819c21e2338bebd410e481763ce526a9138c8c3652fa0123/jiter-0.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd73e3da91a0a722d67165e849ce2cdc10de0e0d48738c142be8c6c5f310f4c", size = 349609, upload-time = "2026-05-19T10:07:01.829Z" }, + { url = "https://files.pythonhosted.org/packages/7a/90/98768ad2ed90c1fda15d64157de2dfbf73c1c074d4b1bfaca915480bc7cf/jiter-0.15.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:ceb8fc27d38793f9c97149be8302720c5b22e5c195a37bf2c45dc36c4600a512", size = 354366, upload-time = "2026-05-19T10:07:03.587Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c4/fbfb806209f1fe4b7dccdfb07bc62bb044300734a945b06fd64db446ef6a/jiter-0.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d726e3ceeb337191324b49de298142f27c3ad10886341555d1d5315b5f252c6a", size = 393519, upload-time = "2026-05-19T10:07:05.08Z" }, + { url = "https://files.pythonhosted.org/packages/37/1c/b9c257cd70cb453b6d10f3ebf0402cdb11669ab455389096f09839670290/jiter-0.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2c8aea7781d2a372227871de4e1a1332aa96f5a89fd76c5e835dafdbad102887", size = 519952, upload-time = "2026-05-19T10:07:06.589Z" }, + { url = "https://files.pythonhosted.org/packages/a9/1a/aa85027db7ab15829c12feebbc33b404f53fc399bd559d85fd0d6365ff0d/jiter-0.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf4bd113a69c0a740e27cb962ce10630c36d2b8f59d759a651b955ee9d18a823", size = 550770, upload-time = "2026-05-19T10:07:08.228Z" }, + { url = "https://files.pythonhosted.org/packages/d4/54/8c3f65c8a5687925e84708f19d63f7f37d28e2b86a48d951702ad94424d8/jiter-0.15.0-cp310-cp310-win32.whl", hash = "sha256:d92a5cd21fdb083931d546c207aa29633787c5dc5b02daab2d32b843f88a2c53", size = 209303, upload-time = "2026-05-19T10:07:10.006Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/0528a1eb9f42dd2d8228a0711458628f35924d131f623eaebc35fd23d3d4/jiter-0.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:e58585a58209d72691ce2d62a9147445f5a87beb0bde97fde284c96ae392a3d1", size = 200404, upload-time = "2026-05-19T10:07:11.426Z" }, + { url = "https://files.pythonhosted.org/packages/e4/13/daa722f5765c393576f466378f9dfd29d77c9bed939e0688f96afa3601ea/jiter-0.15.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0f862193b8696249d22ec433e85fd2ab0ad9596bc3e45e6c0bc55e8aeba97be2", size = 310899, upload-time = "2026-05-19T10:07:12.89Z" }, + { url = "https://files.pythonhosted.org/packages/7f/82/2d2551829b082f4b6d82b9f939b031fb808a10aab1ec0664f82e150bb9a2/jiter-0.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1303d4d68a9b051ea90502402063ecf3807da00ad2affa19ca1ae3b90b3c5f67", size = 314963, upload-time = "2026-05-19T10:07:14.539Z" }, + { url = "https://files.pythonhosted.org/packages/2a/0a/8b1a51466f7fe9f31dbe4bc7e0ca848674f9825e0f737b929b97e8c60aa7/jiter-0.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392b8ab019e5502d08aff85c6272209c24bc2cbe706ea82a56368f524236614a", size = 341730, upload-time = "2026-05-19T10:07:15.869Z" }, + { url = "https://files.pythonhosted.org/packages/f6/2a/e71dea19822e2e404e83992a08c1d6b9b617bb944f28c9c2fbd85d02c91e/jiter-0.15.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:773b6eb282ce11ee19f05f6b2d4404fa308e5bbd353b0b80a0262caad6db2cd7", size = 366214, upload-time = "2026-05-19T10:07:17.259Z" }, + { url = "https://files.pythonhosted.org/packages/c4/59/97e1fa539d124a509a00ab7f669289d1c1d236ecabf12948a18f16c91082/jiter-0.15.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2c0c44d569ce0f2850f5c926f8caeb5f245fbc84475aeb36efccc2103e6dbd", size = 459527, upload-time = "2026-05-19T10:07:18.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/7a/4a68d331aef8cf2e2393c14a3aacb635c62aa86071b0229899fb5baaa907/jiter-0.15.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:032396229564bca02440396bd327710719f724f5e7b7e9f7a8eb3faa4a2c2281", size = 375451, upload-time = "2026-05-19T10:07:20.208Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/1c445c2b6f0e30a274dc8082e0c3c7825411cce80d726bccd697c98cc8d3/jiter-0.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d37768fce7f88dd2a8c6091f2325dea27d30d30d5c6e7a1c0f0af77723b708", size = 349428, upload-time = "2026-05-19T10:07:22.372Z" }, + { url = "https://files.pythonhosted.org/packages/00/94/e20d38984fc17a636371bffd2ae0f698124fdc8e75ef969cd2da6ba7cea7/jiter-0.15.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:2c9cb907439d20bd0c7d7565ca01ee52234203208433749bae5b516907526928", size = 355405, upload-time = "2026-05-19T10:07:23.916Z" }, + { url = "https://files.pythonhosted.org/packages/94/fa/4d09f814779d0ea80a28ed8e4c6662ec9a4a8ecef0ac52190ebac6262d14/jiter-0.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9100ddbec09741cc66feb0fc6773f8bdbd0e3c345689368f260082ff85dcc0cd", size = 393688, upload-time = "2026-05-19T10:07:25.854Z" }, + { url = "https://files.pythonhosted.org/packages/54/9d/8eb5d4fb8bf7e93a75964a5da71a75c67c864baf7fa3f98598187b3c7e57/jiter-0.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ae1b0d82ac2d987f9ea512b1c9adfcc71a28de3dea3a6039b54d76cffda9901e", size = 520853, upload-time = "2026-05-19T10:07:27.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2c/5e07874e59e623a943a0acf1552a80d05b70f31b402287a8fc6d7ec634c7/jiter-0.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8020c99ec13a7db2b6f96cbe82ef4721c88b426a4892f27478044af0284615ef", size = 551016, upload-time = "2026-05-19T10:07:28.846Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/d2d34422143474cadc15b60d482b1c35683dbc5c63c24346ddd0df09bcaf/jiter-0.15.0-cp311-cp311-win32.whl", hash = "sha256:42bfb257930800cf43e7c62c832402c704ab60797c992faf88d20e903eac8f32", size = 209518, upload-time = "2026-05-19T10:07:30.431Z" }, + { url = "https://files.pythonhosted.org/packages/1d/7d/52778b930e5cc3e52a37d950b1c10494244308b4329b25a0ff0d88303a81/jiter-0.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:860a74063284a2ae9bfedd694f299cc2c68e2696c5f3d440cc9d18bb81b9dd04", size = 200565, upload-time = "2026-05-19T10:07:32.125Z" }, + { url = "https://files.pythonhosted.org/packages/3b/4f/d9b4067feb69b3fa6eb0488e1b59e2ad5b463fe39f59e527eab2aca00bb0/jiter-0.15.0-cp311-cp311-win_arm64.whl", hash = "sha256:37a10c377ce3a4a85f4a67f28b7afe093154cde77eaf248a72e856aa08b4d865", size = 195488, upload-time = "2026-05-19T10:07:33.846Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/4f6bddbcde3c71e56d0aa1337ec95950f3d27dd4153e25aadf0feac71751/jiter-0.15.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0e90a1c315a0226ec822d973817967f9223b7701546c8c2a7913e7ab0926294d", size = 308793, upload-time = "2026-05-19T10:07:35.25Z" }, + { url = "https://files.pythonhosted.org/packages/01/84/c01099b59a285a1ebba64ae93f62bfa036675340fd1b0045ae65890a0442/jiter-0.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8c9004af7c8d67cce7f1aae1026fb55607f4aa600710d08ede3a3ce4aeefe7e0", size = 309570, upload-time = "2026-05-19T10:07:36.919Z" }, + { url = "https://files.pythonhosted.org/packages/58/64/8fb7f9d45bb98190355454cd04dad8d8f27223d6bd52f83af07f637168a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c210f8b35dc6f30aafd4b4365ca89b9d1189f21ab49b8e68fa6322a847aef138", size = 336783, upload-time = "2026-05-19T10:07:38.694Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b6/f5739011d009b3a30f6a53c5240979030ba29ae46a8c67e3a15759f7c37d/jiter-0.15.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f30bae8bc1c2d613e28e5af3e8cceb09b742f1c8a8a5f839fb67afaffc03b61", size = 363555, upload-time = "2026-05-19T10:07:40.832Z" }, + { url = "https://files.pythonhosted.org/packages/e5/12/98a9d9f766665e8a3b6252454e17cb0c464606a28cf2fa09399b003345fa/jiter-0.15.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e71b6d10cfc284c9bf36bd885e8d44c46f688ce50aa91b5edd90181dea687", size = 452255, upload-time = "2026-05-19T10:07:42.62Z" }, + { url = "https://files.pythonhosted.org/packages/e8/d5/60f972840f79c5e7544fce567c56f1e4e50468f996baba3e78d823dd62a6/jiter-0.15.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ab068bce62a45aa3e7367eceaffb5dde60b7eb853be8dece45132e3d0ff4879", size = 373559, upload-time = "2026-05-19T10:07:44.201Z" }, + { url = "https://files.pythonhosted.org/packages/ee/cf/d46ef1234ba335aabc2f013210db8e0821a22f5e644a2e9449df199ecc23/jiter-0.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa248c9eb220197d363f688818dac2fd4b2f0cd7d843ca7105d652034823427d", size = 346055, upload-time = "2026-05-19T10:07:46.005Z" }, + { url = "https://files.pythonhosted.org/packages/f0/63/4d2749d8d54d230bad9b3a6b0d00cc28c6ff6b2fdffc26a8ccf76cc5a974/jiter-0.15.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2a77aadd57cac1682e4401a72724d2796d89a4ba129b1a5812aa94ee480826eb", size = 351406, upload-time = "2026-05-19T10:07:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b9/9965b990035d8773328e0a8c8b457a87bf2b19f6c4126d9d99296be5d16a/jiter-0.15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ae901f3a55bfafdde31d289590fa25e3245735a2b1e8c7cc15871710a002871", size = 389357, upload-time = "2026-05-19T10:07:49.665Z" }, + { url = "https://files.pythonhosted.org/packages/2d/55/9ddf903deda1413e87fed792f416b7123daee5b8efbad6a202a7421c36a5/jiter-0.15.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f0b271b462769543716f92d3a4f90527df6ef5ed05ee95ec4137f513e21e1b77", size = 517263, upload-time = "2026-05-19T10:07:51.537Z" }, + { url = "https://files.pythonhosted.org/packages/e8/76/a0c40ad064d3a20a4fde231e35d56e9a01ce82164278180e82d5daf85469/jiter-0.15.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2fb6a5d26af81fc0f00f9360a891e05cf755e149bba391c4d563adc54812973d", size = 548646, upload-time = "2026-05-19T10:07:53.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/4f/eca9b954942916ba2f453891b8593ab444cd872396fe66a3936616f236f3/jiter-0.15.0-cp312-cp312-win32.whl", hash = "sha256:c2f6bb8b5216ab9e7873bc08b5d7bef2b8abbb578a3069bf1cd14a45d71d771d", size = 206427, upload-time = "2026-05-19T10:07:55.307Z" }, + { url = "https://files.pythonhosted.org/packages/95/bf/8ead82a87495149542748e828d153fd232a512a22c83b02c4815c1a9c7d8/jiter-0.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:40b2c7e92c44a84d748d21706c68dc6ff8161d80b59c99d774721a0d2317d7c7", size = 197300, upload-time = "2026-05-19T10:07:56.651Z" }, + { url = "https://files.pythonhosted.org/packages/f4/e4/9b8a78fb2d894471bc344e37f1949bdd784bd914d031dba0ba3a40c71dd7/jiter-0.15.0-cp312-cp312-win_arm64.whl", hash = "sha256:cc0bc345cf2df9d1c00ac443f50d543c1ccfa8b0422cb85b1ab70d681c0b255b", size = 192702, upload-time = "2026-05-19T10:07:58.307Z" }, + { url = "https://files.pythonhosted.org/packages/65/43/1fc62172aa98b50a7de9a25554060db510f85c89cfbed0dfe13e1907a139/jiter-0.15.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:411fa4dfa5a7ae3d11491027ffb9beadec3996010a986862db70d91abba1c750", size = 305585, upload-time = "2026-05-19T10:09:35.995Z" }, + { url = "https://files.pythonhosted.org/packages/e8/c4/dd58fcd9e2df83666e5c1c1347bef58ce919cd8efc3ffa38aeea62ce493b/jiter-0.15.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:2b0074e2f56eb2dacca1689760fd2852a068f85a0547a157b82cb4cafeb6768b", size = 306936, upload-time = "2026-05-19T10:09:37.435Z" }, + { url = "https://files.pythonhosted.org/packages/39/86/b695e16f1180c07f43ea98e73ecd21cf63fa2e1b0c1103739013784d11ae/jiter-0.15.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913d02d29c9606643418d9ccfc3b72492ab25a6bf7889934e09a3490f8d3438b", size = 342453, upload-time = "2026-05-19T10:09:39.294Z" }, + { url = "https://files.pythonhosted.org/packages/34/56/55d76614af37fe3f22a3347d1e410d2a15da581997cb2da499a625000bb5/jiter-0.15.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b15d3ec9b0449c40e85319bdb4caa8b77ab526e74f5532ed94bec15e2f66822c", size = 345606, upload-time = "2026-05-19T10:09:40.727Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/505941b2b092fd5bbbd60a52a880db1173f1690ae6751bed3af1c9ddcb4e/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:631f13a3d04e97d4e083993b10f4b99530e3a10d953e2eb5e196b7dc7f812ce0", size = 303769, upload-time = "2026-05-19T10:09:42.203Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/a06692b29e77473f286e1ec1f426d3ca44d7b5843be8ad21d7a5f3fcdcc0/jiter-0.15.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:b6c0ffae686c39bf3737be60793783267628783ea42545632c10b291105aee45", size = 305128, upload-time = "2026-05-19T10:09:43.657Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/7270d7ad41d6061a25b950c6bf91d638bd9aacb113200a8c8d57a055fd67/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d54fb5b31dea401a41af3f8a7d2512e9b6a6a005491e6166c7e4ffab9639a9c", size = 340459, upload-time = "2026-05-19T10:09:45.452Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8d/302cb2057b7513327b4d575cff6b1d066ee6431a5357fc3f8867cd684406/jiter-0.15.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d5d6090cdc1b7c9e780dfb04949a990adb1e301a2fc0bbcee7de4638d33f9a", size = 344469, upload-time = "2026-05-19T10:09:46.864Z" }, ] [[package]] @@ -1164,7 +1205,7 @@ wheels = [ [[package]] name = "jsonschema" -version = "4.25.1" +version = "4.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1172,9 +1213,9 @@ dependencies = [ { 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" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, ] [[package]] @@ -1233,21 +1274,21 @@ wheels = [ [[package]] name = "limits" -version = "5.5.0" +version = "5.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "deprecated" }, { name = "packaging" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/17/7a2e9378c8b8bd4efe3573fd18d2793ad2a37051af5ccce94550a4e5d62d/limits-5.5.0.tar.gz", hash = "sha256:ee269fedb078a904608b264424d9ef4ab10555acc8d090b6fc1db70e913327ea", size = 95514, upload-time = "2025-08-05T18:23:54.771Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/69/826a5d1f45426c68d8f6539f8d275c0e4fcaa57f0c017ec3100986558a41/limits-5.8.0.tar.gz", hash = "sha256:c9e0d74aed837e8f6f50d1fcebcf5fd8130957287206bc3799adaee5092655da", size = 226104, upload-time = "2026-02-05T07:17:35.859Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/68/ee314018c28da75ece5a639898b4745bd0687c0487fc465811f0c4b9cd44/limits-5.5.0-py3-none-any.whl", hash = "sha256:57217d01ffa5114f7e233d1f5e5bdc6fe60c9b24ade387bf4d5e83c5cf929bae", size = 60948, upload-time = "2025-08-05T18:23:53.335Z" }, + { url = "https://files.pythonhosted.org/packages/b9/98/cb5ca20618d205a09d5bec7591fbc4130369c7e6308d9a676a28ff3ab22c/limits-5.8.0-py3-none-any.whl", hash = "sha256:ae1b008a43eb43073c3c579398bd4eb4c795de60952532dc24720ab45e1ac6b8", size = 60954, upload-time = "2026-02-05T07:17:34.425Z" }, ] [[package]] name = "lnbits" -version = "1.5.2rc3" +version = "1.6.0rc2" source = { editable = "." } dependencies = [ { name = "aiosqlite" }, @@ -1274,6 +1315,7 @@ dependencies = [ { name = "protobuf" }, { name = "pycryptodomex" }, { name = "pydantic" }, + { name = "pyinstrument" }, { name = "pyjwt" }, { name = "pyln-client" }, { name = "pynostr" }, @@ -1282,14 +1324,17 @@ dependencies = [ { name = "python-dotenv" }, { name = "python-multipart" }, { name = "pywebpush" }, + { name = "random-username" }, { name = "shortuuid" }, { name = "slowapi" }, { name = "sqlalchemy" }, { name = "sse-starlette" }, { name = "starlette" }, { name = "typing-extensions" }, + { name = "urllib3" }, { name = "uvicorn" }, { name = "uvloop" }, + { name = "wasmtime" }, { name = "websocket-client" }, { name = "websockets" }, ] @@ -1300,6 +1345,7 @@ breez = [ { name = "breez-sdk-liquid" }, ] liquid = [ + { name = "boltz-client" }, { name = "wallycore" }, ] migration = [ @@ -1317,6 +1363,7 @@ dev = [ { name = "mypy" }, { name = "openai" }, { name = "openapi-spec-validator" }, + { name = "playwright" }, { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-cov" }, @@ -1331,94 +1378,100 @@ dev = [ [package.metadata] requires-dist = [ - { name = "aiosqlite", specifier = "==0.22.1" }, - { name = "asyncpg", specifier = "==0.31.0" }, - { name = "bcrypt", specifier = "==5.0.0" }, - { name = "bech32", specifier = "==1.2.0" }, - { name = "bolt11", specifier = "==2.1.1" }, - { name = "breez-sdk", marker = "extra == 'breez'", specifier = "==0.8.0" }, - { name = "breez-sdk-liquid", marker = "extra == 'breez'", specifier = "==0.11.11" }, - { name = "click", specifier = "==8.3.1" }, - { name = "embit", specifier = "==0.8.0" }, - { name = "fastapi", specifier = "==0.116.1" }, - { name = "fastapi-sso", specifier = "==0.19.0" }, - { name = "filetype", specifier = "==1.2.0" }, - { name = "greenlet", specifier = ">=3.3.0,<4.0.0" }, - { name = "grpcio", specifier = "==1.76.0" }, - { name = "httpx", specifier = "==0.27.2" }, - { name = "itsdangerous", specifier = "==2.2.0" }, - { name = "jinja2", specifier = "==3.1.6" }, - { name = "jsonpath-ng", specifier = "==1.7.0" }, - { name = "lnurl", specifier = "==0.8.3" }, - { name = "loguru", specifier = "==0.7.3" }, - { name = "nostr-sdk", specifier = "==0.44.0" }, - { name = "packaging", specifier = "==25.0" }, - { name = "pillow", specifier = ">=12.1.0" }, - { name = "protobuf", specifier = "==6.33.2" }, - { name = "psycopg2-binary", marker = "extra == 'migration'", specifier = "==2.9.11" }, - { name = "pycryptodomex", specifier = "==3.23.0" }, - { name = "pydantic", specifier = "==1.10.26" }, - { name = "pyjwt", specifier = "==2.10.1" }, - { name = "pyln-client", specifier = "==25.12" }, - { name = "pynostr", specifier = "==0.7.0" }, - { name = "pyqrcode", specifier = "==1.2.1" }, - { name = "python-crontab", specifier = "==3.3.0" }, - { name = "python-dotenv", specifier = ">=1.2.1" }, - { name = "python-multipart", specifier = "==0.0.21" }, - { name = "pywebpush", specifier = "==2.2.0" }, - { name = "shortuuid", specifier = "==1.0.13" }, - { name = "slowapi", specifier = "==0.1.9" }, - { name = "sqlalchemy", specifier = "==1.4.54" }, - { name = "sse-starlette", specifier = "==2.3.6" }, - { name = "starlette", specifier = "==0.47.1" }, - { name = "typing-extensions", specifier = "==4.15.0" }, - { name = "uvicorn", specifier = "==0.40.0" }, - { name = "uvloop", specifier = "==0.22.1" }, - { name = "wallycore", marker = "extra == 'liquid'", specifier = "==1.5.1" }, - { name = "websocket-client", specifier = "==1.9.0" }, - { name = "websockets", specifier = "==15.0.1" }, + { name = "aiosqlite", specifier = "~=0.22.1" }, + { name = "asyncpg", specifier = "~=0.31.0" }, + { name = "bcrypt", specifier = "~=5.0.0" }, + { name = "bech32", specifier = "~=1.2.0" }, + { name = "bolt11", specifier = "~=2.1.1" }, + { name = "boltz-client", marker = "extra == 'liquid'", specifier = "==0.4.0" }, + { name = "breez-sdk", marker = "extra == 'breez'", specifier = "~=0.8.0" }, + { name = "breez-sdk-liquid", marker = "extra == 'breez'", specifier = "~=0.11.11" }, + { name = "click", specifier = "~=8.3.1" }, + { name = "embit", specifier = "~=0.8.0" }, + { name = "fastapi", specifier = "~=0.116.1" }, + { name = "fastapi-sso", specifier = "~=0.19.0" }, + { name = "filetype", specifier = "~=1.2.0" }, + { name = "greenlet", specifier = "~=3.3.0" }, + { name = "grpcio", specifier = "~=1.76.0" }, + { name = "httpx", specifier = "~=0.27.2" }, + { name = "itsdangerous", specifier = "~=2.2.0" }, + { name = "jinja2", specifier = "~=3.1.6" }, + { name = "jsonpath-ng", specifier = "~=1.7.0" }, + { name = "lnurl", specifier = "~=0.10.0" }, + { name = "loguru", specifier = "~=0.7.3" }, + { name = "nostr-sdk", specifier = "~=0.44.0" }, + { name = "packaging", specifier = "~=25.0.0" }, + { name = "pillow", specifier = "~=12.3.0" }, + { name = "protobuf", specifier = "~=6.33.5" }, + { name = "psycopg2-binary", marker = "extra == 'migration'", specifier = "~=2.9.11" }, + { name = "pycryptodomex", specifier = "~=3.23.0" }, + { name = "pydantic", specifier = "~=1.10.26" }, + { name = "pyinstrument", specifier = ">=5.1.2" }, + { name = "pyjwt", specifier = "~=2.12.0" }, + { name = "pyln-client", specifier = "~=25.12.0" }, + { name = "pynostr", specifier = "~=0.7.0" }, + { name = "pyqrcode", specifier = "~=1.2.1" }, + { name = "python-crontab", specifier = "~=3.3.0" }, + { name = "python-dotenv", specifier = "~=1.2.1" }, + { name = "python-multipart", specifier = "~=0.0.22" }, + { name = "pywebpush", specifier = "~=2.2.0" }, + { name = "random-username", specifier = "~=1.0.2" }, + { name = "shortuuid", specifier = "~=1.0.13" }, + { name = "slowapi", specifier = "~=0.1.9" }, + { name = "sqlalchemy", specifier = "~=1.4.54" }, + { name = "sse-starlette", specifier = "~=2.3.6" }, + { name = "starlette", specifier = "~=0.48.0" }, + { name = "typing-extensions", specifier = "~=4.15.0" }, + { name = "urllib3", specifier = ">=2.7.0" }, + { name = "uvicorn", specifier = "~=0.40.0" }, + { name = "uvloop", specifier = "~=0.22.1" }, + { name = "wallycore", marker = "extra == 'liquid'", specifier = "~=1.5.1" }, + { name = "wasmtime", specifier = ">=45.0.0" }, + { name = "websocket-client", specifier = "~=1.9.0" }, + { name = "websockets", specifier = "~=15.0.1" }, ] provides-extras = ["breez", "liquid", "migration"] [package.metadata.requires-dev] dev = [ - { name = "anyio", specifier = ">=4.12.1" }, - { name = "asgi-lifespan", specifier = ">=2.1.0,<3.0.0" }, - { name = "black", specifier = ">=25.12.0,<26.0.0" }, - { name = "grpcio-tools", specifier = ">=1.76.0,<2.0.0" }, - { name = "json5", specifier = ">=0.13.0,<1.0.0" }, - { name = "mock", specifier = ">=5.2.0,<6.0.0" }, - { name = "mypy", specifier = "==1.17.1" }, - { name = "openai", specifier = ">=2.14.0" }, - { name = "openapi-spec-validator", specifier = ">=0.7.2,<1.0.0" }, - { name = "pre-commit", specifier = ">=4.5.1,<5.0.0" }, - { name = "pytest", specifier = ">=9.0.2" }, - { name = "pytest-cov", specifier = ">=7.0.0" }, - { name = "pytest-httpserver", specifier = ">=1.1.3,<2.0.0" }, - { name = "pytest-md", specifier = ">=0.2.0,<0.3.0" }, - { name = "pytest-mock", specifier = ">=3.15.1,<4.0.0" }, - { name = "ruff", specifier = ">=0.14.10,<1.0.0" }, - { name = "types-mock", specifier = ">=5.2.0.20250924,<6.0.0" }, - { name = "types-passlib", specifier = ">=1.7.7.20250602,<2.0.0" }, - { name = "types-protobuf", specifier = ">=6.32.1.20251210,<7.0.0" }, + { name = "anyio", specifier = "~=4.12.1" }, + { name = "asgi-lifespan", specifier = "~=2.1.0" }, + { name = "black", specifier = "~=26.3.1" }, + { name = "grpcio-tools", specifier = "~=1.76.0" }, + { name = "json5", specifier = "~=0.13.0" }, + { name = "mock", specifier = "~=5.2.0" }, + { name = "mypy", specifier = "~=1.17.1" }, + { name = "openai", specifier = "~=2.14.0" }, + { name = "openapi-spec-validator", specifier = "~=0.7.2" }, + { name = "playwright", specifier = "~=1.61.0" }, + { name = "pre-commit", specifier = "~=4.5.1" }, + { name = "pytest", specifier = "~=9.0.2" }, + { name = "pytest-cov", specifier = "~=7.0.0" }, + { name = "pytest-httpserver", specifier = "~=1.1.3" }, + { name = "pytest-md", specifier = "~=0.2.0" }, + { name = "pytest-mock", specifier = "~=3.15.1" }, + { name = "ruff", specifier = "~=0.14.10" }, + { name = "types-mock", specifier = "~=5.2.0.20250924" }, + { name = "types-passlib", specifier = "~=1.7.7.20250602" }, + { name = "types-protobuf", specifier = "~=6.32.1.20251210" }, ] [[package]] name = "lnurl" -version = "0.8.3" +version = "0.10.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bech32" }, { name = "bip32" }, { name = "bolt11" }, - { name = "ecdsa" }, - { name = "httpx" }, + { name = "coincurve" }, + { name = "httpx", extra = ["socks"] }, { name = "pycryptodomex" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9b/dc/29cce6bb8688622c7f5f6db4355c54b5c87bb05be58e49374fd2c6f4b0f2/lnurl-0.8.3.tar.gz", hash = "sha256:8ca73af84fb9ee36a184d731d165f289ba7bc6260d4dadb2b6cf24f381c3afba", size = 17171, upload-time = "2025-09-08T13:30:56.636Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/60/024f09d0728d439cf5e4dd96f3b2b3cc593d11d32b25a2bcf3c061ece422/lnurl-0.10.2.tar.gz", hash = "sha256:0d8d1f84f7663a66bdb618024cacdb549d08b1920d0482d3ef54fd9833be41a3", size = 69345, upload-time = "2026-03-30T11:28:06.412Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/99/e400734afb7469a0cfa661259de2bb66417d6c3f14361444a010e9d186ee/lnurl-0.8.3-py3-none-any.whl", hash = "sha256:670cdeaef2c55de986dad89126ab58275d5199ba6554a93d9965d1e162080c2a", size = 17459, upload-time = "2025-09-08T13:30:55.691Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ae/b7b7d76d93d5000e39908ba1bd8f214b29fc48399a52c09fd132e1a5a97e/lnurl-0.10.2-py3-none-any.whl", hash = "sha256:be2743e61de174d0b4e5c45b8019fde4eea8f73dc291c3290ebf427491e85ff1", size = 17786, upload-time = "2026-03-30T11:28:07.158Z" }, ] [[package]] @@ -1436,52 +1489,55 @@ wheels = [ [[package]] name = "markdown-it-py" -version = "4.0.0" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, ] [[package]] name = "markupsafe" -version = "3.0.2" +version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, ] [[package]] @@ -1504,68 +1560,68 @@ wheels = [ [[package]] name = "multidict" -version = "6.6.4" +version = "6.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/6b/86f353088c1358e76fd30b0146947fddecee812703b604ee901e85cd2a80/multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f", size = 77054, upload-time = "2025-08-11T12:06:02.99Z" }, - { url = "https://files.pythonhosted.org/packages/19/5d/c01dc3d3788bb877bd7f5753ea6eb23c1beeca8044902a8f5bfb54430f63/multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb", size = 44914, upload-time = "2025-08-11T12:06:05.264Z" }, - { url = "https://files.pythonhosted.org/packages/46/44/964dae19ea42f7d3e166474d8205f14bb811020e28bc423d46123ddda763/multidict-6.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0af5f9dee472371e36d6ae38bde009bd8ce65ac7335f55dcc240379d7bed1495", size = 44601, upload-time = "2025-08-11T12:06:06.627Z" }, - { url = "https://files.pythonhosted.org/packages/31/20/0616348a1dfb36cb2ab33fc9521de1f27235a397bf3f59338e583afadd17/multidict-6.6.4-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:d24f351e4d759f5054b641c81e8291e5d122af0fca5c72454ff77f7cbe492de8", size = 224821, upload-time = "2025-08-11T12:06:08.06Z" }, - { url = "https://files.pythonhosted.org/packages/14/26/5d8923c69c110ff51861af05bd27ca6783011b96725d59ccae6d9daeb627/multidict-6.6.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db6a3810eec08280a172a6cd541ff4a5f6a97b161d93ec94e6c4018917deb6b7", size = 242608, upload-time = "2025-08-11T12:06:09.697Z" }, - { url = "https://files.pythonhosted.org/packages/5c/cc/e2ad3ba9459aa34fa65cf1f82a5c4a820a2ce615aacfb5143b8817f76504/multidict-6.6.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b20a9d56b2d81e2ff52ecc0670d583eaabaa55f402e8d16dd062373dbbe796", size = 222324, upload-time = "2025-08-11T12:06:10.905Z" }, - { url = "https://files.pythonhosted.org/packages/19/db/4ed0f65701afbc2cb0c140d2d02928bb0fe38dd044af76e58ad7c54fd21f/multidict-6.6.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c9854df0eaa610a23494c32a6f44a3a550fb398b6b51a56e8c6b9b3689578db", size = 253234, upload-time = "2025-08-11T12:06:12.658Z" }, - { url = "https://files.pythonhosted.org/packages/94/c1/5160c9813269e39ae14b73debb907bfaaa1beee1762da8c4fb95df4764ed/multidict-6.6.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb7627fd7a968f41905a4d6343b0d63244a0623f006e9ed989fa2b78f4438a0", size = 251613, upload-time = "2025-08-11T12:06:13.97Z" }, - { url = "https://files.pythonhosted.org/packages/05/a9/48d1bd111fc2f8fb98b2ed7f9a115c55a9355358432a19f53c0b74d8425d/multidict-6.6.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caebafea30ed049c57c673d0b36238b1748683be2593965614d7b0e99125c877", size = 241649, upload-time = "2025-08-11T12:06:15.204Z" }, - { url = "https://files.pythonhosted.org/packages/85/2a/f7d743df0019408768af8a70d2037546a2be7b81fbb65f040d76caafd4c5/multidict-6.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ad887a8250eb47d3ab083d2f98db7f48098d13d42eb7a3b67d8a5c795f224ace", size = 239238, upload-time = "2025-08-11T12:06:16.467Z" }, - { url = "https://files.pythonhosted.org/packages/cb/b8/4f4bb13323c2d647323f7919201493cf48ebe7ded971717bfb0f1a79b6bf/multidict-6.6.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ed8358ae7d94ffb7c397cecb62cbac9578a83ecefc1eba27b9090ee910e2efb6", size = 233517, upload-time = "2025-08-11T12:06:18.107Z" }, - { url = "https://files.pythonhosted.org/packages/33/29/4293c26029ebfbba4f574febd2ed01b6f619cfa0d2e344217d53eef34192/multidict-6.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecab51ad2462197a4c000b6d5701fc8585b80eecb90583635d7e327b7b6923eb", size = 243122, upload-time = "2025-08-11T12:06:19.361Z" }, - { url = "https://files.pythonhosted.org/packages/20/60/a1c53628168aa22447bfde3a8730096ac28086704a0d8c590f3b63388d0c/multidict-6.6.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c5c97aa666cf70e667dfa5af945424ba1329af5dd988a437efeb3a09430389fb", size = 248992, upload-time = "2025-08-11T12:06:20.661Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3b/55443a0c372f33cae5d9ec37a6a973802884fa0ab3586659b197cf8cc5e9/multidict-6.6.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9a950b7cf54099c1209f455ac5970b1ea81410f2af60ed9eb3c3f14f0bfcf987", size = 243708, upload-time = "2025-08-11T12:06:21.891Z" }, - { url = "https://files.pythonhosted.org/packages/7c/60/a18c6900086769312560b2626b18e8cca22d9e85b1186ba77f4755b11266/multidict-6.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:163c7ea522ea9365a8a57832dea7618e6cbdc3cd75f8c627663587459a4e328f", size = 237498, upload-time = "2025-08-11T12:06:23.206Z" }, - { url = "https://files.pythonhosted.org/packages/11/3d/8bdd8bcaff2951ce2affccca107a404925a2beafedd5aef0b5e4a71120a6/multidict-6.6.4-cp310-cp310-win32.whl", hash = "sha256:17d2cbbfa6ff20821396b25890f155f40c986f9cfbce5667759696d83504954f", size = 41415, upload-time = "2025-08-11T12:06:24.77Z" }, - { url = "https://files.pythonhosted.org/packages/c0/53/cab1ad80356a4cd1b685a254b680167059b433b573e53872fab245e9fc95/multidict-6.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce9a40fbe52e57e7edf20113a4eaddfacac0561a0879734e636aa6d4bb5e3fb0", size = 46046, upload-time = "2025-08-11T12:06:25.893Z" }, - { url = "https://files.pythonhosted.org/packages/cf/9a/874212b6f5c1c2d870d0a7adc5bb4cfe9b0624fa15cdf5cf757c0f5087ae/multidict-6.6.4-cp310-cp310-win_arm64.whl", hash = "sha256:01d0959807a451fe9fdd4da3e139cb5b77f7328baf2140feeaf233e1d777b729", size = 43147, upload-time = "2025-08-11T12:06:27.534Z" }, - { url = "https://files.pythonhosted.org/packages/6b/7f/90a7f01e2d005d6653c689039977f6856718c75c5579445effb7e60923d1/multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c", size = 76472, upload-time = "2025-08-11T12:06:29.006Z" }, - { url = "https://files.pythonhosted.org/packages/54/a3/bed07bc9e2bb302ce752f1dabc69e884cd6a676da44fb0e501b246031fdd/multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb", size = 44634, upload-time = "2025-08-11T12:06:30.374Z" }, - { url = "https://files.pythonhosted.org/packages/a7/4b/ceeb4f8f33cf81277da464307afeaf164fb0297947642585884f5cad4f28/multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e", size = 44282, upload-time = "2025-08-11T12:06:31.958Z" }, - { url = "https://files.pythonhosted.org/packages/03/35/436a5da8702b06866189b69f655ffdb8f70796252a8772a77815f1812679/multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded", size = 229696, upload-time = "2025-08-11T12:06:33.087Z" }, - { url = "https://files.pythonhosted.org/packages/b6/0e/915160be8fecf1fca35f790c08fb74ca684d752fcba62c11daaf3d92c216/multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683", size = 246665, upload-time = "2025-08-11T12:06:34.448Z" }, - { url = "https://files.pythonhosted.org/packages/08/ee/2f464330acd83f77dcc346f0b1a0eaae10230291450887f96b204b8ac4d3/multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a", size = 225485, upload-time = "2025-08-11T12:06:35.672Z" }, - { url = "https://files.pythonhosted.org/packages/71/cc/9a117f828b4d7fbaec6adeed2204f211e9caf0a012692a1ee32169f846ae/multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9", size = 257318, upload-time = "2025-08-11T12:06:36.98Z" }, - { url = "https://files.pythonhosted.org/packages/25/77/62752d3dbd70e27fdd68e86626c1ae6bccfebe2bb1f84ae226363e112f5a/multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50", size = 254689, upload-time = "2025-08-11T12:06:38.233Z" }, - { url = "https://files.pythonhosted.org/packages/00/6e/fac58b1072a6fc59af5e7acb245e8754d3e1f97f4f808a6559951f72a0d4/multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52", size = 246709, upload-time = "2025-08-11T12:06:39.517Z" }, - { url = "https://files.pythonhosted.org/packages/01/ef/4698d6842ef5e797c6db7744b0081e36fb5de3d00002cc4c58071097fac3/multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6", size = 243185, upload-time = "2025-08-11T12:06:40.796Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c9/d82e95ae1d6e4ef396934e9b0e942dfc428775f9554acf04393cce66b157/multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e", size = 237838, upload-time = "2025-08-11T12:06:42.595Z" }, - { url = "https://files.pythonhosted.org/packages/57/cf/f94af5c36baaa75d44fab9f02e2a6bcfa0cd90acb44d4976a80960759dbc/multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3", size = 246368, upload-time = "2025-08-11T12:06:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/4a/fe/29f23460c3d995f6a4b678cb2e9730e7277231b981f0b234702f0177818a/multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c", size = 253339, upload-time = "2025-08-11T12:06:45.597Z" }, - { url = "https://files.pythonhosted.org/packages/29/b6/fd59449204426187b82bf8a75f629310f68c6adc9559dc922d5abe34797b/multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b", size = 246933, upload-time = "2025-08-11T12:06:46.841Z" }, - { url = "https://files.pythonhosted.org/packages/19/52/d5d6b344f176a5ac3606f7a61fb44dc746e04550e1a13834dff722b8d7d6/multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f", size = 242225, upload-time = "2025-08-11T12:06:48.588Z" }, - { url = "https://files.pythonhosted.org/packages/ec/d3/5b2281ed89ff4d5318d82478a2a2450fcdfc3300da48ff15c1778280ad26/multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2", size = 41306, upload-time = "2025-08-11T12:06:49.95Z" }, - { url = "https://files.pythonhosted.org/packages/74/7d/36b045c23a1ab98507aefd44fd8b264ee1dd5e5010543c6fccf82141ccef/multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e", size = 46029, upload-time = "2025-08-11T12:06:51.082Z" }, - { url = "https://files.pythonhosted.org/packages/0f/5e/553d67d24432c5cd52b49047f2d248821843743ee6d29a704594f656d182/multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf", size = 43017, upload-time = "2025-08-11T12:06:52.243Z" }, - { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" }, - { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" }, - { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" }, - { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" }, - { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" }, - { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" }, - { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" }, - { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" }, - { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" }, - { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" }, - { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" }, - { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" }, - { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" }, - { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" }, - { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" }, - { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" }, - { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] [[package]] @@ -1612,31 +1668,31 @@ wheels = [ [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] name = "nostr-sdk" -version = "0.44.0" +version = "0.44.2" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/23/6a5078925ae51809a9c91a1f24d65a260cb6f27d3b6f234be3e1b28e6bf2/nostr_sdk-0.44.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:788bd39dc82733f10ddc2b88112efad18551919b19eda0228588d7a22e799344", size = 3356276, upload-time = "2025-11-06T10:40:46.281Z" }, - { url = "https://files.pythonhosted.org/packages/7f/cd/df78337ea488c3cbad51e3a1faca376aded5d0d231cb7d1bbfa32da48efa/nostr_sdk-0.44.0-cp39-abi3-macosx_11_0_x86_64.whl", hash = "sha256:3c22de46697bfafafde78165cf5ecbe36c708b46d672d05ea4447ee15cc88b61", size = 3471606, upload-time = "2025-11-06T10:40:48.452Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a8/38a372bfb0105eb641c8cdd8cb5e35da438e0b7cac01cc39068de81ab763/nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:c4f82ee06c5e2c49e1f6074b2a94a8985130b766cef182114bd9ec89913cbd89", size = 3607141, upload-time = "2025-11-06T10:40:49.801Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/30d48d69157806ecf1c4b6d03e2ff5fdf1e8f5e05f80da0b573d63f231fb/nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:b82fc26d68eb0d9f2effbea453e745cecbf958179620fad2a182902a57cf7e6e", size = 3359084, upload-time = "2025-11-06T10:40:51.855Z" }, - { url = "https://files.pythonhosted.org/packages/b4/76/c4b280595ebe5fa8710c7d7309b0faf3faf294fc06e7474acdc88522c2d3/nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_i686.whl", hash = "sha256:f2f52e886d2acf6914f02791ba8d0f694dee5a657ea0c09e6b4316b87a09294a", size = 3596507, upload-time = "2025-11-06T10:40:53.285Z" }, - { url = "https://files.pythonhosted.org/packages/8e/e2/dd1888e429cde53172ef7733975be2e8427fcd5b961a65326e28346d63b3/nostr_sdk-0.44.0-cp39-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:650b8e8438da7807d2b1337fa7989b848794cf92e9796d529144a34a9cf0ec77", size = 3722354, upload-time = "2025-11-06T10:40:54.987Z" }, - { url = "https://files.pythonhosted.org/packages/59/34/b0ebe74aa138f747eceece076b7e59b7f7a104b2a03cf33b7797a2266902/nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53785102f4d4e8db8c5f32a26b8f6d87632f156de33163cb371f36c79aeb077c", size = 3600147, upload-time = "2025-11-06T10:40:56.717Z" }, - { url = "https://files.pythonhosted.org/packages/15/af/5f78e5c8954af80dfacff6e5ba30cbceada668b8ffa955014d8b8bda29e7/nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:23e6ace94b35e80a36d49afe22d101d38f57c036f094dc57f73c417708e89096", size = 3355748, upload-time = "2025-11-06T10:40:58.194Z" }, - { url = "https://files.pythonhosted.org/packages/27/25/4404902bd28be61e140af4a84d459eb5abd1980c5d3252c19f36fc6fbb91/nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3f68f278449ff9271b62c193fc842d836d9ca1dcbf3db6c38e5ce3a8198be9e0", size = 3487845, upload-time = "2025-11-06T10:40:59.947Z" }, - { url = "https://files.pythonhosted.org/packages/ce/37/38b1706fbdf032c1caf3fe15cbe7f45430eb90cc8b7db19c78f1458f2c9e/nostr_sdk-0.44.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c1632a8db0a1727481a309c4ebb47a7e5206a485bddca92a966822266b7be5d5", size = 3720672, upload-time = "2025-11-06T10:41:01.598Z" }, - { url = "https://files.pythonhosted.org/packages/c7/04/e6eebee49d41185e55035f039f3763910aa90e223d44cc9fa810ddd08d8f/nostr_sdk-0.44.0-cp39-abi3-win32.whl", hash = "sha256:197d50b7253a1af4db2ce7511542a3d5827208b991fb164794f1c1a750c2ad07", size = 3160841, upload-time = "2025-11-06T10:41:03.482Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/2d5eceeaded77a940c0d799efdef91339de49256cbbb78b8ef59813e5c64/nostr_sdk-0.44.0-cp39-abi3-win_amd64.whl", hash = "sha256:b07cf13ef05fee7dc05d04d84bbcb21e5004e52b315de3212ed8def3dbb2dad5", size = 3379982, upload-time = "2025-11-06T10:41:04.883Z" }, - { url = "https://files.pythonhosted.org/packages/cc/44/fd7a6020d627c7fa52f044761e861fa89668785e4371f38bbbe219d263e9/nostr_sdk-0.44.0-cp39-abi3-win_arm64.whl", hash = "sha256:e2765ba0987717a950e20eb87f976f28e0128d28a9cfad3dc7ff9d3754190a47", size = 3229425, upload-time = "2025-11-06T10:41:06.137Z" }, + { url = "https://files.pythonhosted.org/packages/35/ea/cd40b12352a5cba810116641959a7054f83d5f48d16e5e47614992b9ba64/nostr_sdk-0.44.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:184075689531e34085bc1e71b62f3a964df2d4aeb15a25f94557e15a4294c584", size = 3360561, upload-time = "2026-01-29T10:56:37.285Z" }, + { url = "https://files.pythonhosted.org/packages/ed/66/81057ec283cb6bcc5df27c1d58a0a7996afa4fb96c0c9a4570ae50190f9a/nostr_sdk-0.44.2-cp39-abi3-macosx_11_0_x86_64.whl", hash = "sha256:65e85c79295f4e258e5276a82b52e36ffb3f5cf59c2c7c4a959970ed9303cf6f", size = 3475196, upload-time = "2026-01-29T10:56:39.296Z" }, + { url = "https://files.pythonhosted.org/packages/61/fd/567b67c832b6263817470885e92b059b7d19cd9967b83ef1f59b6e04e603/nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_aarch64.whl", hash = "sha256:d1d557aeb8a423dcd054f699bbf7371eb268a6cec5916bf147957cb3f9f7da02", size = 3613359, upload-time = "2026-01-29T10:56:41.079Z" }, + { url = "https://files.pythonhosted.org/packages/fc/93/cdf2cd98f8fbb045a1ca12f073ad747342961b0a3bbe9cd6a09760cb0132/nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_armv7l.whl", hash = "sha256:41b1bb050f890f81b4c4edaf4d6cc3054ae9e783911eb4ce7dce6b8e97dfa60e", size = 3364451, upload-time = "2026-01-29T10:56:42.987Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ec/7e9e9630af0b49e931cff8f65a5c9ce4086e9f2c372213d355b53871253c/nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_i686.whl", hash = "sha256:db584ba95de5abbb74da77036c3316e9a166bc22d9d2ea3ca38fc09325d9c6a9", size = 3603547, upload-time = "2026-01-29T10:56:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/6a/03/c7ed0230f84615e2930259788b1fc1c485b159093f2070125ae9ddae327e/nostr_sdk-0.44.2-cp39-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:4e1dccf29b7ad6eeb44945175a45334d4e45d82881ae5f3a28433899f155831c", size = 3726609, upload-time = "2026-01-29T10:56:45.709Z" }, + { url = "https://files.pythonhosted.org/packages/d1/8d/bfb2172743a99a21bbba0a4f77572be50cb8b10dbcf837b70be0e0b8f4b7/nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:aa347c6437dc33ae45cc2ed56177f5aeded0fda42285b1b325a840de44e1f708", size = 3607268, upload-time = "2026-01-29T10:56:47.312Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/cb61a46d91bf61f15b628d188a2338b9e76e9fee4078728d4a7ded876381/nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:a7a03b35ddbc69f31d79bea17ac60b8d250ef62bcf1d52fc33b9e36e0ecf772b", size = 3360529, upload-time = "2026-01-29T10:56:49.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dc/5405965ef11cc784be2dd473297caf997f8fa00b5f2e92884a029eae6eee/nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:e53682dbf192acd137a92ae5d91903fbb22728d55452a8fa2315581f1d8413f2", size = 3494705, upload-time = "2026-01-29T10:56:51.158Z" }, + { url = "https://files.pythonhosted.org/packages/03/89/febbbec3d20cb63ab30eee84f59cb06317f24b8e2ab15c2d99212d71d622/nostr_sdk-0.44.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b3e6dd4191997546f157aba4532a995d06ad8b0cf9c17e77c0015553f06a9cf2", size = 3727113, upload-time = "2026-01-29T10:56:52.513Z" }, + { url = "https://files.pythonhosted.org/packages/67/d5/718b0428af9a3c9e33bd6a21b2b32920559db356e0369d0013b6421286d9/nostr_sdk-0.44.2-cp39-abi3-win32.whl", hash = "sha256:aa94a18eb8f4d77559c0290c0f17d6816c00f4fdddba5f1fcf96ff01b4690b42", size = 3164430, upload-time = "2026-01-29T10:56:54.334Z" }, + { url = "https://files.pythonhosted.org/packages/96/67/3f19800f6a52c2e1e7ba2b2b04ed0fca7a11a1819a2d02cdd961c4f4a54b/nostr_sdk-0.44.2-cp39-abi3-win_amd64.whl", hash = "sha256:31e609a864c3857cddde70d8a91181e2b2cadf923e562b6a9d82e655edded117", size = 3384420, upload-time = "2026-01-29T10:56:56.19Z" }, + { url = "https://files.pythonhosted.org/packages/71/bb/b2c2bb390fb309477bff63507c9d6058bea55d01f4938a749269dd5dd8bc/nostr_sdk-0.44.2-cp39-abi3-win_arm64.whl", hash = "sha256:3a9d3284af0547e224bf705d90cd6d9ca5a1b48f5becea1021da915de4408310", size = 3233797, upload-time = "2026-01-29T10:56:57.538Z" }, ] [[package]] @@ -1716,68 +1772,79 @@ wheels = [ [[package]] name = "pathspec" -version = "0.12.1" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] [[package]] name = "pillow" -version = "12.1.1" +version = "12.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099, upload-time = "2026-02-11T04:20:06.13Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880, upload-time = "2026-02-11T04:20:09.291Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587, upload-time = "2026-02-11T04:20:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678, upload-time = "2026-02-11T04:20:12.455Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777, upload-time = "2026-02-11T04:20:14.441Z" }, - { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140, upload-time = "2026-02-11T04:20:16.387Z" }, - { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855, upload-time = "2026-02-11T04:20:18.554Z" }, - { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329, upload-time = "2026-02-11T04:20:20.646Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574, upload-time = "2026-02-11T04:20:22.43Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347, upload-time = "2026-02-11T04:20:23.932Z" }, - { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457, upload-time = "2026-02-11T04:20:25.392Z" }, - { url = "https://files.pythonhosted.org/packages/2b/46/5da1ec4a5171ee7bf1a0efa064aba70ba3d6e0788ce3f5acd1375d23c8c0/pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32", size = 5304084, upload-time = "2026-02-11T04:20:27.501Z" }, - { url = "https://files.pythonhosted.org/packages/78/93/a29e9bc02d1cf557a834da780ceccd54e02421627200696fcf805ebdc3fb/pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38", size = 4657866, upload-time = "2026-02-11T04:20:29.827Z" }, - { url = "https://files.pythonhosted.org/packages/13/84/583a4558d492a179d31e4aae32eadce94b9acf49c0337c4ce0b70e0a01f2/pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5", size = 6232148, upload-time = "2026-02-11T04:20:31.329Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e2/53c43334bbbb2d3b938978532fbda8e62bb6e0b23a26ce8592f36bcc4987/pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090", size = 8038007, upload-time = "2026-02-11T04:20:34.225Z" }, - { url = "https://files.pythonhosted.org/packages/b8/a6/3d0e79c8a9d58150dd98e199d7c1c56861027f3829a3a60b3c2784190180/pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af", size = 6345418, upload-time = "2026-02-11T04:20:35.858Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b", size = 7034590, upload-time = "2026-02-11T04:20:37.91Z" }, - { url = "https://files.pythonhosted.org/packages/af/bf/e6f65d3db8a8bbfeaf9e13cc0417813f6319863a73de934f14b2229ada18/pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5", size = 6458655, upload-time = "2026-02-11T04:20:39.496Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c2/66091f3f34a25894ca129362e510b956ef26f8fb67a0e6417bc5744e56f1/pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d", size = 7159286, upload-time = "2026-02-11T04:20:41.139Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5a/24bc8eb526a22f957d0cec6243146744966d40857e3d8deb68f7902ca6c1/pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c", size = 6328663, upload-time = "2026-02-11T04:20:43.184Z" }, - { url = "https://files.pythonhosted.org/packages/31/03/bef822e4f2d8f9d7448c133d0a18185d3cce3e70472774fffefe8b0ed562/pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563", size = 7031448, upload-time = "2026-02-11T04:20:44.696Z" }, - { url = "https://files.pythonhosted.org/packages/49/70/f76296f53610bd17b2e7d31728b8b7825e3ac3b5b3688b51f52eab7c0818/pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80", size = 2453651, upload-time = "2026-02-11T04:20:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" }, - { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" }, - { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" }, - { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" }, - { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" }, - { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" }, - { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" }, - { url = "https://files.pythonhosted.org/packages/56/11/5d43209aa4cb58e0cc80127956ff1796a68b928e6324bbf06ef4db34367b/pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f", size = 5228606, upload-time = "2026-02-11T04:22:52.106Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d5/3b005b4e4fda6698b371fa6c21b097d4707585d7db99e98d9b0b87ac612a/pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9", size = 4622321, upload-time = "2026-02-11T04:22:53.827Z" }, - { url = "https://files.pythonhosted.org/packages/df/36/ed3ea2d594356fd8037e5a01f6156c74bc8d92dbb0fa60746cc96cabb6e8/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e", size = 5247579, upload-time = "2026-02-11T04:22:56.094Z" }, - { url = "https://files.pythonhosted.org/packages/54/9a/9cc3e029683cf6d20ae5085da0dafc63148e3252c2f13328e553aaa13cfb/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9", size = 6989094, upload-time = "2026-02-11T04:22:58.288Z" }, - { url = "https://files.pythonhosted.org/packages/00/98/fc53ab36da80b88df0967896b6c4b4cd948a0dc5aa40a754266aa3ae48b3/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3", size = 5313850, upload-time = "2026-02-11T04:23:00.554Z" }, - { url = "https://files.pythonhosted.org/packages/30/02/00fa585abfd9fe9d73e5f6e554dc36cc2b842898cbfc46d70353dae227f8/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735", size = 5963343, upload-time = "2026-02-11T04:23:02.934Z" }, - { url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" }, + { url = "https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size = 5392418, upload-time = "2026-07-01T11:53:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size = 4785287, upload-time = "2026-07-01T11:53:29.761Z" }, + { url = "https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size = 6253754, upload-time = "2026-07-01T11:53:32.298Z" }, + { url = "https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size = 6925605, upload-time = "2026-07-01T11:53:34.487Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size = 6327788, upload-time = "2026-07-01T11:53:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size = 7036288, upload-time = "2026-07-01T11:53:38.712Z" }, + { url = "https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size = 6472396, upload-time = "2026-07-01T11:53:40.781Z" }, + { url = "https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size = 7226887, upload-time = "2026-07-01T11:53:42.764Z" }, + { url = "https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size = 2568039, upload-time = "2026-07-01T11:53:45.372Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size = 5392415, upload-time = "2026-07-01T11:53:47.162Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size = 4785266, upload-time = "2026-07-01T11:53:49.079Z" }, + { url = "https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size = 6263814, upload-time = "2026-07-01T11:53:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size = 6934408, upload-time = "2026-07-01T11:53:53.487Z" }, + { url = "https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size = 6337160, upload-time = "2026-07-01T11:53:55.457Z" }, + { url = "https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size = 7045172, upload-time = "2026-07-01T11:53:57.736Z" }, + { url = "https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size = 6472232, upload-time = "2026-07-01T11:53:59.767Z" }, + { url = "https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size = 7233653, upload-time = "2026-07-01T11:54:02.066Z" }, + { url = "https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size = 2568195, upload-time = "2026-07-01T11:54:04.622Z" }, + { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, + { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, + { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, + { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, + { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, + { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, + { url = "https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size = 5302510, upload-time = "2026-07-01T11:56:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size = 4736058, upload-time = "2026-07-01T11:56:28.041Z" }, + { url = "https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size = 5237776, upload-time = "2026-07-01T11:56:30.263Z" }, + { url = "https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size = 5860358, upload-time = "2026-07-01T11:56:32.68Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size = 7231786, upload-time = "2026-07-01T11:56:35.046Z" }, ] [[package]] name = "platformdirs" -version = "4.5.0" +version = "4.9.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/4a/0883b8e3802965322523f0b200ecf33d31f10991d0401162f4b23c698b42/platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a", size = 29400, upload-time = "2026-04-09T00:04:10.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, + { url = "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917", size = 21348, upload-time = "2026-04-09T00:04:09.463Z" }, +] + +[[package]] +name = "playwright" +version = "1.61.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet" }, + { name = "pyee" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/ee/31e4e0db36588b817a10b299a0285082545fde7d36543c2abe498bb3d61a/playwright-1.61.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:ff138c3a604f69911e9d42fd036e55c2a171e5616edf04c1e7f60a2a285540b0", size = 43421877, upload-time = "2026-06-29T10:32:48.428Z" }, + { url = "https://files.pythonhosted.org/packages/42/35/71395dd3ecc798965be4a3ef8c443217d4abca168e7cb34536304f9489e6/playwright-1.61.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:009588c2a7e499bc5a8b425b61fa65490968bbda9cd69e0cf2cff10f8304659a", size = 42205016, upload-time = "2026-06-29T10:32:52.104Z" }, + { url = "https://files.pythonhosted.org/packages/f4/44/323164cf5cd1647bdefce76ffce27651aadb959d089b48f53ea40918276e/playwright-1.61.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9f7de4536088d12037c13a52b7ea34b59270b78926bb56935070597ffac6b1af", size = 43421884, upload-time = "2026-06-29T10:32:55.773Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f8/a35bf179e4ba2522c1893635094a64e407572547bd61528820fc0abc87fe/playwright-1.61.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:54f3b39f6eab832e33458c1dd7da0b5682aedab3b09ae731b5c59fa12fd2024e", size = 47421381, upload-time = "2026-06-29T10:32:59.903Z" }, + { url = "https://files.pythonhosted.org/packages/b7/eb/e3f922348ec17c315f98c463f72faa1181a1c3de0bfe31a8d2edf6561723/playwright-1.61.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93454322ade8c11d5d6c211bfd91bdfb9ffb4810e3e026371bcbc4bec1b7ee4c", size = 47120545, upload-time = "2026-06-29T10:33:03.574Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a6/5be4e52b40a9c0c8a073e7c5b0785c05cf5a9ea8f8a7b5b260e32d970342/playwright-1.61.0-py3-none-win32.whl", hash = "sha256:372d55a6f1248fa1dd47599686980cb8fb5bbe6fcda59eab793eb657c11d8a9b", size = 37844841, upload-time = "2026-06-29T10:33:07.361Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fd/2b78036e5fbe9d5f5645bbe08a1eac7160c51243c0093963edbcf67c35d9/playwright-1.61.0-py3-none-win_amd64.whl", hash = "sha256:35c6cc4589a5d00964a59d7b3e59641e0aac0c02f15479a7af77d20f6bc79597", size = 37844846, upload-time = "2026-06-29T10:33:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/27/0d/1b0f3c4ee4eb0514bc805b5c2f9a223e5b6de4f11a926f5235d51d0fc81b/playwright-1.61.0-py3-none-win_arm64.whl", hash = "sha256:e9fcbffcf557a8620fdedd92491eb59a32d18e23d6f3b4f6214b952be324fe51", size = 33955127, upload-time = "2026-06-29T10:33:14.008Z" }, ] [[package]] @@ -1816,136 +1883,139 @@ wheels = [ [[package]] name = "propcache" -version = "0.3.2" +version = "0.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, + { url = "https://files.pythonhosted.org/packages/5b/56/030b7b4719d53085722893e0009dffb9236aa10bca1b12121bdc5626ef16/propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b", size = 93417, upload-time = "2026-05-08T20:59:15.597Z" }, + { url = "https://files.pythonhosted.org/packages/1a/55/1140a8e067b8ec093a18a4ae7bb0045d9db65da38a08618ddc5e2f1994aa/propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c", size = 53847, upload-time = "2026-05-08T20:59:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb", size = 53512, upload-time = "2026-05-08T20:59:18.64Z" }, + { url = "https://files.pythonhosted.org/packages/b7/db/cf51a71bab2009517d1a7f0ee07657e3bd446c4d69f67e6966cf17bcf956/propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e", size = 58068, upload-time = "2026-05-08T20:59:20.683Z" }, + { url = "https://files.pythonhosted.org/packages/b7/43/39b6bdee9699fa1e1641c519feeb64a67e2a9f93bb465c70776b37a7333f/propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e", size = 61020, upload-time = "2026-05-08T20:59:22.112Z" }, + { url = "https://files.pythonhosted.org/packages/26/0b/843726fbb0a29a8c5684fdb25971823638399f31e52e9d1f06a02dc9aa6b/propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b", size = 62732, upload-time = "2026-05-08T20:59:23.805Z" }, + { url = "https://files.pythonhosted.org/packages/39/6e/899fed76dc1942b8a64193a4f059d7f1a2c7ef65085e8a9366ed8ec0d199/propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d", size = 60140, upload-time = "2026-05-08T20:59:25.389Z" }, + { url = "https://files.pythonhosted.org/packages/ab/09/3da4be9b5b879219ad234aa535b3dd4a080ed1ad48d3a73ca07a9e798f22/propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d", size = 60400, upload-time = "2026-05-08T20:59:27.238Z" }, + { url = "https://files.pythonhosted.org/packages/60/2f/09b72b874a9aa0044faf52a69807a6ed618e267ceaa9ec4a63195fa5b504/propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0", size = 58155, upload-time = "2026-05-08T20:59:28.48Z" }, + { url = "https://files.pythonhosted.org/packages/8a/37/97489848c54c95578045473954f10956d619ce6a09e7ac137b71cdcb698b/propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b", size = 57037, upload-time = "2026-05-08T20:59:30.146Z" }, + { url = "https://files.pythonhosted.org/packages/22/db/6c695285ccfc49012743ee9c98212b8c5dd0aed7b63cfd816d4a0f7a1601/propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf", size = 61103, upload-time = "2026-05-08T20:59:31.626Z" }, + { url = "https://files.pythonhosted.org/packages/98/a9/1e500401ca593b0bdb6bf75a70bc2d723835fd53360edff6af70692c7546/propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf", size = 60394, upload-time = "2026-05-08T20:59:32.829Z" }, + { url = "https://files.pythonhosted.org/packages/1f/87/f638b6e375eae0f30a1a2325d8b34fd85fdc785bb9960cf805f3bf1ec69a/propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e", size = 63084, upload-time = "2026-05-08T20:59:35.964Z" }, + { url = "https://files.pythonhosted.org/packages/f6/18/884573f5d97b6d9eba68de759a82c901b7e39d7904d30f7b8d58d42d2a12/propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274", size = 60999, upload-time = "2026-05-08T20:59:38.481Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1a/c3915eb059ceec9e758a56e4cfd955292bc0f201be2176a46b76d94b303a/propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe", size = 39036, upload-time = "2026-05-08T20:59:40.323Z" }, + { url = "https://files.pythonhosted.org/packages/5b/02/1dfd5607501a602d19c1c449d2d193b7d1c611f9246b4059026a1189a80e/propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d", size = 42190, upload-time = "2026-05-08T20:59:42.232Z" }, + { url = "https://files.pythonhosted.org/packages/57/93/f71588ad08b3e6f4b555b5ef215808a3c02b042d0151ad82fa6f15be677a/propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5", size = 38545, upload-time = "2026-05-08T20:59:44.087Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f1/8a8cc1c2c7e7934ab77e0163414f736fadbc0f5e8dd9673b952355ac175b/propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78", size = 90744, upload-time = "2026-05-08T20:59:45.799Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f4/651b1225e976bd1a2ba5cfba0c29d096581c2636b437e3a9a7ab6276270a/propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959", size = 52033, upload-time = "2026-05-08T20:59:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7", size = 52754, upload-time = "2026-05-08T20:59:49.202Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fe/b3551b41bbc2f5b5bb088fc6920567cd43101253e68fbaa261339eb96fe1/propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511", size = 57573, upload-time = "2026-05-08T20:59:50.778Z" }, + { url = "https://files.pythonhosted.org/packages/83/27/ab851ebd1b7172e3e161f5f8d39e315d54a91bea246f01f4d872d3376aef/propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660", size = 60645, upload-time = "2026-05-08T20:59:52.227Z" }, + { url = "https://files.pythonhosted.org/packages/95/7d/466b3d18022e9897cbda9c735c493c5bd747d7a4c6f5ea1480b4cec434b6/propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66", size = 61563, upload-time = "2026-05-08T20:59:53.866Z" }, + { url = "https://files.pythonhosted.org/packages/27/1b/16ab7f2cf2041da2f60d156ba64c2484eadf9168075b4ff43c3ef60045af/propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b", size = 58888, upload-time = "2026-05-08T20:59:55.457Z" }, + { url = "https://files.pythonhosted.org/packages/0a/67/bb777ffd907633563bf35fd859c4ce97b0512c32f4633cf5d1eb7c33512b/propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67", size = 59253, upload-time = "2026-05-08T20:59:57.075Z" }, + { url = "https://files.pythonhosted.org/packages/b9/42/64f8d90b73fd9cdc1499b48057ff6d9cd2a98a25734c9bb62ecf07e87061/propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f", size = 57558, upload-time = "2026-05-08T20:59:58.602Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/dba5bc03c9041f2092ea55a449caf5dfe68352c6654511b29ba0654ddb69/propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c", size = 55007, upload-time = "2026-05-08T20:59:59.837Z" }, + { url = "https://files.pythonhosted.org/packages/14/c0/43f649c7aa2a77a3b100d84e9dea3a483120ecb608bfe36ce49eaff517fe/propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0", size = 60355, upload-time = "2026-05-08T21:00:01.144Z" }, + { url = "https://files.pythonhosted.org/packages/83/c0/435dafd27f1cb4a495381dae60e25883ccfe4020bb72818e8184c1678092/propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6", size = 59057, upload-time = "2026-05-08T21:00:02.401Z" }, + { url = "https://files.pythonhosted.org/packages/53/ae/6e292df9135d659944e96cb3389258e4a663e5b2b5f6c217ef0ddc8d2f73/propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27", size = 61938, upload-time = "2026-05-08T21:00:03.638Z" }, + { url = "https://files.pythonhosted.org/packages/0b/42/314ebc50d8159055411fd6b0bda322ff510e4b1f7d2e4927940ad0f6af20/propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f", size = 59731, upload-time = "2026-05-08T21:00:04.881Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9b/2da6dee38871c3c8772fabc2758325a5c9077d6d18c597737dc04dd884cd/propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0", size = 38966, upload-time = "2026-05-08T21:00:06.511Z" }, + { url = "https://files.pythonhosted.org/packages/42/4e/f17363fb58c0afe05b067361cb6d86ed2d29de6506779a27547c4d183075/propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82", size = 42135, upload-time = "2026-05-08T21:00:08.088Z" }, + { url = "https://files.pythonhosted.org/packages/c6/eb/6af6685077d22e8b33358d3c548e3282706a0b3cd85044ffba4e5dd08e3b/propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab", size = 38381, upload-time = "2026-05-08T21:00:09.692Z" }, + { url = "https://files.pythonhosted.org/packages/4a/cb/e27bc2b2737a0bb49962b275efa051e8f1c35a936df7d5139b6b658b7dc9/propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba", size = 95887, upload-time = "2026-05-08T21:00:11.277Z" }, + { url = "https://files.pythonhosted.org/packages/e6/13/b8ae04c59392f8d11c6cd9fb4011d1dc7c86b81225c770280300e259ffe1/propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a", size = 54654, upload-time = "2026-05-08T21:00:12.604Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf", size = 55190, upload-time = "2026-05-08T21:00:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/085d0cd63062e84044e3f05797749c3f8e3938ff3aeb0eb2f69d43fafc91/propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144", size = 59995, upload-time = "2026-05-08T21:00:15.526Z" }, + { url = "https://files.pythonhosted.org/packages/9c/42/32cf8e3009e92b2645cf1e944f701e8ea4e924dffde1ee26db860bcbf7e4/propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9", size = 63422, upload-time = "2026-05-08T21:00:16.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f112433f99fc979431b87a39ef169e3f8df070d99a72792c56d6937ac48b/propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42", size = 64342, upload-time = "2026-05-08T21:00:18.362Z" }, + { url = "https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476", size = 61639, upload-time = "2026-05-08T21:00:19.692Z" }, + { url = "https://files.pythonhosted.org/packages/cc/da/4d775080b1490c0ae604acda868bd71aabe3a89ed16f2aa4339eb8a283e7/propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba", size = 61588, upload-time = "2026-05-08T21:00:21.155Z" }, + { url = "https://files.pythonhosted.org/packages/04/ac/f076982cbe2195ee9cf32de5a1e46951d9fb399fc207f390562dd0fd8fb2/propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a", size = 60029, upload-time = "2026-05-08T21:00:22.713Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/189be62e0dd898dce3b331e1b8c7a543cd3a405ac0c81fe8ee8a9d5d77e1/propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64", size = 56774, upload-time = "2026-05-08T21:00:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/93377b9c7939c1ffae98f878dee955efadfd638078bc86dbc21f9d52f651/propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913", size = 63532, upload-time = "2026-05-08T21:00:25.545Z" }, + { url = "https://files.pythonhosted.org/packages/14/f9/590ef6cfb9b8028d516d287812ece32bb0bc5f11fbb9c8bf6b2e6313fec8/propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1", size = 61592, upload-time = "2026-05-08T21:00:27.186Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5e/70958b3034c297a630bba2f17ca7abc2d5f39a803ad7e370ab79d1ecd022/propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33", size = 64788, upload-time = "2026-05-08T21:00:28.8Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/77fe5936d8c3086ca9048f7f415f122ed82e53884a9ec193646b42deef06/propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a", size = 62514, upload-time = "2026-05-08T21:00:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/cf/74/66bd798b5b3be70aa1b391f5cc9d6a0a5532d7fd3b19ec0b213e72e6ad9d/propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031", size = 39018, upload-time = "2026-05-08T21:00:31.622Z" }, + { url = "https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42", size = 42322, upload-time = "2026-05-08T21:00:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/4d/91/875812f1a3feb20ceba818ef39fbe4d92f1081e04ac815c822496d0d038b/propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84", size = 38172, upload-time = "2026-05-08T21:00:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, ] [[package]] name = "protobuf" -version = "6.33.2" +version = "6.33.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296, upload-time = "2025-12-06T00:17:53.311Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603, upload-time = "2025-12-06T00:17:41.114Z" }, - { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930, upload-time = "2025-12-06T00:17:43.278Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621, upload-time = "2025-12-06T00:17:44.445Z" }, - { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460, upload-time = "2025-12-06T00:17:45.678Z" }, - { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168, upload-time = "2025-12-06T00:17:46.813Z" }, - { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270, upload-time = "2025-12-06T00:17:48.253Z" }, - { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501, upload-time = "2025-12-06T00:17:52.211Z" }, + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, ] [[package]] name = "psycopg2-binary" -version = "2.9.11" +version = "2.9.12" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/6c/8767aaa597ba424643dc87348c6f1754dd9f48e80fdc1b9f7ca5c3a7c213/psycopg2-binary-2.9.11.tar.gz", hash = "sha256:b6aed9e096bf63f9e75edf2581aa9a7e7186d97ab5c177aa6c87797cd591236c", size = 379620, upload-time = "2025-10-10T11:14:48.041Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/60/a3624f79acea344c16fbef3a94d28b89a8042ddfb8f3e4ca83f538671409/psycopg2_binary-2.9.12.tar.gz", hash = "sha256:5ac9444edc768c02a6b6a591f070b8aae28ff3a99be57560ac996001580f294c", size = 379686, upload-time = "2026-04-21T09:40:34.304Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/f2/8e377d29c2ecf99f6062d35ea606b036e8800720eccfec5fe3dd672c2b24/psycopg2_binary-2.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6fe6b47d0b42ce1c9f1fa3e35bb365011ca22e39db37074458f27921dca40f2", size = 3756506, upload-time = "2025-10-10T11:10:30.144Z" }, - { url = "https://files.pythonhosted.org/packages/24/cc/dc143ea88e4ec9d386106cac05023b69668bd0be20794c613446eaefafe5/psycopg2_binary-2.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6c0e4262e089516603a09474ee13eabf09cb65c332277e39af68f6233911087", size = 3863943, upload-time = "2025-10-10T11:10:34.586Z" }, - { url = "https://files.pythonhosted.org/packages/8c/df/16848771155e7c419c60afeb24950b8aaa3ab09c0a091ec3ccca26a574d0/psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c47676e5b485393f069b4d7a811267d3168ce46f988fa602658b8bb901e9e64d", size = 4410873, upload-time = "2025-10-10T11:10:38.951Z" }, - { url = "https://files.pythonhosted.org/packages/43/79/5ef5f32621abd5a541b89b04231fe959a9b327c874a1d41156041c75494b/psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a28d8c01a7b27a1e3265b11250ba7557e5f72b5ee9e5f3a2fa8d2949c29bf5d2", size = 4468016, upload-time = "2025-10-10T11:10:43.319Z" }, - { url = "https://files.pythonhosted.org/packages/f0/9b/d7542d0f7ad78f57385971f426704776d7b310f5219ed58da5d605b1892e/psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f3f2732cf504a1aa9e9609d02f79bea1067d99edf844ab92c247bbca143303b", size = 4164996, upload-time = "2025-10-10T11:10:46.705Z" }, - { url = "https://files.pythonhosted.org/packages/14/ed/e409388b537fa7414330687936917c522f6a77a13474e4238219fcfd9a84/psycopg2_binary-2.9.11-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:865f9945ed1b3950d968ec4690ce68c55019d79e4497366d36e090327ce7db14", size = 3981881, upload-time = "2025-10-30T02:54:57.182Z" }, - { url = "https://files.pythonhosted.org/packages/bf/30/50e330e63bb05efc6fa7c1447df3e08954894025ca3dcb396ecc6739bc26/psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91537a8df2bde69b1c1db01d6d944c831ca793952e4f57892600e96cee95f2cd", size = 3650857, upload-time = "2025-10-10T11:10:50.112Z" }, - { url = "https://files.pythonhosted.org/packages/f0/e0/4026e4c12bb49dd028756c5b0bc4c572319f2d8f1c9008e0dad8cc9addd7/psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dca1f356a67ecb68c81a7bc7809f1569ad9e152ce7fd02c2f2036862ca9f66b", size = 3296063, upload-time = "2025-10-10T11:10:54.089Z" }, - { url = "https://files.pythonhosted.org/packages/2c/34/eb172be293c886fef5299fe5c3fcf180a05478be89856067881007934a7c/psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0da4de5c1ac69d94ed4364b6cbe7190c1a70d325f112ba783d83f8440285f152", size = 3043464, upload-time = "2025-10-30T02:55:02.483Z" }, - { url = "https://files.pythonhosted.org/packages/18/1c/532c5d2cb11986372f14b798a95f2eaafe5779334f6a80589a68b5fcf769/psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37d8412565a7267f7d79e29ab66876e55cb5e8e7b3bbf94f8206f6795f8f7e7e", size = 3345378, upload-time = "2025-10-10T11:11:01.039Z" }, - { url = "https://files.pythonhosted.org/packages/70/e7/de420e1cf16f838e1fa17b1120e83afff374c7c0130d088dba6286fcf8ea/psycopg2_binary-2.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:c665f01ec8ab273a61c62beeb8cce3014c214429ced8a308ca1fc410ecac3a39", size = 2713904, upload-time = "2025-10-10T11:11:04.81Z" }, - { url = "https://files.pythonhosted.org/packages/c7/ae/8d8266f6dd183ab4d48b95b9674034e1b482a3f8619b33a0d86438694577/psycopg2_binary-2.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0e8480afd62362d0a6a27dd09e4ca2def6fa50ed3a4e7c09165266106b2ffa10", size = 3756452, upload-time = "2025-10-10T11:11:11.583Z" }, - { url = "https://files.pythonhosted.org/packages/4b/34/aa03d327739c1be70e09d01182619aca8ebab5970cd0cfa50dd8b9cec2ac/psycopg2_binary-2.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:763c93ef1df3da6d1a90f86ea7f3f806dc06b21c198fa87c3c25504abec9404a", size = 3863957, upload-time = "2025-10-10T11:11:16.932Z" }, - { url = "https://files.pythonhosted.org/packages/48/89/3fdb5902bdab8868bbedc1c6e6023a4e08112ceac5db97fc2012060e0c9a/psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e164359396576a3cc701ba8af4751ae68a07235d7a380c631184a611220d9a4", size = 4410955, upload-time = "2025-10-10T11:11:21.21Z" }, - { url = "https://files.pythonhosted.org/packages/ce/24/e18339c407a13c72b336e0d9013fbbbde77b6fd13e853979019a1269519c/psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d57c9c387660b8893093459738b6abddbb30a7eab058b77b0d0d1c7d521ddfd7", size = 4468007, upload-time = "2025-10-10T11:11:24.831Z" }, - { url = "https://files.pythonhosted.org/packages/91/7e/b8441e831a0f16c159b5381698f9f7f7ed54b77d57bc9c5f99144cc78232/psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2c226ef95eb2250974bf6fa7a842082b31f68385c4f3268370e3f3870e7859ee", size = 4165012, upload-time = "2025-10-10T11:11:29.51Z" }, - { url = "https://files.pythonhosted.org/packages/0d/61/4aa89eeb6d751f05178a13da95516c036e27468c5d4d2509bb1e15341c81/psycopg2_binary-2.9.11-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a311f1edc9967723d3511ea7d2708e2c3592e3405677bf53d5c7246753591fbb", size = 3981881, upload-time = "2025-10-30T02:55:07.332Z" }, - { url = "https://files.pythonhosted.org/packages/76/a1/2f5841cae4c635a9459fe7aca8ed771336e9383b6429e05c01267b0774cf/psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ebb415404821b6d1c47353ebe9c8645967a5235e6d88f914147e7fd411419e6f", size = 3650985, upload-time = "2025-10-10T11:11:34.975Z" }, - { url = "https://files.pythonhosted.org/packages/84/74/4defcac9d002bca5709951b975173c8c2fa968e1a95dc713f61b3a8d3b6a/psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f07c9c4a5093258a03b28fab9b4f151aa376989e7f35f855088234e656ee6a94", size = 3296039, upload-time = "2025-10-10T11:11:40.432Z" }, - { url = "https://files.pythonhosted.org/packages/6d/c2/782a3c64403d8ce35b5c50e1b684412cf94f171dc18111be8c976abd2de1/psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:00ce1830d971f43b667abe4a56e42c1e2d594b32da4802e44a73bacacb25535f", size = 3043477, upload-time = "2025-10-30T02:55:11.182Z" }, - { url = "https://files.pythonhosted.org/packages/c8/31/36a1d8e702aa35c38fc117c2b8be3f182613faa25d794b8aeaab948d4c03/psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cffe9d7697ae7456649617e8bb8d7a45afb71cd13f7ab22af3e5c61f04840908", size = 3345842, upload-time = "2025-10-10T11:11:45.366Z" }, - { url = "https://files.pythonhosted.org/packages/6e/b4/a5375cda5b54cb95ee9b836930fea30ae5a8f14aa97da7821722323d979b/psycopg2_binary-2.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:304fd7b7f97eef30e91b8f7e720b3db75fee010b520e434ea35ed1ff22501d03", size = 2713894, upload-time = "2025-10-10T11:11:48.775Z" }, - { url = "https://files.pythonhosted.org/packages/d8/91/f870a02f51be4a65987b45a7de4c2e1897dd0d01051e2b559a38fa634e3e/psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4", size = 3756603, upload-time = "2025-10-10T11:11:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/27/fa/cae40e06849b6c9a95eb5c04d419942f00d9eaac8d81626107461e268821/psycopg2_binary-2.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f090b7ddd13ca842ebfe301cd587a76a4cf0913b1e429eb92c1be5dbeb1a19bc", size = 3864509, upload-time = "2025-10-10T11:11:56.452Z" }, - { url = "https://files.pythonhosted.org/packages/2d/75/364847b879eb630b3ac8293798e380e441a957c53657995053c5ec39a316/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a", size = 4411159, upload-time = "2025-10-10T11:12:00.49Z" }, - { url = "https://files.pythonhosted.org/packages/6f/a0/567f7ea38b6e1c62aafd58375665a547c00c608a471620c0edc364733e13/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e", size = 4468234, upload-time = "2025-10-10T11:12:04.892Z" }, - { url = "https://files.pythonhosted.org/packages/30/da/4e42788fb811bbbfd7b7f045570c062f49e350e1d1f3df056c3fb5763353/psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db", size = 4166236, upload-time = "2025-10-10T11:12:11.674Z" }, - { url = "https://files.pythonhosted.org/packages/3c/94/c1777c355bc560992af848d98216148be5f1be001af06e06fc49cbded578/psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757", size = 3983083, upload-time = "2025-10-30T02:55:15.73Z" }, - { url = "https://files.pythonhosted.org/packages/bd/42/c9a21edf0e3daa7825ed04a4a8588686c6c14904344344a039556d78aa58/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3", size = 3652281, upload-time = "2025-10-10T11:12:17.713Z" }, - { url = "https://files.pythonhosted.org/packages/12/22/dedfbcfa97917982301496b6b5e5e6c5531d1f35dd2b488b08d1ebc52482/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a", size = 3298010, upload-time = "2025-10-10T11:12:22.671Z" }, - { url = "https://files.pythonhosted.org/packages/66/ea/d3390e6696276078bd01b2ece417deac954dfdd552d2edc3d03204416c0c/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34", size = 3044641, upload-time = "2025-10-30T02:55:19.929Z" }, - { url = "https://files.pythonhosted.org/packages/12/9a/0402ded6cbd321da0c0ba7d34dc12b29b14f5764c2fc10750daa38e825fc/psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d", size = 3347940, upload-time = "2025-10-10T11:12:26.529Z" }, - { url = "https://files.pythonhosted.org/packages/b1/d2/99b55e85832ccde77b211738ff3925a5d73ad183c0b37bcbbe5a8ff04978/psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d", size = 2714147, upload-time = "2025-10-10T11:12:29.535Z" }, + { url = "https://files.pythonhosted.org/packages/78/80/49bacf9e51617d8309f6f0123e29edc793f6f5f6700c7d1f1b20782fbb37/psycopg2_binary-2.9.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b818ceff717f98851a64bffd4c5eb5b3059ae280276dcecc52ac658dcf006a4", size = 3712314, upload-time = "2026-04-20T23:33:31.363Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f2/98eeac7d60c43df9338287834edf9b3e69be68a2db78a57b1b81d705e735/psycopg2_binary-2.9.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d2fa0d7caca8635c56e373055094eeda3208d901d55dd0ff5abc1d4e47f82b56", size = 3822389, upload-time = "2026-04-20T23:33:34.178Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7c/30575e75f14d5351a56a1971bb43fe7f8bf7edf1b654fb1bec65c42a8812/psycopg2_binary-2.9.12-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:864c261b3690e1207d14bbfe0a61e27567981b80c47a778561e49f676f7ce433", size = 4578448, upload-time = "2026-04-20T23:33:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/65/9b/4df366d89f28c527dc39d0b6c98a5ca74e30d37ac097b73f3352147568ae/psycopg2_binary-2.9.12-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c5ee5213445dd45312459029b8c4c0a695461eb517b753d2582315bd07995f5e", size = 4273705, upload-time = "2026-04-20T23:33:39.291Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8a/c566803818eb03161ba869b6ba612bf7ad56816d98b9e5121e0a22ad6b0b/psycopg2_binary-2.9.12-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f9cae1f848779b5b01f417e762c40d026ea93eb0648249a604728cda991dde3", size = 5893784, upload-time = "2026-04-20T23:33:41.658Z" }, + { url = "https://files.pythonhosted.org/packages/63/fe/0dfa5797e0b229e0567bc378695224caf14d547f73b05be0c80549089772/psycopg2_binary-2.9.12-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:63a3ebbd543d3d1eda088ac99164e8c5bac15293ee91f20281fd17d050aee1c4", size = 4109306, upload-time = "2026-04-20T23:33:43.953Z" }, + { url = "https://files.pythonhosted.org/packages/3c/89/28063adf17a4ba501eedd9890feab0c649ee4d8bd0a97df0ff1e9584feab/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d6fcbba8c9fed08a73b8ac61ea79e4821e45b1e92bb466230c5e746bbf3d5256", size = 3654400, upload-time = "2026-04-20T23:33:46.115Z" }, + { url = "https://files.pythonhosted.org/packages/84/94/5a01de0aa4ead0b8d8d1aa4ec18cec0bd36d03fa714eaa5bb8a0b1b50020/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:36512911ebb2b60a0c3e44d0bb5048c1980aced91235d133b7874f3d1d93487c", size = 3299215, upload-time = "2026-04-20T23:33:48.202Z" }, + { url = "https://files.pythonhosted.org/packages/7a/85/723bb085a61c6ac2dc0a0043f375f2fe7365363e27b073bad56ca5bda979/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:8ffdb59fe88f99589e34354a130217aa1fd2d615612402d6edc8b3dbc7a44463", size = 3047724, upload-time = "2026-04-20T23:33:50.74Z" }, + { url = "https://files.pythonhosted.org/packages/b4/67/4d8b1e0d2fc4166677380eac0edf9cdff91013aca2546e8ef7bc04b56158/psycopg2_binary-2.9.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a46fe069b65255df410f856d842bc235f90e22ffdf532dda625fd4213d3fd9b1", size = 3349183, upload-time = "2026-04-20T23:33:59.635Z" }, + { url = "https://files.pythonhosted.org/packages/73/99/21af7a5498637ea4dc91a17c281a53bc1d632fbafe00f6689fbfb32a9fed/psycopg2_binary-2.9.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab29414b25dcb698bf26bf213e3348abdcd07bbd5de032a5bec15bd75b298b03", size = 2757036, upload-time = "2026-04-20T23:34:01.606Z" }, + { url = "https://files.pythonhosted.org/packages/d5/19/d4ce60954f3bb9d8e3bc5e5c4d1f2487de2d3851bf2391d54954c9df12a6/psycopg2_binary-2.9.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5c8ce6c61bd1b1f6b9c24ee32211599f6166af2c55abb19456090a21fd16554b", size = 3712338, upload-time = "2026-04-20T23:34:03.961Z" }, + { url = "https://files.pythonhosted.org/packages/53/71/c85409ee0d78890f0660eff262e815e7dd2bb741a17611d82e9e8cd9dc5e/psycopg2_binary-2.9.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4a9eaa6e7f4ff91bec10aa3fb296878e75187bced5cc4bafe17dc40915e1326", size = 3822407, upload-time = "2026-04-20T23:34:05.977Z" }, + { url = "https://files.pythonhosted.org/packages/3c/ed/60486c2c7f0d4d1ede2bfb1ed27e2498477ce646bc7f6b2759906303117e/psycopg2_binary-2.9.12-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c6528cefc8e50fcc6f4a107e27a672058b36cc5736d665476aeb413ba88dbb06", size = 4578425, upload-time = "2026-04-20T23:34:08.246Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b9/656cb03fad9f4f49f2145c334b1126ee75189929ca4e6187d485a2d59951/psycopg2_binary-2.9.12-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4e184b1fb6072bf05388aa41c697e1b2d01b3473f107e7ec44f186a32cfd0b8", size = 4273709, upload-time = "2026-04-20T23:34:10.974Z" }, + { url = "https://files.pythonhosted.org/packages/99/66/08cf0da0e25cc6fb142c89be45fc8418792858f0c4cbff5e24530ff02cd6/psycopg2_binary-2.9.12-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4766ab678563054d3f1d064a4db19cc4b5f9e3a8d9018592a8285cf200c248f3", size = 5893779, upload-time = "2026-04-20T23:34:13.905Z" }, + { url = "https://files.pythonhosted.org/packages/17/d7/eecd9ce8e146d3721115d82d3836efdbb712187e4590325df549989d18f4/psycopg2_binary-2.9.12-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5a0253224780c978746cb9be55a946bcdaf40fe3519c0f622924cdabdafe2c39", size = 4109308, upload-time = "2026-04-20T23:34:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2e/b1dc289b362cc8d45697b57eefbd673186f49a4ea0906928988e3affcc98/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0dc9228d47c46bda253d2ecd6bb93b56a9f2d7ad33b684a1fa3622bf74ffe30c", size = 3654405, upload-time = "2026-04-20T23:34:19.303Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/4c4aea6473214dbdbd0fbba11aa4691e76dc01722c55724c5951719865ff/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f921f3cd87035ef7df233383011d7a53ea1d346224752c1385f1edfd790ceb6a", size = 3299187, upload-time = "2026-04-20T23:34:21.206Z" }, + { url = "https://files.pythonhosted.org/packages/ba/5d/b03b99986446a4f57b170ed9a2579fb7ff9783ca0fa5226b19db99737fee/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3d999bd982a723113c1a45b55a7a6a90d64d0ed2278020ed625c490ff7bef96c", size = 3047716, upload-time = "2026-04-20T23:34:23.077Z" }, + { url = "https://files.pythonhosted.org/packages/14/86/382ee4afbd1d97500c9d2862b20c2fdeddf4b7335e984df3fb4309f64108/psycopg2_binary-2.9.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29d4d134bd0ab46ffb04e94aa3c5fa3ef582e9026609165e2f758ff76fc3a3be", size = 3349237, upload-time = "2026-04-20T23:34:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/a8/16/9a57c75ba1eda7165c017342f526810d5f5a12647dde749c99ae9a7141d7/psycopg2_binary-2.9.12-cp311-cp311-win_amd64.whl", hash = "sha256:cb4a1dacdd48077150dc762a9e5ddbf32c256d66cb46f80839391aa458774936", size = 2757036, upload-time = "2026-04-20T23:34:27.77Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/ef4ef3c8e15083df90ca35265cfd1a081a2f0cc07bb229c6314c6af817f4/psycopg2_binary-2.9.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5cdc05117180c5fa9c40eea8ea559ce64d73824c39d928b7da9fb5f6a9392433", size = 3712459, upload-time = "2026-04-20T23:34:30.549Z" }, + { url = "https://files.pythonhosted.org/packages/b5/01/3dd14e46ba48c1e1a6ec58ee599fa1b5efa00c246d5046cd903d0eeb1af1/psycopg2_binary-2.9.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d3227a3bc228c10d21011a99245edca923e4e8bf461857e869a507d9a41fe9f6", size = 3822936, upload-time = "2026-04-20T23:34:32.77Z" }, + { url = "https://files.pythonhosted.org/packages/a6/f7/0640e4901119d8a9f7a1784b927f494e2198e213ceb593753d1f2c8b1b30/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:995ce929eede89db6254b50827e2b7fd61e50d11f0b116b29fffe4a2e53c4580", size = 4578676, upload-time = "2026-04-20T23:34:35.18Z" }, + { url = "https://files.pythonhosted.org/packages/b0/55/44df3965b5f297c50cc0b1b594a31c67d6127a9d133045b8a66611b14dfb/psycopg2_binary-2.9.12-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9fe06d93e72f1c048e731a2e3e7854a5bfaa58fc736068df90b352cefe66f03f", size = 4274917, upload-time = "2026-04-20T23:34:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/b0/4b/74535248b1eac0c9336862e8617c765ac94dac76f9e25d7c4a79588c8907/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40e7b28b63aaf737cb3a1edc3a9bbc9a9f4ad3dcb7152e8c1130e4050eddcb7d", size = 5894843, upload-time = "2026-04-20T23:34:40.856Z" }, + { url = "https://files.pythonhosted.org/packages/f2/ba/f1bf8d2ae71868ad800b661099086ee52bc0f8d9f05be1acd8ebb06757cc/psycopg2_binary-2.9.12-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:89d19a9f7899e8eb0656a2b3a08e0da04c720a06db6e0033eab5928aabe60fa9", size = 4110556, upload-time = "2026-04-20T23:34:44.016Z" }, + { url = "https://files.pythonhosted.org/packages/45/46/c15706c338403b7c420bcc0c2905aad116cc064545686d8bf85f1999ea00/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:612b965daee295ae2da8f8218ce1d274645dc76ef3f1abf6a0a94fd57eff876d", size = 3655714, upload-time = "2026-04-20T23:34:46.233Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7c/a2d5dc09b64a4564db242a0fe418fde7d33f6f8259dd2c5b9d7def00fb5a/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b9a339b79d37c1b45f3235265f07cdeb0cb5ad7acd2ac7720a5920989c17c24e", size = 3301154, upload-time = "2026-04-20T23:34:49.528Z" }, + { url = "https://files.pythonhosted.org/packages/c0/e8/cc8c9a4ce71461f9ec548d38cadc41dc184b34c73e6455450775a9334ccd/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:3471336e1acfd9c7fe507b8bad5af9317b6a89294f9eb37bd9a030bb7bebcdc6", size = 3048882, upload-time = "2026-04-20T23:34:51.86Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/31e2296bc0787c5ab75d3d118e40b239db8151b5192b90b77c72bc9256e9/psycopg2_binary-2.9.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7af18183109e23502c8b2ae7f6926c0882766f35b5175a4cd737ad825e4d7a1b", size = 3351298, upload-time = "2026-04-20T23:34:54.124Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a8/75f4e3e11203b590150abed2cf7794b9c9c9f7eceddae955191138b44dde/psycopg2_binary-2.9.12-cp312-cp312-win_amd64.whl", hash = "sha256:398fcd4db988c7d7d3713e2b8e18939776fd3fb447052daae4f24fa39daede4c", size = 2757230, upload-time = "2026-04-20T23:34:56.242Z" }, ] [[package]] name = "py-vapid" -version = "1.9.2" +version = "1.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/57/5c1c61f27ce01f939443cf3f6c279a295f7ec0327b18a1cbbcfefe0b5456/py_vapid-1.9.2.tar.gz", hash = "sha256:3c8973b6cf8384ad0c9ae64d6270ccc480e0b92c702d8f5ea2cc03e6b51247f9", size = 20300, upload-time = "2024-11-19T21:55:41.859Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/ed/c648c8018fab319951764f4babe68ddcbbff7f2bbcd7ff7e531eac1788c8/py_vapid-1.9.4.tar.gz", hash = "sha256:a004023560cbc54e34fc06380a0580f04ffcc788e84fb6d19e9339eeb6551a28", size = 74750, upload-time = "2026-01-05T22:13:25.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/fb/b877a221b09dabcebeb073d5e7f19244f3fa1d5aec87092c359a6049a006/py_vapid-1.9.2-py3-none-any.whl", hash = "sha256:4ccf8a00fc54f1f99f66fb543c96f2c82622508ad814b6e9225f2c26948934d7", size = 21492, upload-time = "2024-11-19T21:55:40.832Z" }, + { url = "https://files.pythonhosted.org/packages/7f/15/f9d0171e1ad863ca49e826d5afb6b50566f20dc9b4f76965096d3555ce9e/py_vapid-1.9.4-py2.py3-none-any.whl", hash = "sha256:f165a5bf90dcf966b226114f01f178f137579a09784c7f0628fa2f0a299741b6", size = 23912, upload-time = "2026-01-05T20:42:05.455Z" }, ] [[package]] name = "pycparser" -version = "2.22" +version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] @@ -2005,21 +2075,68 @@ email = [ ] [[package]] -name = "pygments" -version = "2.19.2" +name = "pyee" +version = "13.0.1" 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" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/04/e7c1fe4dc78a6fdbfd6c337b1c3732ff543b8a397683ab38378447baa331/pyee-13.0.1.tar.gz", hash = "sha256:0b931f7c14535667ed4c7e0d531716368715e860b988770fc7eb8578d1f67fc8", size = 31655, upload-time = "2026-02-14T21:12:28.044Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/a0/c4/b4d4827c93ef43c01f599ef31453ccc1c132b353284fc6c87d535c233129/pyee-13.0.1-py3-none-any.whl", hash = "sha256:af2f8fede4171ef667dfded53f96e2ed0d6e6bd7ee3bb46437f77e3b57689228", size = 15659, upload-time = "2026-02-14T21:12:26.263Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyinstrument" +version = "5.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/32/7f/d3c4ef7c43f3294bd5a475dfa6f295a9fee5243c292d5c8122044fa83bcb/pyinstrument-5.1.2.tar.gz", hash = "sha256:af149d672da9493fa37334a1cc68f7b80c3e6cb9fd99b9e426c447db5c650bf0", size = 266889, upload-time = "2026-01-04T18:38:58.464Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/74/c66e1bf3565600d78f53195efb6f8fd31610f85a58aa3fee39c56bf71d1b/pyinstrument-5.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f224fe80ba288a00980af298d3808219f9d246fd95b4f91729c9c33a0dc54fe6", size = 131470, upload-time = "2026-01-04T18:37:22.536Z" }, + { url = "https://files.pythonhosted.org/packages/1a/6b/606c5bfa311b5be74f58ef505c678216dda2be3b76a2ac770c2b0fccff77/pyinstrument-5.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7df09fc0d5b72daf48b73cdf07738761bff7f656c81aff686b3ccdd7d2abe236", size = 124567, upload-time = "2026-01-04T18:37:24.161Z" }, + { url = "https://files.pythonhosted.org/packages/15/70/c8a88defb77873513971f590549c48ceb70f7ef10f30a689762ef36dd877/pyinstrument-5.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75a7e17377d4405666bbaf126b1fd7bbb7e206d7246e6db3d62864d3d4790ae3", size = 149205, upload-time = "2026-01-04T18:37:25.696Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4b/0e64fefb939af472c3fbc63ab45224766447bde73f51579f3ecc335b0a49/pyinstrument-5.1.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5381cc6583d26e04d9298acded4242f4fe71986f1472c8aee6992c6816f0cac5", size = 147900, upload-time = "2026-01-04T18:37:27.343Z" }, + { url = "https://files.pythonhosted.org/packages/38/6e/b4209711c61176acfeb6c351e9f88a37ed3d3bc3b749c374c0a655ee8f50/pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ec08a530bef8d3492d31d8b0b12d0cfde09539f2a1c4b9678662ebc3c843e478", size = 148133, upload-time = "2026-01-04T18:37:29.047Z" }, + { url = "https://files.pythonhosted.org/packages/26/28/f323b70789833baf0628af7b9f797b8c1a13b695bd8aa582b1312f14b602/pyinstrument-5.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d671168508129b472be570bc9aee361190ba917b997c703bd134bb4de445ce7", size = 147652, upload-time = "2026-01-04T18:37:30.682Z" }, + { url = "https://files.pythonhosted.org/packages/16/cd/9b0af0307a3a2cffb48ca76275c50b8bec3f85ca6e7b996e2e6cfbda1207/pyinstrument-5.1.2-cp310-cp310-win32.whl", hash = "sha256:5957a94f84564b374a7f856d1b322345d600964280b0d687b8ddcc483f21e576", size = 125793, upload-time = "2026-01-04T18:37:31.906Z" }, + { url = "https://files.pythonhosted.org/packages/05/89/fe4c650c252aefb8064bfdff6c0a020d33d15c55dc22abfa1f352dcc2dd1/pyinstrument-5.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:38a2180a7801c51610b50e5d423674b21872efd019ccf05a11b7f9016cb1dcfc", size = 126679, upload-time = "2026-01-04T18:37:33.59Z" }, + { url = "https://files.pythonhosted.org/packages/79/ef/0288edd620fb0cf2074d8c8e3567007a6bac66307b839d99988563de4eb8/pyinstrument-5.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3739a05583ea6312c385eb59fe985cd20d9048e95f9eeeb6a2f6c35202e2d36e", size = 131284, upload-time = "2026-01-04T18:37:35.01Z" }, + { url = "https://files.pythonhosted.org/packages/0b/4e/2a90a6997d9f7a39a6998d56de72e52673ebf5a9169a1c39dbf173e95105/pyinstrument-5.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c9ee05dc75ac5fb18498c311e624f77f7f321f7ff325b251aa09e52e46f1d6a", size = 124468, upload-time = "2026-01-04T18:37:36.628Z" }, + { url = "https://files.pythonhosted.org/packages/04/74/7bfd403e81f9b5ec523f60cced8f516ee52312752bb2e0fafabfd90bbd78/pyinstrument-5.1.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a49a55ca5b75218767e29cacbe515d0b66fc18cb48a937bca0f77b8dafc7202", size = 148057, upload-time = "2026-01-04T18:37:37.998Z" }, + { url = "https://files.pythonhosted.org/packages/50/3a/7205d7c199947d18edcd013af4ddf4d3cca85c5488fbe493050035947f7c/pyinstrument-5.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c45c14974ff04b1bfdc6c2a448627c6da7409c7800d0eb7bd03fb435dcb41d7", size = 146526, upload-time = "2026-01-04T18:37:39.642Z" }, + { url = "https://files.pythonhosted.org/packages/24/e8/f6864172e7ebe4bc5209bafbc574a619b4c511b9506b941789b11441be7c/pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:22b9c04b3982c41c04b1c5ed05d1bc3a2ba26533450084058119f6dc160e70a3", size = 147179, upload-time = "2026-01-04T18:37:41.332Z" }, + { url = "https://files.pythonhosted.org/packages/6d/04/89ef2d1c34767bfdbcc74ab0c7e0d021d7fac5e79873239e4ca26e97d6da/pyinstrument-5.1.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5c4995ee0774801790c138f0dfec17d4e7a7ef09a6d56d53cbcbf0578a711021", size = 146354, upload-time = "2026-01-04T18:37:42.808Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d4/64441547ec12391b92c739a3b0685059e7dfa088d928df8364676ef7abc7/pyinstrument-5.1.2-cp311-cp311-win32.whl", hash = "sha256:fe449e4a8ee60a2a27cf509350a584670f4c3704649601be7937598f09dbe7ca", size = 125790, upload-time = "2026-01-04T18:37:44.141Z" }, + { url = "https://files.pythonhosted.org/packages/4d/8b/0a5f6b239294decb0ecd932711f3470bfbd42fc2e08a94cd5c1f4f6da7f1/pyinstrument-5.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:3fb839429671a42bf349335af4c1ce5cf83386ac11f04df0bc40720d4cb7d77d", size = 126578, upload-time = "2026-01-04T18:37:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/26/d9/8fa5571ddd21b2b7189bd8b0bb4e90be1659a54dda5af51c7f6bf2b5666f/pyinstrument-5.1.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2519865d4bf58936f2506c1c46a82d29a20f3239aa50c941df1ca9618c7da5f0", size = 131419, upload-time = "2026-01-04T18:37:46.843Z" }, + { url = "https://files.pythonhosted.org/packages/6f/50/0512adb83cadfeaa1a215dc9784defff5043c5aa052d15015e3d8013af75/pyinstrument-5.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:059442106b8b5de29ae5ac1bdc20d044fed4da534b8caba434b6ffb119037bf5", size = 124446, upload-time = "2026-01-04T18:37:48.572Z" }, + { url = "https://files.pythonhosted.org/packages/9b/78/c45f0b668fb3c8c0d32058a451a8e1d34737cd7586387982185e12df1977/pyinstrument-5.1.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd51f2d54fc39a4cfd73ba6be27cd0187123132ce3f445b639bff5e1b23d7e26", size = 149694, upload-time = "2026-01-04T18:37:49.876Z" }, + { url = "https://files.pythonhosted.org/packages/91/4d/2ca3ca9906ce6e05070f431c54d54ccbaf57a980cfa58032d35b0b0ac1f8/pyinstrument-5.1.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12af1e83795b6c640d657d339014dd1ff718b182dec736d7d1f1d8a97534eb53", size = 148461, upload-time = "2026-01-04T18:37:51.544Z" }, + { url = "https://files.pythonhosted.org/packages/18/d2/bfe84a4326172ef68655b65b49fd041eeb94c8e59ee47258589b8b79dd3b/pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2565513658e742c5eb691a779cb29d19d01bc9ee951d0eb76482e9f343c38c2e", size = 148560, upload-time = "2026-01-04T18:37:52.931Z" }, + { url = "https://files.pythonhosted.org/packages/d0/00/db7f5def351e869230b0165828c4edacbf3fdda8d66aff30dd73a62082c2/pyinstrument-5.1.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5afd0ba788a1d112da49fb77966918e01df1f9e7d62e72894d82f7acb0996c2d", size = 148178, upload-time = "2026-01-04T18:37:54.278Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bc/aea3329576e20b987d205027b8e6442ece845d681b9f9d8682d5404f81f3/pyinstrument-5.1.2-cp312-cp312-win32.whl", hash = "sha256:554077b031b278593cb2301f0057be771ea62a729878c69aaf29fcdfb7b71281", size = 125927, upload-time = "2026-01-04T18:37:55.615Z" }, + { url = "https://files.pythonhosted.org/packages/14/e2/d928434ec3a840478e95fd0d73b0dfc0b8060a07b06f4b45e9df30444e9a/pyinstrument-5.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:55a905384ba43efc924b8863aa6cfd276f029e4aa70c4a0e3b7389e27b191e45", size = 126675, upload-time = "2026-01-04T18:37:57.278Z" }, ] [[package]] name = "pyjwt" -version = "2.10.1" +version = "2.12.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" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" }, ] [[package]] @@ -2033,20 +2150,20 @@ wheels = [ [[package]] name = "pyln-client" -version = "25.12" +version = "25.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyln-bolt7" }, { name = "pyln-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/c3/6375d73950df8cda594ca7ee1069f63a817190b08ea8cb57c9ce65019664/pyln_client-25.12.tar.gz", hash = "sha256:9a0435436dea7ce471e096aac9c4e3ede704c305b862b0a3b5e410279b54d8d6", size = 92109, upload-time = "2025-12-04T00:25:55.808Z" } +sdist = { url = "https://files.pythonhosted.org/packages/75/b1/28c46889cf1822f89a5d23644aa08806cedd17c2553afee2d72c4e101c62/pyln_client-25.12.1.tar.gz", hash = "sha256:4e92d18ce79879b891355d4a9bb79117466e98e12b83c1b5f321fc3e77039d5b", size = 92116, upload-time = "2026-01-15T00:04:15.621Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/e7/76f13dc3174b58f91aecf7890efc174ef12721dc015601a200ac40044356/pyln_client-25.12-py3-none-any.whl", hash = "sha256:9e4ff323acb71cbc4522d160dd931599f59a4c167076db016ec5d63e6a002f86", size = 37618, upload-time = "2025-12-04T00:25:54.365Z" }, + { url = "https://files.pythonhosted.org/packages/41/51/fb302f67a8e62eaa49d869b489cad61dac66fda9a3fd737ac56422b1b920/pyln_client-25.12.1-py3-none-any.whl", hash = "sha256:cb8c42bf4b432a3a2ec0b1ee94b96f5ad91fee1ddd0289930d55c988ab801293", size = 37633, upload-time = "2026-01-15T00:04:14.386Z" }, ] [[package]] name = "pyln-proto" -version = "25.9.3" +version = "26.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "base58" }, @@ -2055,9 +2172,9 @@ dependencies = [ { name = "cryptography" }, { name = "pysocks" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/94/b55d3ad680f947ebc0aebf5bcdc0fee3e619b9b49ad97aa288ed3056feff/pyln_proto-25.9.3.tar.gz", hash = "sha256:beb56848b569e7a2dba15de18650d9909a5198b05c73bc99aed7d04435f3cbc4", size = 44861, upload-time = "2025-11-07T01:53:33.877Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/4b/c8d676ad84d6066553b203668c0e36f45cfae0a4d7140eb88aed6d65b38b/pyln_proto-26.4.1.tar.gz", hash = "sha256:d73f261bacc06a6a613dcece05fc429699b740a4673f24dffb7c41bd3542d589", size = 44864, upload-time = "2026-04-24T04:53:10.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/40/02d2ec15ae3c3e7d24eed02e64d8f62f5f1e262d3f67c5c1a49fe1db860f/pyln_proto-25.9.3-py3-none-any.whl", hash = "sha256:c550bc0ae3abed09c1c9a03c2780e151cde9480afa7875da6526ce936ac71876", size = 31829, upload-time = "2025-11-07T01:53:32.961Z" }, + { url = "https://files.pythonhosted.org/packages/a3/f1/6541b6cd8a017d3505fcb49885d3f01b8e6bb09e40db18e686edb9edeb99/pyln_proto-26.4.1-py3-none-any.whl", hash = "sha256:b5d10d5e69cf3debd9b289e2ffa49713fca6c349a71cb0eaf9e733024f15b3da", size = 31833, upload-time = "2026-04-24T04:53:08.686Z" }, ] [[package]] @@ -2095,7 +2212,7 @@ wheels = [ [[package]] name = "pytest" -version = "9.0.2" +version = "9.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -2106,9 +2223,9 @@ dependencies = [ { name = "pygments" }, { name = "tomli", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] [[package]] @@ -2127,14 +2244,14 @@ wheels = [ [[package]] name = "pytest-httpserver" -version = "1.1.3" +version = "1.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f1/d8/def15ba33bd696dd72dd4562a5287c0cba4d18a591eeb82e0b08ab385afc/pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec", size = 68870, upload-time = "2025-04-10T08:17:15.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/17/ad187f46998814014f7cda309de700b87c0eb4b2e111e18bc8c819be7116/pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1", size = 70974, upload-time = "2026-02-14T13:27:23.412Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/d2/dfc2f25f3905921c2743c300a48d9494d29032f1389fc142e718d6978fb2/pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9", size = 21000, upload-time = "2025-04-10T08:17:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/ec/df/0bdf90b84c6a586a9fd2b509523a3ab26b1cc1b1dba2fb62a32e4411ea9e/pytest_httpserver-1.1.5-py3-none-any.whl", hash = "sha256:ee83feb587ab652c0c6729598db2820e9048233bac8df756818b7845a1621d0a", size = 23330, upload-time = "2026-02-14T13:27:22.119Z" }, ] [[package]] @@ -2171,35 +2288,63 @@ wheels = [ ] [[package]] -name = "python-dotenv" -version = "1.2.1" +name = "python-discovery" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/60/e88788207d81e46362cfbef0d4aaf4c0f49efc3c12d4c3fa3f542c34ebec/python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6", size = 68011, upload-time = "2026-05-12T20:53:36.336Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/b7/6f/a05a317a66fee0aad270011461f1a63a453ed12471249f172f7d2e2bc7b4/python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c", size = 33185, upload-time = "2026-05-12T20:53:34.969Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] name = "python-multipart" -version = "0.0.21" +version = "0.0.31" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/7e/9b35ad8f3d9ca680f7c87a88f19612fdd8da9796c4d3b46e560ac79dcc4a/python_multipart-0.0.31.tar.gz", hash = "sha256:fc631183bb13e56db3158a4909908dfb2e23565286744e798241e63750e5d680", size = 46689, upload-time = "2026-06-04T08:27:49.014Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/7f7f299527a5a8ad90acd5f2f78dfa6c8495c6301a3205106ea68a84de96/python_multipart-0.0.31-py3-none-any.whl", hash = "sha256:8408153d68a9773291fc1da39a8b85a50044bddbabd2dd72e9229776b7b15e28", size = 29996, upload-time = "2026-06-04T08:27:47.804Z" }, ] [[package]] name = "pytokens" -version = "0.3.0" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, + { url = "https://files.pythonhosted.org/packages/42/24/f206113e05cb8ef51b3850e7ef88f20da6f4bf932190ceb48bd3da103e10/pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5", size = 161522, upload-time = "2026-01-30T01:02:50.393Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e9/06a6bf1b90c2ed81a9c7d2544232fe5d2891d1cd480e8a1809ca354a8eb2/pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe", size = 246945, upload-time = "2026-01-30T01:02:52.399Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/f6fb1007a4c3d8b682d5d65b7c1fb33257587a5f782647091e3408abe0b8/pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c", size = 259525, upload-time = "2026-01-30T01:02:53.737Z" }, + { url = "https://files.pythonhosted.org/packages/04/92/086f89b4d622a18418bac74ab5db7f68cf0c21cf7cc92de6c7b919d76c88/pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7", size = 262693, upload-time = "2026-01-30T01:02:54.871Z" }, + { url = "https://files.pythonhosted.org/packages/b4/7b/8b31c347cf94a3f900bdde750b2e9131575a61fdb620d3d3c75832262137/pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2", size = 103567, upload-time = "2026-01-30T01:02:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, + { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, + { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, ] [[package]] name = "pywebpush" -version = "2.2.0" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -2207,11 +2352,10 @@ dependencies = [ { name = "http-ece" }, { name = "py-vapid" }, { name = "requests" }, - { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/7d/327de9752338521ee85d67a8e70b99ae45f21cb251643b726a2281ffc907/pywebpush-2.2.0.tar.gz", hash = "sha256:d4c0ee4981e7ac08cf14729fec8b6c3aeec58d54e6da388635c5706fcc2db3f6", size = 28317, upload-time = "2026-01-05T19:13:08.421Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/8f/b408c7b6bae8451016a54e378a2b05d65c1929565332c1befa3e09b9271c/pywebpush-2.2.1.tar.gz", hash = "sha256:d881a427a291b4d44e5e6bf920bcb0b4b382bbeb4a63dda63cae5124e65042d8", size = 28414, upload-time = "2026-02-09T19:05:20.215Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/b1/ca100d0563d14280732d405d9eb0adea2ba80fa8ad86c06cded5fc0a0cb1/pywebpush-2.2.0-py3-none-any.whl", hash = "sha256:f5a03eeeec422f62519d5a94f590937f143b2e9d05ee0da843d0dddd3c335835", size = 22822, upload-time = "2026-01-05T19:13:05.438Z" }, + { url = "https://files.pythonhosted.org/packages/97/2c/c1b4a483d0dc549f37a6576acb78d1c852cc3982daa19e94d51216cbac9e/pywebpush-2.2.1-py3-none-any.whl", hash = "sha256:50cd824a0af949c7ca2d5c757f10e6b931626740e0aa39fb5f62a4b4662a303d", size = 22850, upload-time = "2026-02-09T19:05:18.297Z" }, ] [[package]] @@ -2250,6 +2394,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, ] +[[package]] +name = "random-username" +version = "1.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/84/7004e0038707827e7ebe91a09e0f46483e36134de3b20bc0d5cf864a4caa/random-username-1.0.2.tar.gz", hash = "sha256:5fdc0604b5d1bdfe4acf4cd7491a9de1caf41bbdd890f646b434e09ae2a1b7ce", size = 3805, upload-time = "2019-01-11T22:57:45.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/d8/0f96b9bdea0683884b0ff2d8663b2580e2bad4418848540d1a12e1fd1d7b/random_username-1.0.2-py3-none-any.whl", hash = "sha256:2536feb63fecde7e01ede4a541aadb6f0b58794a7ab327ca5369d2a4b7664c06", size = 6673, upload-time = "2019-01-11T22:57:43.656Z" }, +] + [[package]] name = "referencing" version = "0.36.2" @@ -2266,7 +2419,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.34.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -2274,9 +2427,9 @@ dependencies = [ { 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" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, ] [[package]] @@ -2293,114 +2446,114 @@ wheels = [ [[package]] name = "rich" -version = "14.1.0" +version = "15.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8", size = 224441, upload-time = "2025-07-25T07:32:58.125Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", size = 243368, upload-time = "2025-07-25T07:32:56.73Z" }, + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, ] [[package]] name = "rpds-py" -version = "0.28.0" +version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" } +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/82/f8/13bb772dc7cbf2c3c5b816febc34fa0cb2c64a08e0569869585684ce6631/rpds_py-0.28.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7b6013db815417eeb56b2d9d7324e64fcd4fa289caeee6e7a78b2e11fc9b438a", size = 362820, upload-time = "2025-10-22T22:21:15.074Z" }, - { url = "https://files.pythonhosted.org/packages/84/91/6acce964aab32469c3dbe792cb041a752d64739c534e9c493c701ef0c032/rpds_py-0.28.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a4c6b05c685c0c03f80dabaeb73e74218c49deea965ca63f76a752807397207", size = 348499, upload-time = "2025-10-22T22:21:17.658Z" }, - { url = "https://files.pythonhosted.org/packages/f1/93/c05bb1f4f5e0234db7c4917cb8dd5e2e0a9a7b26dc74b1b7bee3c9cfd477/rpds_py-0.28.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4794c6c3fbe8f9ac87699b131a1f26e7b4abcf6d828da46a3a52648c7930eba", size = 379356, upload-time = "2025-10-22T22:21:19.847Z" }, - { url = "https://files.pythonhosted.org/packages/5c/37/e292da436f0773e319753c567263427cdf6c645d30b44f09463ff8216cda/rpds_py-0.28.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e8456b6ee5527112ff2354dd9087b030e3429e43a74f480d4a5ca79d269fd85", size = 390151, upload-time = "2025-10-22T22:21:21.569Z" }, - { url = "https://files.pythonhosted.org/packages/76/87/a4e3267131616e8faf10486dc00eaedf09bd61c87f01e5ef98e782ee06c9/rpds_py-0.28.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:beb880a9ca0a117415f241f66d56025c02037f7c4efc6fe59b5b8454f1eaa50d", size = 524831, upload-time = "2025-10-22T22:21:23.394Z" }, - { url = "https://files.pythonhosted.org/packages/e1/c8/4a4ca76f0befae9515da3fad11038f0fce44f6bb60b21fe9d9364dd51fb0/rpds_py-0.28.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6897bebb118c44b38c9cb62a178e09f1593c949391b9a1a6fe777ccab5934ee7", size = 404687, upload-time = "2025-10-22T22:21:25.201Z" }, - { url = "https://files.pythonhosted.org/packages/6a/65/118afe854424456beafbbebc6b34dcf6d72eae3a08b4632bc4220f8240d9/rpds_py-0.28.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1b553dd06e875249fd43efd727785efb57a53180e0fde321468222eabbeaafa", size = 382683, upload-time = "2025-10-22T22:21:26.536Z" }, - { url = "https://files.pythonhosted.org/packages/f7/bc/0625064041fb3a0c77ecc8878c0e8341b0ae27ad0f00cf8f2b57337a1e63/rpds_py-0.28.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:f0b2044fdddeea5b05df832e50d2a06fe61023acb44d76978e1b060206a8a476", size = 398927, upload-time = "2025-10-22T22:21:27.864Z" }, - { url = "https://files.pythonhosted.org/packages/5d/1a/fed7cf2f1ee8a5e4778f2054153f2cfcf517748875e2f5b21cf8907cd77d/rpds_py-0.28.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05cf1e74900e8da73fa08cc76c74a03345e5a3e37691d07cfe2092d7d8e27b04", size = 411590, upload-time = "2025-10-22T22:21:29.474Z" }, - { url = "https://files.pythonhosted.org/packages/c1/64/a8e0f67fa374a6c472dbb0afdaf1ef744724f165abb6899f20e2f1563137/rpds_py-0.28.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:efd489fec7c311dae25e94fe7eeda4b3d06be71c68f2cf2e8ef990ffcd2cd7e8", size = 559843, upload-time = "2025-10-22T22:21:30.917Z" }, - { url = "https://files.pythonhosted.org/packages/a9/ea/e10353f6d7c105be09b8135b72787a65919971ae0330ad97d87e4e199880/rpds_py-0.28.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada7754a10faacd4f26067e62de52d6af93b6d9542f0df73c57b9771eb3ba9c4", size = 584188, upload-time = "2025-10-22T22:21:32.827Z" }, - { url = "https://files.pythonhosted.org/packages/18/b0/a19743e0763caf0c89f6fc6ba6fbd9a353b24ffb4256a492420c5517da5a/rpds_py-0.28.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c2a34fd26588949e1e7977cfcbb17a9a42c948c100cab890c6d8d823f0586457", size = 550052, upload-time = "2025-10-22T22:21:34.702Z" }, - { url = "https://files.pythonhosted.org/packages/de/bc/ec2c004f6c7d6ab1e25dae875cdb1aee087c3ebed5b73712ed3000e3851a/rpds_py-0.28.0-cp310-cp310-win32.whl", hash = "sha256:f9174471d6920cbc5e82a7822de8dfd4dcea86eb828b04fc8c6519a77b0ee51e", size = 215110, upload-time = "2025-10-22T22:21:36.645Z" }, - { url = "https://files.pythonhosted.org/packages/6c/de/4ce8abf59674e17187023933547d2018363e8fc76ada4f1d4d22871ccb6e/rpds_py-0.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:6e32dd207e2c4f8475257a3540ab8a93eff997abfa0a3fdb287cae0d6cd874b8", size = 223850, upload-time = "2025-10-22T22:21:38.006Z" }, - { url = "https://files.pythonhosted.org/packages/a6/34/058d0db5471c6be7bef82487ad5021ff8d1d1d27794be8730aad938649cf/rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296", size = 362344, upload-time = "2025-10-22T22:21:39.713Z" }, - { url = "https://files.pythonhosted.org/packages/5d/67/9503f0ec8c055a0782880f300c50a2b8e5e72eb1f94dfc2053da527444dd/rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27", size = 348440, upload-time = "2025-10-22T22:21:41.056Z" }, - { url = "https://files.pythonhosted.org/packages/68/2e/94223ee9b32332a41d75b6f94b37b4ce3e93878a556fc5f152cbd856a81f/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c", size = 379068, upload-time = "2025-10-22T22:21:42.593Z" }, - { url = "https://files.pythonhosted.org/packages/b4/25/54fd48f9f680cfc44e6a7f39a5fadf1d4a4a1fd0848076af4a43e79f998c/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205", size = 390518, upload-time = "2025-10-22T22:21:43.998Z" }, - { url = "https://files.pythonhosted.org/packages/1b/85/ac258c9c27f2ccb1bd5d0697e53a82ebcf8088e3186d5d2bf8498ee7ed44/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95", size = 525319, upload-time = "2025-10-22T22:21:45.645Z" }, - { url = "https://files.pythonhosted.org/packages/40/cb/c6734774789566d46775f193964b76627cd5f42ecf246d257ce84d1912ed/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9", size = 404896, upload-time = "2025-10-22T22:21:47.544Z" }, - { url = "https://files.pythonhosted.org/packages/1f/53/14e37ce83202c632c89b0691185dca9532288ff9d390eacae3d2ff771bae/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2", size = 382862, upload-time = "2025-10-22T22:21:49.176Z" }, - { url = "https://files.pythonhosted.org/packages/6a/83/f3642483ca971a54d60caa4449f9d6d4dbb56a53e0072d0deff51b38af74/rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0", size = 398848, upload-time = "2025-10-22T22:21:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/44/09/2d9c8b2f88e399b4cfe86efdf2935feaf0394e4f14ab30c6c5945d60af7d/rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e", size = 412030, upload-time = "2025-10-22T22:21:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f5/e1cec473d4bde6df1fd3738be8e82d64dd0600868e76e92dfeaebbc2d18f/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67", size = 559700, upload-time = "2025-10-22T22:21:54.123Z" }, - { url = "https://files.pythonhosted.org/packages/8d/be/73bb241c1649edbf14e98e9e78899c2c5e52bbe47cb64811f44d2cc11808/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d", size = 584581, upload-time = "2025-10-22T22:21:56.102Z" }, - { url = "https://files.pythonhosted.org/packages/9c/9c/ffc6e9218cd1eb5c2c7dbd276c87cd10e8c2232c456b554169eb363381df/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6", size = 549981, upload-time = "2025-10-22T22:21:58.253Z" }, - { url = "https://files.pythonhosted.org/packages/5f/50/da8b6d33803a94df0149345ee33e5d91ed4d25fc6517de6a25587eae4133/rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c", size = 214729, upload-time = "2025-10-22T22:21:59.625Z" }, - { url = "https://files.pythonhosted.org/packages/12/fd/b0f48c4c320ee24c8c20df8b44acffb7353991ddf688af01eef5f93d7018/rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa", size = 223977, upload-time = "2025-10-22T22:22:01.092Z" }, - { url = "https://files.pythonhosted.org/packages/b4/21/c8e77a2ac66e2ec4e21f18a04b4e9a0417ecf8e61b5eaeaa9360a91713b4/rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120", size = 217326, upload-time = "2025-10-22T22:22:02.944Z" }, - { url = "https://files.pythonhosted.org/packages/b8/5c/6c3936495003875fe7b14f90ea812841a08fca50ab26bd840e924097d9c8/rpds_py-0.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6b4f28583a4f247ff60cd7bdda83db8c3f5b05a7a82ff20dd4b078571747708f", size = 366439, upload-time = "2025-10-22T22:22:04.525Z" }, - { url = "https://files.pythonhosted.org/packages/56/f9/a0f1ca194c50aa29895b442771f036a25b6c41a35e4f35b1a0ea713bedae/rpds_py-0.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d678e91b610c29c4b3d52a2c148b641df2b4676ffe47c59f6388d58b99cdc424", size = 348170, upload-time = "2025-10-22T22:22:06.397Z" }, - { url = "https://files.pythonhosted.org/packages/18/ea/42d243d3a586beb72c77fa5def0487daf827210069a95f36328e869599ea/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e819e0e37a44a78e1383bf1970076e2ccc4dc8c2bbaa2f9bd1dc987e9afff628", size = 378838, upload-time = "2025-10-22T22:22:07.932Z" }, - { url = "https://files.pythonhosted.org/packages/e7/78/3de32e18a94791af8f33601402d9d4f39613136398658412a4e0b3047327/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ee514e0f0523db5d3fb171f397c54875dbbd69760a414dccf9d4d7ad628b5bd", size = 393299, upload-time = "2025-10-22T22:22:09.435Z" }, - { url = "https://files.pythonhosted.org/packages/13/7e/4bdb435afb18acea2eb8a25ad56b956f28de7c59f8a1d32827effa0d4514/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3fa06d27fdcee47f07a39e02862da0100cb4982508f5ead53ec533cd5fe55e", size = 518000, upload-time = "2025-10-22T22:22:11.326Z" }, - { url = "https://files.pythonhosted.org/packages/31/d0/5f52a656875cdc60498ab035a7a0ac8f399890cc1ee73ebd567bac4e39ae/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46959ef2e64f9e4a41fc89aa20dbca2b85531f9a72c21099a3360f35d10b0d5a", size = 408746, upload-time = "2025-10-22T22:22:13.143Z" }, - { url = "https://files.pythonhosted.org/packages/3e/cd/49ce51767b879cde77e7ad9fae164ea15dce3616fe591d9ea1df51152706/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8455933b4bcd6e83fde3fefc987a023389c4b13f9a58c8d23e4b3f6d13f78c84", size = 386379, upload-time = "2025-10-22T22:22:14.602Z" }, - { url = "https://files.pythonhosted.org/packages/6a/99/e4e1e1ee93a98f72fc450e36c0e4d99c35370220e815288e3ecd2ec36a2a/rpds_py-0.28.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ad50614a02c8c2962feebe6012b52f9802deec4263946cddea37aaf28dd25a66", size = 401280, upload-time = "2025-10-22T22:22:16.063Z" }, - { url = "https://files.pythonhosted.org/packages/61/35/e0c6a57488392a8b319d2200d03dad2b29c0db9996f5662c3b02d0b86c02/rpds_py-0.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5deca01b271492553fdb6c7fd974659dce736a15bae5dad7ab8b93555bceb28", size = 412365, upload-time = "2025-10-22T22:22:17.504Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6a/841337980ea253ec797eb084665436007a1aad0faac1ba097fb906c5f69c/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:735f8495a13159ce6a0d533f01e8674cec0c57038c920495f87dcb20b3ddb48a", size = 559573, upload-time = "2025-10-22T22:22:19.108Z" }, - { url = "https://files.pythonhosted.org/packages/e7/5e/64826ec58afd4c489731f8b00729c5f6afdb86f1df1df60bfede55d650bb/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:961ca621ff10d198bbe6ba4957decca61aa2a0c56695384c1d6b79bf61436df5", size = 583973, upload-time = "2025-10-22T22:22:20.768Z" }, - { url = "https://files.pythonhosted.org/packages/b6/ee/44d024b4843f8386a4eeaa4c171b3d31d55f7177c415545fd1a24c249b5d/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2374e16cc9131022e7d9a8f8d65d261d9ba55048c78f3b6e017971a4f5e6353c", size = 553800, upload-time = "2025-10-22T22:22:22.25Z" }, - { url = "https://files.pythonhosted.org/packages/7d/89/33e675dccff11a06d4d85dbb4d1865f878d5020cbb69b2c1e7b2d3f82562/rpds_py-0.28.0-cp312-cp312-win32.whl", hash = "sha256:d15431e334fba488b081d47f30f091e5d03c18527c325386091f31718952fe08", size = 216954, upload-time = "2025-10-22T22:22:24.105Z" }, - { url = "https://files.pythonhosted.org/packages/af/36/45f6ebb3210887e8ee6dbf1bc710ae8400bb417ce165aaf3024b8360d999/rpds_py-0.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:a410542d61fc54710f750d3764380b53bf09e8c4edbf2f9141a82aa774a04f7c", size = 227844, upload-time = "2025-10-22T22:22:25.551Z" }, - { url = "https://files.pythonhosted.org/packages/57/91/f3fb250d7e73de71080f9a221d19bd6a1c1eb0d12a1ea26513f6c1052ad6/rpds_py-0.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:1f0cfd1c69e2d14f8c892b893997fa9a60d890a0c8a603e88dca4955f26d1edd", size = 217624, upload-time = "2025-10-22T22:22:26.914Z" }, - { url = "https://files.pythonhosted.org/packages/ae/bc/b43f2ea505f28119bd551ae75f70be0c803d2dbcd37c1b3734909e40620b/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16", size = 363913, upload-time = "2025-10-22T22:24:07.129Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/db318195d324c89a2c57dc5195058cbadd71b20d220685c5bd1da79ee7fe/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d", size = 350452, upload-time = "2025-10-22T22:24:08.754Z" }, - { url = "https://files.pythonhosted.org/packages/ae/f2/1391c819b8573a4898cedd6b6c5ec5bc370ce59e5d6bdcebe3c9c1db4588/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db", size = 380957, upload-time = "2025-10-22T22:24:10.826Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5c/e5de68ee7eb7248fce93269833d1b329a196d736aefb1a7481d1e99d1222/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7", size = 391919, upload-time = "2025-10-22T22:24:12.559Z" }, - { url = "https://files.pythonhosted.org/packages/fb/4f/2376336112cbfeb122fd435d608ad8d5041b3aed176f85a3cb32c262eb80/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78", size = 528541, upload-time = "2025-10-22T22:24:14.197Z" }, - { url = "https://files.pythonhosted.org/packages/68/53/5ae232e795853dd20da7225c5dd13a09c0a905b1a655e92bdf8d78a99fd9/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec", size = 405629, upload-time = "2025-10-22T22:24:16.001Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2d/351a3b852b683ca9b6b8b38ed9efb2347596973849ba6c3a0e99877c10aa/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72", size = 384123, upload-time = "2025-10-22T22:24:17.585Z" }, - { url = "https://files.pythonhosted.org/packages/e0/15/870804daa00202728cc91cb8e2385fa9f1f4eb49857c49cfce89e304eae6/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27", size = 400923, upload-time = "2025-10-22T22:24:19.512Z" }, - { url = "https://files.pythonhosted.org/packages/53/25/3706b83c125fa2a0bccceac951de3f76631f6bd0ee4d02a0ed780712ef1b/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316", size = 413767, upload-time = "2025-10-22T22:24:21.316Z" }, - { url = "https://files.pythonhosted.org/packages/ef/f9/ce43dbe62767432273ed2584cef71fef8411bddfb64125d4c19128015018/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912", size = 561530, upload-time = "2025-10-22T22:24:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/46/c9/ffe77999ed8f81e30713dd38fd9ecaa161f28ec48bb80fa1cd9118399c27/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829", size = 585453, upload-time = "2025-10-22T22:24:24.779Z" }, - { url = "https://files.pythonhosted.org/packages/ed/d2/4a73b18821fd4669762c855fd1f4e80ceb66fb72d71162d14da58444a763/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f", size = 552199, upload-time = "2025-10-22T22:24:26.54Z" }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, + { url = "https://files.pythonhosted.org/packages/4d/6e/f964e88b3d2abee2a82c1ac8366da848fce1c6d834dc2132c3fda3970290/rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425", size = 370157, upload-time = "2025-11-30T20:21:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/94/ba/24e5ebb7c1c82e74c4e4f33b2112a5573ddc703915b13a073737b59b86e0/rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d", size = 359676, upload-time = "2025-11-30T20:21:55.475Z" }, + { url = "https://files.pythonhosted.org/packages/84/86/04dbba1b087227747d64d80c3b74df946b986c57af0a9f0c98726d4d7a3b/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4", size = 389938, upload-time = "2025-11-30T20:21:57.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/bb/1463f0b1722b7f45431bdd468301991d1328b16cffe0b1c2918eba2c4eee/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f", size = 402932, upload-time = "2025-11-30T20:21:58.47Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/2520700a5c1f2d76631f948b0736cdf9b0acb25abd0ca8e889b5c62ac2e3/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4", size = 525830, upload-time = "2025-11-30T20:21:59.699Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ad/bd0331f740f5705cc555a5e17fdf334671262160270962e69a2bdef3bf76/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97", size = 412033, upload-time = "2025-11-30T20:22:00.991Z" }, + { url = "https://files.pythonhosted.org/packages/f8/1e/372195d326549bb51f0ba0f2ecb9874579906b97e08880e7a65c3bef1a99/rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89", size = 390828, upload-time = "2025-11-30T20:22:02.723Z" }, + { url = "https://files.pythonhosted.org/packages/ab/2b/d88bb33294e3e0c76bc8f351a3721212713629ffca1700fa94979cb3eae8/rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d", size = 404683, upload-time = "2025-11-30T20:22:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/50/32/c759a8d42bcb5289c1fac697cd92f6fe01a018dd937e62ae77e0e7f15702/rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038", size = 421583, upload-time = "2025-11-30T20:22:05.814Z" }, + { url = "https://files.pythonhosted.org/packages/2b/81/e729761dbd55ddf5d84ec4ff1f47857f4374b0f19bdabfcf929164da3e24/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7", size = 572496, upload-time = "2025-11-30T20:22:07.713Z" }, + { url = "https://files.pythonhosted.org/packages/14/f6/69066a924c3557c9c30baa6ec3a0aa07526305684c6f86c696b08860726c/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed", size = 598669, upload-time = "2025-11-30T20:22:09.312Z" }, + { url = "https://files.pythonhosted.org/packages/5f/48/905896b1eb8a05630d20333d1d8ffd162394127b74ce0b0784ae04498d32/rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85", size = 561011, upload-time = "2025-11-30T20:22:11.309Z" }, + { url = "https://files.pythonhosted.org/packages/22/16/cd3027c7e279d22e5eb431dd3c0fbc677bed58797fe7581e148f3f68818b/rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c", size = 221406, upload-time = "2025-11-30T20:22:13.101Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/e7b7aa136f28462b344e652ee010d4de26ee9fd16f1bfd5811f5153ccf89/rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825", size = 236024, upload-time = "2025-11-30T20:22:14.853Z" }, + { url = "https://files.pythonhosted.org/packages/14/a6/364bba985e4c13658edb156640608f2c9e1d3ea3c81b27aa9d889fff0e31/rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229", size = 229069, upload-time = "2025-11-30T20:22:16.577Z" }, + { url = "https://files.pythonhosted.org/packages/03/e7/98a2f4ac921d82f33e03f3835f5bf3a4a40aa1bfdc57975e74a97b2b4bdd/rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad", size = 375086, upload-time = "2025-11-30T20:22:17.93Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a1/bca7fd3d452b272e13335db8d6b0b3ecde0f90ad6f16f3328c6fb150c889/rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05", size = 359053, upload-time = "2025-11-30T20:22:19.297Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/ae157e83a6357eceff62ba7e52113e3ec4834a84cfe07fa4b0757a7d105f/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28", size = 390763, upload-time = "2025-11-30T20:22:21.661Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/eb2eb8515e2ad24c0bd43c3ee9cd74c33f7ca6430755ccdb240fd3144c44/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd", size = 408951, upload-time = "2025-11-30T20:22:23.408Z" }, + { url = "https://files.pythonhosted.org/packages/d6/65/ad8dc1784a331fabbd740ef6f71ce2198c7ed0890dab595adb9ea2d775a1/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f", size = 514622, upload-time = "2025-11-30T20:22:25.16Z" }, + { url = "https://files.pythonhosted.org/packages/63/8e/0cfa7ae158e15e143fe03993b5bcd743a59f541f5952e1546b1ac1b5fd45/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1", size = 414492, upload-time = "2025-11-30T20:22:26.505Z" }, + { url = "https://files.pythonhosted.org/packages/60/1b/6f8f29f3f995c7ffdde46a626ddccd7c63aefc0efae881dc13b6e5d5bb16/rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23", size = 394080, upload-time = "2025-11-30T20:22:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/a266341051a7a3ca2f4b750a3aa4abc986378431fc2da508c5034d081b70/rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6", size = 408680, upload-time = "2025-11-30T20:22:29.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/3b/71b725851df9ab7a7a4e33cf36d241933da66040d195a84781f49c50490c/rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51", size = 423589, upload-time = "2025-11-30T20:22:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/00/2b/e59e58c544dc9bd8bd8384ecdb8ea91f6727f0e37a7131baeff8d6f51661/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5", size = 573289, upload-time = "2025-11-30T20:22:32.997Z" }, + { url = "https://files.pythonhosted.org/packages/da/3e/a18e6f5b460893172a7d6a680e86d3b6bc87a54c1f0b03446a3c8c7b588f/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e", size = 599737, upload-time = "2025-11-30T20:22:34.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e2/714694e4b87b85a18e2c243614974413c60aa107fd815b8cbc42b873d1d7/rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394", size = 563120, upload-time = "2025-11-30T20:22:35.903Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ab/d5d5e3bcedb0a77f4f613706b750e50a5a3ba1c15ccd3665ecc636c968fd/rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf", size = 223782, upload-time = "2025-11-30T20:22:37.271Z" }, + { url = "https://files.pythonhosted.org/packages/39/3b/f786af9957306fdc38a74cef405b7b93180f481fb48453a114bb6465744a/rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b", size = 240463, upload-time = "2025-11-30T20:22:39.021Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d2/b91dc748126c1559042cfe41990deb92c4ee3e2b415f6b5234969ffaf0cc/rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e", size = 230868, upload-time = "2025-11-30T20:22:40.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/71/3f34339ee70521864411f8b6992e7ab13ac30d8e4e3309e07c7361767d91/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58", size = 372292, upload-time = "2025-11-30T20:24:16.537Z" }, + { url = "https://files.pythonhosted.org/packages/57/09/f183df9b8f2d66720d2ef71075c59f7e1b336bec7ee4c48f0a2b06857653/rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a", size = 362128, upload-time = "2025-11-30T20:24:18.086Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/5c2594e937253457342e078f0cc1ded3dd7b2ad59afdbf2d354869110a02/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb", size = 391542, upload-time = "2025-11-30T20:24:20.092Z" }, + { url = "https://files.pythonhosted.org/packages/49/5c/31ef1afd70b4b4fbdb2800249f34c57c64beb687495b10aec0365f53dfc4/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c", size = 404004, upload-time = "2025-11-30T20:24:22.231Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/0cfbea38d05756f3440ce6534d51a491d26176ac045e2707adc99bb6e60a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3", size = 527063, upload-time = "2025-11-30T20:24:24.302Z" }, + { url = "https://files.pythonhosted.org/packages/42/e6/01e1f72a2456678b0f618fc9a1a13f882061690893c192fcad9f2926553a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5", size = 413099, upload-time = "2025-11-30T20:24:25.916Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/8df56677f209003dcbb180765520c544525e3ef21ea72279c98b9aa7c7fb/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738", size = 392177, upload-time = "2025-11-30T20:24:27.834Z" }, + { url = "https://files.pythonhosted.org/packages/4a/b4/0a771378c5f16f8115f796d1f437950158679bcd2a7c68cf251cfb00ed5b/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f", size = 406015, upload-time = "2025-11-30T20:24:29.457Z" }, + { url = "https://files.pythonhosted.org/packages/36/d8/456dbba0af75049dc6f63ff295a2f92766b9d521fa00de67a2bd6427d57a/rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877", size = 423736, upload-time = "2025-11-30T20:24:31.22Z" }, + { url = "https://files.pythonhosted.org/packages/13/64/b4d76f227d5c45a7e0b796c674fd81b0a6c4fbd48dc29271857d8219571c/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a", size = 573981, upload-time = "2025-11-30T20:24:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/092bacadeda3edf92bf743cc96a7be133e13a39cdbfd7b5082e7ab638406/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4", size = 599782, upload-time = "2025-11-30T20:24:35.169Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] [[package]] name = "ruff" -version = "0.14.10" +version = "0.14.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/08/52232a877978dd8f9cf2aeddce3e611b40a63287dfca29b6b8da791f5e8d/ruff-0.14.10.tar.gz", hash = "sha256:9a2e830f075d1a42cd28420d7809ace390832a490ed0966fe373ba288e77aaf4", size = 5859763, upload-time = "2025-12-18T19:28:57.98Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/01/933704d69f3f05ee16ef11406b78881733c186fe14b6a46b05cfcaf6d3b2/ruff-0.14.10-py3-none-linux_armv6l.whl", hash = "sha256:7a3ce585f2ade3e1f29ec1b92df13e3da262178df8c8bdf876f48fa0e8316c49", size = 13527080, upload-time = "2025-12-18T19:29:25.642Z" }, - { url = "https://files.pythonhosted.org/packages/df/58/a0349197a7dfa603ffb7f5b0470391efa79ddc327c1e29c4851e85b09cc5/ruff-0.14.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:674f9be9372907f7257c51f1d4fc902cb7cf014b9980152b802794317941f08f", size = 13797320, upload-time = "2025-12-18T19:29:02.571Z" }, - { url = "https://files.pythonhosted.org/packages/7b/82/36be59f00a6082e38c23536df4e71cdbc6af8d7c707eade97fcad5c98235/ruff-0.14.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d85713d522348837ef9df8efca33ccb8bd6fcfc86a2cde3ccb4bc9d28a18003d", size = 12918434, upload-time = "2025-12-18T19:28:51.202Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/45c62a7f7e34da92a25804f813ebe05c88aa9e0c25e5cb5a7d23dd7450e3/ruff-0.14.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6987ebe0501ae4f4308d7d24e2d0fe3d7a98430f5adfd0f1fead050a740a3a77", size = 13371961, upload-time = "2025-12-18T19:29:04.991Z" }, - { url = "https://files.pythonhosted.org/packages/40/31/a5906d60f0405f7e57045a70f2d57084a93ca7425f22e1d66904769d1628/ruff-0.14.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16a01dfb7b9e4eee556fbfd5392806b1b8550c9b4a9f6acd3dbe6812b193c70a", size = 13275629, upload-time = "2025-12-18T19:29:21.381Z" }, - { url = "https://files.pythonhosted.org/packages/3e/60/61c0087df21894cf9d928dc04bcd4fb10e8b2e8dca7b1a276ba2155b2002/ruff-0.14.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7165d31a925b7a294465fa81be8c12a0e9b60fb02bf177e79067c867e71f8b1f", size = 14029234, upload-time = "2025-12-18T19:29:00.132Z" }, - { url = "https://files.pythonhosted.org/packages/44/84/77d911bee3b92348b6e5dab5a0c898d87084ea03ac5dc708f46d88407def/ruff-0.14.10-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c561695675b972effb0c0a45db233f2c816ff3da8dcfbe7dfc7eed625f218935", size = 15449890, upload-time = "2025-12-18T19:28:53.573Z" }, - { url = "https://files.pythonhosted.org/packages/e9/36/480206eaefa24a7ec321582dda580443a8f0671fdbf6b1c80e9c3e93a16a/ruff-0.14.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bb98fcbbc61725968893682fd4df8966a34611239c9fd07a1f6a07e7103d08e", size = 15123172, upload-time = "2025-12-18T19:29:23.453Z" }, - { url = "https://files.pythonhosted.org/packages/5c/38/68e414156015ba80cef5473d57919d27dfb62ec804b96180bafdeaf0e090/ruff-0.14.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f24b47993a9d8cb858429e97bdf8544c78029f09b520af615c1d261bf827001d", size = 14460260, upload-time = "2025-12-18T19:29:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/b3/19/9e050c0dca8aba824d67cc0db69fb459c28d8cd3f6855b1405b3f29cc91d/ruff-0.14.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59aabd2e2c4fd614d2862e7939c34a532c04f1084476d6833dddef4afab87e9f", size = 14229978, upload-time = "2025-12-18T19:29:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/51/eb/e8dd1dd6e05b9e695aa9dd420f4577debdd0f87a5ff2fedda33c09e9be8c/ruff-0.14.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:213db2b2e44be8625002dbea33bb9c60c66ea2c07c084a00d55732689d697a7f", size = 14338036, upload-time = "2025-12-18T19:29:09.184Z" }, - { url = "https://files.pythonhosted.org/packages/6a/12/f3e3a505db7c19303b70af370d137795fcfec136d670d5de5391e295c134/ruff-0.14.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b914c40ab64865a17a9a5b67911d14df72346a634527240039eb3bd650e5979d", size = 13264051, upload-time = "2025-12-18T19:29:13.431Z" }, - { url = "https://files.pythonhosted.org/packages/08/64/8c3a47eaccfef8ac20e0484e68e0772013eb85802f8a9f7603ca751eb166/ruff-0.14.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1484983559f026788e3a5c07c81ef7d1e97c1c78ed03041a18f75df104c45405", size = 13283998, upload-time = "2025-12-18T19:29:06.994Z" }, - { url = "https://files.pythonhosted.org/packages/12/84/534a5506f4074e5cc0529e5cd96cfc01bb480e460c7edf5af70d2bcae55e/ruff-0.14.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c70427132db492d25f982fffc8d6c7535cc2fd2c83fc8888f05caaa248521e60", size = 13601891, upload-time = "2025-12-18T19:28:55.811Z" }, - { url = "https://files.pythonhosted.org/packages/0d/1e/14c916087d8598917dbad9b2921d340f7884824ad6e9c55de948a93b106d/ruff-0.14.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5bcf45b681e9f1ee6445d317ce1fa9d6cba9a6049542d1c3d5b5958986be8830", size = 14336660, upload-time = "2025-12-18T19:29:16.531Z" }, - { url = "https://files.pythonhosted.org/packages/f2/1c/d7b67ab43f30013b47c12b42d1acd354c195351a3f7a1d67f59e54227ede/ruff-0.14.10-py3-none-win32.whl", hash = "sha256:104c49fc7ab73f3f3a758039adea978869a918f31b73280db175b43a2d9b51d6", size = 13196187, upload-time = "2025-12-18T19:29:19.006Z" }, - { url = "https://files.pythonhosted.org/packages/fb/9c/896c862e13886fae2af961bef3e6312db9ebc6adc2b156fe95e615dee8c1/ruff-0.14.10-py3-none-win_amd64.whl", hash = "sha256:466297bd73638c6bdf06485683e812db1c00c7ac96d4ddd0294a338c62fdc154", size = 14661283, upload-time = "2025-12-18T19:29:30.16Z" }, - { url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" }, + { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, + { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, + { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, + { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, + { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, + { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, + { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, + { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, + { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, + { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, + { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, ] [[package]] name = "setuptools" -version = "80.9.0" +version = "83.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/34/26/f5d29e25ffdb535afef2d35cdb55b325298f96debd670da4c325e08d70f4/setuptools-83.0.0.tar.gz", hash = "sha256:025bccbbf0fa05b6192bc64ae1e7b16e001fd6d6d4d5de03c97b1c1ade523bef", size = 1154254, upload-time = "2026-07-04T15:31:22.699Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/5d/40/e1e72872c6354b306daef1703549e8e83b4d43cfea356311bf722a043752/setuptools-83.0.0-py3-none-any.whl", hash = "sha256:29b23c360f22f414dc7336bb39178cc7bcbf6021ed2733cde173f09dba19abb3", size = 1008090, upload-time = "2026-07-04T15:31:20.885Z" }, ] [[package]] @@ -2451,6 +2604,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] +[[package]] +name = "socksio" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/5c/48a7d9495be3d1c651198fd99dbb6ce190e2274d0f28b9051307bdec6b85/socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac", size = 19055, upload-time = "2020-04-17T15:50:34.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/c3/6eeb6034408dac0fa653d126c9204ade96b819c936e136c5e8a6897eee9c/socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3", size = 12763, upload-time = "2020-04-17T15:50:31.878Z" }, +] + [[package]] name = "sqlalchemy" version = "1.4.54" @@ -2493,15 +2655,38 @@ wheels = [ [[package]] name = "starlette" -version = "0.47.1" +version = "0.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" }, + { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" }, +] + +[[package]] +name = "tibs" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/cd/6cf028decf1c2df4d26077dd5d0532587d93d4917233d5e004133166a940/tibs-0.5.7.tar.gz", hash = "sha256:173dfbecb2309edd9771f453580c88cf251e775613461566b23dbd756b3d54cb", size = 78255, upload-time = "2026-03-12T13:06:29.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/2d/de2c579d3eea0f18212b5b16decb04568b7a0ef912d00581a77492609d4e/tibs-0.5.7-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:859f05315ffb307d3474c505d694f3a547f00730a024c982f5f60316a5505b3c", size = 411352, upload-time = "2026-03-12T13:06:52.016Z" }, + { url = "https://files.pythonhosted.org/packages/74/71/4c21ccc5c2e1672f9cd91ed2c46604c250cffd9d386113772dded128b5cf/tibs-0.5.7-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:a883ca13a922a66b2c1326a9c188123a574741a72510a4bf52fd6f97db191e44", size = 383971, upload-time = "2026-03-12T13:06:50.143Z" }, + { url = "https://files.pythonhosted.org/packages/38/85/399940ac5393772792a209911a5efa42cf55cf621771e48b863211ac5a2a/tibs-0.5.7-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f70bd250769381c73110d6f24feaf8b6fcd44f680b3cb28a20ea06db3d04fb6f", size = 416256, upload-time = "2026-03-12T13:06:24.222Z" }, + { url = "https://files.pythonhosted.org/packages/02/94/481a73e74d398949f57d297b1809a10a951d252e7ec94b6715ed952ce500/tibs-0.5.7-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76746f01b3db9dbd802f5e615f11f68df7a29ecef521b082dca53f3fa7d0084f", size = 428003, upload-time = "2026-03-12T13:06:23.064Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e0/72db1760a7f7fec1d5f3690e0855fbbccbcf0a4a2fd318c9d71f3b33f3a7/tibs-0.5.7-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:847709c108800ad6a45efaf9a040628278956938a4897f7427a2587013dc3b98", size = 455589, upload-time = "2026-03-12T13:06:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/3e/26/9cd3395914bf705d6ae1e9a6c323f727e9dc88fef716327ce7f486e0b55a/tibs-0.5.7-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad61df93b50f875b277ab736c5d37b6bce56f9abce489a22f4e02d9daa2966e3", size = 459266, upload-time = "2026-03-12T13:06:21.678Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3b/267f19a008d13c704dc0b044138a56239272a43531ccb05464129d0fbd01/tibs-0.5.7-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e13b9c7ff2604b0146772025e1ac6f85c8c625bf6ac73736ff671eaf357dda41", size = 423466, upload-time = "2026-03-12T13:06:41.212Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d4/424ae3515e0e013ad83186074bf3beb53399b9052c00da703415ccc316ca/tibs-0.5.7-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a7ce857ef05c59dc61abadc31c4b9b1e3c62f9e5fb29217988c308936aea71e", size = 452080, upload-time = "2026-03-12T13:06:32.112Z" }, + { url = "https://files.pythonhosted.org/packages/b0/15/ab80beba83a134745439d33763e1d3b017f994abeb9c309a3ac9fd94e90e/tibs-0.5.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1d5521cc6768bfa6282a0c591ba06b079ab91b5c7d5696925ad2abac59779a54", size = 592311, upload-time = "2026-03-12T13:06:47.807Z" }, + { url = "https://files.pythonhosted.org/packages/4c/21/f5cf41c15431e63aeaefb494e714d48d9e9061b4e01fcc01d1987e2e5faa/tibs-0.5.7-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:477608f9b87e24a22ab6d50b81da04a5cb59bfa49598ff7ec5165035a18fb392", size = 703400, upload-time = "2026-03-12T13:06:16.968Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ec/b3bdb7dcc3de8513c5678a685f4e25bb85ef48526d7d535ddc592f9e8602/tibs-0.5.7-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:ac0aa2aae38f7325c91c261ce1d18f769c4c7033c98d6ea3ea5534585cf16452", size = 664623, upload-time = "2026-03-12T13:06:48.894Z" }, + { url = "https://files.pythonhosted.org/packages/a4/71/7b85af3ad1b2cd9871c8f50ba0eb17e54e12481b467678535e58aced0d98/tibs-0.5.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b56583db148e5094d781c3d746815dbcbb6378c6f813c8ce291efd4ab21da8b", size = 635199, upload-time = "2026-03-12T13:06:34.798Z" }, + { url = "https://files.pythonhosted.org/packages/b9/63/60220fb502beb857306afd4a5bac4a8617ae496f3b1f4968d127380fdefe/tibs-0.5.7-cp38-abi3-win32.whl", hash = "sha256:d4f3ff613d486650816bc5516760c0382a2cc0ca8aeddd8914d011bc3b81d9a2", size = 288454, upload-time = "2026-03-12T13:06:30.978Z" }, + { url = "https://files.pythonhosted.org/packages/46/ab/aab78827ba7e0d65fe346b86d1d61e0792c38d5f9b7547e0f71b7027c835/tibs-0.5.7-cp38-abi3-win_amd64.whl", hash = "sha256:a61d36155f8ab8642e1b6744e13822f72050fc7ec4f86ec6965295afa04949e2", size = 304135, upload-time = "2026-03-12T13:06:35.884Z" }, + { url = "https://files.pythonhosted.org/packages/48/59/e9e6a610928a4bcbf04f0ac1436ee320aa8cbe95181f1aa32687c50e858b/tibs-0.5.7-cp38-abi3-win_arm64.whl", hash = "sha256:130bc68ff500fc8185677df7a97350b5d5339e6ba7e325bc3031337f6424ede7", size = 289272, upload-time = "2026-03-12T13:06:19.247Z" }, ] [[package]] @@ -2512,98 +2697,100 @@ sdist = { url = "https://files.pythonhosted.org/packages/bb/89/6df40b0c5fd9a1c30 [[package]] name = "tomli" -version = "2.3.0" +version = "2.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, - { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, - { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, - { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, - { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, - { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, - { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, ] [[package]] name = "tornado" -version = "6.5.5" +version = "6.5.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/24/95ec527ad67b76d59299e5465b3935d05e4294b7e0290a3924b7487df30b/tornado-6.5.7.tar.gz", hash = "sha256:66c513a76cda70d53907bc27cf1447557699c2e95aa48ba27a442ff61c3ddfc2", size = 519252, upload-time = "2026-06-08T17:34:51.232Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, - { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, - { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, - { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, - { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, - { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, - { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, + { url = "https://files.pythonhosted.org/packages/02/dc/c7043cab6fed8ae159fc1923ce829ada35c4dbd797d408a43858ffaf9639/tornado-6.5.7-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:148b2eb15c2c765a50796172c1e499649b35f30d2e3c3d3e15913cfa56bfb163", size = 448543, upload-time = "2026-06-08T17:34:38.052Z" }, + { url = "https://files.pythonhosted.org/packages/92/4f/090b1431e5a43df696feceffc268c5383cc079ecb5f08ce58f917109aafe/tornado-6.5.7-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9da38de27f1da3b78a966f0dae12b5a1ea9afe72ca805d84ff06508272ddf100", size = 446707, upload-time = "2026-06-08T17:34:39.594Z" }, + { url = "https://files.pythonhosted.org/packages/37/d8/ef374952fd5da67d4463122c2b8e5a96536ec10b4b339254c6dcde81d01c/tornado-6.5.7-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8d759e71906ee783f8867b93bf26a265743da4c1e2f4a018464c1ba019862972", size = 449774, upload-time = "2026-06-08T17:34:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/35/37/d434c73f4c6e014b745b9b37085f34f40c022f007efff3d7fe65991899f3/tornado-6.5.7-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a46347a18f23fb92b396beebe0fb78f61dda0cc302445202c16203d8a18848b", size = 450745, upload-time = "2026-06-08T17:34:42.531Z" }, + { url = "https://files.pythonhosted.org/packages/b6/2b/56b9aff361d7f1ab728a805ec7d7ea835f8807afa9f5cc690ea0e630efb9/tornado-6.5.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7778b30bef919231265e91c69963ce0f49a1e9c07ac900bbe75b19ce2575ba92", size = 450578, upload-time = "2026-06-08T17:34:43.787Z" }, + { url = "https://files.pythonhosted.org/packages/02/30/a7444fb23aa76860a14198fab96ac79f1866b0a6e19e26c4381b0938e50f/tornado-6.5.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e726f0c75da7726eec023aa62751ff8878bd2737e34fbdd33b1ae5897d2200f5", size = 449985, upload-time = "2026-06-08T17:34:45.326Z" }, + { url = "https://files.pythonhosted.org/packages/5c/42/5f0e56c01e8d9d36f4e23f367b85ae6cae0c1ecddd5e6977d8388ad27488/tornado-6.5.7-cp39-abi3-win32.whl", hash = "sha256:f8de3bf12d3efdd0cbe7c8887868198f8a91415e3f29fcf258d9b8eb7b1d9ae4", size = 451047, upload-time = "2026-06-08T17:34:46.784Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a4/b393076ffb21b469eec5b328a0534cf03a3b90bfc6b1f09507cdd075d938/tornado-6.5.7-cp39-abi3-win_amd64.whl", hash = "sha256:de942f843533a039ef9fa3d9c88c7cd8a7c94553fb5ad0154270989b3d99a2c4", size = 451485, upload-time = "2026-06-08T17:34:48.248Z" }, + { url = "https://files.pythonhosted.org/packages/71/2e/7b1c769803121b809112cf9a00681c472eae1d80e32d7ec0e0bd61d0d0e1/tornado-6.5.7-cp39-abi3-win_arm64.whl", hash = "sha256:ff934fce95643af5f11efdae618eaa73d469dc588641e5c8d19295a0c65c4796", size = 450506, upload-time = "2026-06-08T17:34:49.702Z" }, ] [[package]] name = "tqdm" -version = "4.67.1" +version = "4.67.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, ] [[package]] name = "typer" -version = "0.16.1" +version = "0.26.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, + { name = "annotated-doc" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "rich" }, { name = "shellingham" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } +sdist = { url = "https://files.pythonhosted.org/packages/67/a5/756f2e6bc81a7dd79aa3c625dd01b74cabc4516628cace2caaec09ca6ff2/typer-0.26.2.tar.gz", hash = "sha256:9b4f19e08fcc9427a822d1ef467b1fe76737a2f65c7926bdeba2337d73569b68", size = 198991, upload-time = "2026-05-27T10:41:39.166Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a5/6ffd702beda8798b2b82ff70805ed4a66d963557e43a5d1823ab456251a4/typer-0.26.2-py3-none-any.whl", hash = "sha256:39beff72ffbb31978a5b545f677d57edb97c6f980f433b38556deb0af25f094d", size = 123123, upload-time = "2026-05-27T10:41:40.504Z" }, ] [[package]] name = "types-mock" -version = "5.2.0.20250924" +version = "5.2.0.20260518" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/c3/00cf1e62c27fd195aaf22b249884f82643141b73f151ff019aa24c99bd17/types_mock-5.2.0.20250924.tar.gz", hash = "sha256:953197543b4183f00363e8e626f6c7abea1a3f7a4dd69d199addb70b01b6bb35", size = 11319, upload-time = "2025-09-24T02:53:33.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/a4/26595e2a9407752c2e3cd5b17d7884db847e39834a2575cf15b5c3b19a27/types_mock-5.2.0.20260518.tar.gz", hash = "sha256:49af9c18aac4caa90e0e1e8437e2160cd8b3f126053dae6453d65b393590fcf9", size = 11577, upload-time = "2026-05-18T06:02:42.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/85/52004fb81add2b05494cbd1c0dab71f3706f19935cabb4ad220643884382/types_mock-5.2.0.20250924-py3-none-any.whl", hash = "sha256:23617ffb4cf948c085db69ec90bd474afbce634ef74995045ae0a5748afbe57d", size = 10499, upload-time = "2025-09-24T02:53:32.054Z" }, + { url = "https://files.pythonhosted.org/packages/82/d6/da3bf7cc26ebe587e8c50a505d302f5755840fc24fbbd704b770c43b764b/types_mock-5.2.0.20260518-py3-none-any.whl", hash = "sha256:3c511875b6f37d30c70add3e72265d1c21202b8544751361e3ca94f7a757a03d", size = 10459, upload-time = "2026-05-18T06:02:41.224Z" }, ] [[package]] name = "types-passlib" -version = "1.7.7.20250602" +version = "1.7.7.20260211" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fa/3e/501a5832130e5f93450b1e02090e2ee27a37135d11378a47debf960e3131/types_passlib-1.7.7.20250602.tar.gz", hash = "sha256:cf2350e78d36b6b09e4db44284d96651b57285f499cfabf111b616065abab7b3", size = 25406, upload-time = "2025-06-02T03:14:56.033Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/f4/718ff8cbef9366e597aefd58929321702d3e183998cea89949ab5423281f/types_passlib-1.7.7.20260211.tar.gz", hash = "sha256:af73afffe1ce94c95c7f6072bd261572c29845de74fdffa3a265fc7634bca056", size = 25666, upload-time = "2026-02-10T15:11:59.517Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/fc/530236c21f1a0be84c42b23c91c250ef96404c475b739ac4479430ebd7d4/types_passlib-1.7.7.20250602-py3-none-any.whl", hash = "sha256:ed73a91be9a22484ebd62cc0d127675ded542b892b99776db92dab760bbfe274", size = 40410, upload-time = "2025-06-02T03:14:54.834Z" }, + { url = "https://files.pythonhosted.org/packages/14/6a/e9fc6a5b8f9a380a4a56b9f1e4dba5c6899561868017b17f6de382808b6f/types_passlib-1.7.7.20260211-py3-none-any.whl", hash = "sha256:c0f1ad440c513a6c07f333b28249530686056fd54a7b3ac6128ae31fd46305d3", size = 40457, upload-time = "2026-02-10T15:11:58.647Z" }, ] [[package]] name = "types-protobuf" -version = "6.32.1.20251210" +version = "6.32.1.20260221" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c2/59/c743a842911887cd96d56aa8936522b0cd5f7a7f228c96e81b59fced45be/types_protobuf-6.32.1.20251210.tar.gz", hash = "sha256:c698bb3f020274b1a2798ae09dc773728ce3f75209a35187bd11916ebfde6763", size = 63900, upload-time = "2025-12-10T03:14:25.451Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/e2/9aa4a3b2469508bd7b4e2ae11cbedaf419222a09a1b94daffcd5efca4023/types_protobuf-6.32.1.20260221.tar.gz", hash = "sha256:6d5fb060a616bfb076cbb61b4b3c3969f5fc8bec5810f9a2f7e648ee5cbcbf6e", size = 64408, upload-time = "2026-02-21T03:55:13.916Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/43/58e75bac4219cbafee83179505ff44cae3153ec279be0e30583a73b8f108/types_protobuf-6.32.1.20251210-py3-none-any.whl", hash = "sha256:2641f78f3696822a048cfb8d0ff42ccd85c25f12f871fbebe86da63793692140", size = 77921, upload-time = "2025-12-10T03:14:24.477Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e8/1fd38926f9cf031188fbc5a96694203ea6f24b0e34bd64a225ec6f6291ba/types_protobuf-6.32.1.20260221-py3-none-any.whl", hash = "sha256:da7cdd947975964a93c30bfbcc2c6841ee646b318d3816b033adc2c4eb6448e4", size = 77956, upload-time = "2026-02-21T03:55:12.894Z" }, ] [[package]] @@ -2617,11 +2804,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.3" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] [[package]] @@ -2666,46 +2853,66 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.36.1" +version = "21.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, + { name = "python-discovery" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } +sdist = { url = "https://files.pythonhosted.org/packages/15/ba/1f6e8c957e4932be060dcdc482d339c12e0216351478add3645cdaa53c05/virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328", size = 7613784, upload-time = "2026-05-13T18:01:30.19Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, + { url = "https://files.pythonhosted.org/packages/f4/34/a9dbe051de88a63eb7408ea66630bac38e72f7f6077d4be58737106860d9/virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3", size = 7594554, upload-time = "2026-05-13T18:01:27.815Z" }, ] [[package]] name = "wallycore" -version = "1.5.1" +version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/a9/a53f2c3a97f2af8af3ac8bd1e6251b6196e9d051e7bf93ee0d5a6aadd82d/wallycore-1.5.1.tar.gz", hash = "sha256:e691d713d449c5fcf91703dd7af9b0c7262db70abd4f69d3242b4fbe63bd7490", size = 3950231, upload-time = "2025-08-22T04:27:27.708Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/03/907f542ba2db105bba9021099246950f7ade8ac29bba5c2bd87227fba418/wallycore-1.5.3.tar.gz", hash = "sha256:dc2fad7db42482364e558a8c920f9d96879726ebeab8c10daa3a290beec36191", size = 3960658, upload-time = "2026-04-15T22:05:28.784Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/ff/b839e08a45aa3335fb129b0a54ef97cb21daddc50a32c1049c1f7bbca4b9/wallycore-1.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb72f18f90e85cb8fbd423d7ffa04037221290be4965a42e657516bd2b4a916f", size = 3502324, upload-time = "2025-08-22T04:25:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/00/12/19b58a865b385ebdfcf24f8e6e51fe3a3e7cc67a7a26b8849a66da75ebad/wallycore-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5ce19b90bb153f25f4e6c18cee23b6b0517791b9dfb6c462d7620fe79598258b", size = 1784249, upload-time = "2025-08-22T04:25:34.002Z" }, - { url = "https://files.pythonhosted.org/packages/0d/cc/bec4a8f5b655f6c207901dcd9b26072f0a60b3dcf48296470e121768a33a/wallycore-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c460c8111e26fb9aab3ba548f1ad989c88364b2e7154d8b7f285696bddd3a14d", size = 1738389, upload-time = "2025-08-22T04:25:37.117Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/7f136d38a8da108e2e7e5e15ed2560b4ddddcf04dd797bebfad12548c421/wallycore-1.5.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cb5fdcee29453541361782d4a22164299c3468cea142bbe380fe0f405f836955", size = 4173587, upload-time = "2025-08-22T04:25:41.676Z" }, - { url = "https://files.pythonhosted.org/packages/87/87/75b94a22c57440b2bc2d14cada9ecd23d9d97d8fdd50d579dc9879cba82c/wallycore-1.5.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c7baa21ac524e130a8800d4ba173668f7164ed6c884bbafe431a9ec8a9bd5fde", size = 4355795, upload-time = "2025-08-22T04:25:46.271Z" }, - { url = "https://files.pythonhosted.org/packages/86/ca/e8248c2a82fb86462de2919920bc5a7f415fe0bce6cf5ccdf245da31f8f1/wallycore-1.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d365c7453ea2abeed668800b3fac5c8ab4971add26904ab667fbd962053a4147", size = 4251117, upload-time = "2025-08-22T04:25:50.818Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d5/e915ca5db557e12337d94a0ea5c229838bdc7e8645332ee8f06182bdda9d/wallycore-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:018f2a6cc53b8465f4ed9f519f4b4bf14914588ca1f28bd2ca69cef8ebad7c6d", size = 1727473, upload-time = "2025-08-22T04:25:53.911Z" }, - { url = "https://files.pythonhosted.org/packages/4d/72/8f70820abd6d88363756816ffc4da32b3cb4d27c9a3eb331a689afe73915/wallycore-1.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:856af4c3c17c4d57f2b61cec248925302b9cdde1898f6553257f96ca55d7293b", size = 3502321, upload-time = "2025-08-22T04:25:57.128Z" }, - { url = "https://files.pythonhosted.org/packages/be/d4/c3374e227c253514fcb817bb75c98a088e5611adbddcd6894f5010ec7876/wallycore-1.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8303a7fbc48def1a070b54f88104782a469ac71b10c1e8dcc30afe562aab265", size = 1784247, upload-time = "2025-08-22T04:25:59.415Z" }, - { url = "https://files.pythonhosted.org/packages/ab/f5/84ea175a8f7ac52519e2218759d7c15e9df37ece7f7d6404da97160e7860/wallycore-1.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:216e2e7d2e573c5e81b175c66db1dbf63b8932fda084c1f4b3ea6463ba754445", size = 1738390, upload-time = "2025-08-22T04:26:02.24Z" }, - { url = "https://files.pythonhosted.org/packages/9f/d6/1ea941599cc26bc8b8d2c803b0594526767ac8e44a483ce58c891b859b05/wallycore-1.5.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5f19e8fd45933d4780ed2fcb7c23105156860bffadeb61e54fa4cd81b93ccd43", size = 4233649, upload-time = "2025-08-22T04:26:05.864Z" }, - { url = "https://files.pythonhosted.org/packages/86/02/c9f8fd814df039bceef27c61e5a4c17eeca57f6e9f1e8376bff9215f6713/wallycore-1.5.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:bcc23a01efa070a88fa4952369d7e064d6a8e70f8cc11b8a2d2ab5140675343b", size = 4417205, upload-time = "2025-08-22T04:26:10.308Z" }, - { url = "https://files.pythonhosted.org/packages/3b/32/834a043be12ee4f4cf94f90cd29d6e09aa2e92a746b4834233cf5727eef0/wallycore-1.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:78635dcd112604ad86067d79bcb1dc834342f95da1481ccabaf23aba85be08b1", size = 4307666, upload-time = "2025-08-22T04:26:14.344Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c6/2e70819f78442d43c96fae4789cc5d12ebda55e5b35c32c7564c039922f1/wallycore-1.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:aa85dbd16e0506aae6accc8c9d71706f5f895f3143d3ec35160aaec94c29bc57", size = 1727479, upload-time = "2025-08-22T04:26:16.819Z" }, - { url = "https://files.pythonhosted.org/packages/07/3e/56fc17cc26ef3e098d3490b1e1b5f9dbb0a8e825f5d5b1fa3c288a80c662/wallycore-1.5.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:6535e9315aff369224ca57f0cb8ecd68e7134fa34762211c05ee7150bb03566e", size = 3501500, upload-time = "2025-08-22T04:26:20.227Z" }, - { url = "https://files.pythonhosted.org/packages/16/7a/c6b7dc7030399cfc949793a6d43a2efea96ca5c0ec09a6822f23ea5eb89a/wallycore-1.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:94c4669c8721e1750d3c1580de892aba1aa69f5cbda348b881e0606ac27eca0d", size = 1783244, upload-time = "2025-08-22T04:26:23.056Z" }, - { url = "https://files.pythonhosted.org/packages/7a/f2/05bbc191fa6b1b0b314b9c1c630ab5850c6d4763e2bf370d0a933c439704/wallycore-1.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:619e5239dda0f2cc681942a8cde0a6f04809ed7f3982f19063c75dc820625abb", size = 1738704, upload-time = "2025-08-22T04:26:25.887Z" }, - { url = "https://files.pythonhosted.org/packages/7a/6d/5ea8d708c3119ff369bbf8b7297294942cc05af21c8ed3374b0bc52be494/wallycore-1.5.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:2e86a45232f7dc9c306903b261ac08fa4090cf9396cfb45f355e23e3a5b9cd8d", size = 4227822, upload-time = "2025-08-22T04:26:29.857Z" }, - { url = "https://files.pythonhosted.org/packages/c0/95/5d88baf2cfedcd92072fba7ff2e257e89c89377da1ae477f6e6e5bb1600c/wallycore-1.5.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:acc59c95a3959121bac558581218647589836839a5a592cdb123e88dffbc3409", size = 4413207, upload-time = "2025-08-22T04:26:34.128Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f1/164bba36e4e26afb43d2e9515190bc2833968840f191e22c334cf51844db/wallycore-1.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d30ab245d761b62139c29cf3b1e7a2c186d63c4e586871b3a41e52b6a2e4b698", size = 4305955, upload-time = "2025-08-22T04:26:38.341Z" }, - { url = "https://files.pythonhosted.org/packages/49/4b/8e43c5d27753135fa8df3de333c1f1917d6dc315d119ffa60d0587d8d9ff/wallycore-1.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:0b932510c859ac3e1fc57161420ecb2bb9b6562fce7acd1d9351337cc2cc3515", size = 1728013, upload-time = "2025-08-22T04:26:40.774Z" }, + { url = "https://files.pythonhosted.org/packages/94/68/936e1ca6e905b7a660acc6d4871c10cc0ba18666fe182537348133db121c/wallycore-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:31383cdf4e6473dd2d99b62de3144e4b7c172ff317f646a90607e681305782d1", size = 3507848, upload-time = "2026-04-15T22:03:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/ca/2e/ece1b7bb2ae2f2d90716b4dc7b81f8e7ae7ed092e27c5c9161eacae7bf5f/wallycore-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146640621c4b1fa04b8ec6284fce84f6914982fe60da2b0d34cf5157f31627c7", size = 1786740, upload-time = "2026-04-15T22:03:26.224Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/708d03156c11fe48840013f0a58f1b8771e412b7e77f472002dc3f46f4c8/wallycore-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4707fdc084e206384f8446780c03f8c60658e604edc10a17cb95859342d43a0c", size = 1741529, upload-time = "2026-04-15T22:03:29.262Z" }, + { url = "https://files.pythonhosted.org/packages/70/ac/b84ddd7c3cb03ceb419114c3c0d6280b2945fbd47d4cae373a51a383cf33/wallycore-1.5.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3d9bf4b45b390c7f01f83325057fd04b8bc64df63b75e87e421624c2ccb29ed3", size = 4175412, upload-time = "2026-04-15T22:03:33.648Z" }, + { url = "https://files.pythonhosted.org/packages/cf/11/904738c7e4f303b5bfab18f0ab8f371c7d7396a749b163f489de89565558/wallycore-1.5.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:de2aa4f88deabf3a8e3dfcd85986a6023ba9c65e18df7ad3e01a5b6232fd147b", size = 4357578, upload-time = "2026-04-15T22:03:37.849Z" }, + { url = "https://files.pythonhosted.org/packages/01/84/b5b8b26d2b3728d362ad015084c219cfc6d31edaa0284f95bc026df8a2b0/wallycore-1.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9a7c29e9d63a07dd78b63e498cac65e014dc118536fc47be9616295c081c2f4", size = 4253379, upload-time = "2026-04-15T22:03:42.579Z" }, + { url = "https://files.pythonhosted.org/packages/bc/92/623396c5894bd807a6627518a8251cf27ff5a1c6b064030a7ffe53dd363c/wallycore-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:66b33836b1bf6949d134ef914cb31d4c068fb2b3c2e403d4e1fb480cb580f45e", size = 1727845, upload-time = "2026-04-15T22:03:45.716Z" }, + { url = "https://files.pythonhosted.org/packages/81/88/59d71c466b659da5c0b8ab9bfe5c3550e44441f0ad8d918ab04a2b826d49/wallycore-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:818d3d1fc90fd1312d622ceb743eb15910778b3b07bc9f958751129cf4a8fa35", size = 3507852, upload-time = "2026-04-15T22:03:49.195Z" }, + { url = "https://files.pythonhosted.org/packages/b8/68/ffd7e3fa6f2cc997f9bcee6fff82387fc6687b47ca8dc0c77e5ed4ecaa83/wallycore-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:346309b1c491439338d63ed36bd25e448015cfe2da654908f5657bcc1d9076fc", size = 1786740, upload-time = "2026-04-15T22:03:52.436Z" }, + { url = "https://files.pythonhosted.org/packages/0d/fd/07c165a89097ebb6e9b2da10d6c65285c6ee8cd600ca2c43e524ef3a8cb9/wallycore-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20078d7ceee385971dd457f659097c8145c25c1b3abf006c425482721b13399c", size = 1741530, upload-time = "2026-04-15T22:03:55.504Z" }, + { url = "https://files.pythonhosted.org/packages/e2/24/3056dfdfae05c69389c23495109be8df1b7e89d6ed149a35f840949161c6/wallycore-1.5.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:042aaf0c24da8fec6e479a37f17855fcc9ce866ce4aeb76da82cee9c46cc157d", size = 4236112, upload-time = "2026-04-15T22:03:59.599Z" }, + { url = "https://files.pythonhosted.org/packages/8a/5f/6e3f21106ea7714ff7292dfc1c160d7e31da90aa46400d6c0542524fdcc5/wallycore-1.5.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:0cd5c5a060e09931d06527c6065c4e6b47424e68bbc192015f0b17049a1c0496", size = 4418272, upload-time = "2026-04-15T22:04:03.834Z" }, + { url = "https://files.pythonhosted.org/packages/72/0c/7fd4eebb9ce751c27ffeb3a3ddc8bf3561020209c4d0616614ea509a8516/wallycore-1.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:04f48b6790835eea74805ac8b75e53dd487b7ab61daf83d9fac14ee77236582f", size = 4309359, upload-time = "2026-04-15T22:04:07.929Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e1/523181a4fa2358dd44b61140d878e1d6cbc63ba5087af16cff2759196afd/wallycore-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:3da743c065425cd4a3bb5c02157b558164d9100cd571fe11ed78774232717847", size = 1727859, upload-time = "2026-04-15T22:04:10.459Z" }, + { url = "https://files.pythonhosted.org/packages/9b/01/6ac5b85b5f665eb2a0010cad760c47898ad1e31469900baed06f8a48e8f2/wallycore-1.5.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a86225e290233f46f65837b957f84d5dd65d2844d9ca9bd0ebea5a3e4029797d", size = 3506334, upload-time = "2026-04-15T22:04:13.527Z" }, + { url = "https://files.pythonhosted.org/packages/61/42/d6c6b3eef9ce5835930738be3844229c14374c165988c01143e8939db0dd/wallycore-1.5.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:10750069e04cf5875f3e2df50e3494b0f0bae4b79de80b5df7f00d3dd7705b9b", size = 1785116, upload-time = "2026-04-15T22:04:15.995Z" }, + { url = "https://files.pythonhosted.org/packages/a1/bd/fdb39e0cba71646ebabbb79fda30d158f18bfdd3e75e721434dd8fd9ec76/wallycore-1.5.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ac1bd614605f58b89283cb69d8f2dfa90fccbc2c12893c675024d0dc518900c8", size = 1741798, upload-time = "2026-04-15T22:04:19.386Z" }, + { url = "https://files.pythonhosted.org/packages/63/1e/ffd1c18687410a66904ec48b47668e2ab10903559403af8a7c0a52b12333/wallycore-1.5.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01fd8497bd005c4222ef628742eacb5325d47f647763ce6bdd4f189da11503b1", size = 4229550, upload-time = "2026-04-15T22:04:24.266Z" }, + { url = "https://files.pythonhosted.org/packages/a1/f2/3ebe2523c988130d5317b6f1d72606ab314b89698e61a7adea584c230be6/wallycore-1.5.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3dba21b8b16a484f873e5a32b7342407b4b38f5c2556e4212842359adb563aa3", size = 4414976, upload-time = "2026-04-15T22:04:28.686Z" }, + { url = "https://files.pythonhosted.org/packages/41/4f/a343382aec64e15336b1849a335e93dc4f518a416a2059a87d99b86b0501/wallycore-1.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:09037840cba79f68723b2fa06b41b3c131a142d239d57681c63d26e207d7a6f5", size = 4307358, upload-time = "2026-04-15T22:04:33.009Z" }, + { url = "https://files.pythonhosted.org/packages/41/e5/1c1d2979d074cba4f0a1516f2bf4c3ee66067b6ba3b96e5cb4460555d474/wallycore-1.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:c3343a1df11a7ef4572521e002f4550a0157aea2c749dcfd9be62fb5babe0d03", size = 1728038, upload-time = "2026-04-15T22:04:36.434Z" }, +] + +[[package]] +name = "wasmtime" +version = "45.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/ff/db9cfc61d988bc15303134bb174176a29839976876dfd18c3a12548ad291/wasmtime-45.0.0.tar.gz", hash = "sha256:2ad4bf7ca286ceea35c1e420d10b368d7f83faf9a5ffde87b4ee334a9b7f55f3", size = 128297, upload-time = "2026-05-26T17:57:39.131Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/56/7d941adba273210dcf4198266a47f472a5eeca20172005b443af71a9a3e7/wasmtime-45.0.0-py3-none-android_26_arm64_v8a.whl", hash = "sha256:4e843795b53e66c71313f2254731467372e5e1549227cf14accb9e2d57701c10", size = 8659052, upload-time = "2026-05-26T17:57:12.338Z" }, + { url = "https://files.pythonhosted.org/packages/3f/81/c4d81ebf3db8aa28f789a9569640f30790d5234c509a0234cd502aa2638b/wasmtime-45.0.0-py3-none-android_26_x86_64.whl", hash = "sha256:35e713f907264e470f3bc9b592b81b8ed0f8f5651725d9f07a5d52beb0642e38", size = 9619373, upload-time = "2026-05-26T17:57:14.979Z" }, + { url = "https://files.pythonhosted.org/packages/e1/c7/7594da7fa8a3bc5e765733ad57aac9b7b27262c4afa47521bd500e4a4574/wasmtime-45.0.0-py3-none-any.whl", hash = "sha256:6251ee5074a8b8bfaa98e6e99cb5d49d6d0f2320b3265d5aa6c2ee5df5fb4519", size = 8019034, upload-time = "2026-05-26T17:57:20.138Z" }, + { url = "https://files.pythonhosted.org/packages/75/76/7d0e440ca03a717a97889dbb7b68f952c20ed4ffd3f59addf9553579e1d5/wasmtime-45.0.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:3579b0ec6d001750d66ec7089aaeee2c048f88328c82743e15f099af01b0cf84", size = 9401625, upload-time = "2026-05-26T17:57:22.149Z" }, + { url = "https://files.pythonhosted.org/packages/5b/0b/a81b5daf5adea482ecb68d9615f6a348486ab4d8e980a915d4420e57ee4d/wasmtime-45.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:31d10f25c330cebcfb364e9a357123deeec96c41725ff2bba91b705587f38a93", size = 8255954, upload-time = "2026-05-26T17:57:24.769Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8c/e9019a28e908214031310aefd78e4755221d02303190b54b2c85cb69573e/wasmtime-45.0.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:5d1416ec6da8cd87c29e2e9eb074358c91839c2fff971fe428c8921eaae68e73", size = 9681185, upload-time = "2026-05-26T17:57:26.641Z" }, + { url = "https://files.pythonhosted.org/packages/42/56/ed5f492bd553a31c8e28d621f8256f2c7b1a133b28f73525d96ca355891a/wasmtime-45.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a499f6ab0eebb70dca83d6a4904b743cd122f322af3abe86af08ad753533d946", size = 8582001, upload-time = "2026-05-26T17:57:28.883Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/9b41740da83f51014b88181c9086de0ed75d736a5329baff7323c4fb6eff/wasmtime-45.0.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:bef65282b7de744106a91da43e4d06ba19d2d587bc54abb83b3e757f0c4fc030", size = 8633462, upload-time = "2026-05-26T17:57:31.423Z" }, + { url = "https://files.pythonhosted.org/packages/ea/63/49d8317706a108d9ed1d4166d0fc710796da1b20e591a98a96575dec367a/wasmtime-45.0.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a0b6ca14b4628a5d1ffa91ccf2c0f2c58fa171f126ec085d564b09d5795395dd", size = 9712524, upload-time = "2026-05-26T17:57:33.839Z" }, + { url = "https://files.pythonhosted.org/packages/20/71/8e31ea472ceb934e7261ac59a786e82cd82b4d4dcb7c870d498aa9c3c21e/wasmtime-45.0.0-py3-none-win_amd64.whl", hash = "sha256:1736a70a48f713aaf1a878514d29cc6f554213b5431e04447813a3b9b4320381", size = 8019039, upload-time = "2026-05-26T17:57:36.04Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d1/ac536e92ac95a02e137be5b6829f15b87d5eef93ace32e5ee8035155b839/wasmtime-45.0.0-py3-none-win_arm64.whl", hash = "sha256:ae9726590e6d90c6305b8b507c93468b145204d4390aa9a2e29e26babcae110e", size = 6845659, upload-time = "2026-05-26T17:57:37.696Z" }, ] [[package]] @@ -2767,14 +2974,14 @@ wheels = [ [[package]] name = "werkzeug" -version = "3.1.6" +version = "3.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/f1/ee81806690a87dab5f5653c1f146c92bc066d7f4cebc603ef88eb9e13957/werkzeug-3.1.6.tar.gz", hash = "sha256:210c6bede5a420a913956b4791a7f4d6843a43b6fcee4dfa08a65e93007d0d25", size = 864736, upload-time = "2026-02-19T15:17:18.884Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/b2/381be8cfdee792dd117872481b6e378f85c957dd7c5bca38897b08f765fd/werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44", size = 875852, upload-time = "2026-04-02T18:49:14.268Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/ec/d58832f89ede95652fd01f4f24236af7d32b70cab2196dfcc2d2fd13c5c2/werkzeug-3.1.6-py3-none-any.whl", hash = "sha256:7ddf3357bb9564e407607f988f683d72038551200c704012bb9a4c523d42f131", size = 225166, upload-time = "2026-02-19T15:17:17.475Z" }, + { url = "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50", size = 226459, upload-time = "2026-04-02T18:49:12.72Z" }, ] [[package]] @@ -2788,104 +2995,107 @@ wheels = [ [[package]] name = "wrapt" -version = "1.17.3" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/8f/aeb76c5b46e273670962298c23e7ddde79916cb74db802131d49a85e4b7d/wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0", size = 55547, upload-time = "2025-08-12T05:53:21.714Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/9f/06263fcd8ad6c405f05a3905fd7a84dd3176eb5ad46e44bccc0cd16348bb/wrapt-2.2.1.tar.gz", hash = "sha256:6744f504375775d7609c82c8d3d94af1c9a6f05586984536905908ba905277b9", size = 127620, upload-time = "2026-05-22T14:49:43.056Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/23/bb82321b86411eb51e5a5db3fb8f8032fd30bd7c2d74bfe936136b2fa1d6/wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04", size = 53482, upload-time = "2025-08-12T05:51:44.467Z" }, - { url = "https://files.pythonhosted.org/packages/45/69/f3c47642b79485a30a59c63f6d739ed779fb4cc8323205d047d741d55220/wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2", size = 38676, upload-time = "2025-08-12T05:51:32.636Z" }, - { url = "https://files.pythonhosted.org/packages/d1/71/e7e7f5670c1eafd9e990438e69d8fb46fa91a50785332e06b560c869454f/wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c", size = 38957, upload-time = "2025-08-12T05:51:54.655Z" }, - { url = "https://files.pythonhosted.org/packages/de/17/9f8f86755c191d6779d7ddead1a53c7a8aa18bccb7cea8e7e72dfa6a8a09/wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775", size = 81975, upload-time = "2025-08-12T05:52:30.109Z" }, - { url = "https://files.pythonhosted.org/packages/f2/15/dd576273491f9f43dd09fce517f6c2ce6eb4fe21681726068db0d0467096/wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd", size = 83149, upload-time = "2025-08-12T05:52:09.316Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c4/5eb4ce0d4814521fee7aa806264bf7a114e748ad05110441cd5b8a5c744b/wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05", size = 82209, upload-time = "2025-08-12T05:52:10.331Z" }, - { url = "https://files.pythonhosted.org/packages/31/4b/819e9e0eb5c8dc86f60dfc42aa4e2c0d6c3db8732bce93cc752e604bb5f5/wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418", size = 81551, upload-time = "2025-08-12T05:52:31.137Z" }, - { url = "https://files.pythonhosted.org/packages/f8/83/ed6baf89ba3a56694700139698cf703aac9f0f9eb03dab92f57551bd5385/wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390", size = 36464, upload-time = "2025-08-12T05:53:01.204Z" }, - { url = "https://files.pythonhosted.org/packages/2f/90/ee61d36862340ad7e9d15a02529df6b948676b9a5829fd5e16640156627d/wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6", size = 38748, upload-time = "2025-08-12T05:53:00.209Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c3/cefe0bd330d389c9983ced15d326f45373f4073c9f4a8c2f99b50bfea329/wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18", size = 36810, upload-time = "2025-08-12T05:52:51.906Z" }, - { url = "https://files.pythonhosted.org/packages/52/db/00e2a219213856074a213503fdac0511203dceefff26e1daa15250cc01a0/wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7", size = 53482, upload-time = "2025-08-12T05:51:45.79Z" }, - { url = "https://files.pythonhosted.org/packages/5e/30/ca3c4a5eba478408572096fe9ce36e6e915994dd26a4e9e98b4f729c06d9/wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85", size = 38674, upload-time = "2025-08-12T05:51:34.629Z" }, - { url = "https://files.pythonhosted.org/packages/31/25/3e8cc2c46b5329c5957cec959cb76a10718e1a513309c31399a4dad07eb3/wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f", size = 38959, upload-time = "2025-08-12T05:51:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/5d/8f/a32a99fc03e4b37e31b57cb9cefc65050ea08147a8ce12f288616b05ef54/wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311", size = 82376, upload-time = "2025-08-12T05:52:32.134Z" }, - { url = "https://files.pythonhosted.org/packages/31/57/4930cb8d9d70d59c27ee1332a318c20291749b4fba31f113c2f8ac49a72e/wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1", size = 83604, upload-time = "2025-08-12T05:52:11.663Z" }, - { url = "https://files.pythonhosted.org/packages/a8/f3/1afd48de81d63dd66e01b263a6fbb86e1b5053b419b9b33d13e1f6d0f7d0/wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5", size = 82782, upload-time = "2025-08-12T05:52:12.626Z" }, - { url = "https://files.pythonhosted.org/packages/1e/d7/4ad5327612173b144998232f98a85bb24b60c352afb73bc48e3e0d2bdc4e/wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2", size = 82076, upload-time = "2025-08-12T05:52:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/bb/59/e0adfc831674a65694f18ea6dc821f9fcb9ec82c2ce7e3d73a88ba2e8718/wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89", size = 36457, upload-time = "2025-08-12T05:53:03.936Z" }, - { url = "https://files.pythonhosted.org/packages/83/88/16b7231ba49861b6f75fc309b11012ede4d6b0a9c90969d9e0db8d991aeb/wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77", size = 38745, upload-time = "2025-08-12T05:53:02.885Z" }, - { url = "https://files.pythonhosted.org/packages/9a/1e/c4d4f3398ec073012c51d1c8d87f715f56765444e1a4b11e5180577b7e6e/wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a", size = 36806, upload-time = "2025-08-12T05:52:53.368Z" }, - { url = "https://files.pythonhosted.org/packages/9f/41/cad1aba93e752f1f9268c77270da3c469883d56e2798e7df6240dcb2287b/wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0", size = 53998, upload-time = "2025-08-12T05:51:47.138Z" }, - { url = "https://files.pythonhosted.org/packages/60/f8/096a7cc13097a1869fe44efe68dace40d2a16ecb853141394047f0780b96/wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba", size = 39020, upload-time = "2025-08-12T05:51:35.906Z" }, - { url = "https://files.pythonhosted.org/packages/33/df/bdf864b8997aab4febb96a9ae5c124f700a5abd9b5e13d2a3214ec4be705/wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd", size = 39098, upload-time = "2025-08-12T05:51:57.474Z" }, - { url = "https://files.pythonhosted.org/packages/9f/81/5d931d78d0eb732b95dc3ddaeeb71c8bb572fb01356e9133916cd729ecdd/wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828", size = 88036, upload-time = "2025-08-12T05:52:34.784Z" }, - { url = "https://files.pythonhosted.org/packages/ca/38/2e1785df03b3d72d34fc6252d91d9d12dc27a5c89caef3335a1bbb8908ca/wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9", size = 88156, upload-time = "2025-08-12T05:52:13.599Z" }, - { url = "https://files.pythonhosted.org/packages/b3/8b/48cdb60fe0603e34e05cffda0b2a4adab81fd43718e11111a4b0100fd7c1/wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396", size = 87102, upload-time = "2025-08-12T05:52:14.56Z" }, - { url = "https://files.pythonhosted.org/packages/3c/51/d81abca783b58f40a154f1b2c56db1d2d9e0d04fa2d4224e357529f57a57/wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc", size = 87732, upload-time = "2025-08-12T05:52:36.165Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b1/43b286ca1392a006d5336412d41663eeef1ad57485f3e52c767376ba7e5a/wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe", size = 36705, upload-time = "2025-08-12T05:53:07.123Z" }, - { url = "https://files.pythonhosted.org/packages/28/de/49493f962bd3c586ab4b88066e967aa2e0703d6ef2c43aa28cb83bf7b507/wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c", size = 38877, upload-time = "2025-08-12T05:53:05.436Z" }, - { url = "https://files.pythonhosted.org/packages/f1/48/0f7102fe9cb1e8a5a77f80d4f0956d62d97034bbe88d33e94699f99d181d/wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6", size = 36885, upload-time = "2025-08-12T05:52:54.367Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f6/a933bd70f98e9cf3e08167fc5cd7aaaca49147e48411c0bd5ae701bb2194/wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22", size = 23591, upload-time = "2025-08-12T05:53:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8b/84bc1ea68b620fe0e2696a8cff07e82f4b962d952ab14efee8955997bb70/wrapt-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0f68f478004475d97906686e702ddbddeaf717c0b68ad2794384308f2dc713ae", size = 80093, upload-time = "2026-05-22T14:47:27.074Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8f/64ec81194a0bc708d9720174c998c8a32116e82b5b32c04e20a7fe01176c/wrapt-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e422b2d647a65d6b080cad5accd09055d3809bdff00c76fba8dca00ca935572a", size = 81183, upload-time = "2026-05-22T14:47:29.062Z" }, + { url = "https://files.pythonhosted.org/packages/94/c2/3d186944aae923631d1def58f4c4ff8f0b6309906afc0b6978de3e69b3e0/wrapt-2.2.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:036dfb40128819a751c6f451c6b9c10172c49e4c401aebcdb8ecf2aec1683598", size = 152494, upload-time = "2026-05-22T14:47:30.583Z" }, + { url = "https://files.pythonhosted.org/packages/01/d1/6b3d0ea995b867d2862aad5619bd5e17de09a9d64a821f46832dcd272d40/wrapt-2.2.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09ac16c081bebfd15d8e4dfa5bdc805990bbd52249ecff22530da7a129d6120b", size = 154310, upload-time = "2026-05-22T14:47:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/f9/4b/37ecb90a8c3753e580327fb40731a984b754e3df65d2ef932bf359fe4adc/wrapt-2.2.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:07be671fa8875971222b0ba9059ed8b4dc738631122feba17c93aa36b4213e9a", size = 149002, upload-time = "2026-05-22T14:47:34.021Z" }, + { url = "https://files.pythonhosted.org/packages/e7/d0/918884d9dfa84d0d135b42a51c00910f5c5447fe7a5e211a8e16ac324dd4/wrapt-2.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:93fc2bf40cd7f4a0256010dce073d44eeb4a351b9bca94d0477ce2b6e62532b3", size = 153185, upload-time = "2026-05-22T14:47:35.722Z" }, + { url = "https://files.pythonhosted.org/packages/4c/00/382299d8ced610b29b59b099a89eda821e8c489aa152b7183748ac83f32a/wrapt-2.2.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ba519b2d765df9871a25879e6f7fa78948ea59a2a31f9c1a257e34b651994afc", size = 148040, upload-time = "2026-05-22T14:47:37.052Z" }, + { url = "https://files.pythonhosted.org/packages/6c/46/62a79b79e35bbebb1207ca5d15b81192f37f20cc5659cf4e3ce955b7fcc8/wrapt-2.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9011395be8db1827d106c6449b4bb6dd17e331ff6ec521f227e4588f1c78e46f", size = 151773, upload-time = "2026-05-22T14:47:38.713Z" }, + { url = "https://files.pythonhosted.org/packages/a1/db/95c152151d206d4b430516c89725306e92484072f38e65492afde63f6d19/wrapt-2.2.1-cp310-cp310-win32.whl", hash = "sha256:a8f7176b83664af44567e9cc06e0d3827823fcc1a5e52307ebb8ac3aa95860b9", size = 77393, upload-time = "2026-05-22T14:47:40.061Z" }, + { url = "https://files.pythonhosted.org/packages/13/d3/882d50452c6fbd13f24fe5d2644b97cdad2565a7e1522cbb6312de8a52cf/wrapt-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:d7f513d3185e6fec82d0c3518f2e6365d8b4e49f5f45f29640d5162d56a23b54", size = 80350, upload-time = "2026-05-22T14:47:41.194Z" }, + { url = "https://files.pythonhosted.org/packages/58/0f/148376523b4e370692286a9ba14d5715cf3c5b86da3bd3630926367b6b73/wrapt-2.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:44255c84bc57554fed822e83e70036b51afa9edb56fc7ca56c54410ece7898c9", size = 79149, upload-time = "2026-05-22T14:47:42.835Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ac/4370bde262c0e633e6c4f0e56d55095710024cf9a5cecc20c59a10de483c/wrapt-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd57607acc85678925940bd5df0385ff8332083a32fa8d7a43f8767f4997263c", size = 80321, upload-time = "2026-05-22T14:47:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/eb/79/b8ff3a61e71babf58a8cf4c0d63358e8bad383e15bf7f35e62d2f6b6e4a4/wrapt-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ae574d65c9fa8e86f64f6a7c2668f9fcd507b183e0e577619f504b883cb0a6c", size = 81216, upload-time = "2026-05-22T14:47:45.243Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fd/c0cac1f77c9c4f6fe58a920ca632ce379bb8be928720e11e8d73de28a5e9/wrapt-2.2.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9a04c28c10ba7fd12842b109d2edb0678872a2fe65277ca4ff06a0d61edee245", size = 159208, upload-time = "2026-05-22T14:47:47.176Z" }, + { url = "https://files.pythonhosted.org/packages/d9/4f/744132a7b2fbefa6b81118ec5942eca5fc2e9a129f9055a0c5e46885a549/wrapt-2.2.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e2f02472a1cbbf3884b365714a810b5947134a95ad6952b554cb8cce9d492b0", size = 160322, upload-time = "2026-05-22T14:47:49.04Z" }, + { url = "https://files.pythonhosted.org/packages/d6/95/b7cd9a22a06cf93e6482904ee6afc956248983553593fd1009296d1b3b31/wrapt-2.2.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac2745950b2bff80219c15ebf2fa9d8427eba7e249739f97e55c9d169e47e9e1", size = 153243, upload-time = "2026-05-22T14:47:50.386Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4a/eb79423192015f46f0db2872e7e04a3dde8d359b83411e8959e7c9287eaa/wrapt-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:67a97e5b6c457f0cd3cfc19ebb2d84463e60c3ece754cc831e4281a3ca29bb18", size = 159231, upload-time = "2026-05-22T14:47:51.753Z" }, + { url = "https://files.pythonhosted.org/packages/ec/dc/435015b58ce33c6fc4104158fa91ddb0e809ab03a5751fb7465d1d461456/wrapt-2.2.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:c803a3d331796255af51ba2c79ed0ac8275865b516c09e61f248d1e7aff31ce9", size = 152351, upload-time = "2026-05-22T14:47:53.214Z" }, + { url = "https://files.pythonhosted.org/packages/77/ac/5d203f98df8fd136b95c5227139aea02d34505e18baf812d0c005df61963/wrapt-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9b984d1eb252145d6302c1dbd5e87fc6d404d45531447c84eadec04bf1fcb027", size = 158347, upload-time = "2026-05-22T14:47:54.982Z" }, + { url = "https://files.pythonhosted.org/packages/52/2f/a92427dbdc74e54c1674abbed27e61b2cb5e7a94441b8c1270c70671d928/wrapt-2.2.1-cp311-cp311-win32.whl", hash = "sha256:8a983a603a18c8708f024f7f6991b2e66159219abbf894634c5056243c55f3cd", size = 77562, upload-time = "2026-05-22T14:47:56.275Z" }, + { url = "https://files.pythonhosted.org/packages/c8/56/987b9c13b3e1c1a3c6de71284076f996b79caec90e75a87c044a40c23db9/wrapt-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:9c210a6994b21aa9b29e81c8d11560e8fdab54c117e9cff37870d0a27bde1343", size = 80616, upload-time = "2026-05-22T14:47:57.854Z" }, + { url = "https://files.pythonhosted.org/packages/7e/25/d01f560888d99d94a959c85533de349ce68d71ace3f2591d6ea8f632cfed/wrapt-2.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:401229e9d63ca09f9b8891ecf83798d26c11bbb445d11ed9f1836b6d4585b38a", size = 79025, upload-time = "2026-05-22T14:47:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/89/0c/bfae7b9401583b6d05938cd16dedc43857d96da2f8a3d50d78cc515bf6ff/wrapt-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ffad790d9d11d8ecf9f17c4bb671a5b4089e4d8b575c46c5129597f41f836b0", size = 81021, upload-time = "2026-05-22T14:48:00.313Z" }, + { url = "https://files.pythonhosted.org/packages/26/58/80f6a6599f933f4caecc1cb3ee88a04faf81e8b9bddbd6109c688dd63e0f/wrapt-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:628f5220c7a904d5fc78f7075c8d7871433eb6d035c94728a22fdf85f193d2a8", size = 81692, upload-time = "2026-05-22T14:48:01.49Z" }, + { url = "https://files.pythonhosted.org/packages/17/93/fb357cc7847c58a8ae790be718903afa81a28d23e642c843dc4129e8a0b2/wrapt-2.2.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:61acce4257a9883669703c525447c5b4c392edf0f987ae77ec32668440158f0e", size = 169364, upload-time = "2026-05-22T14:48:02.791Z" }, + { url = "https://files.pythonhosted.org/packages/aa/0b/76b601ee309a8bd556af0eecb184394c20b3c49aa9c8e085aa1ffacc2568/wrapt-2.2.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:727ab4244622cd6ad2390f322642090c877d2e83a608d2653a7643ae5368d926", size = 171079, upload-time = "2026-05-22T14:48:04.22Z" }, + { url = "https://files.pythonhosted.org/packages/cd/87/ee3f32d5658e3e26d3e0e457922b47a36dd3bfbdfee7f97bb3e802344a66/wrapt-2.2.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:03df9ebed4c73ab93fa8c07e3d41d818dfca1852b15731a3de59457b27814624", size = 160205, upload-time = "2026-05-22T14:48:05.553Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d0/ae2fd64277a67f5d7bffcf2d05eea1e476263fb2a072baf0b0129ab85984/wrapt-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0d9ff006f420b2ec8296aa56ade43ea7da3e997e85769f0aafc5e0661aacb710", size = 168922, upload-time = "2026-05-22T14:48:07.132Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f3/2d541a060c5bbafb9400bca4917e4d78bfd1f239f404782c86831a8f6b29/wrapt-2.2.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:844c858fc3bb7eacc0ba8efa904935d16aac6a4470948ad1e7e55c9f5a2a665f", size = 158388, upload-time = "2026-05-22T14:48:08.629Z" }, + { url = "https://files.pythonhosted.org/packages/1d/68/8d92c8800c57e93cb116ae9e9d6cbafc34fade5ee9f9107b6f203fb4dc35/wrapt-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87bacdaf225117a342a20d9c03438d701c02112f6e3f351ce9b7f32354f14797", size = 167682, upload-time = "2026-05-22T14:48:10.042Z" }, + { url = "https://files.pythonhosted.org/packages/30/72/83ea3790ea352439442349388e29ff07b76e0686265f9088bbb505d1608d/wrapt-2.2.1-cp312-cp312-win32.whl", hash = "sha256:2f8c90c8afde51969487be4e1343ae049b268854877d415c2510baf833775052", size = 77857, upload-time = "2026-05-22T14:48:11.782Z" }, + { url = "https://files.pythonhosted.org/packages/ef/cb/99450668dd3502d62a54a1c8aa56e44f34cb8c1261b381cfe2e7926c3b75/wrapt-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ce32763ac31ce94fe9aada947e479b1975012bff166da409b4b9e4e376cf7e5", size = 80825, upload-time = "2026-05-22T14:48:13.046Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3a/87512881be64e743f9ee4c66f4cbe8e884974bef2a5989af71f999653ac7/wrapt-2.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d1b4d0e0c2119587a31f5c029abd547e0c81d93b89d394566fe1588659eb579", size = 79087, upload-time = "2026-05-22T14:48:14.323Z" }, + { url = "https://files.pythonhosted.org/packages/53/46/29ac9daf11a86c22a8c38cd9236c62928ccae83f7ceb06bd3b0467cf9d05/wrapt-2.2.1-py3-none-any.whl", hash = "sha256:3aafea2975caef8ca49400640dde02cc7426e798f24870ed01f490bc3cffd32f", size = 61000, upload-time = "2026-05-22T14:49:41.593Z" }, ] [[package]] name = "yarl" -version = "1.20.1" +version = "1.24.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +sdist = { url = "https://files.pythonhosted.org/packages/79/12/1e8f37460ea0f7eb59c221fdaf0ed75e7ac43e97f8093b9c6f411df50a78/yarl-1.24.2.tar.gz", hash = "sha256:9ac374123c6fd7abf64d1fec93962b0bd4ee2c19751755a762a72dd96c0378f8", size = 210798, upload-time = "2026-05-19T21:31:05.599Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, + { url = "https://files.pythonhosted.org/packages/3f/df/f1c7a3de0831cd83194f1a85c5bb431b13f81e6b45079314c86d1c4ef3f2/yarl-1.24.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5249a113065c2b7a958bc699759e359cd61cfc81e3069662208f48f191b7ed12", size = 129057, upload-time = "2026-05-19T21:27:47.564Z" }, + { url = "https://files.pythonhosted.org/packages/48/41/7daafb32dd7562bf45b1ce56562e7e1a9146f6479b6456873eb8a3413c40/yarl-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4425fa244fbf530b006d0c5f79ce920114cfff5b4f5f6056e669f8e160fdc0", size = 91545, upload-time = "2026-05-19T21:27:50.089Z" }, + { url = "https://files.pythonhosted.org/packages/a8/8f/7b3ec212f1ea0683f55f978e3246bc313c38818664edfc97a9f349a4901e/yarl-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15c0b5e49d3c44e2a0b93e6a49476c5edad0a7686b92c395765a7ea775572a75", size = 91380, upload-time = "2026-05-19T21:27:51.953Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1b/8bafab7db23b0567ae9db749099b329d91e3b82bc6028b2050ba583e116c/yarl-1.24.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:246d32a53a947c8f0189f5d699cbd4c7036de45d9359e13ba238d1239678c727", size = 105957, upload-time = "2026-05-19T21:27:53.98Z" }, + { url = "https://files.pythonhosted.org/packages/7f/77/21030c2f8d21d21559719beafc772ada2014be933418ed1eaed9cc800e42/yarl-1.24.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:64480fb3e4d4ed9ed71c48a91a477384fc342a50ca30071d2f8a88d51d9c9413", size = 97242, upload-time = "2026-05-19T21:27:55.981Z" }, + { url = "https://files.pythonhosted.org/packages/50/d8/f9ea63d1b6aa910a866e089d871fff6cbd49caab29b86b35221a62dfa0d5/yarl-1.24.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:349de4701dc3760b6e876628423a8f147ef4f5599d10aba1e10702075d424ed9", size = 114719, upload-time = "2026-05-19T21:27:58.037Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a3/04e0ee98ac58a249ea7ed75223f5f901ba81a834f0b4921b58e5cec11757/yarl-1.24.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d162677af8d5d3d6ebab8394b021f4d041ac107a4b705873148a77a49dc9e1b2", size = 112140, upload-time = "2026-05-19T21:27:59.618Z" }, + { url = "https://files.pythonhosted.org/packages/02/ad/0b9cc9f38a7324a7eb1d80f834eaa5283d17e9271bbda3186e598dddaeac/yarl-1.24.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f5f5c6ec23a9043f2d139cc072f53dd23168d202a334b9b2fda8de4c3e890d90", size = 106721, upload-time = "2026-05-19T21:28:02.586Z" }, + { url = "https://files.pythonhosted.org/packages/65/e7/a52478ebfc66ec989e085c6ae038b9f1bfa4190baa193b133b669c709e2f/yarl-1.24.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:60de6742447fbbf697f16f070b8a443f1b5fe6ca3826fbef9fe70ecd5328e643", size = 106478, upload-time = "2026-05-19T21:28:04.523Z" }, + { url = "https://files.pythonhosted.org/packages/04/d8/5508530fea8472542de00013ae280765fc938ee196fc4030c43a498afb36/yarl-1.24.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acf93187c3710e422368eb768aee98db551ec7c85adc250207a95c16548ab7ac", size = 105423, upload-time = "2026-05-19T21:28:06.515Z" }, + { url = "https://files.pythonhosted.org/packages/84/f1/ece28505e9628e8b756e11bb4f28864a17cc33b6b44db4d2aaf0622bf630/yarl-1.24.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f4b0352fd41fd34b6651934606268816afd6914d09626f9bcbbf018edb0afb3f", size = 99878, upload-time = "2026-05-19T21:28:08.637Z" }, + { url = "https://files.pythonhosted.org/packages/3f/52/fb5d34529b46dd84013afcfb30b8d2bc2832ed03d412736f577d604fa393/yarl-1.24.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6b208bb939099b4b297438da4e9b25357f0b1c791888669b963e45b203ea9f36", size = 114025, upload-time = "2026-05-19T21:28:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/43/f0/ff9d31aaab024f7a251c0ed308a98ae29bf9f7dc344e78f28b1322431ca2/yarl-1.24.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4b85b8825e631295ff4bc8943f7471d54c533a9360bbe15ebb38e018b555bb8a", size = 105613, upload-time = "2026-05-19T21:28:12.784Z" }, + { url = "https://files.pythonhosted.org/packages/31/7d/3296fb3f3ecd52bf9ae6c16b0895c1cda7e9170a2083861552b683f70264/yarl-1.24.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e26acf20c26cb4fefc631fdb75aca2a6b8fa8b7b5d7f204fb6a8f1e63c706f53", size = 111665, upload-time = "2026-05-19T21:28:14.393Z" }, + { url = "https://files.pythonhosted.org/packages/1a/74/77aa6ddaca4fbf42e45e675a465c43956dd40702281049975a2aa04eae59/yarl-1.24.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:819ca24f8eafcfb683c1bd5f44f2f488cea1274eb8944731ffd2e1f10f619342", size = 106914, upload-time = "2026-05-19T21:28:15.893Z" }, + { url = "https://files.pythonhosted.org/packages/d8/02/7611f22cd1d4ed7373eb7f9ee21fde1046edba2e7c0e514880d760352f48/yarl-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:5cb0f995a901c36be096ccbf4c673591c2faabbe96279598ffaec8c030f85bf4", size = 92658, upload-time = "2026-05-19T21:28:17.471Z" }, + { url = "https://files.pythonhosted.org/packages/91/00/671d0add79938127292839ae44506ce2f7fe8909c72d5a931864f128fd0b/yarl-1.24.2-cp310-cp310-win_arm64.whl", hash = "sha256:f408eace7e22a68b467a0562e0d27d322f91fe3eaaa6f466b962c6cfaea9fa39", size = 87887, upload-time = "2026-05-19T21:28:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c5/1ce244152ff2839645e7cae92f90e7bafcb2c52bea7ff586ac714f14f5df/yarl-1.24.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:36348bebb147b83818b9d7e673ea4debc75970afc6ffdc7e3975ad05ce5a58c1", size = 128971, upload-time = "2026-05-19T21:28:20.543Z" }, + { url = "https://files.pythonhosted.org/packages/87/5a/00f36967203ed89cb3acd2c8ed526cc3fed9418eb70ce128160a911c8499/yarl-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a97e42c8a2233f2f279ecadd9e4a037bcb5d813b78435e8eedd4db5a9e9708c", size = 91507, upload-time = "2026-05-19T21:28:22.556Z" }, + { url = "https://files.pythonhosted.org/packages/31/d0/1fb0c1cd27288f39f6974da4318c32768d72c9890984541fdf1e2e32a51d/yarl-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d027d56f1035e339d1001ac33eceab5b2ec8e42e449787bb75e289fb9a5cd1d", size = 91343, upload-time = "2026-05-19T21:28:24.092Z" }, + { url = "https://files.pythonhosted.org/packages/03/ce/d4a646508bed2f8dec6435b40166fe9308dd191262033d3f307b2bbcaecd/yarl-1.24.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a6377060e7927187a42b7eb202090cbe2b34933a4eeaf90e3bd9e33432e5cae", size = 105704, upload-time = "2026-05-19T21:28:25.872Z" }, + { url = "https://files.pythonhosted.org/packages/4b/07/b3278e82d8bc41485bcf6d856cd0433262593de615b1d3dc43bd3f5bead4/yarl-1.24.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:17076578bce0049a5ce57d14ad1bded391b68a3b213e9b81b0097b090244999a", size = 97281, upload-time = "2026-05-19T21:28:27.352Z" }, + { url = "https://files.pythonhosted.org/packages/17/5b/4cee6e7c92e487bebe7afc797da0aa54a248ab4e776a68fe369ec29665a5/yarl-1.24.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:50713f1d4d6be6375bb178bb43d140ee1acb8abe589cd723320b7925a275be1e", size = 114020, upload-time = "2026-05-19T21:28:29.458Z" }, + { url = "https://files.pythonhosted.org/packages/5c/82/111076571545a7d4f9cca3fbd5c6f40615af58642be09f12328f48022468/yarl-1.24.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:34263e2fa8fb5bb63a0d97706cda38edbad62fddb58c7f12d6acbc092812aa50", size = 111450, upload-time = "2026-05-19T21:28:31.262Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ec/08f671f69a444d704aeecebf92af659b67b97a869942411d0a578b08c334/yarl-1.24.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49016d82f032b1bd1e10b01078a7d29ae71bf468eeae0ea22df8bab691e60003", size = 106384, upload-time = "2026-05-19T21:28:32.856Z" }, + { url = "https://files.pythonhosted.org/packages/e5/86/ce41e7a7a199340b2330d52b60f25c4074b6636dd0e60b1a80d31a9db042/yarl-1.24.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3f6d2c216318f8f32038ca3f72501ba08536f0fd18a36e858836b121b2deed9f", size = 106153, upload-time = "2026-05-19T21:28:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5d/31be8a729531ab3e55ac3e7e5c800be8c89ea98947f418b2f6ea259fb6ee/yarl-1.24.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:08d3a33218e0c64393e7610284e770409a9c31c429b078bcb24096ed0a783b8f", size = 105322, upload-time = "2026-05-19T21:28:36.642Z" }, + { url = "https://files.pythonhosted.org/packages/47/9b/b57afb22b386ae87ac9940f09878b98d8c333f89113e6fc96fcf4ca9eb64/yarl-1.24.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5d699376c4ca3cba49bbfae3a05b5b70ded572937171ce1e0b8d87118e2ba294", size = 99057, upload-time = "2026-05-19T21:28:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/a3/4f/06348c27c8389256c313e8a57d796808fc0264c915dd5e7cfd3c0e314dc7/yarl-1.24.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a1cab588b4fa14bea2e55ebea27478adfb05372f47573738e1acc4a36c0b05d2", size = 113502, upload-time = "2026-05-19T21:28:40.091Z" }, + { url = "https://files.pythonhosted.org/packages/5f/1c/284f307b298e4a17b7943b07d9d7ecc4151537f8d137ba51f3bb6c31ca20/yarl-1.24.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ec87ccc31bd21db7ad009d8572c127c1000f268517618a4cc09adba3c2a7f21c", size = 105253, upload-time = "2026-05-19T21:28:41.987Z" }, + { url = "https://files.pythonhosted.org/packages/c8/bf/0de123bec8619e45c80cbded9085f61b5b4a9eddb8abe6d25d28ee1ec866/yarl-1.24.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d1dd47a22843b212baa8d74f37796815d43bd046b42a0f41e9da433386c3136b", size = 111345, upload-time = "2026-05-19T21:28:43.93Z" }, + { url = "https://files.pythonhosted.org/packages/90/af/0248eb065e51129d2a9b2436cd1b5c772c19a6b04e5b6a186955671e3319/yarl-1.24.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7b54b9c67c2b06bd7b9a77253d242124b9c95d2c02def5a1144001ee547dd9d5", size = 106558, upload-time = "2026-05-19T21:28:45.806Z" }, + { url = "https://files.pythonhosted.org/packages/21/3c/f960d7a65ef97d8ba9b424fb5128796a4bc710fc6df2ddbbd7dfdc3bbd20/yarl-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:f8fdbcff8b2c7c9284e60c196f693588598ddcee31e11c18e14949ce44519d45", size = 92808, upload-time = "2026-05-19T21:28:48.465Z" }, + { url = "https://files.pythonhosted.org/packages/03/1a/49fb03750e4de4d2284cd5b885a383133c34eef45bd59631b2bb8b7e81e8/yarl-1.24.2-cp311-cp311-win_arm64.whl", hash = "sha256:b32c37a7a337e90822c45797bf3d79d60875cfcccd3ecc80e9f453d87026c122", size = 87610, upload-time = "2026-05-19T21:28:50.07Z" }, + { url = "https://files.pythonhosted.org/packages/f0/da/866bcb01076ba49d2b42b309867bed3826421f1c479655eb7a607b44f20b/yarl-1.24.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b975866c184564c827e0877380f0dae57dcca7e52782128381b72feff6dfceb8", size = 129957, upload-time = "2026-05-19T21:28:51.695Z" }, + { url = "https://files.pythonhosted.org/packages/bf/1d/fcefb70922ea2268a8971d8e5874d9a8218644200fb8465f1dcad55e6851/yarl-1.24.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3b075301a2836a0e297b1b658cb6d6135df535d62efefdd60366bd589c2c82f2", size = 92164, upload-time = "2026-05-19T21:28:53.242Z" }, + { url = "https://files.pythonhosted.org/packages/29/b6/170e2b8d4e3bc30e6bfdcca53556537f5bf595e938632dfcb059311f3ff6/yarl-1.24.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ae44649b00947634ab0dab2a374a638f52923a6e67083f2c156cd5cbd1a881d", size = 91688, upload-time = "2026-05-19T21:28:54.865Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a5/c9f655d5553ea0b99fdac9d6a99ad3f9b3e73b8e5758bb46f58c9831f74c/yarl-1.24.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:507cc19f0b45454e2d6dcd62ff7d062b9f77a2812404e62dbdaec05b50faa035", size = 102902, upload-time = "2026-05-19T21:28:56.963Z" }, + { url = "https://files.pythonhosted.org/packages/5d/bc/6b9664d815d79af4ee553337f9d606c56bbf269186ada9172de45f1b5f60/yarl-1.24.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4c17bad5a530912d2111825d3f05e89bab2dd376aaa8cbc77e449e6db63e576", size = 97931, upload-time = "2026-05-19T21:28:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/98/ec/32ba48acae30fecd60928f5791188b80a9d6ee3840507ffda29fecd37b71/yarl-1.24.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5f0cbb112838a4a293985b6ed73948a547dadcc1ba6d2089938e7abdedceef8", size = 111030, upload-time = "2026-05-19T21:29:00.148Z" }, + { url = "https://files.pythonhosted.org/packages/82/5a/6f4cd081e5f4934d2ae3a8ef4abe3afacc010d26f0035ee91b35cd7d7c37/yarl-1.24.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ec8356b8a6afcf81fc7aeeef13b1ff7a49dec00f313394bbb9e83830d32ccd7", size = 110392, upload-time = "2026-05-19T21:29:02.155Z" }, + { url = "https://files.pythonhosted.org/packages/7a/da/323a01c349bd5fb01bb6652e314d9bb218cee630a736bdb810ad50e4013f/yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7e7ebcdef69dec6c6451e616f32b622a6d4a2e92b445c992f7c8e5274a6bbc4c", size = 105612, upload-time = "2026-05-19T21:29:04.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/80/264ab684f181e1a876389374519ff05d10248725535ae2ac4e8ac4e563d6/yarl-1.24.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:47a55d6cf6db2f401017a9e96e5288844e5051911fb4e0c8311a3980f5e59a7d", size = 104487, upload-time = "2026-05-19T21:29:06.491Z" }, + { url = "https://files.pythonhosted.org/packages/41/07/efabe5df87e96d7ad5959760b888344be48cd6884db127b407c6b5503adc/yarl-1.24.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3065657c80a2321225e804048597ad55658a7e76b32d6f5ee4074d04c50401db", size = 102333, upload-time = "2026-05-19T21:29:08.267Z" }, + { url = "https://files.pythonhosted.org/packages/44/0c/bcf7c42603e1009295f586d8890f2ba032c8b53310e815adf0a202c73d9f/yarl-1.24.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cb84b80d88e19ede158619b80813968713d8d008b0e2497a576e6a0557d50712", size = 99025, upload-time = "2026-05-19T21:29:10.682Z" }, + { url = "https://files.pythonhosted.org/packages/4f/82/84482ab1a57a0f21a08afe6a7004c61d741f8f2ecc3b05c321577c612164/yarl-1.24.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:990de4f680b1c217e77ff0d6aa0029f9eb79889c11fb3e9a3942c7eba29c1996", size = 110507, upload-time = "2026-05-19T21:29:12.954Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8d/a546ba1dfe1b0f290e05fef145cd07614c0f15df1a707195e512d1e39d1d/yarl-1.24.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:abb8ec0323b80161e3802da3150ef660b41d0e9be2048b76a363d93eee992c2b", size = 103719, upload-time = "2026-05-19T21:29:14.893Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b6/267f2a09213138473adfce6b8a6e17791d7fee70bd4d9003218e4dec58b0/yarl-1.24.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e7977781f83638a4c73e0f88425563d70173e0dfd90ac006a45c65036293ee3c", size = 110438, upload-time = "2026-05-19T21:29:16.485Z" }, + { url = "https://files.pythonhosted.org/packages/48/2d/1c8d89c7c5f9cad9fb2902445d94e2ab1d7aa35de029afbb8ae95c42d00f/yarl-1.24.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e30dd55825dc554ec5b66a94953b8eda8745926514c5089dfcacecb9c99b5bd1", size = 105719, upload-time = "2026-05-19T21:29:18.367Z" }, + { url = "https://files.pythonhosted.org/packages/a7/25/722e3b93bd687009afb2d59a35e13d30ddd8f80571445bb0c4e4ce26ec66/yarl-1.24.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dafe10c12ddd4d120d528c4b5599c953bd7b12845347d507b95451195bb6cad", size = 92901, upload-time = "2026-05-19T21:29:20.014Z" }, + { url = "https://files.pythonhosted.org/packages/39/47/4486ccfb674c04854a1ef8aa77868b6a6f765feaf69633409d7ca4f02cb8/yarl-1.24.2-cp312-cp312-win_arm64.whl", hash = "sha256:044a09d8401fcf8681977faef6d286b8ade1e2d2e9dceda175d1cfa5ca496f30", size = 87229, upload-time = "2026-05-19T21:29:22.1Z" }, + { url = "https://files.pythonhosted.org/packages/fd/4d/4b880086bd0d3e034d25647be1d830afc3e3f610e98c4ab3490af6b1b6d5/yarl-1.24.2-py3-none-any.whl", hash = "sha256:2783d9226db8797636cd6896e4de81feed252d1db72265686c9558d97a4d94b9", size = 53576, upload-time = "2026-05-19T21:31:03.909Z" }, ]